From fdcd03e91d2a8335c0db37ca080c4b4f11ce8419 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 5 Dec 2023 15:21:25 +0100 Subject: [PATCH 01/33] Started working on contiguous scope modifier --- .../src/modifiers/simple_scope_modifier.py | 10 +- cursorless-talon/src/spoken_forms.json | 2 +- .../command/PartialTargetDescriptor.types.ts | 6 + .../ModifierStageFactoryImpl.ts | 7 ++ .../modifiers/ContiguousScopeStage.ts | 116 ++++++++++++++++++ .../spokenForms/defaultSpokenFormMapCore.ts | 1 + 6 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 packages/cursorless-engine/src/processTargets/modifiers/ContiguousScopeStage.ts diff --git a/cursorless-talon/src/modifiers/simple_scope_modifier.py b/cursorless-talon/src/modifiers/simple_scope_modifier.py index 7725623304..d655956983 100644 --- a/cursorless-talon/src/modifiers/simple_scope_modifier.py +++ b/cursorless-talon/src/modifiers/simple_scope_modifier.py @@ -15,7 +15,15 @@ ) def cursorless_simple_scope_modifier(m) -> dict[str, Any]: """Containing scope, every scope, etc""" + match m[0]: + case "every": + type = "everyScope" + case "contiguous": + type = "contiguousScope" + case _: + type = "containingScope" + return { - "type": "everyScope" if m[0] == "every" else "containingScope", + "type": type, "scopeType": m.cursorless_scope_type, } diff --git a/cursorless-talon/src/spoken_forms.json b/cursorless-talon/src/spoken_forms.json index 40a0fd16b1..59bbd53625 100644 --- a/cursorless-talon/src/spoken_forms.json +++ b/cursorless-talon/src/spoken_forms.json @@ -78,7 +78,7 @@ "empty": "keepEmptyFilter", "its": "inferPreviousMark" }, - "simple_scope_modifier": { "every": "every" }, + "simple_scope_modifier": { "every": "every", "slurp": "contiguous" }, "interior_modifier": { "inside": "interiorOnly" }, diff --git a/packages/common/src/types/command/PartialTargetDescriptor.types.ts b/packages/common/src/types/command/PartialTargetDescriptor.types.ts index b6a35d243e..ab89984505 100644 --- a/packages/common/src/types/command/PartialTargetDescriptor.types.ts +++ b/packages/common/src/types/command/PartialTargetDescriptor.types.ts @@ -238,6 +238,11 @@ export interface ContainingScopeModifier { ancestorIndex?: number; } +export interface ContiguousScopeModifier { + type: "contiguousScope"; + scopeType: ScopeType; +} + export interface EveryScopeModifier { type: "everyScope"; scopeType: ScopeType; @@ -376,6 +381,7 @@ export type Modifier = | InteriorOnlyModifier | ExcludeInteriorModifier | ContainingScopeModifier + | ContiguousScopeModifier | EveryScopeModifier | OrdinalScopeModifier | RelativeScopeModifier diff --git a/packages/cursorless-engine/src/processTargets/ModifierStageFactoryImpl.ts b/packages/cursorless-engine/src/processTargets/ModifierStageFactoryImpl.ts index 7f8c7ae2f5..60e2a0b64b 100644 --- a/packages/cursorless-engine/src/processTargets/ModifierStageFactoryImpl.ts +++ b/packages/cursorless-engine/src/processTargets/ModifierStageFactoryImpl.ts @@ -11,6 +11,7 @@ import { ModifierStage } from "./PipelineStages.types"; import { CascadingStage } from "./modifiers/CascadingStage"; import { ModifyIfUntypedStage } from "./modifiers/ConditionalModifierStages"; import { ContainingScopeStage } from "./modifiers/ContainingScopeStage"; +import { ContiguousScopeStage } from "./modifiers/ContiguousScopeStage"; import { EveryScopeStage } from "./modifiers/EveryScopeStage"; import { KeepContentFilterStage, @@ -74,6 +75,12 @@ export class ModifierStageFactoryImpl implements ModifierStageFactory { this.scopeHandlerFactory, modifier, ); + case "contiguousScope": + return new ContiguousScopeStage( + this, + this.scopeHandlerFactory, + modifier, + ); case "everyScope": if (modifier.scopeType.type === "instance") { return new InstanceStage(this, this.storedTargets, modifier); diff --git a/packages/cursorless-engine/src/processTargets/modifiers/ContiguousScopeStage.ts b/packages/cursorless-engine/src/processTargets/modifiers/ContiguousScopeStage.ts new file mode 100644 index 0000000000..f9ff769ff5 --- /dev/null +++ b/packages/cursorless-engine/src/processTargets/modifiers/ContiguousScopeStage.ts @@ -0,0 +1,116 @@ +import type { + ContiguousScopeModifier, + Direction, + Position, + TextEditor, +} from "@cursorless/common"; +import { NoContainingScopeError } from "@cursorless/common"; +import type { Target } from "../../typings/target.types"; +import { ModifierStageFactory } from "../ModifierStageFactory"; +import type { ModifierStage } from "../PipelineStages.types"; +import { ScopeHandlerFactory } from "./scopeHandlers/ScopeHandlerFactory"; +import { TargetScope } from "./scopeHandlers/scope.types"; +import { ScopeHandler } from "./scopeHandlers/scopeHandler.types"; + +/** + * This modifier returns all scopes intersecting the input target if the target + * has an explicit range (ie {@link Target.hasExplicitRange} is `true`). If the + * target does not have an explicit range, this modifier returns all scopes in + * the canonical iteration scope defined by the scope handler in + * {@link ScopeHandler.getIterationScopesTouchingPosition}. + * + * We proceed as follows: + * + * 1. If target has an explicit range, call + * {@link ScopeHandler.getScopesOverlappingRange} on our scope handler. If + * we get back at least one {@link TargetScope} whose + * {@link TargetScope.domain|domain} terminates within the input target + * range, just return all targets directly. + * 2. If we didn't get any scopes that terminate within the input target, or if + * the target had no explicit range, then expand to the containing instance + * of {@link ScopeHandler.iterationScopeType}, and then return all targets + * returned from {@link ScopeHandler.getScopesOverlappingRange} when applied + * to the expanded target's {@link Target.contentRange}. + */ +export class ContiguousScopeStage implements ModifierStage { + constructor( + private modifierStageFactory: ModifierStageFactory, + private scopeHandlerFactory: ScopeHandlerFactory, + private modifier: ContiguousScopeModifier, + ) {} + + run(target: Target): Target[] { + const { scopeType } = this.modifier; + const { editor, isReversed, contentRange } = target; + + const scopeHandler = this.scopeHandlerFactory.create( + scopeType, + editor.document.languageId, + ); + + if (scopeHandler == null) { + throw new NoContainingScopeError(scopeType.type); + } + + const start = getDistalScope( + scopeHandler, + editor, + contentRange.start, + "backward", + ); + const end = getDistalScope( + scopeHandler, + editor, + contentRange.end, + "forward", + ); + + if (start == null || end == null) { + throw new NoContainingScopeError(scopeType.type); + } + + return [ + new Target... + ] + + // return scopes.flatMap((scope) => scope.getTargets(isReversed)); + } +} + +function getDistalScope( + scopeHandler: ScopeHandler, + editor: TextEditor, + position: Position, + direction: Direction, +): TargetScope | undefined { + let result: TargetScope | undefined; + + const generator = scopeHandler.generateScopes(editor, position, direction, { + skipAncestorScopes: true, + }); + + for (const scope of generator) { + if (result == null) { + result = scope; + continue; + } + + const [previousScope, nextScope] = (() => { + if (direction === "forward") { + return [result, scope]; + } + return [scope, result]; + })(); + + if (isAdjacent(previousScope, nextScope)) { + result = scope; + } + } + + return result; +} + +function isAdjacent( + previousScope: TargetScope, + nextScope: TargetScope, +): boolean {} diff --git a/packages/cursorless-engine/src/spokenForms/defaultSpokenFormMapCore.ts b/packages/cursorless-engine/src/spokenForms/defaultSpokenFormMapCore.ts index 1b01cba10a..76e9fa82bd 100644 --- a/packages/cursorless-engine/src/spokenForms/defaultSpokenFormMapCore.ts +++ b/packages/cursorless-engine/src/spokenForms/defaultSpokenFormMapCore.ts @@ -120,6 +120,7 @@ export const defaultSpokenFormMapCore: DefaultSpokenFormMapDefinition = { extendThroughStartOf: "head", extendThroughEndOf: "tail", everyScope: "every", + contiguousScope: "slurp", }, modifierExtra: { From b549ca53a9e0fcc8f3c05a1956d56ac6abb9a045 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 5 Dec 2023 19:21:23 +0100 Subject: [PATCH 02/33] more work --- .../modifiers/ContiguousScopeStage.ts | 85 ++++++++----------- 1 file changed, 35 insertions(+), 50 deletions(-) diff --git a/packages/cursorless-engine/src/processTargets/modifiers/ContiguousScopeStage.ts b/packages/cursorless-engine/src/processTargets/modifiers/ContiguousScopeStage.ts index f9ff769ff5..6526497a89 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/ContiguousScopeStage.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/ContiguousScopeStage.ts @@ -4,7 +4,7 @@ import type { Position, TextEditor, } from "@cursorless/common"; -import { NoContainingScopeError } from "@cursorless/common"; +import { NoContainingScopeError, Range } from "@cursorless/common"; import type { Target } from "../../typings/target.types"; import { ModifierStageFactory } from "../ModifierStageFactory"; import type { ModifierStage } from "../PipelineStages.types"; @@ -12,26 +12,6 @@ import { ScopeHandlerFactory } from "./scopeHandlers/ScopeHandlerFactory"; import { TargetScope } from "./scopeHandlers/scope.types"; import { ScopeHandler } from "./scopeHandlers/scopeHandler.types"; -/** - * This modifier returns all scopes intersecting the input target if the target - * has an explicit range (ie {@link Target.hasExplicitRange} is `true`). If the - * target does not have an explicit range, this modifier returns all scopes in - * the canonical iteration scope defined by the scope handler in - * {@link ScopeHandler.getIterationScopesTouchingPosition}. - * - * We proceed as follows: - * - * 1. If target has an explicit range, call - * {@link ScopeHandler.getScopesOverlappingRange} on our scope handler. If - * we get back at least one {@link TargetScope} whose - * {@link TargetScope.domain|domain} terminates within the input target - * range, just return all targets directly. - * 2. If we didn't get any scopes that terminate within the input target, or if - * the target had no explicit range, then expand to the containing instance - * of {@link ScopeHandler.iterationScopeType}, and then return all targets - * returned from {@link ScopeHandler.getScopesOverlappingRange} when applied - * to the expanded target's {@link Target.contentRange}. - */ export class ContiguousScopeStage implements ModifierStage { constructor( private modifierStageFactory: ModifierStageFactory, @@ -41,7 +21,7 @@ export class ContiguousScopeStage implements ModifierStage { run(target: Target): Target[] { const { scopeType } = this.modifier; - const { editor, isReversed, contentRange } = target; + const { editor, contentRange } = target; const scopeHandler = this.scopeHandlerFactory.create( scopeType, @@ -52,65 +32,70 @@ export class ContiguousScopeStage implements ModifierStage { throw new NoContainingScopeError(scopeType.type); } - const start = getDistalScope( - scopeHandler, - editor, - contentRange.start, - "backward", - ); - const end = getDistalScope( - scopeHandler, - editor, - contentRange.end, - "forward", - ); + const targets = [ + ...getScopes(scopeHandler, editor, contentRange.start, "backward"), + ...getScopes(scopeHandler, editor, contentRange.end, "forward"), + ] + .filter((scope) => scope != null) + .flatMap((scope) => scope?.getTargets(false) ?? []); - if (start == null || end == null) { + if (targets.length === 0) { throw new NoContainingScopeError(scopeType.type); } - return [ - new Target... - ] + let newContentRange = targets[0].contentRange; - // return scopes.flatMap((scope) => scope.getTargets(isReversed)); + for (const target of targets) { + newContentRange = newContentRange.union(target.contentRange); + } + + return [targets[0].withContentRange(newContentRange)]; } } -function getDistalScope( +function getScopes( scopeHandler: ScopeHandler, editor: TextEditor, position: Position, direction: Direction, -): TargetScope | undefined { - let result: TargetScope | undefined; +): [TargetScope | undefined, TargetScope | undefined] { + let first, last: TargetScope | undefined; const generator = scopeHandler.generateScopes(editor, position, direction, { skipAncestorScopes: true, }); for (const scope of generator) { - if (result == null) { - result = scope; + if (first == null || last == null) { + first = scope; + last = scope; continue; } const [previousScope, nextScope] = (() => { if (direction === "forward") { - return [result, scope]; + return [last, scope]; } - return [scope, result]; + return [scope, last]; })(); - if (isAdjacent(previousScope, nextScope)) { - result = scope; + if (isAdjacent(editor, previousScope, nextScope)) { + last = scope; } } - return result; + return [first, last]; } function isAdjacent( + editor: TextEditor, previousScope: TargetScope, nextScope: TargetScope, -): boolean {} +): boolean { + const rangeBetween = new Range( + previousScope.domain.end, + nextScope.domain.start, + ); + const text = editor.document.getText(rangeBetween); + return /^\s*$/.test(text); +} From a71f017c9bd65e706972b12af54f6c6c25b94629 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 6 Dec 2023 06:24:38 +0100 Subject: [PATCH 03/33] Change continuous scope modifier into continuous scope type --- cursorless-talon/src/modifiers/scopes.py | 34 +++- .../src/modifiers/simple_scope_modifier.py | 10 +- cursorless-talon/src/spoken_forms.json | 3 +- .../command/PartialTargetDescriptor.types.ts | 14 +- packages/common/src/util/itertools.ts | 7 + .../primitiveTargetToSpokenForm.ts | 5 + .../ModifierStageFactoryImpl.ts | 7 - .../modifiers/ContiguousScopeStage.ts | 101 ---------- .../scopeHandlers/ContiguousScopeHandler.ts | 182 ++++++++++++++++++ .../scopeHandlers/ScopeHandlerFactoryImpl.ts | 3 + .../src/scopeProviders/ScopeInfoProvider.ts | 1 + .../src/spokenForms/SpokenFormType.ts | 3 +- .../spokenForms/defaultSpokenFormMapCore.ts | 2 +- 13 files changed, 237 insertions(+), 135 deletions(-) delete mode 100644 packages/cursorless-engine/src/processTargets/modifiers/ContiguousScopeStage.ts create mode 100644 packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts diff --git a/cursorless-talon/src/modifiers/scopes.py b/cursorless-talon/src/modifiers/scopes.py index 02b98da19e..ef44321081 100644 --- a/cursorless-talon/src/modifiers/scopes.py +++ b/cursorless-talon/src/modifiers/scopes.py @@ -1,3 +1,4 @@ +from typing import Any from talon import Module mod = Module() @@ -12,28 +13,45 @@ "cursorless_custom_regex_scope_type_plural", desc="Supported plural custom regular expression scope types", ) +mod.list( + "cursorless_contiguous_scope_type", + desc="Cursorless contiguous scope type", +) @mod.capture( - rule="{user.cursorless_scope_type} | {user.cursorless_custom_regex_scope_type}" + rule="[{user.cursorless_contiguous_scope_type}] ({user.cursorless_scope_type} | {user.cursorless_custom_regex_scope_type})" ) -def cursorless_scope_type(m) -> dict[str, str]: +def cursorless_scope_type(m) -> dict[str, Any]: """Cursorless scope type singular""" try: - return {"type": m.cursorless_scope_type} + scope_type = {"type": m.cursorless_scope_type} + except AttributeError: + scope_type = { + "type": "customRegex", + "regex": m.cursorless_custom_regex_scope_type, + } + + try: + return {"type": m.cursorless_contiguous_scope_type, "scopeType": scope_type} except AttributeError: - return {"type": "customRegex", "regex": m.cursorless_custom_regex_scope_type} + return scope_type @mod.capture( - rule="{user.cursorless_scope_type_plural} | {user.cursorless_custom_regex_scope_type_plural}" + rule="[{user.cursorless_contiguous_scope_type}] ({user.cursorless_scope_type_plural} | {user.cursorless_custom_regex_scope_type_plural})" ) -def cursorless_scope_type_plural(m) -> dict[str, str]: +def cursorless_scope_type_plural(m) -> dict[str, Any]: """Cursorless scope type plural""" try: - return {"type": m.cursorless_scope_type_plural} + scope_type = {"type": m.cursorless_scope_type_plural} except AttributeError: - return { + scope_type = { "type": "customRegex", "regex": m.cursorless_custom_regex_scope_type_plural, } + + try: + return {"type": m.cursorless_contiguous_scope_type, "scopeType": scope_type} + except AttributeError: + return scope_type diff --git a/cursorless-talon/src/modifiers/simple_scope_modifier.py b/cursorless-talon/src/modifiers/simple_scope_modifier.py index d655956983..7725623304 100644 --- a/cursorless-talon/src/modifiers/simple_scope_modifier.py +++ b/cursorless-talon/src/modifiers/simple_scope_modifier.py @@ -15,15 +15,7 @@ ) def cursorless_simple_scope_modifier(m) -> dict[str, Any]: """Containing scope, every scope, etc""" - match m[0]: - case "every": - type = "everyScope" - case "contiguous": - type = "contiguousScope" - case _: - type = "containingScope" - return { - "type": type, + "type": "everyScope" if m[0] == "every" else "containingScope", "scopeType": m.cursorless_scope_type, } diff --git a/cursorless-talon/src/spoken_forms.json b/cursorless-talon/src/spoken_forms.json index 426c4af3c3..7f4d7f70d3 100644 --- a/cursorless-talon/src/spoken_forms.json +++ b/cursorless-talon/src/spoken_forms.json @@ -79,7 +79,8 @@ "its": "inferPreviousMark", "visible": "visible" }, - "simple_scope_modifier": { "every": "every", "slurp": "contiguous" }, + "simple_scope_modifier": { "every": "every" }, + "contiguous_scope_type": { "fat": "contiguous" }, "interior_modifier": { "inside": "interiorOnly" }, diff --git a/packages/common/src/types/command/PartialTargetDescriptor.types.ts b/packages/common/src/types/command/PartialTargetDescriptor.types.ts index ed4e356a5d..31e8be8d3e 100644 --- a/packages/common/src/types/command/PartialTargetDescriptor.types.ts +++ b/packages/common/src/types/command/PartialTargetDescriptor.types.ts @@ -205,11 +205,17 @@ export interface OneOfScopeType { scopeTypes: ScopeType[]; } +export interface ContiguousScopeType { + type: "contiguous"; + scopeType: ScopeType; +} + export type ScopeType = | SimpleScopeType | SurroundingPairScopeType | CustomRegexScopeType - | OneOfScopeType; + | OneOfScopeType + | ContiguousScopeType; export interface ContainingSurroundingPairModifier extends ContainingScopeModifier { @@ -242,11 +248,6 @@ export interface ContainingScopeModifier { ancestorIndex?: number; } -export interface ContiguousScopeModifier { - type: "contiguousScope"; - scopeType: ScopeType; -} - export interface EveryScopeModifier { type: "everyScope"; scopeType: ScopeType; @@ -386,7 +387,6 @@ export type Modifier = | ExcludeInteriorModifier | VisibleModifier | ContainingScopeModifier - | ContiguousScopeModifier | EveryScopeModifier | OrdinalScopeModifier | RelativeScopeModifier diff --git a/packages/common/src/util/itertools.ts b/packages/common/src/util/itertools.ts index 435b3d044c..8cced967c9 100644 --- a/packages/common/src/util/itertools.ts +++ b/packages/common/src/util/itertools.ts @@ -65,3 +65,10 @@ export function isEmptyIterable(iterable: Iterable): boolean { return true; } + +export function next(generator: Iterable): T | undefined { + for (const value of generator) { + return value; + } + return undefined; +} diff --git a/packages/cursorless-engine/src/generateSpokenForm/primitiveTargetToSpokenForm.ts b/packages/cursorless-engine/src/generateSpokenForm/primitiveTargetToSpokenForm.ts index 05b22e0e5f..bdba73b9ba 100644 --- a/packages/cursorless-engine/src/generateSpokenForm/primitiveTargetToSpokenForm.ts +++ b/packages/cursorless-engine/src/generateSpokenForm/primitiveTargetToSpokenForm.ts @@ -208,6 +208,11 @@ export class PrimitiveTargetSpokenFormGenerator { switch (scopeType.type) { case "oneOf": throw new NoSpokenFormError(`Scope type '${scopeType.type}'`); + case "contiguous": { + const scope = this.handleScopeType(scopeType.scopeType); + return [this.spokenFormMap.modifierExtra.contiguousScope, scope]; + } + case "surroundingPair": { const pair = this.spokenFormMap.pairedDelimiter[scopeType.delimiter]; if (scopeType.forceDirection != null) { diff --git a/packages/cursorless-engine/src/processTargets/ModifierStageFactoryImpl.ts b/packages/cursorless-engine/src/processTargets/ModifierStageFactoryImpl.ts index 8cb179c225..24e0bd3a70 100644 --- a/packages/cursorless-engine/src/processTargets/ModifierStageFactoryImpl.ts +++ b/packages/cursorless-engine/src/processTargets/ModifierStageFactoryImpl.ts @@ -11,7 +11,6 @@ import { ModifierStage } from "./PipelineStages.types"; import { CascadingStage } from "./modifiers/CascadingStage"; import { ModifyIfUntypedStage } from "./modifiers/ConditionalModifierStages"; import { ContainingScopeStage } from "./modifiers/ContainingScopeStage"; -import { ContiguousScopeStage } from "./modifiers/ContiguousScopeStage"; import { EveryScopeStage } from "./modifiers/EveryScopeStage"; import { KeepContentFilterStage, @@ -78,12 +77,6 @@ export class ModifierStageFactoryImpl implements ModifierStageFactory { this.scopeHandlerFactory, modifier, ); - case "contiguousScope": - return new ContiguousScopeStage( - this, - this.scopeHandlerFactory, - modifier, - ); case "everyScope": if (modifier.scopeType.type === "instance") { return new InstanceStage(this, this.storedTargets, modifier); diff --git a/packages/cursorless-engine/src/processTargets/modifiers/ContiguousScopeStage.ts b/packages/cursorless-engine/src/processTargets/modifiers/ContiguousScopeStage.ts deleted file mode 100644 index 6526497a89..0000000000 --- a/packages/cursorless-engine/src/processTargets/modifiers/ContiguousScopeStage.ts +++ /dev/null @@ -1,101 +0,0 @@ -import type { - ContiguousScopeModifier, - Direction, - Position, - TextEditor, -} from "@cursorless/common"; -import { NoContainingScopeError, Range } from "@cursorless/common"; -import type { Target } from "../../typings/target.types"; -import { ModifierStageFactory } from "../ModifierStageFactory"; -import type { ModifierStage } from "../PipelineStages.types"; -import { ScopeHandlerFactory } from "./scopeHandlers/ScopeHandlerFactory"; -import { TargetScope } from "./scopeHandlers/scope.types"; -import { ScopeHandler } from "./scopeHandlers/scopeHandler.types"; - -export class ContiguousScopeStage implements ModifierStage { - constructor( - private modifierStageFactory: ModifierStageFactory, - private scopeHandlerFactory: ScopeHandlerFactory, - private modifier: ContiguousScopeModifier, - ) {} - - run(target: Target): Target[] { - const { scopeType } = this.modifier; - const { editor, contentRange } = target; - - const scopeHandler = this.scopeHandlerFactory.create( - scopeType, - editor.document.languageId, - ); - - if (scopeHandler == null) { - throw new NoContainingScopeError(scopeType.type); - } - - const targets = [ - ...getScopes(scopeHandler, editor, contentRange.start, "backward"), - ...getScopes(scopeHandler, editor, contentRange.end, "forward"), - ] - .filter((scope) => scope != null) - .flatMap((scope) => scope?.getTargets(false) ?? []); - - if (targets.length === 0) { - throw new NoContainingScopeError(scopeType.type); - } - - let newContentRange = targets[0].contentRange; - - for (const target of targets) { - newContentRange = newContentRange.union(target.contentRange); - } - - return [targets[0].withContentRange(newContentRange)]; - } -} - -function getScopes( - scopeHandler: ScopeHandler, - editor: TextEditor, - position: Position, - direction: Direction, -): [TargetScope | undefined, TargetScope | undefined] { - let first, last: TargetScope | undefined; - - const generator = scopeHandler.generateScopes(editor, position, direction, { - skipAncestorScopes: true, - }); - - for (const scope of generator) { - if (first == null || last == null) { - first = scope; - last = scope; - continue; - } - - const [previousScope, nextScope] = (() => { - if (direction === "forward") { - return [last, scope]; - } - return [scope, last]; - })(); - - if (isAdjacent(editor, previousScope, nextScope)) { - last = scope; - } - } - - return [first, last]; -} - -function isAdjacent( - editor: TextEditor, - previousScope: TargetScope, - nextScope: TargetScope, -): boolean { - const rangeBetween = new Range( - previousScope.domain.end, - nextScope.domain.start, - ); - const text = editor.document.getText(rangeBetween); - return /^\s*$/.test(text); -} diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts new file mode 100644 index 0000000000..58bcd647cf --- /dev/null +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts @@ -0,0 +1,182 @@ +import { + ContiguousScopeType, + Direction, + Position, + Range, + ScopeType, + TextEditor, + next, +} from "@cursorless/common"; +import { ScopeHandlerFactory } from "."; +import { Target } from "../../../typings/target.types"; +import { BaseScopeHandler } from "./BaseScopeHandler"; +import type { TargetScope } from "./scope.types"; +import { CustomScopeType, ScopeHandler } from "./scopeHandler.types"; + +export class ContiguousScopeHandler extends BaseScopeHandler { + protected readonly isHierarchical = false; + private readonly scopeHandler: ScopeHandler; + + constructor( + private scopeHandlerFactory: ScopeHandlerFactory, + public scopeType: ContiguousScopeType, + languageId: string, + ) { + super(); + const handler = scopeHandlerFactory.create(scopeType.scopeType, languageId); + if (handler == null) { + throw new Error( + `No available scope handler for '${scopeType.scopeType.type}'`, + ); + } + this.scopeHandler = handler; + } + + get iterationScopeType(): ScopeType | CustomScopeType { + return this.scopeHandler.iterationScopeType; + } + + generateScopeCandidates( + editor: TextEditor, + position: Position, + direction: Direction, + ): Iterable { + return direction === "backward" + ? this.generateScopeCandidatesBackward(editor, position) + : this.generateScopeCandidatesForward(editor, position); + } + + *generateScopeCandidatesBackward( + editor: TextEditor, + position: Position, + ): Iterable { + const targetsForward = next( + getTargetsInDirection(this.scopeHandler, editor, position, "forward"), + ); + + const targetsBackward = getTargetsInDirection( + this.scopeHandler, + editor, + position, + "backward", + ); + + for (const targets of targetsBackward) { + if (targetsForward != null && isAdjacent(targets[1], targetsForward[0])) { + yield targetsToScope(targets[0], targetsForward[1]); + } else { + yield targetsToScope(...targets); + } + } + } + + *generateScopeCandidatesForward( + editor: TextEditor, + position: Position, + ): Iterable { + const targetsBackward = next( + getTargetsInDirection(this.scopeHandler, editor, position, "backward"), + ); + + const targetsForward = getTargetsInDirection( + this.scopeHandler, + editor, + position, + "forward", + ); + + for (const targets of targetsForward) { + if ( + targetsBackward != null && + isAdjacent(targetsBackward[1], targets[0]) + ) { + yield targetsToScope(targetsBackward[0], targets[1]); + } else { + yield targetsToScope(...targets); + } + } + } +} + +function targetsToScope( + leadingTarget: Target, + trailingTarget: Target, +): TargetScope { + const range = leadingTarget.contentRange.union(trailingTarget.contentRange); + return { + editor: leadingTarget.editor, + domain: range, + getTargets: () => [leadingTarget.withContentRange(range)], + }; +} + +function* getTargetsInDirection( + scopeHandler: ScopeHandler, + editor: TextEditor, + position: Position, + direction: Direction, +): Iterable<[Target, Target]> { + const isForward = direction === "forward"; + let first, last: Target | undefined; + + const generator = scopeHandler.generateScopes(editor, position, direction, { + allowAdjacentScopes: true, + skipAncestorScopes: true, + }); + + for (const scope of generator) { + for (const target of scope.getTargets(false)) { + if (first == null) { + first = target; + } + + if (last != null) { + const [leadingTarget, trailingTarget] = isForward + ? [last, target] + : [target, last]; + + if (!isAdjacent(leadingTarget, trailingTarget)) { + yield isForward ? [first, last] : [last, first]; + first = target; + last = undefined; + } + } + + last = target; + } + } + + if (first != null && last != null) { + yield isForward ? [first, last] : [last, first]; + } +} + +function isAdjacent(leadingTarget: Target, trailingTarget: Target): boolean { + if ( + leadingTarget.contentRange.intersection(trailingTarget.contentRange) != null + ) { + return true; + } + + const leadingRange = + leadingTarget.getTrailingDelimiterTarget()?.contentRange ?? + leadingTarget.contentRange; + const trailingRange = + trailingTarget.getLeadingDelimiterTarget()?.contentRange ?? + trailingTarget.contentRange; + + if (leadingRange.intersection(trailingRange) != null) { + return true; + } + + if ( + !leadingTarget.isLine && + trailingRange.start.line - leadingRange.end.line > 1 + ) { + return false; + } + + const rangeBetween = new Range(leadingRange.end, trailingRange.start); + const text = leadingTarget.editor.document.getText(rangeBetween); + return /^\s*$/.test(text); +} diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ScopeHandlerFactoryImpl.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ScopeHandlerFactoryImpl.ts index b9a87fd865..49053dce09 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ScopeHandlerFactoryImpl.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ScopeHandlerFactoryImpl.ts @@ -14,6 +14,7 @@ import { UrlScopeHandler } from "./RegexScopeHandler"; import { WordScopeHandler } from "./WordScopeHandler/WordScopeHandler"; import { LanguageDefinitions } from "../../../languages/LanguageDefinitions"; import type { CustomScopeType, ScopeHandler } from "./scopeHandler.types"; +import { ContiguousScopeHandler } from "./ContiguousScopeHandler"; /** * Returns a scope handler for the given scope type and language id, or @@ -72,6 +73,8 @@ export class ScopeHandlerFactoryImpl implements ScopeHandlerFactory { return new CustomRegexScopeHandler(this, scopeType, languageId); case "custom": return scopeType.scopeHandler; + case "contiguous": + return new ContiguousScopeHandler(this, scopeType, languageId); case "instance": // Handle instance pseudoscope with its own special modifier throw Error("Unexpected scope type 'instance'"); diff --git a/packages/cursorless-engine/src/scopeProviders/ScopeInfoProvider.ts b/packages/cursorless-engine/src/scopeProviders/ScopeInfoProvider.ts index 9a697a48aa..ebc9054b48 100644 --- a/packages/cursorless-engine/src/scopeProviders/ScopeInfoProvider.ts +++ b/packages/cursorless-engine/src/scopeProviders/ScopeInfoProvider.ts @@ -176,6 +176,7 @@ function isLanguageSpecific(scopeType: ScopeType): boolean { return false; case "oneOf": + case "contiguous": throw Error( `Can't decide whether scope type ${JSON.stringify( scopeType, diff --git a/packages/cursorless-engine/src/spokenForms/SpokenFormType.ts b/packages/cursorless-engine/src/spokenForms/SpokenFormType.ts index 06a52eae60..747d1f6f40 100644 --- a/packages/cursorless-engine/src/spokenForms/SpokenFormType.ts +++ b/packages/cursorless-engine/src/spokenForms/SpokenFormType.ts @@ -59,6 +59,7 @@ type ModifierExtra = | "previous" | "next" | "forward" - | "backward"; + | "backward" + | "contiguousScope"; export type SpokenFormType = keyof SpokenFormMapKeyTypes; diff --git a/packages/cursorless-engine/src/spokenForms/defaultSpokenFormMapCore.ts b/packages/cursorless-engine/src/spokenForms/defaultSpokenFormMapCore.ts index 049291f2b0..2b2c1928e6 100644 --- a/packages/cursorless-engine/src/spokenForms/defaultSpokenFormMapCore.ts +++ b/packages/cursorless-engine/src/spokenForms/defaultSpokenFormMapCore.ts @@ -121,7 +121,6 @@ export const defaultSpokenFormMapCore: DefaultSpokenFormMapDefinition = { extendThroughStartOf: "head", extendThroughEndOf: "tail", everyScope: "every", - contiguousScope: "slurp", }, modifierExtra: { @@ -131,6 +130,7 @@ export const defaultSpokenFormMapCore: DefaultSpokenFormMapDefinition = { next: "next", forward: "forward", backward: "backward", + contiguousScope: "fat", }, customRegex: {}, From da8d6ec7ab5402fe98762641084ca7929562b2ee Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 6 Dec 2023 06:30:19 +0100 Subject: [PATCH 04/33] Added tests --- .../scopeHandlers/ContiguousScopeHandler.ts | 8 +++++ .../scope/contiguous/changeFatBlock.yml | 29 +++++++++++++++++ .../scope/contiguous/changeFatComment.yml | 27 ++++++++++++++++ .../scope/contiguous/changeFatComment2.yml | 32 +++++++++++++++++++ .../scope/contiguous/changeFatIdentifier.yml | 25 +++++++++++++++ .../scope/contiguous/changeFatIdentifier2.yml | 25 +++++++++++++++ .../scope/contiguous/changeFatToken.yml | 25 +++++++++++++++ 7 files changed, 171 insertions(+) create mode 100644 packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatBlock.yml create mode 100644 packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatComment.yml create mode 100644 packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatComment2.yml create mode 100644 packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatIdentifier.yml create mode 100644 packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatIdentifier2.yml create mode 100644 packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatToken.yml diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts index 58bcd647cf..478b6fac34 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts @@ -102,6 +102,14 @@ function targetsToScope( leadingTarget: Target, trailingTarget: Target, ): TargetScope { + if (leadingTarget.contentRange.isRangeEqual(trailingTarget.contentRange)) { + return { + editor: leadingTarget.editor, + domain: leadingTarget.contentRange, + getTargets: () => [leadingTarget], + }; + } + const range = leadingTarget.contentRange.union(trailingTarget.contentRange); return { editor: leadingTarget.editor, diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatBlock.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatBlock.yml new file mode 100644 index 0000000000..8eaa9aec34 --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatBlock.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + version: 6 + spokenForm: change fat block + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - type: containingScope + scopeType: + type: contiguous + scopeType: {type: paragraph} + usePrePhraseSnapshot: true +initialState: + documentContents: |- + aaa + aaa + + bbb + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: {} +finalState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatComment.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatComment.yml new file mode 100644 index 0000000000..114df38bb4 --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatComment.yml @@ -0,0 +1,27 @@ +languageId: typescript +command: + version: 6 + spokenForm: change fat comment + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - type: containingScope + scopeType: + type: contiguous + scopeType: {type: comment} + usePrePhraseSnapshot: true +initialState: + documentContents: |- + // 111 + // 222 + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: {} +finalState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatComment2.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatComment2.yml new file mode 100644 index 0000000000..3b9fba609d --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatComment2.yml @@ -0,0 +1,32 @@ +languageId: typescript +command: + version: 6 + spokenForm: change fat comment + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - type: containingScope + scopeType: + type: contiguous + scopeType: {type: comment} + usePrePhraseSnapshot: true +initialState: + documentContents: |- + // 111 + // 222 + + // 333 + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: {} +finalState: + documentContents: |- + + + // 333 + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatIdentifier.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatIdentifier.yml new file mode 100644 index 0000000000..342edd1f7a --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatIdentifier.yml @@ -0,0 +1,25 @@ +languageId: plaintext +command: + version: 6 + spokenForm: change fat identifier + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - type: containingScope + scopeType: + type: contiguous + scopeType: {type: identifier} + usePrePhraseSnapshot: true +initialState: + documentContents: aaa bbb | ccc + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: {} +finalState: + documentContents: " | ccc" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatIdentifier2.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatIdentifier2.yml new file mode 100644 index 0000000000..ee9d0e35de --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatIdentifier2.yml @@ -0,0 +1,25 @@ +languageId: plaintext +command: + version: 6 + spokenForm: change fat identifier + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - type: containingScope + scopeType: + type: contiguous + scopeType: {type: identifier} + usePrePhraseSnapshot: true +initialState: + documentContents: aaa bbb | ccc + selections: + - anchor: {line: 0, character: 13} + active: {line: 0, character: 13} + marks: {} +finalState: + documentContents: "aaa bbb | " + selections: + - anchor: {line: 0, character: 10} + active: {line: 0, character: 10} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatToken.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatToken.yml new file mode 100644 index 0000000000..634842379e --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatToken.yml @@ -0,0 +1,25 @@ +languageId: plaintext +command: + version: 6 + spokenForm: change fat token + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - type: containingScope + scopeType: + type: contiguous + scopeType: {type: token} + usePrePhraseSnapshot: true +initialState: + documentContents: aaa bbb | ccc + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: {} +finalState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} From a3fa351b69ff5c125568cc937fcf712a6550769f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Wed, 6 Dec 2023 05:35:37 +0000 Subject: [PATCH 05/33] [pre-commit.ci lite] apply automatic fixes --- cursorless-talon/src/modifiers/scopes.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cursorless-talon/src/modifiers/scopes.py b/cursorless-talon/src/modifiers/scopes.py index ef44321081..13c5c72764 100644 --- a/cursorless-talon/src/modifiers/scopes.py +++ b/cursorless-talon/src/modifiers/scopes.py @@ -1,4 +1,5 @@ from typing import Any + from talon import Module mod = Module() From 53351e8f8608882bec79da1003857e2516124fb3 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 6 Dec 2023 06:43:25 +0100 Subject: [PATCH 06/33] Moved tests --- .../modifiers/scopeHandlers/ContiguousScopeHandler.ts | 6 ++++-- .../contiguous => contiguousScopes}/changeFatBlock.yml | 0 .../contiguous => contiguousScopes}/changeFatComment.yml | 0 .../contiguous => contiguousScopes}/changeFatComment2.yml | 0 .../contiguous => contiguousScopes}/changeFatIdentifier.yml | 0 .../changeFatIdentifier2.yml | 0 .../contiguous => contiguousScopes}/changeFatToken.yml | 0 7 files changed, 4 insertions(+), 2 deletions(-) rename packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/{scope/contiguous => contiguousScopes}/changeFatBlock.yml (100%) rename packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/{scope/contiguous => contiguousScopes}/changeFatComment.yml (100%) rename packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/{scope/contiguous => contiguousScopes}/changeFatComment2.yml (100%) rename packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/{scope/contiguous => contiguousScopes}/changeFatIdentifier.yml (100%) rename packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/{scope/contiguous => contiguousScopes}/changeFatIdentifier2.yml (100%) rename packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/{scope/contiguous => contiguousScopes}/changeFatToken.yml (100%) diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts index 478b6fac34..e93e0ea010 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts @@ -50,7 +50,7 @@ export class ContiguousScopeHandler extends BaseScopeHandler { editor: TextEditor, position: Position, ): Iterable { - const targetsForward = next( + let targetsForward = next( getTargetsInDirection(this.scopeHandler, editor, position, "forward"), ); @@ -64,6 +64,7 @@ export class ContiguousScopeHandler extends BaseScopeHandler { for (const targets of targetsBackward) { if (targetsForward != null && isAdjacent(targets[1], targetsForward[0])) { yield targetsToScope(targets[0], targetsForward[1]); + targetsForward = undefined; } else { yield targetsToScope(...targets); } @@ -74,7 +75,7 @@ export class ContiguousScopeHandler extends BaseScopeHandler { editor: TextEditor, position: Position, ): Iterable { - const targetsBackward = next( + let targetsBackward = next( getTargetsInDirection(this.scopeHandler, editor, position, "backward"), ); @@ -91,6 +92,7 @@ export class ContiguousScopeHandler extends BaseScopeHandler { isAdjacent(targetsBackward[1], targets[0]) ) { yield targetsToScope(targetsBackward[0], targets[1]); + targetsBackward = undefined; } else { yield targetsToScope(...targets); } diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatBlock.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeFatBlock.yml similarity index 100% rename from packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatBlock.yml rename to packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeFatBlock.yml diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatComment.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeFatComment.yml similarity index 100% rename from packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatComment.yml rename to packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeFatComment.yml diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatComment2.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeFatComment2.yml similarity index 100% rename from packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatComment2.yml rename to packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeFatComment2.yml diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatIdentifier.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeFatIdentifier.yml similarity index 100% rename from packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatIdentifier.yml rename to packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeFatIdentifier.yml diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatIdentifier2.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeFatIdentifier2.yml similarity index 100% rename from packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatIdentifier2.yml rename to packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeFatIdentifier2.yml diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatToken.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeFatToken.yml similarity index 100% rename from packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/scope/contiguous/changeFatToken.yml rename to packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeFatToken.yml From d370690f2d001ea3e68a12c31366c82df04c2736 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 6 Dec 2023 06:46:35 +0100 Subject: [PATCH 07/33] Added comment --- packages/common/src/util/itertools.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/common/src/util/itertools.ts b/packages/common/src/util/itertools.ts index 8cced967c9..cf5342fe61 100644 --- a/packages/common/src/util/itertools.ts +++ b/packages/common/src/util/itertools.ts @@ -66,6 +66,13 @@ export function isEmptyIterable(iterable: Iterable): boolean { return true; } +/** + * Returns the first element of the given iterable, or `undefined` if the + * iterable is empty + * @param iterable The iterable to get the first element of + * @returns The first element of the iterable, or `undefined` if the iterable + * is empty + */ export function next(generator: Iterable): T | undefined { for (const value of generator) { return value; From 48f97ee573c5b70feb4490e4120e7e4b34ca4793 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 6 Dec 2023 06:53:06 +0100 Subject: [PATCH 08/33] cleanup --- .../primitiveTargetToSpokenForm.ts | 1 + .../scopeHandlers/ScopeHandlerFactoryImpl.ts | 12 +++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/cursorless-engine/src/generateSpokenForm/primitiveTargetToSpokenForm.ts b/packages/cursorless-engine/src/generateSpokenForm/primitiveTargetToSpokenForm.ts index bdba73b9ba..f39dd5bf04 100644 --- a/packages/cursorless-engine/src/generateSpokenForm/primitiveTargetToSpokenForm.ts +++ b/packages/cursorless-engine/src/generateSpokenForm/primitiveTargetToSpokenForm.ts @@ -208,6 +208,7 @@ export class PrimitiveTargetSpokenFormGenerator { switch (scopeType.type) { case "oneOf": throw new NoSpokenFormError(`Scope type '${scopeType.type}'`); + case "contiguous": { const scope = this.handleScopeType(scopeType.scopeType); return [this.spokenFormMap.modifierExtra.contiguousScope, scope]; diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ScopeHandlerFactoryImpl.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ScopeHandlerFactoryImpl.ts index 49053dce09..7854e916d3 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ScopeHandlerFactoryImpl.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ScopeHandlerFactoryImpl.ts @@ -1,20 +1,22 @@ import type { ScopeType } from "@cursorless/common"; +import { LanguageDefinitions } from "../../../languages/LanguageDefinitions"; import { CharacterScopeHandler } from "./CharacterScopeHandler"; -import { CustomRegexScopeHandler } from "./RegexScopeHandler"; +import { ContiguousScopeHandler } from "./ContiguousScopeHandler"; import { DocumentScopeHandler } from "./DocumentScopeHandler"; import { IdentifierScopeHandler } from "./IdentifierScopeHandler"; import { LineScopeHandler } from "./LineScopeHandler"; -import { NonWhitespaceSequenceScopeHandler } from "./RegexScopeHandler"; import { OneOfScopeHandler } from "./OneOfScopeHandler"; import { ParagraphScopeHandler } from "./ParagraphScopeHandler"; +import { + CustomRegexScopeHandler, + NonWhitespaceSequenceScopeHandler, + UrlScopeHandler, +} from "./RegexScopeHandler"; import { ScopeHandlerFactory } from "./ScopeHandlerFactory"; import { SentenceScopeHandler } from "./SentenceScopeHandler/SentenceScopeHandler"; import { TokenScopeHandler } from "./TokenScopeHandler"; -import { UrlScopeHandler } from "./RegexScopeHandler"; import { WordScopeHandler } from "./WordScopeHandler/WordScopeHandler"; -import { LanguageDefinitions } from "../../../languages/LanguageDefinitions"; import type { CustomScopeType, ScopeHandler } from "./scopeHandler.types"; -import { ContiguousScopeHandler } from "./ContiguousScopeHandler"; /** * Returns a scope handler for the given scope type and language id, or From e2ec5c807c3a1cefd983f6ce23abdd736c6a5804 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 6 Dec 2023 06:57:34 +0100 Subject: [PATCH 09/33] more cleanup --- .../modifiers/scopeHandlers/ContiguousScopeHandler.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts index e93e0ea010..ff042fcaf6 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts @@ -148,7 +148,6 @@ function* getTargetsInDirection( if (!isAdjacent(leadingTarget, trailingTarget)) { yield isForward ? [first, last] : [last, first]; first = target; - last = undefined; } } From d1020a8b13acf3759508beab8dbdab855f85ca0c Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 6 Dec 2023 16:21:30 +0100 Subject: [PATCH 10/33] Update packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts Co-authored-by: Pokey Rule <755842+pokey@users.noreply.github.com> --- .../modifiers/scopeHandlers/ContiguousScopeHandler.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts index ff042fcaf6..4900c7355e 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts @@ -40,6 +40,7 @@ export class ContiguousScopeHandler extends BaseScopeHandler { editor: TextEditor, position: Position, direction: Direction, + _hints: ScopeIteratorRequirements, ): Iterable { return direction === "backward" ? this.generateScopeCandidatesBackward(editor, position) From 02a295e0cbedd80e96a7ec3dcc30eab4d749476a Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 6 Dec 2023 16:22:21 +0100 Subject: [PATCH 11/33] Import --- .../modifiers/scopeHandlers/ContiguousScopeHandler.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts index 4900c7355e..75a3995a54 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts @@ -8,10 +8,14 @@ import { next, } from "@cursorless/common"; import { ScopeHandlerFactory } from "."; -import { Target } from "../../../typings/target.types"; +import type { Target } from "../../../typings/target.types"; import { BaseScopeHandler } from "./BaseScopeHandler"; import type { TargetScope } from "./scope.types"; -import { CustomScopeType, ScopeHandler } from "./scopeHandler.types"; +import type { + CustomScopeType, + ScopeHandler, + ScopeIteratorRequirements, +} from "./scopeHandler.types"; export class ContiguousScopeHandler extends BaseScopeHandler { protected readonly isHierarchical = false; From 9d75eade3ae2632119b817e1d998de35af067942 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 6 Dec 2023 16:22:44 +0100 Subject: [PATCH 12/33] Update packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts Co-authored-by: Pokey Rule <755842+pokey@users.noreply.github.com> --- .../modifiers/scopeHandlers/ContiguousScopeHandler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts index 75a3995a54..207711030b 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts @@ -51,7 +51,7 @@ export class ContiguousScopeHandler extends BaseScopeHandler { : this.generateScopeCandidatesForward(editor, position); } - *generateScopeCandidatesBackward( + private *generateScopeCandidatesBackward( editor: TextEditor, position: Position, ): Iterable { From 48c7a65c81774660ef514ca177b22327eb5e79b5 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 6 Dec 2023 16:22:50 +0100 Subject: [PATCH 13/33] Update packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts Co-authored-by: Pokey Rule <755842+pokey@users.noreply.github.com> --- .../modifiers/scopeHandlers/ContiguousScopeHandler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts index 207711030b..44b9cb73c4 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts @@ -76,7 +76,7 @@ export class ContiguousScopeHandler extends BaseScopeHandler { } } - *generateScopeCandidatesForward( + private *generateScopeCandidatesForward( editor: TextEditor, position: Position, ): Iterable { From fa57ab29c0f50d7d86ab7f74f872d4f89b5b32eb Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 6 Dec 2023 16:23:47 +0100 Subject: [PATCH 14/33] Update packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts Co-authored-by: Pokey Rule <755842+pokey@users.noreply.github.com> --- .../modifiers/scopeHandlers/ContiguousScopeHandler.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts index 44b9cb73c4..472e136fa3 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts @@ -55,8 +55,8 @@ export class ContiguousScopeHandler extends BaseScopeHandler { editor: TextEditor, position: Position, ): Iterable { - let targetsForward = next( - getTargetsInDirection(this.scopeHandler, editor, position, "forward"), + let targetRangeForward = next( + generateTargetRangesInDirection(this.scopeHandler, editor, position, "forward"), ); const targetsBackward = getTargetsInDirection( From c9435424b3059b211bffc3eb8bf02fa5ae4080d7 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 6 Dec 2023 16:23:58 +0100 Subject: [PATCH 15/33] Update packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts Co-authored-by: Pokey Rule <755842+pokey@users.noreply.github.com> --- .../modifiers/scopeHandlers/ContiguousScopeHandler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts index 472e136fa3..1c008606d4 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts @@ -59,7 +59,7 @@ export class ContiguousScopeHandler extends BaseScopeHandler { generateTargetRangesInDirection(this.scopeHandler, editor, position, "forward"), ); - const targetsBackward = getTargetsInDirection( + const targetRangesBackwardIter = generateTargetRangesInDirection( this.scopeHandler, editor, position, From c26d704a85e81a5719f4cf07b0d40694b9f7dcd5 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 6 Dec 2023 16:24:13 +0100 Subject: [PATCH 16/33] Update packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts Co-authored-by: Pokey Rule <755842+pokey@users.noreply.github.com> --- .../modifiers/scopeHandlers/ContiguousScopeHandler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts index 1c008606d4..cc99331ab0 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts @@ -66,7 +66,7 @@ export class ContiguousScopeHandler extends BaseScopeHandler { "backward", ); - for (const targets of targetsBackward) { + for (const targetRange of targetRangesBackwardIter) { if (targetsForward != null && isAdjacent(targets[1], targetsForward[0])) { yield targetsToScope(targets[0], targetsForward[1]); targetsForward = undefined; From e0b6b5bebba613f401c392fa5199ca69d57adb11 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Wed, 6 Dec 2023 15:26:48 +0000 Subject: [PATCH 17/33] [pre-commit.ci lite] apply automatic fixes --- .../modifiers/scopeHandlers/ContiguousScopeHandler.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts index cc99331ab0..d49a8be3b8 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts @@ -55,8 +55,13 @@ export class ContiguousScopeHandler extends BaseScopeHandler { editor: TextEditor, position: Position, ): Iterable { - let targetRangeForward = next( - generateTargetRangesInDirection(this.scopeHandler, editor, position, "forward"), + const targetRangeForward = next( + generateTargetRangesInDirection( + this.scopeHandler, + editor, + position, + "forward", + ), ); const targetRangesBackwardIter = generateTargetRangesInDirection( From 2988adb47d0dffcb1f2ae8304c3baeb052c15c2c Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 6 Dec 2023 16:26:56 +0100 Subject: [PATCH 18/33] rename --- .../scopeHandlers/ContiguousScopeHandler.ts | 43 ++++++++++++------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts index cc99331ab0..8975bb59c5 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts @@ -56,7 +56,12 @@ export class ContiguousScopeHandler extends BaseScopeHandler { position: Position, ): Iterable { let targetRangeForward = next( - generateTargetRangesInDirection(this.scopeHandler, editor, position, "forward"), + generateTargetRangesInDirection( + this.scopeHandler, + editor, + position, + "forward", + ), ); const targetRangesBackwardIter = generateTargetRangesInDirection( @@ -67,11 +72,14 @@ export class ContiguousScopeHandler extends BaseScopeHandler { ); for (const targetRange of targetRangesBackwardIter) { - if (targetsForward != null && isAdjacent(targets[1], targetsForward[0])) { - yield targetsToScope(targets[0], targetsForward[1]); - targetsForward = undefined; + if ( + targetRangeForward != null && + isAdjacent(targetRange[1], targetRangeForward[0]) + ) { + yield targetsToScope(targetRange[0], targetRangeForward[1]); + targetRangeForward = undefined; } else { - yield targetsToScope(...targets); + yield targetsToScope(...targetRange); } } } @@ -80,26 +88,31 @@ export class ContiguousScopeHandler extends BaseScopeHandler { editor: TextEditor, position: Position, ): Iterable { - let targetsBackward = next( - getTargetsInDirection(this.scopeHandler, editor, position, "backward"), + let targetRangeBackward = next( + generateTargetRangesInDirection( + this.scopeHandler, + editor, + position, + "backward", + ), ); - const targetsForward = getTargetsInDirection( + const targetRangesForwardIter = generateTargetRangesInDirection( this.scopeHandler, editor, position, "forward", ); - for (const targets of targetsForward) { + for (const targetRange of targetRangesForwardIter) { if ( - targetsBackward != null && - isAdjacent(targetsBackward[1], targets[0]) + targetRangeBackward != null && + isAdjacent(targetRangeBackward[1], targetRange[0]) ) { - yield targetsToScope(targetsBackward[0], targets[1]); - targetsBackward = undefined; + yield targetsToScope(targetRangeBackward[0], targetRange[1]); + targetRangeBackward = undefined; } else { - yield targetsToScope(...targets); + yield targetsToScope(...targetRange); } } } @@ -125,7 +138,7 @@ function targetsToScope( }; } -function* getTargetsInDirection( +function* generateTargetRangesInDirection( scopeHandler: ScopeHandler, editor: TextEditor, position: Position, From 34cbbb12c1ccdf04c3dd915687974d5c57c83368 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 6 Dec 2023 16:32:49 +0100 Subject: [PATCH 19/33] update --- .../cursorless-engine/src/scopeProviders/ScopeInfoProvider.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/cursorless-engine/src/scopeProviders/ScopeInfoProvider.ts b/packages/cursorless-engine/src/scopeProviders/ScopeInfoProvider.ts index ebc9054b48..1d4d12006d 100644 --- a/packages/cursorless-engine/src/scopeProviders/ScopeInfoProvider.ts +++ b/packages/cursorless-engine/src/scopeProviders/ScopeInfoProvider.ts @@ -175,8 +175,10 @@ function isLanguageSpecific(scopeType: ScopeType): boolean { case "customRegex": return false; - case "oneOf": case "contiguous": + return isLanguageSpecific(scopeType.scopeType); + + case "oneOf": throw Error( `Can't decide whether scope type ${JSON.stringify( scopeType, From 8b5a95fe5e4dace66eb0b349413e1810d304235a Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 7 Dec 2023 05:09:44 +0100 Subject: [PATCH 20/33] Use proximal and distal --- .../scopeHandlers/ContiguousScopeHandler.ts | 103 +++++------------- 1 file changed, 30 insertions(+), 73 deletions(-) diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts index 8975bb59c5..f53e538779 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts @@ -40,79 +40,37 @@ export class ContiguousScopeHandler extends BaseScopeHandler { return this.scopeHandler.iterationScopeType; } - generateScopeCandidates( + *generateScopeCandidates( editor: TextEditor, position: Position, direction: Direction, _hints: ScopeIteratorRequirements, ): Iterable { - return direction === "backward" - ? this.generateScopeCandidatesBackward(editor, position) - : this.generateScopeCandidatesForward(editor, position); - } - - private *generateScopeCandidatesBackward( - editor: TextEditor, - position: Position, - ): Iterable { - let targetRangeForward = next( + let targetRangeOpposite = next( generateTargetRangesInDirection( this.scopeHandler, editor, position, - "forward", + direction === "forward" ? "backward" : "forward", ), ); - const targetRangesBackwardIter = generateTargetRangesInDirection( + const targetRangesIter = generateTargetRangesInDirection( this.scopeHandler, editor, position, - "backward", + direction, ); - for (const targetRange of targetRangesBackwardIter) { + for (const targetRange of targetRangesIter) { if ( - targetRangeForward != null && - isAdjacent(targetRange[1], targetRangeForward[0]) + targetRangeOpposite != null && + isAdjacent(targetRangeOpposite.proximal, targetRange.proximal) ) { - yield targetsToScope(targetRange[0], targetRangeForward[1]); - targetRangeForward = undefined; + yield targetsToScope(targetRangeOpposite.distal, targetRange.distal); + targetRangeOpposite = undefined; } else { - yield targetsToScope(...targetRange); - } - } - } - - private *generateScopeCandidatesForward( - editor: TextEditor, - position: Position, - ): Iterable { - let targetRangeBackward = next( - generateTargetRangesInDirection( - this.scopeHandler, - editor, - position, - "backward", - ), - ); - - const targetRangesForwardIter = generateTargetRangesInDirection( - this.scopeHandler, - editor, - position, - "forward", - ); - - for (const targetRange of targetRangesForwardIter) { - if ( - targetRangeBackward != null && - isAdjacent(targetRangeBackward[1], targetRange[0]) - ) { - yield targetsToScope(targetRangeBackward[0], targetRange[1]); - targetRangeBackward = undefined; - } else { - yield targetsToScope(...targetRange); + yield targetsToScope(targetRange.proximal, targetRange.distal); } } } @@ -143,9 +101,8 @@ function* generateTargetRangesInDirection( editor: TextEditor, position: Position, direction: Direction, -): Iterable<[Target, Target]> { - const isForward = direction === "forward"; - let first, last: Target | undefined; +): Iterable<{ proximal: Target; distal: Target }> { + let proximal, distal: Target | undefined; const generator = scopeHandler.generateScopes(editor, position, direction, { allowAdjacentScopes: true, @@ -154,37 +111,37 @@ function* generateTargetRangesInDirection( for (const scope of generator) { for (const target of scope.getTargets(false)) { - if (first == null) { - first = target; + if (proximal == null) { + proximal = target; } - if (last != null) { - const [leadingTarget, trailingTarget] = isForward - ? [last, target] - : [target, last]; - - if (!isAdjacent(leadingTarget, trailingTarget)) { - yield isForward ? [first, last] : [last, first]; - first = target; + if (distal != null) { + if (!isAdjacent(distal, target)) { + yield { proximal, distal }; + proximal = target; } } - last = target; + distal = target; } } - if (first != null && last != null) { - yield isForward ? [first, last] : [last, first]; + if (proximal != null && distal != null) { + yield { proximal, distal }; } } -function isAdjacent(leadingTarget: Target, trailingTarget: Target): boolean { - if ( - leadingTarget.contentRange.intersection(trailingTarget.contentRange) != null - ) { +function isAdjacent(target1: Target, target2: Target): boolean { + if (target1.contentRange.isRangeEqual(target2.contentRange)) { return true; } + const [leadingTarget, trailingTarget] = target1.contentRange.start.isBefore( + target2.contentRange.start, + ) + ? [target1, target2] + : [target2, target1]; + const leadingRange = leadingTarget.getTrailingDelimiterTarget()?.contentRange ?? leadingTarget.contentRange; From bd86a64b0ec63976d70bb6db5b0b45789b394450 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 7 Dec 2023 05:22:44 +0100 Subject: [PATCH 21/33] Continues target --- .../scopeHandlers/ContiguousScopeHandler.ts | 65 ++++++++++--------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts index f53e538779..749310051f 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts @@ -8,7 +8,7 @@ import { next, } from "@cursorless/common"; import { ScopeHandlerFactory } from "."; -import type { Target } from "../../../typings/target.types"; +import { createContinuousRangeTarget } from "../../createContinuousRangeTarget"; import { BaseScopeHandler } from "./BaseScopeHandler"; import type { TargetScope } from "./scope.types"; import type { @@ -67,32 +67,32 @@ export class ContiguousScopeHandler extends BaseScopeHandler { targetRangeOpposite != null && isAdjacent(targetRangeOpposite.proximal, targetRange.proximal) ) { - yield targetsToScope(targetRangeOpposite.distal, targetRange.distal); + yield combineScopes(targetRangeOpposite.distal, targetRange.distal); targetRangeOpposite = undefined; } else { - yield targetsToScope(targetRange.proximal, targetRange.distal); + yield combineScopes(targetRange.proximal, targetRange.distal); } } } } -function targetsToScope( - leadingTarget: Target, - trailingTarget: Target, -): TargetScope { - if (leadingTarget.contentRange.isRangeEqual(trailingTarget.contentRange)) { - return { - editor: leadingTarget.editor, - domain: leadingTarget.contentRange, - getTargets: () => [leadingTarget], - }; +function combineScopes(scope1: TargetScope, scope2: TargetScope): TargetScope { + if (scope1.domain.isRangeEqual(scope2.domain)) { + return scope1; } - const range = leadingTarget.contentRange.union(trailingTarget.contentRange); return { - editor: leadingTarget.editor, - domain: range, - getTargets: () => [leadingTarget.withContentRange(range)], + editor: scope1.editor, + domain: scope1.domain.union(scope2.domain), + getTargets: (isReversed) => [ + createContinuousRangeTarget( + isReversed, + scope1.getTargets(false)[0], + scope2.getTargets(false)[0], + true, + true, + ), + ], }; } @@ -101,8 +101,8 @@ function* generateTargetRangesInDirection( editor: TextEditor, position: Position, direction: Direction, -): Iterable<{ proximal: Target; distal: Target }> { - let proximal, distal: Target | undefined; +): Iterable<{ proximal: TargetScope; distal: TargetScope }> { + let proximal, distal: TargetScope | undefined; const generator = scopeHandler.generateScopes(editor, position, direction, { allowAdjacentScopes: true, @@ -110,20 +110,18 @@ function* generateTargetRangesInDirection( }); for (const scope of generator) { - for (const target of scope.getTargets(false)) { - if (proximal == null) { - proximal = target; - } + if (proximal == null) { + proximal = scope; + } - if (distal != null) { - if (!isAdjacent(distal, target)) { - yield { proximal, distal }; - proximal = target; - } + if (distal != null) { + if (!isAdjacent(distal, scope)) { + yield { proximal, distal }; + proximal = scope; } - - distal = target; } + + distal = scope; } if (proximal != null && distal != null) { @@ -131,11 +129,14 @@ function* generateTargetRangesInDirection( } } -function isAdjacent(target1: Target, target2: Target): boolean { - if (target1.contentRange.isRangeEqual(target2.contentRange)) { +function isAdjacent(scope1: TargetScope, scope2: TargetScope): boolean { + if (scope1.domain.isRangeEqual(scope2.domain)) { return true; } + const target1 = scope1.getTargets(false)[0]; + const target2 = scope2.getTargets(false)[0]; + const [leadingTarget, trailingTarget] = target1.contentRange.start.isBefore( target2.contentRange.start, ) From 5a905eaafc804432d5a8ada337619a7c25b66252 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 7 Dec 2023 05:33:35 +0100 Subject: [PATCH 22/33] Added tests --- .../scopeHandlers/ContiguousScopeHandler.ts | 29 +++++++++++++------ .../changeNextFatIdentifier.yml | 28 ++++++++++++++++++ .../changeNextFatIdentifier2.yml | 28 ++++++++++++++++++ .../changePreviousFatIdentifier.yml | 28 ++++++++++++++++++ .../changePreviousFatIdentifier2.yml | 28 ++++++++++++++++++ 5 files changed, 132 insertions(+), 9 deletions(-) create mode 100644 packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeNextFatIdentifier.yml create mode 100644 packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeNextFatIdentifier2.yml create mode 100644 packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changePreviousFatIdentifier.yml create mode 100644 packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changePreviousFatIdentifier2.yml diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts index 749310051f..f3d788c11c 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts @@ -84,15 +84,26 @@ function combineScopes(scope1: TargetScope, scope2: TargetScope): TargetScope { return { editor: scope1.editor, domain: scope1.domain.union(scope2.domain), - getTargets: (isReversed) => [ - createContinuousRangeTarget( - isReversed, - scope1.getTargets(false)[0], - scope2.getTargets(false)[0], - true, - true, - ), - ], + getTargets: (isReversed) => { + const target1 = scope1.getTargets(isReversed)[0]; + const target2 = scope2.getTargets(isReversed)[0]; + + const [startTarget, endTarget] = target1.contentRange.start.isBefore( + target2.contentRange.start, + ) + ? [target1, target2] + : [target2, target1]; + + return [ + createContinuousRangeTarget( + isReversed, + startTarget, + endTarget, + true, + true, + ), + ]; + }, }; } diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeNextFatIdentifier.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeNextFatIdentifier.yml new file mode 100644 index 0000000000..9ba0407113 --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeNextFatIdentifier.yml @@ -0,0 +1,28 @@ +languageId: plaintext +command: + version: 6 + spokenForm: change next fat identifier + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - type: relativeScope + scopeType: + type: contiguous + scopeType: {type: identifier} + offset: 1 + length: 1 + direction: forward + usePrePhraseSnapshot: true +initialState: + documentContents: aaa bbb | ccc + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: {} +finalState: + documentContents: "aaa bbb | " + selections: + - anchor: {line: 0, character: 10} + active: {line: 0, character: 10} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeNextFatIdentifier2.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeNextFatIdentifier2.yml new file mode 100644 index 0000000000..e49d728d35 --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeNextFatIdentifier2.yml @@ -0,0 +1,28 @@ +languageId: plaintext +command: + version: 6 + spokenForm: change next fat identifier + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - type: relativeScope + scopeType: + type: contiguous + scopeType: {type: identifier} + offset: 1 + length: 1 + direction: forward + usePrePhraseSnapshot: true +initialState: + documentContents: aaa bbb | ccc + selections: + - anchor: {line: 0, character: 7} + active: {line: 0, character: 7} + marks: {} +finalState: + documentContents: "aaa bbb | " + selections: + - anchor: {line: 0, character: 10} + active: {line: 0, character: 10} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changePreviousFatIdentifier.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changePreviousFatIdentifier.yml new file mode 100644 index 0000000000..4b199e2fec --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changePreviousFatIdentifier.yml @@ -0,0 +1,28 @@ +languageId: plaintext +command: + version: 6 + spokenForm: change previous fat identifier + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - type: relativeScope + scopeType: + type: contiguous + scopeType: {type: identifier} + offset: 1 + length: 1 + direction: backward + usePrePhraseSnapshot: true +initialState: + documentContents: aaa bbb | ccc + selections: + - anchor: {line: 0, character: 13} + active: {line: 0, character: 13} + marks: {} +finalState: + documentContents: " | ccc" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changePreviousFatIdentifier2.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changePreviousFatIdentifier2.yml new file mode 100644 index 0000000000..d25be291a2 --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changePreviousFatIdentifier2.yml @@ -0,0 +1,28 @@ +languageId: plaintext +command: + version: 6 + spokenForm: change previous fat identifier + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - type: relativeScope + scopeType: + type: contiguous + scopeType: {type: identifier} + offset: 1 + length: 1 + direction: backward + usePrePhraseSnapshot: true +initialState: + documentContents: aaa bbb | ccc + selections: + - anchor: {line: 0, character: 10} + active: {line: 0, character: 10} + marks: {} +finalState: + documentContents: " | ccc" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} From 661281825e68a77bb026d73ffa979bd8c96b2cf6 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 7 Dec 2023 05:43:06 +0100 Subject: [PATCH 23/33] cleanup --- .../scopeHandlers/ContiguousScopeHandler.ts | 62 +++++++++++-------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts index f3d788c11c..73b1a04340 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts @@ -7,7 +7,9 @@ import { TextEditor, next, } from "@cursorless/common"; +import { zip } from "itertools"; import { ScopeHandlerFactory } from "."; +import { Target } from "../../../typings/target.types"; import { createContinuousRangeTarget } from "../../createContinuousRangeTarget"; import { BaseScopeHandler } from "./BaseScopeHandler"; import type { TargetScope } from "./scope.types"; @@ -85,24 +87,23 @@ function combineScopes(scope1: TargetScope, scope2: TargetScope): TargetScope { editor: scope1.editor, domain: scope1.domain.union(scope2.domain), getTargets: (isReversed) => { - const target1 = scope1.getTargets(isReversed)[0]; - const target2 = scope2.getTargets(isReversed)[0]; - - const [startTarget, endTarget] = target1.contentRange.start.isBefore( - target2.contentRange.start, - ) - ? [target1, target2] - : [target2, target1]; - - return [ - createContinuousRangeTarget( + return zip( + scope1.getTargets(isReversed), + scope2.getTargets(isReversed), + ).map(([target1, target2]) => { + const [startTarget, endTarget] = getTargetsInDocumentOrder( + target1, + target2, + ); + + return createContinuousRangeTarget( isReversed, startTarget, endTarget, true, true, - ), - ]; + ); + }); }, }; } @@ -145,34 +146,41 @@ function isAdjacent(scope1: TargetScope, scope2: TargetScope): boolean { return true; } - const target1 = scope1.getTargets(false)[0]; - const target2 = scope2.getTargets(false)[0]; - - const [leadingTarget, trailingTarget] = target1.contentRange.start.isBefore( - target2.contentRange.start, - ) - ? [target1, target2] - : [target2, target1]; + const [startTarget, endTarget] = getTargetsInDocumentOrder( + scope1.getTargets(false)[0], + scope2.getTargets(false)[0], + ); const leadingRange = - leadingTarget.getTrailingDelimiterTarget()?.contentRange ?? - leadingTarget.contentRange; + startTarget.getTrailingDelimiterTarget()?.contentRange ?? + startTarget.contentRange; const trailingRange = - trailingTarget.getLeadingDelimiterTarget()?.contentRange ?? - trailingTarget.contentRange; + endTarget.getLeadingDelimiterTarget()?.contentRange ?? + endTarget.contentRange; if (leadingRange.intersection(trailingRange) != null) { return true; } + // Non line targets are excluded if they are separated by more than one line if ( - !leadingTarget.isLine && + !startTarget.isLine && trailingRange.start.line - leadingRange.end.line > 1 ) { return false; } + // Finally targets are excluded if there is non whitespace text between them const rangeBetween = new Range(leadingRange.end, trailingRange.start); - const text = leadingTarget.editor.document.getText(rangeBetween); + const text = startTarget.editor.document.getText(rangeBetween); return /^\s*$/.test(text); } + +function getTargetsInDocumentOrder( + target1: Target, + target2: Target, +): [Target, Target] { + return target1.contentRange.start.isBefore(target2.contentRange.start) + ? [target1, target2] + : [target2, target1]; +} From d3eb68770359f2b92026fe6aa571070cb69c448f Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Fri, 8 Dec 2023 12:08:11 +0100 Subject: [PATCH 24/33] clean up --- .../scopeHandlers/ContiguousScopeHandler.ts | 21 ++----------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts index 73b1a04340..f488ba93c9 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts @@ -7,10 +7,9 @@ import { TextEditor, next, } from "@cursorless/common"; -import { zip } from "itertools"; import { ScopeHandlerFactory } from "."; import { Target } from "../../../typings/target.types"; -import { createContinuousRangeTarget } from "../../createContinuousRangeTarget"; +import { constructScopeRangeTarget } from "../constructScopeRangeTarget"; import { BaseScopeHandler } from "./BaseScopeHandler"; import type { TargetScope } from "./scope.types"; import type { @@ -87,23 +86,7 @@ function combineScopes(scope1: TargetScope, scope2: TargetScope): TargetScope { editor: scope1.editor, domain: scope1.domain.union(scope2.domain), getTargets: (isReversed) => { - return zip( - scope1.getTargets(isReversed), - scope2.getTargets(isReversed), - ).map(([target1, target2]) => { - const [startTarget, endTarget] = getTargetsInDocumentOrder( - target1, - target2, - ); - - return createContinuousRangeTarget( - isReversed, - startTarget, - endTarget, - true, - true, - ); - }); + return constructScopeRangeTarget(isReversed, scope1, scope2); }, }; } From 2f15dc662c40c3f0840c9121b08a3bd785dd9caa Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 14 Dec 2023 15:46:41 +0100 Subject: [PATCH 25/33] Only do contiguous for comments --- cursorless-talon/src/modifiers/scopes.py | 43 ++++++++----------- cursorless-talon/src/spoken_forms.json | 1 - .../command/PartialTargetDescriptor.types.ts | 8 +--- .../primitiveTargetToSpokenForm.ts | 5 --- .../src/languages/LanguageDefinition.ts | 18 ++++++-- .../scopeHandlers/ContiguousScopeHandler.ts | 20 +++------ .../scopeHandlers/ScopeHandlerFactoryImpl.ts | 2 - .../src/scopeProviders/ScopeInfoProvider.ts | 3 -- .../src/spokenForms/SpokenFormType.ts | 3 +- .../spokenForms/defaultSpokenFormMapCore.ts | 1 - .../changeComment.yml} | 12 +++--- .../changeComment2.yml} | 15 +++---- .../changeComment3.yml} | 18 +++----- .../contiguousScopes/changeFatIdentifier.yml | 25 ----------- .../contiguousScopes/changeFatIdentifier2.yml | 25 ----------- .../contiguousScopes/changeFatToken.yml | 25 ----------- .../changeNextFatIdentifier.yml | 28 ------------ .../changeNextFatIdentifier2.yml | 28 ------------ .../changePreviousFatIdentifier.yml | 28 ------------ .../changePreviousFatIdentifier2.yml | 28 ------------ 20 files changed, 58 insertions(+), 278 deletions(-) rename packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/{contiguousScopes/changeFatComment.yml => contiguousScope/changeComment.yml} (72%) rename packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/{contiguousScopes/changeFatComment2.yml => contiguousScope/changeComment2.yml} (70%) rename packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/{contiguousScopes/changeFatBlock.yml => contiguousScope/changeComment3.yml} (59%) delete mode 100644 packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeFatIdentifier.yml delete mode 100644 packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeFatIdentifier2.yml delete mode 100644 packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeFatToken.yml delete mode 100644 packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeNextFatIdentifier.yml delete mode 100644 packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeNextFatIdentifier2.yml delete mode 100644 packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changePreviousFatIdentifier.yml delete mode 100644 packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changePreviousFatIdentifier2.yml diff --git a/cursorless-talon/src/modifiers/scopes.py b/cursorless-talon/src/modifiers/scopes.py index 13c5c72764..ee1efb9b2c 100644 --- a/cursorless-talon/src/modifiers/scopes.py +++ b/cursorless-talon/src/modifiers/scopes.py @@ -1,5 +1,3 @@ -from typing import Any - from talon import Module mod = Module() @@ -14,45 +12,42 @@ "cursorless_custom_regex_scope_type_plural", desc="Supported plural custom regular expression scope types", ) -mod.list( - "cursorless_contiguous_scope_type", - desc="Cursorless contiguous scope type", -) @mod.capture( - rule="[{user.cursorless_contiguous_scope_type}] ({user.cursorless_scope_type} | {user.cursorless_custom_regex_scope_type})" + rule="{user.cursorless_scope_type} | | {user.cursorless_custom_regex_scope_type}" ) -def cursorless_scope_type(m) -> dict[str, Any]: +def cursorless_scope_type(m) -> dict[str, str]: """Cursorless scope type singular""" try: - scope_type = {"type": m.cursorless_scope_type} + return {"type": m.cursorless_scope_type} except AttributeError: - scope_type = { - "type": "customRegex", - "regex": m.cursorless_custom_regex_scope_type, - } + pass try: - return {"type": m.cursorless_contiguous_scope_type, "scopeType": scope_type} + return m.cursorless_glyph_scope_type except AttributeError: - return scope_type + pass + + return {"type": "customRegex", "regex": m.cursorless_custom_regex_scope_type} @mod.capture( - rule="[{user.cursorless_contiguous_scope_type}] ({user.cursorless_scope_type_plural} | {user.cursorless_custom_regex_scope_type_plural})" + rule="{user.cursorless_scope_type_plural} | | {user.cursorless_custom_regex_scope_type_plural}" ) -def cursorless_scope_type_plural(m) -> dict[str, Any]: +def cursorless_scope_type_plural(m) -> dict[str, str]: """Cursorless scope type plural""" try: - scope_type = {"type": m.cursorless_scope_type_plural} + return {"type": m.cursorless_scope_type_plural} except AttributeError: - scope_type = { - "type": "customRegex", - "regex": m.cursorless_custom_regex_scope_type_plural, - } + pass try: - return {"type": m.cursorless_contiguous_scope_type, "scopeType": scope_type} + return m.cursorless_glyph_scope_type_plural except AttributeError: - return scope_type + pass + + return { + "type": "customRegex", + "regex": m.cursorless_custom_regex_scope_type_plural, + } diff --git a/cursorless-talon/src/spoken_forms.json b/cursorless-talon/src/spoken_forms.json index 819a478089..4c7ec7b5db 100644 --- a/cursorless-talon/src/spoken_forms.json +++ b/cursorless-talon/src/spoken_forms.json @@ -81,7 +81,6 @@ "visible": "visible" }, "simple_scope_modifier": { "every": "every" }, - "contiguous_scope_type": { "fat": "contiguous" }, "interior_modifier": { "inside": "interiorOnly" }, diff --git a/packages/common/src/types/command/PartialTargetDescriptor.types.ts b/packages/common/src/types/command/PartialTargetDescriptor.types.ts index 31e8be8d3e..0a5293046e 100644 --- a/packages/common/src/types/command/PartialTargetDescriptor.types.ts +++ b/packages/common/src/types/command/PartialTargetDescriptor.types.ts @@ -205,17 +205,11 @@ export interface OneOfScopeType { scopeTypes: ScopeType[]; } -export interface ContiguousScopeType { - type: "contiguous"; - scopeType: ScopeType; -} - export type ScopeType = | SimpleScopeType | SurroundingPairScopeType | CustomRegexScopeType - | OneOfScopeType - | ContiguousScopeType; + | OneOfScopeType; export interface ContainingSurroundingPairModifier extends ContainingScopeModifier { diff --git a/packages/cursorless-engine/src/generateSpokenForm/primitiveTargetToSpokenForm.ts b/packages/cursorless-engine/src/generateSpokenForm/primitiveTargetToSpokenForm.ts index f39dd5bf04..ae93390d09 100644 --- a/packages/cursorless-engine/src/generateSpokenForm/primitiveTargetToSpokenForm.ts +++ b/packages/cursorless-engine/src/generateSpokenForm/primitiveTargetToSpokenForm.ts @@ -209,11 +209,6 @@ export class PrimitiveTargetSpokenFormGenerator { case "oneOf": throw new NoSpokenFormError(`Scope type '${scopeType.type}'`); - case "contiguous": { - const scope = this.handleScopeType(scopeType.scopeType); - return [this.spokenFormMap.modifierExtra.contiguousScope, scope]; - } - case "surroundingPair": { const pair = this.spokenFormMap.pairedDelimiter[scopeType.delimiter]; if (scopeType.forceDirection != null) { diff --git a/packages/cursorless-engine/src/languages/LanguageDefinition.ts b/packages/cursorless-engine/src/languages/LanguageDefinition.ts index 3576b94124..4234c77495 100644 --- a/packages/cursorless-engine/src/languages/LanguageDefinition.ts +++ b/packages/cursorless-engine/src/languages/LanguageDefinition.ts @@ -2,10 +2,11 @@ import { ScopeType, SimpleScopeType, showError } from "@cursorless/common"; import { existsSync, readFileSync } from "fs"; import { dirname, join } from "path"; import { TreeSitterScopeHandler } from "../processTargets/modifiers/scopeHandlers"; +import { ContiguousScopeHandler } from "../processTargets/modifiers/scopeHandlers/ContiguousScopeHandler"; import { TreeSitterTextFragmentScopeHandler } from "../processTargets/modifiers/scopeHandlers/TreeSitterScopeHandler/TreeSitterTextFragmentScopeHandler"; -import { ScopeHandler } from "../processTargets/modifiers/scopeHandlers/scopeHandler.types"; +import type { ScopeHandler } from "../processTargets/modifiers/scopeHandlers/scopeHandler.types"; import { ide } from "../singletons/ide.singleton"; -import { TreeSitter } from "../typings/TreeSitter"; +import type { TreeSitter } from "../typings/TreeSitter"; import { matchAll } from "../util/regex"; import { TreeSitterQuery } from "./TreeSitterQuery"; import { TEXT_FRAGMENT_CAPTURE_NAME } from "./captureNames"; @@ -60,12 +61,21 @@ export class LanguageDefinition { * undefined if the given scope type / language id combination is still using * legacy pathways */ - getScopeHandler(scopeType: ScopeType) { + getScopeHandler(scopeType: ScopeType): ScopeHandler | undefined { if (!this.query.captureNames.includes(scopeType.type)) { return undefined; } - return new TreeSitterScopeHandler(this.query, scopeType as SimpleScopeType); + const scopeHandler = new TreeSitterScopeHandler( + this.query, + scopeType as SimpleScopeType, + ); + + if (scopeType.type === "comment") { + return new ContiguousScopeHandler(scopeHandler); + } + + return scopeHandler; } getTextFragmentScopeHandler(): ScopeHandler | undefined { diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts index f488ba93c9..d18416fce9 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts @@ -1,5 +1,4 @@ import { - ContiguousScopeType, Direction, Position, Range, @@ -7,7 +6,6 @@ import { TextEditor, next, } from "@cursorless/common"; -import { ScopeHandlerFactory } from "."; import { Target } from "../../../typings/target.types"; import { constructScopeRangeTarget } from "../constructScopeRangeTarget"; import { BaseScopeHandler } from "./BaseScopeHandler"; @@ -20,21 +18,13 @@ import type { export class ContiguousScopeHandler extends BaseScopeHandler { protected readonly isHierarchical = false; - private readonly scopeHandler: ScopeHandler; - constructor( - private scopeHandlerFactory: ScopeHandlerFactory, - public scopeType: ContiguousScopeType, - languageId: string, - ) { + constructor(private scopeHandler: ScopeHandler) { super(); - const handler = scopeHandlerFactory.create(scopeType.scopeType, languageId); - if (handler == null) { - throw new Error( - `No available scope handler for '${scopeType.scopeType.type}'`, - ); - } - this.scopeHandler = handler; + } + + get scopeType(): ScopeType | undefined { + return this.scopeHandler.scopeType; } get iterationScopeType(): ScopeType | CustomScopeType { diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ScopeHandlerFactoryImpl.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ScopeHandlerFactoryImpl.ts index 7854e916d3..22afc7fa11 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ScopeHandlerFactoryImpl.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ScopeHandlerFactoryImpl.ts @@ -75,8 +75,6 @@ export class ScopeHandlerFactoryImpl implements ScopeHandlerFactory { return new CustomRegexScopeHandler(this, scopeType, languageId); case "custom": return scopeType.scopeHandler; - case "contiguous": - return new ContiguousScopeHandler(this, scopeType, languageId); case "instance": // Handle instance pseudoscope with its own special modifier throw Error("Unexpected scope type 'instance'"); diff --git a/packages/cursorless-engine/src/scopeProviders/ScopeInfoProvider.ts b/packages/cursorless-engine/src/scopeProviders/ScopeInfoProvider.ts index 1d4d12006d..9a697a48aa 100644 --- a/packages/cursorless-engine/src/scopeProviders/ScopeInfoProvider.ts +++ b/packages/cursorless-engine/src/scopeProviders/ScopeInfoProvider.ts @@ -175,9 +175,6 @@ function isLanguageSpecific(scopeType: ScopeType): boolean { case "customRegex": return false; - case "contiguous": - return isLanguageSpecific(scopeType.scopeType); - case "oneOf": throw Error( `Can't decide whether scope type ${JSON.stringify( diff --git a/packages/cursorless-engine/src/spokenForms/SpokenFormType.ts b/packages/cursorless-engine/src/spokenForms/SpokenFormType.ts index 747d1f6f40..06a52eae60 100644 --- a/packages/cursorless-engine/src/spokenForms/SpokenFormType.ts +++ b/packages/cursorless-engine/src/spokenForms/SpokenFormType.ts @@ -59,7 +59,6 @@ type ModifierExtra = | "previous" | "next" | "forward" - | "backward" - | "contiguousScope"; + | "backward"; export type SpokenFormType = keyof SpokenFormMapKeyTypes; diff --git a/packages/cursorless-engine/src/spokenForms/defaultSpokenFormMapCore.ts b/packages/cursorless-engine/src/spokenForms/defaultSpokenFormMapCore.ts index 2b2c1928e6..15b4e5ee2b 100644 --- a/packages/cursorless-engine/src/spokenForms/defaultSpokenFormMapCore.ts +++ b/packages/cursorless-engine/src/spokenForms/defaultSpokenFormMapCore.ts @@ -130,7 +130,6 @@ export const defaultSpokenFormMapCore: DefaultSpokenFormMapDefinition = { next: "next", forward: "forward", backward: "backward", - contiguousScope: "fat", }, customRegex: {}, diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeFatComment.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment.yml similarity index 72% rename from packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeFatComment.yml rename to packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment.yml index 114df38bb4..5862397660 100644 --- a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeFatComment.yml +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment.yml @@ -1,21 +1,19 @@ -languageId: typescript +languageId: javascript command: version: 6 - spokenForm: change fat comment + spokenForm: change comment action: name: clearAndSetSelection target: type: primitive modifiers: - type: containingScope - scopeType: - type: contiguous - scopeType: {type: comment} + scopeType: {type: comment} usePrePhraseSnapshot: true initialState: documentContents: |- - // 111 - // 222 + // hello + // world selections: - anchor: {line: 0, character: 0} active: {line: 0, character: 0} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeFatComment2.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment2.yml similarity index 70% rename from packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeFatComment2.yml rename to packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment2.yml index 3b9fba609d..1dc52eaa64 100644 --- a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeFatComment2.yml +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment2.yml @@ -1,23 +1,20 @@ -languageId: typescript +languageId: javascript command: version: 6 - spokenForm: change fat comment + spokenForm: change comment action: name: clearAndSetSelection target: type: primitive modifiers: - type: containingScope - scopeType: - type: contiguous - scopeType: {type: comment} + scopeType: {type: comment} usePrePhraseSnapshot: true initialState: documentContents: |- - // 111 - // 222 + // hello - // 333 + // world selections: - anchor: {line: 0, character: 0} active: {line: 0, character: 0} @@ -26,7 +23,7 @@ finalState: documentContents: |- - // 333 + // world selections: - anchor: {line: 0, character: 0} active: {line: 0, character: 0} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeFatBlock.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment3.yml similarity index 59% rename from packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeFatBlock.yml rename to packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment3.yml index 8eaa9aec34..76b2c53287 100644 --- a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeFatBlock.yml +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment3.yml @@ -1,26 +1,22 @@ -languageId: plaintext +languageId: javascript command: version: 6 - spokenForm: change fat block + spokenForm: change comment action: name: clearAndSetSelection target: type: primitive modifiers: - type: containingScope - scopeType: - type: contiguous - scopeType: {type: paragraph} + scopeType: {type: comment} usePrePhraseSnapshot: true initialState: documentContents: |- - aaa - aaa - - bbb + // hello + // world selections: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} + - anchor: {line: 1, character: 8} + active: {line: 1, character: 8} marks: {} finalState: documentContents: "" diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeFatIdentifier.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeFatIdentifier.yml deleted file mode 100644 index 342edd1f7a..0000000000 --- a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeFatIdentifier.yml +++ /dev/null @@ -1,25 +0,0 @@ -languageId: plaintext -command: - version: 6 - spokenForm: change fat identifier - action: - name: clearAndSetSelection - target: - type: primitive - modifiers: - - type: containingScope - scopeType: - type: contiguous - scopeType: {type: identifier} - usePrePhraseSnapshot: true -initialState: - documentContents: aaa bbb | ccc - selections: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} - marks: {} -finalState: - documentContents: " | ccc" - selections: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeFatIdentifier2.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeFatIdentifier2.yml deleted file mode 100644 index ee9d0e35de..0000000000 --- a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeFatIdentifier2.yml +++ /dev/null @@ -1,25 +0,0 @@ -languageId: plaintext -command: - version: 6 - spokenForm: change fat identifier - action: - name: clearAndSetSelection - target: - type: primitive - modifiers: - - type: containingScope - scopeType: - type: contiguous - scopeType: {type: identifier} - usePrePhraseSnapshot: true -initialState: - documentContents: aaa bbb | ccc - selections: - - anchor: {line: 0, character: 13} - active: {line: 0, character: 13} - marks: {} -finalState: - documentContents: "aaa bbb | " - selections: - - anchor: {line: 0, character: 10} - active: {line: 0, character: 10} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeFatToken.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeFatToken.yml deleted file mode 100644 index 634842379e..0000000000 --- a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeFatToken.yml +++ /dev/null @@ -1,25 +0,0 @@ -languageId: plaintext -command: - version: 6 - spokenForm: change fat token - action: - name: clearAndSetSelection - target: - type: primitive - modifiers: - - type: containingScope - scopeType: - type: contiguous - scopeType: {type: token} - usePrePhraseSnapshot: true -initialState: - documentContents: aaa bbb | ccc - selections: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} - marks: {} -finalState: - documentContents: "" - selections: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeNextFatIdentifier.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeNextFatIdentifier.yml deleted file mode 100644 index 9ba0407113..0000000000 --- a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeNextFatIdentifier.yml +++ /dev/null @@ -1,28 +0,0 @@ -languageId: plaintext -command: - version: 6 - spokenForm: change next fat identifier - action: - name: clearAndSetSelection - target: - type: primitive - modifiers: - - type: relativeScope - scopeType: - type: contiguous - scopeType: {type: identifier} - offset: 1 - length: 1 - direction: forward - usePrePhraseSnapshot: true -initialState: - documentContents: aaa bbb | ccc - selections: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} - marks: {} -finalState: - documentContents: "aaa bbb | " - selections: - - anchor: {line: 0, character: 10} - active: {line: 0, character: 10} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeNextFatIdentifier2.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeNextFatIdentifier2.yml deleted file mode 100644 index e49d728d35..0000000000 --- a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changeNextFatIdentifier2.yml +++ /dev/null @@ -1,28 +0,0 @@ -languageId: plaintext -command: - version: 6 - spokenForm: change next fat identifier - action: - name: clearAndSetSelection - target: - type: primitive - modifiers: - - type: relativeScope - scopeType: - type: contiguous - scopeType: {type: identifier} - offset: 1 - length: 1 - direction: forward - usePrePhraseSnapshot: true -initialState: - documentContents: aaa bbb | ccc - selections: - - anchor: {line: 0, character: 7} - active: {line: 0, character: 7} - marks: {} -finalState: - documentContents: "aaa bbb | " - selections: - - anchor: {line: 0, character: 10} - active: {line: 0, character: 10} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changePreviousFatIdentifier.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changePreviousFatIdentifier.yml deleted file mode 100644 index 4b199e2fec..0000000000 --- a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changePreviousFatIdentifier.yml +++ /dev/null @@ -1,28 +0,0 @@ -languageId: plaintext -command: - version: 6 - spokenForm: change previous fat identifier - action: - name: clearAndSetSelection - target: - type: primitive - modifiers: - - type: relativeScope - scopeType: - type: contiguous - scopeType: {type: identifier} - offset: 1 - length: 1 - direction: backward - usePrePhraseSnapshot: true -initialState: - documentContents: aaa bbb | ccc - selections: - - anchor: {line: 0, character: 13} - active: {line: 0, character: 13} - marks: {} -finalState: - documentContents: " | ccc" - selections: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changePreviousFatIdentifier2.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changePreviousFatIdentifier2.yml deleted file mode 100644 index d25be291a2..0000000000 --- a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScopes/changePreviousFatIdentifier2.yml +++ /dev/null @@ -1,28 +0,0 @@ -languageId: plaintext -command: - version: 6 - spokenForm: change previous fat identifier - action: - name: clearAndSetSelection - target: - type: primitive - modifiers: - - type: relativeScope - scopeType: - type: contiguous - scopeType: {type: identifier} - offset: 1 - length: 1 - direction: backward - usePrePhraseSnapshot: true -initialState: - documentContents: aaa bbb | ccc - selections: - - anchor: {line: 0, character: 10} - active: {line: 0, character: 10} - marks: {} -finalState: - documentContents: " | ccc" - selections: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} From 0ccdcc6590cf18041f9fed40239dfb4f2600ba7a Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 14 Dec 2023 15:50:49 +0100 Subject: [PATCH 26/33] cleanup --- .../src/languages/LanguageDefinition.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/cursorless-engine/src/languages/LanguageDefinition.ts b/packages/cursorless-engine/src/languages/LanguageDefinition.ts index 4234c77495..3ec2dd6c9c 100644 --- a/packages/cursorless-engine/src/languages/LanguageDefinition.ts +++ b/packages/cursorless-engine/src/languages/LanguageDefinition.ts @@ -71,7 +71,7 @@ export class LanguageDefinition { scopeType as SimpleScopeType, ); - if (scopeType.type === "comment") { + if (useContiguousScopeHandler(scopeType)) { return new ContiguousScopeHandler(scopeHandler); } @@ -151,3 +151,15 @@ function readQueryFileAndImports(languageQueryPath: string) { return Object.values(rawQueryStrings).join("\n"); } + +/** + * Returns true if the given scope type should use a contiguous scope handler. + */ +function useContiguousScopeHandler(scopeType: ScopeType): boolean { + switch (scopeType.type) { + case "comment": + return true; + default: + return false; + } +} From d898f26192b6ac434a15406ca4cab7c7c7776057 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 14 Dec 2023 15:59:08 +0100 Subject: [PATCH 27/33] cleanup --- .../modifiers/scopeHandlers/ContiguousScopeHandler.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts index d18416fce9..c6d2eb2435 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts @@ -7,6 +7,7 @@ import { next, } from "@cursorless/common"; import { Target } from "../../../typings/target.types"; +import { ensureSingleTarget } from "../../../util/targetUtils"; import { constructScopeRangeTarget } from "../constructScopeRangeTarget"; import { BaseScopeHandler } from "./BaseScopeHandler"; import type { TargetScope } from "./scope.types"; @@ -120,8 +121,8 @@ function isAdjacent(scope1: TargetScope, scope2: TargetScope): boolean { } const [startTarget, endTarget] = getTargetsInDocumentOrder( - scope1.getTargets(false)[0], - scope2.getTargets(false)[0], + ensureSingleTarget(scope1.getTargets(false)), + ensureSingleTarget(scope2.getTargets(false)), ); const leadingRange = From ea5a5425030b0a62e50b3b1268e3b37e59feacd7 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 14 Dec 2023 16:10:10 +0100 Subject: [PATCH 28/33] Update test --- .../contiguousScope/changeComment2.yml | 10 ++----- .../contiguousScope/changeComment3.yml | 6 ++-- .../contiguousScope/changeComment4.yml | 29 +++++++++++++++++++ 3 files changed, 35 insertions(+), 10 deletions(-) create mode 100644 packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment4.yml diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment2.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment2.yml index 1dc52eaa64..76b2c53287 100644 --- a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment2.yml +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment2.yml @@ -13,17 +13,13 @@ command: initialState: documentContents: |- // hello - // world selections: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} + - anchor: {line: 1, character: 8} + active: {line: 1, character: 8} marks: {} finalState: - documentContents: |- - - - // world + documentContents: "" selections: - anchor: {line: 0, character: 0} active: {line: 0, character: 0} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment3.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment3.yml index 76b2c53287..437c0febad 100644 --- a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment3.yml +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment3.yml @@ -13,10 +13,10 @@ command: initialState: documentContents: |- // hello - // world + // world selections: - - anchor: {line: 1, character: 8} - active: {line: 1, character: 8} + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} marks: {} finalState: documentContents: "" diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment4.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment4.yml new file mode 100644 index 0000000000..1dc52eaa64 --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment4.yml @@ -0,0 +1,29 @@ +languageId: javascript +command: + version: 6 + spokenForm: change comment + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - type: containingScope + scopeType: {type: comment} + usePrePhraseSnapshot: true +initialState: + documentContents: |- + // hello + + // world + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: {} +finalState: + documentContents: |- + + + // world + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} From 66731e46a738106367ed6df4bdb5c7d26bf8927f Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Fri, 15 Dec 2023 08:45:40 +0100 Subject: [PATCH 29/33] Added predicate --- .../languages/TreeSitterQuery/QueryCapture.ts | 4 +++ .../TreeSitterQuery/TreeSitterQuery.ts | 2 ++ .../checkCaptureStartEnd.test.ts | 6 ++++- .../queryPredicateOperators.ts | 18 +++++++++++++ .../rewriteStartOfEndOf.test.ts | 1 + .../scopeHandlers/ContiguousScopeHandler.ts | 4 +++ .../BaseTreeSitterScopeHandler.ts | 1 + .../TreeSitterIterationScopeHandler.ts | 3 ++- .../TreeSitterScopeHandler.ts | 8 +++++- .../TreeSitterTextFragmentScopeHandler.ts | 3 ++- .../modifiers/scopeHandlers/scope.types.ts | 3 +++ .../contiguousScope/changeComment.yml | 4 +-- .../contiguousScope/changeComment2.yml | 4 +-- .../contiguousScope/changeComment3.yml | 4 +-- .../contiguousScope/changeComment4.yml | 6 ++--- .../contiguousScope/changeComment5.yml | 25 +++++++++++++++++ .../contiguousScope/changeComment6.yml | 25 +++++++++++++++++ .../contiguousScope/changeComment7.yml | 27 +++++++++++++++++++ .../contiguousScope/changeComment8.yml | 27 +++++++++++++++++++ queries/java.scm | 12 ++++++--- queries/javascript.core.scm | 5 +++- queries/python.scm | 5 +++- 22 files changed, 178 insertions(+), 19 deletions(-) create mode 100644 packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment5.yml create mode 100644 packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment6.yml create mode 100644 packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment7.yml create mode 100644 packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment8.yml diff --git a/packages/cursorless-engine/src/languages/TreeSitterQuery/QueryCapture.ts b/packages/cursorless-engine/src/languages/TreeSitterQuery/QueryCapture.ts index f92fde3098..ad9d09b3da 100644 --- a/packages/cursorless-engine/src/languages/TreeSitterQuery/QueryCapture.ts +++ b/packages/cursorless-engine/src/languages/TreeSitterQuery/QueryCapture.ts @@ -36,6 +36,9 @@ export interface QueryCapture { * content ranges. */ readonly allowMultiple: boolean; + /** Whether this scope should expand contiguously to its siblings. */ + readonly contiguous: boolean; + /** The insertion delimiter to use if any */ readonly insertionDelimiter: string | undefined; } @@ -63,6 +66,7 @@ export interface MutableQueryCapture extends QueryCapture { readonly document: TextDocument; range: Range; allowMultiple: boolean; + contiguous: boolean; insertionDelimiter: string | undefined; } diff --git a/packages/cursorless-engine/src/languages/TreeSitterQuery/TreeSitterQuery.ts b/packages/cursorless-engine/src/languages/TreeSitterQuery/TreeSitterQuery.ts index 3ecd56b1a5..20f29b41ed 100644 --- a/packages/cursorless-engine/src/languages/TreeSitterQuery/TreeSitterQuery.ts +++ b/packages/cursorless-engine/src/languages/TreeSitterQuery/TreeSitterQuery.ts @@ -82,6 +82,7 @@ export class TreeSitterQuery { range: getNodeRange(node), insertionDelimiter: undefined, allowMultiple: false, + contiguous: false, })), }), ) @@ -114,6 +115,7 @@ export class TreeSitterQuery { .map(({ range }) => range) .reduce((accumulator, range) => range.union(accumulator)), allowMultiple: captures.some((capture) => capture.allowMultiple), + contiguous: captures.some((capture) => capture.contiguous), insertionDelimiter: captures.find( (capture) => capture.insertionDelimiter != null, )?.insertionDelimiter, diff --git a/packages/cursorless-engine/src/languages/TreeSitterQuery/checkCaptureStartEnd.test.ts b/packages/cursorless-engine/src/languages/TreeSitterQuery/checkCaptureStartEnd.test.ts index 3d4afa5729..946d7dd52c 100644 --- a/packages/cursorless-engine/src/languages/TreeSitterQuery/checkCaptureStartEnd.test.ts +++ b/packages/cursorless-engine/src/languages/TreeSitterQuery/checkCaptureStartEnd.test.ts @@ -5,7 +5,10 @@ import assert from "assert"; interface TestCase { name: string; - captures: Omit[]; + captures: Omit< + QueryCapture, + "allowMultiple" | "contiguous" | "insertionDelimiter" + >[]; isValid: boolean; expectedErrorMessageIds: string[]; } @@ -192,6 +195,7 @@ suite("checkCaptureStartEnd", () => { testCase.captures.map((capture) => ({ ...capture, allowMultiple: false, + contiguous: false, insertionDelimiter: undefined, })), messages, diff --git a/packages/cursorless-engine/src/languages/TreeSitterQuery/queryPredicateOperators.ts b/packages/cursorless-engine/src/languages/TreeSitterQuery/queryPredicateOperators.ts index 92177ace8f..b2ced4ed42 100644 --- a/packages/cursorless-engine/src/languages/TreeSitterQuery/queryPredicateOperators.ts +++ b/packages/cursorless-engine/src/languages/TreeSitterQuery/queryPredicateOperators.ts @@ -185,6 +185,23 @@ class AllowMultiple extends QueryPredicateOperator { } } +/** Indicates that it's okay for this scope to extend contiguously it through its siblings. */ +class Contiguous extends QueryPredicateOperator { + name = "contiguous!" as const; + schema = z.union([z.tuple([q.node]), z.tuple([q.node, q.string])]); + + run(nodeInfo: MutableQueryCapture, pattern?: string) { + if (pattern != null) { + const text = nodeInfo.document.getText(nodeInfo.range); + nodeInfo.contiguous = new RegExp(pattern, "s").test(text); + } else { + nodeInfo.contiguous = true; + } + + return true; + } +} + /** * A predicate operator that logs a node, for debugging. */ @@ -254,6 +271,7 @@ export const queryPredicateOperators = [ new ChildRange(), new ShrinkToMatch(), new AllowMultiple(), + new Contiguous(), new InsertionDelimiter(), new SingleOrMultilineDelimiter(), new HasMultipleChildrenOfType(), diff --git a/packages/cursorless-engine/src/languages/TreeSitterQuery/rewriteStartOfEndOf.test.ts b/packages/cursorless-engine/src/languages/TreeSitterQuery/rewriteStartOfEndOf.test.ts index cc8e99c789..cd2152e19f 100644 --- a/packages/cursorless-engine/src/languages/TreeSitterQuery/rewriteStartOfEndOf.test.ts +++ b/packages/cursorless-engine/src/languages/TreeSitterQuery/rewriteStartOfEndOf.test.ts @@ -54,6 +54,7 @@ function fillOutCapture(capture: NameRange): MutableQueryCapture { return { ...capture, allowMultiple: false, + contiguous: false, insertionDelimiter: undefined, document: null as unknown as TextDocument, node: null as unknown as SyntaxNode, diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts index c6d2eb2435..77aa7f73a4 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ContiguousScopeHandler.ts @@ -116,6 +116,10 @@ function* generateTargetRangesInDirection( } function isAdjacent(scope1: TargetScope, scope2: TargetScope): boolean { + if (!scope1.contiguous || !scope2.contiguous) { + return false; + } + if (scope1.domain.isRangeEqual(scope2.domain)) { return true; } diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/TreeSitterScopeHandler/BaseTreeSitterScopeHandler.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/TreeSitterScopeHandler/BaseTreeSitterScopeHandler.ts index 373f8112cd..882933d39c 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/TreeSitterScopeHandler/BaseTreeSitterScopeHandler.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/TreeSitterScopeHandler/BaseTreeSitterScopeHandler.ts @@ -95,4 +95,5 @@ export abstract class BaseTreeSitterScopeHandler extends BaseScopeHandler { export interface ExtendedTargetScope extends TargetScope { allowMultiple: boolean; + contiguous: boolean; } diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/TreeSitterScopeHandler/TreeSitterIterationScopeHandler.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/TreeSitterScopeHandler/TreeSitterIterationScopeHandler.ts index 7b0a044103..8f3c11285a 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/TreeSitterScopeHandler/TreeSitterIterationScopeHandler.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/TreeSitterScopeHandler/TreeSitterIterationScopeHandler.ts @@ -42,7 +42,7 @@ export class TreeSitterIterationScopeHandler extends BaseTreeSitterScopeHandler return undefined; } - const { range: contentRange, allowMultiple } = capture; + const { range: contentRange, allowMultiple, contiguous } = capture; const domain = getRelatedRange(match, scopeTypeType, "iteration.domain", false) ?? @@ -52,6 +52,7 @@ export class TreeSitterIterationScopeHandler extends BaseTreeSitterScopeHandler editor, domain, allowMultiple, + contiguous, getTargets: (isReversed) => [ new PlainTarget({ editor, diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/TreeSitterScopeHandler/TreeSitterScopeHandler.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/TreeSitterScopeHandler/TreeSitterScopeHandler.ts index e5d054ee63..e97e49e7ce 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/TreeSitterScopeHandler/TreeSitterScopeHandler.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/TreeSitterScopeHandler/TreeSitterScopeHandler.ts @@ -48,7 +48,12 @@ export class TreeSitterScopeHandler extends BaseTreeSitterScopeHandler { return undefined; } - const { range: contentRange, allowMultiple, insertionDelimiter } = capture; + const { + range: contentRange, + allowMultiple, + contiguous, + insertionDelimiter, + } = capture; const domain = getRelatedRange(match, scopeTypeType, "domain", true) ?? contentRange; @@ -87,6 +92,7 @@ export class TreeSitterScopeHandler extends BaseTreeSitterScopeHandler { editor, domain, allowMultiple, + contiguous, getTargets: (isReversed) => [ new ScopeTypeTarget({ scopeTypeType, diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/TreeSitterScopeHandler/TreeSitterTextFragmentScopeHandler.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/TreeSitterScopeHandler/TreeSitterTextFragmentScopeHandler.ts index a7fb8609dd..79684e9278 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/TreeSitterScopeHandler/TreeSitterTextFragmentScopeHandler.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/TreeSitterScopeHandler/TreeSitterTextFragmentScopeHandler.ts @@ -38,7 +38,7 @@ export class TreeSitterTextFragmentScopeHandler extends BaseTreeSitterScopeHandl return undefined; } - const { range: contentRange, allowMultiple } = capture; + const { range: contentRange, allowMultiple, contiguous } = capture; if (allowMultiple) { throw Error( @@ -50,6 +50,7 @@ export class TreeSitterTextFragmentScopeHandler extends BaseTreeSitterScopeHandl editor, domain: contentRange, allowMultiple, + contiguous, getTargets: (isReversed) => [ new PlainTarget({ editor, diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/scope.types.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/scope.types.ts index 73ce68be3d..4b191dd942 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/scope.types.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/scope.types.ts @@ -32,6 +32,9 @@ export interface TargetScope { */ readonly domain: Range; + /** Whether this scope could expand contiguously to its siblings. */ + readonly contiguous?: boolean; + /** * The targets corresponding to this scope. Note that there will almost * always be exactly one target, but there are some exceptions, eg "tags" in diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment.yml index 5862397660..08e61a9eb8 100644 --- a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment.yml +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment.yml @@ -12,8 +12,8 @@ command: usePrePhraseSnapshot: true initialState: documentContents: |- - // hello - // world + // Hello + // World selections: - anchor: {line: 0, character: 0} active: {line: 0, character: 0} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment2.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment2.yml index 76b2c53287..670bb896fa 100644 --- a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment2.yml +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment2.yml @@ -12,8 +12,8 @@ command: usePrePhraseSnapshot: true initialState: documentContents: |- - // hello - // world + // Hello + // World selections: - anchor: {line: 1, character: 8} active: {line: 1, character: 8} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment3.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment3.yml index 437c0febad..9e3ab8cef8 100644 --- a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment3.yml +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment3.yml @@ -12,8 +12,8 @@ command: usePrePhraseSnapshot: true initialState: documentContents: |- - // hello - // world + // Hello + // World selections: - anchor: {line: 1, character: 0} active: {line: 1, character: 0} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment4.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment4.yml index 1dc52eaa64..ea955c8d5c 100644 --- a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment4.yml +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment4.yml @@ -12,9 +12,9 @@ command: usePrePhraseSnapshot: true initialState: documentContents: |- - // hello + // Hello - // world + // World selections: - anchor: {line: 0, character: 0} active: {line: 0, character: 0} @@ -23,7 +23,7 @@ finalState: documentContents: |- - // world + // World selections: - anchor: {line: 0, character: 0} active: {line: 0, character: 0} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment5.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment5.yml new file mode 100644 index 0000000000..ad8dd1d273 --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment5.yml @@ -0,0 +1,25 @@ +languageId: python +command: + version: 6 + spokenForm: change comment + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - type: containingScope + scopeType: {type: comment} + usePrePhraseSnapshot: true +initialState: + documentContents: |- + # Hello + # World + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: {} +finalState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment6.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment6.yml new file mode 100644 index 0000000000..caacfd20b1 --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment6.yml @@ -0,0 +1,25 @@ +languageId: java +command: + version: 6 + spokenForm: change comment + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - type: containingScope + scopeType: {type: comment} + usePrePhraseSnapshot: true +initialState: + documentContents: |- + // Hello + // World + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: {} +finalState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment7.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment7.yml new file mode 100644 index 0000000000..a49a209eab --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment7.yml @@ -0,0 +1,27 @@ +languageId: java +command: + version: 6 + spokenForm: change comment + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - type: containingScope + scopeType: {type: comment} + usePrePhraseSnapshot: true +initialState: + documentContents: |- + /* Hello */ + /* Wold */ + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: {} +finalState: + documentContents: |- + + /* Wold */ + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment8.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment8.yml new file mode 100644 index 0000000000..971002a4b0 --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment8.yml @@ -0,0 +1,27 @@ +languageId: javascript +command: + version: 6 + spokenForm: change comment + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - type: containingScope + scopeType: {type: comment} + usePrePhraseSnapshot: true +initialState: + documentContents: |- + /** Hello */ + /** World */ + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: {} +finalState: + documentContents: |- + + /** World */ + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} diff --git a/queries/java.scm b/queries/java.scm index 3058270539..b74ff0b67a 100644 --- a/queries/java.scm +++ b/queries/java.scm @@ -66,10 +66,14 @@ ;;!! // comment ;;! ^^^^^^^^^^ -[ - (line_comment) - (block_comment) -] @comment @textFragment +( + (line_comment) @comment @textFragment + (#contiguous! @comment) +) + +;;!! /* comment */ +;;! ^^^^^^^^^^^^^ +(block_comment) @comment @textFragment ;;!! int[] values = {1, 2, 3}; ;;! ^^^^^^^^^ diff --git a/queries/javascript.core.scm b/queries/javascript.core.scm index d69ee12fca..ddaae57e3c 100644 --- a/queries/javascript.core.scm +++ b/queries/javascript.core.scm @@ -434,7 +434,10 @@ ;;!! // comment ;;! ^^^^^^^^^^ -(comment) @comment +( + (comment) @comment + (#contiguous! @comment "^//") +) ;;!! /\w+/ ;;! ^^^^^ diff --git a/queries/python.scm b/queries/python.scm index 8095d88f18..1083c7baa0 100644 --- a/queries/python.scm +++ b/queries/python.scm @@ -163,7 +163,10 @@ ":" @_.domain.end ) @_.domain.start.startOf -(comment) @comment @textFragment +( + (comment) @comment @textFragment + (#contiguous! @comment) +) (string _ @textFragment.start.endOf From b6ac60f708834daa151b24cf4d3f86f7728c4c8c Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Fri, 15 Dec 2023 09:31:07 +0100 Subject: [PATCH 30/33] Added comment facets --- .../common/src/scopeSupportFacets/java.ts | 3 +++ .../common/src/scopeSupportFacets/python.ts | 3 +++ .../common/src/scopeSupportFacets/talon.ts | 3 +++ .../fixtures/scopes/java/comment.block.scope | 16 +++++++++++++++ .../fixtures/scopes/java/comment.block2.scope | 16 +++++++++++++++ .../fixtures/scopes/java/comment.block3.scope | 13 ++++++++++++ .../fixtures/scopes/java/comment.line.scope | 10 ++++++++++ .../scopes/javascript/comment.block3.scope | 13 ++++++++++++ .../scopes/python/comment.block.scope | 13 ++++++++++++ .../fixtures/scopes/python/comment.line.scope | 10 ++++++++++ .../fixtures/scopes/talon/comment.block.scope | 13 ++++++++++++ .../fixtures/scopes/talon/comment.line.scope | 10 ++++++++++ .../src/suite/scopes.vscode.test.ts | 20 +++++++++---------- queries/talon.scm | 5 ++++- 14 files changed, 136 insertions(+), 12 deletions(-) create mode 100644 packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/java/comment.block.scope create mode 100644 packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/java/comment.block2.scope create mode 100644 packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/java/comment.block3.scope create mode 100644 packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/java/comment.line.scope create mode 100644 packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/javascript/comment.block3.scope create mode 100644 packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/python/comment.block.scope create mode 100644 packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/python/comment.line.scope create mode 100644 packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/talon/comment.block.scope create mode 100644 packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/talon/comment.line.scope diff --git a/packages/common/src/scopeSupportFacets/java.ts b/packages/common/src/scopeSupportFacets/java.ts index 1d4e56c7e8..79832ddeb2 100644 --- a/packages/common/src/scopeSupportFacets/java.ts +++ b/packages/common/src/scopeSupportFacets/java.ts @@ -12,6 +12,9 @@ export const javaScopeSupport: LanguageScopeSupportFacetMap = { "value.foreach": supported, "type.foreach": supported, + "comment.line": supported, + "comment.block": supported, + element: notApplicable, tags: notApplicable, attribute: notApplicable, diff --git a/packages/common/src/scopeSupportFacets/python.ts b/packages/common/src/scopeSupportFacets/python.ts index 4c6d25572e..26198da4be 100644 --- a/packages/common/src/scopeSupportFacets/python.ts +++ b/packages/common/src/scopeSupportFacets/python.ts @@ -16,6 +16,9 @@ export const pythonScopeSupport: LanguageScopeSupportFacetMap = { "argument.formal": supportedLegacy, "argument.formal.iteration": supportedLegacy, + "comment.line": supported, + "comment.block": supported, + element: notApplicable, tags: notApplicable, attribute: notApplicable, diff --git a/packages/common/src/scopeSupportFacets/talon.ts b/packages/common/src/scopeSupportFacets/talon.ts index b9cff24296..e4aae83ca6 100644 --- a/packages/common/src/scopeSupportFacets/talon.ts +++ b/packages/common/src/scopeSupportFacets/talon.ts @@ -9,4 +9,7 @@ const { supported } = ScopeSupportFacetLevel; export const talonScopeSupport: LanguageScopeSupportFacetMap = { command: supported, + + "comment.line": supported, + "comment.block": supported, }; diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/java/comment.block.scope b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/java/comment.block.scope new file mode 100644 index 0000000000..c6263b704d --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/java/comment.block.scope @@ -0,0 +1,16 @@ +/* + Hello world +*/ +--- + +[Content] = +[Removal] = +[Domain] = 0:0-2:2 +0| /* + >-- +1| Hello world + ------------- +2| */ + --< + +[Insertion delimiter] = "\n" diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/java/comment.block2.scope b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/java/comment.block2.scope new file mode 100644 index 0000000000..0b1fc29e6e --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/java/comment.block2.scope @@ -0,0 +1,16 @@ +/** +* Hello world +*/ +--- + +[Content] = +[Removal] = +[Domain] = 0:0-2:2 +0| /** + >--- +1| * Hello world + ------------- +2| */ + --< + +[Insertion delimiter] = "\n" diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/java/comment.block3.scope b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/java/comment.block3.scope new file mode 100644 index 0000000000..4e43c0ebd8 --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/java/comment.block3.scope @@ -0,0 +1,13 @@ +// Hello +// World +--- + +[Content] = +[Removal] = +[Domain] = 0:0-1:8 +0| // Hello + >-------- +1| // World + --------< + +[Insertion delimiter] = "\n" diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/java/comment.line.scope b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/java/comment.line.scope new file mode 100644 index 0000000000..517cc2e6e2 --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/java/comment.line.scope @@ -0,0 +1,10 @@ +// Hello world +--- + +[Content] = +[Removal] = +[Domain] = 0:0-0:14 +0| // Hello world + >--------------< + +[Insertion delimiter] = "\n" diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/javascript/comment.block3.scope b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/javascript/comment.block3.scope new file mode 100644 index 0000000000..4e43c0ebd8 --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/javascript/comment.block3.scope @@ -0,0 +1,13 @@ +// Hello +// World +--- + +[Content] = +[Removal] = +[Domain] = 0:0-1:8 +0| // Hello + >-------- +1| // World + --------< + +[Insertion delimiter] = "\n" diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/python/comment.block.scope b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/python/comment.block.scope new file mode 100644 index 0000000000..2763f25c13 --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/python/comment.block.scope @@ -0,0 +1,13 @@ +# Hello +# World +--- + +[Content] = +[Removal] = +[Domain] = 0:0-1:7 +0| # Hello + >------- +1| # World + -------< + +[Insertion delimiter] = "\n" diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/python/comment.line.scope b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/python/comment.line.scope new file mode 100644 index 0000000000..94396062e4 --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/python/comment.line.scope @@ -0,0 +1,10 @@ +# Hello world +--- + +[Content] = +[Removal] = +[Domain] = 0:0-0:13 +0| # Hello world + >-------------< + +[Insertion delimiter] = "\n" diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/talon/comment.block.scope b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/talon/comment.block.scope new file mode 100644 index 0000000000..2763f25c13 --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/talon/comment.block.scope @@ -0,0 +1,13 @@ +# Hello +# World +--- + +[Content] = +[Removal] = +[Domain] = 0:0-1:7 +0| # Hello + >------- +1| # World + -------< + +[Insertion delimiter] = "\n" diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/talon/comment.line.scope b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/talon/comment.line.scope new file mode 100644 index 0000000000..94396062e4 --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/talon/comment.line.scope @@ -0,0 +1,10 @@ +# Hello world +--- + +[Content] = +[Removal] = +[Domain] = 0:0-0:13 +0| # Hello world + >-------------< + +[Insertion delimiter] = "\n" diff --git a/packages/cursorless-vscode-e2e/src/suite/scopes.vscode.test.ts b/packages/cursorless-vscode-e2e/src/suite/scopes.vscode.test.ts index c53ba5d837..6527a7deb1 100644 --- a/packages/cursorless-vscode-e2e/src/suite/scopes.vscode.test.ts +++ b/packages/cursorless-vscode-e2e/src/suite/scopes.vscode.test.ts @@ -145,19 +145,17 @@ function getScopeType( scopeType: ScopeType; isIteration: boolean; } { - if (languageId === "textual") { - const { scopeType, isIteration } = - textualScopeSupportFacetInfos[facetId as TextualScopeSupportFacet]; - return { - scopeType: { type: scopeType }, - isIteration: isIteration ?? false, - }; + const facetInfo = + languageId === "textual" + ? textualScopeSupportFacetInfos[facetId as TextualScopeSupportFacet] + : scopeSupportFacetInfos[facetId as ScopeSupportFacet]; + + if (facetInfo == null) { + throw Error(`Unknown facet '${facetId}'`); } - const { scopeType, isIteration } = - scopeSupportFacetInfos[facetId as ScopeSupportFacet]; return { - scopeType: { type: scopeType }, - isIteration: isIteration ?? false, + scopeType: { type: facetInfo.scopeType }, + isIteration: facetInfo.isIteration ?? false, }; } diff --git a/queries/talon.scm b/queries/talon.scm index 884e7b94ff..ce796296c7 100644 --- a/queries/talon.scm +++ b/queries/talon.scm @@ -174,4 +174,7 @@ arguments: (_) @argumentOrParameter.iteration ;;!! # foo ;;! ^^^^^ -(comment) @comment +( + (comment) @comment + (#contiguous! @comment) +) From 17b0507d1379d99ec298f5b660de268190369c56 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 26 Feb 2024 07:24:07 +0100 Subject: [PATCH 31/33] Remove pattern argument from contiguous predicate --- .../TreeSitterQuery/queryPredicateOperators.ts | 15 +++++---------- queries/javascript.core.scm | 7 ++++++- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/cursorless-engine/src/languages/TreeSitterQuery/queryPredicateOperators.ts b/packages/cursorless-engine/src/languages/TreeSitterQuery/queryPredicateOperators.ts index b2ced4ed42..3f24854546 100644 --- a/packages/cursorless-engine/src/languages/TreeSitterQuery/queryPredicateOperators.ts +++ b/packages/cursorless-engine/src/languages/TreeSitterQuery/queryPredicateOperators.ts @@ -185,18 +185,13 @@ class AllowMultiple extends QueryPredicateOperator { } } -/** Indicates that it's okay for this scope to extend contiguously it through its siblings. */ +/** Indicates that it's okay for this scope to extend contiguously through its siblings of same type. */ class Contiguous extends QueryPredicateOperator { name = "contiguous!" as const; - schema = z.union([z.tuple([q.node]), z.tuple([q.node, q.string])]); - - run(nodeInfo: MutableQueryCapture, pattern?: string) { - if (pattern != null) { - const text = nodeInfo.document.getText(nodeInfo.range); - nodeInfo.contiguous = new RegExp(pattern, "s").test(text); - } else { - nodeInfo.contiguous = true; - } + schema = z.tuple([q.node]); + + run(nodeInfo: MutableQueryCapture) { + nodeInfo.contiguous = true; return true; } diff --git a/queries/javascript.core.scm b/queries/javascript.core.scm index 95842b6eeb..0c7676d62f 100644 --- a/queries/javascript.core.scm +++ b/queries/javascript.core.scm @@ -435,7 +435,12 @@ ;;! ^^^^^^^^^^ ( (comment) @comment - (#contiguous! @comment "^//") + (#match? @comment "^//") + (#contiguous! @comment) +) +( + (comment) @comment + (#not-match? @comment "^//") ) ;;!! /\w+/ From 9f156a68abf4897f66920d6cb2f6e133cd787399 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 26 Feb 2024 07:41:47 +0100 Subject: [PATCH 32/33] Update scope fixtures --- .../src/suite/fixtures/scopes/java/comment.block.scope | 3 +-- .../src/suite/fixtures/scopes/java/comment.block2.scope | 3 +-- .../src/suite/fixtures/scopes/java/comment.block3.scope | 2 +- .../src/suite/fixtures/scopes/java/comment.line.scope | 2 +- .../src/suite/fixtures/scopes/javascript/comment.block3.scope | 2 +- .../src/suite/fixtures/scopes/python/comment.block.scope | 2 +- .../src/suite/fixtures/scopes/python/comment.line.scope | 2 +- .../src/suite/fixtures/scopes/talon/comment.block.scope | 2 +- .../src/suite/fixtures/scopes/talon/comment.line.scope | 2 +- 9 files changed, 9 insertions(+), 11 deletions(-) diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/java/comment.block.scope b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/java/comment.block.scope index c6263b704d..f8b38ca6af 100644 --- a/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/java/comment.block.scope +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/java/comment.block.scope @@ -6,10 +6,9 @@ [Content] = [Removal] = [Domain] = 0:0-2:2 -0| /* >-- +0| /* 1| Hello world - ------------- 2| */ --< diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/java/comment.block2.scope b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/java/comment.block2.scope index 0b1fc29e6e..a0ab76da25 100644 --- a/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/java/comment.block2.scope +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/java/comment.block2.scope @@ -6,10 +6,9 @@ [Content] = [Removal] = [Domain] = 0:0-2:2 -0| /** >--- +0| /** 1| * Hello world - ------------- 2| */ --< diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/java/comment.block3.scope b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/java/comment.block3.scope index 4e43c0ebd8..b4fbefaaaa 100644 --- a/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/java/comment.block3.scope +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/java/comment.block3.scope @@ -5,8 +5,8 @@ [Content] = [Removal] = [Domain] = 0:0-1:8 -0| // Hello >-------- +0| // Hello 1| // World --------< diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/java/comment.line.scope b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/java/comment.line.scope index 517cc2e6e2..7d1477b8a1 100644 --- a/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/java/comment.line.scope +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/java/comment.line.scope @@ -4,7 +4,7 @@ [Content] = [Removal] = [Domain] = 0:0-0:14 -0| // Hello world >--------------< +0| // Hello world [Insertion delimiter] = "\n" diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/javascript/comment.block3.scope b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/javascript/comment.block3.scope index 4e43c0ebd8..b4fbefaaaa 100644 --- a/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/javascript/comment.block3.scope +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/javascript/comment.block3.scope @@ -5,8 +5,8 @@ [Content] = [Removal] = [Domain] = 0:0-1:8 -0| // Hello >-------- +0| // Hello 1| // World --------< diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/python/comment.block.scope b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/python/comment.block.scope index 2763f25c13..6d40f81d29 100644 --- a/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/python/comment.block.scope +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/python/comment.block.scope @@ -5,8 +5,8 @@ [Content] = [Removal] = [Domain] = 0:0-1:7 -0| # Hello >------- +0| # Hello 1| # World -------< diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/python/comment.line.scope b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/python/comment.line.scope index 94396062e4..42719cdbb8 100644 --- a/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/python/comment.line.scope +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/python/comment.line.scope @@ -4,7 +4,7 @@ [Content] = [Removal] = [Domain] = 0:0-0:13 -0| # Hello world >-------------< +0| # Hello world [Insertion delimiter] = "\n" diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/talon/comment.block.scope b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/talon/comment.block.scope index 2763f25c13..6d40f81d29 100644 --- a/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/talon/comment.block.scope +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/talon/comment.block.scope @@ -5,8 +5,8 @@ [Content] = [Removal] = [Domain] = 0:0-1:7 -0| # Hello >------- +0| # Hello 1| # World -------< diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/talon/comment.line.scope b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/talon/comment.line.scope index 94396062e4..42719cdbb8 100644 --- a/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/talon/comment.line.scope +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/scopes/talon/comment.line.scope @@ -4,7 +4,7 @@ [Content] = [Removal] = [Domain] = 0:0-0:13 -0| # Hello world >-------------< +0| # Hello world [Insertion delimiter] = "\n" From 883eb1ed88c23d55fb9cd6fd7a640b652af3902f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Fri, 14 Jun 2024 15:32:03 +0000 Subject: [PATCH 33/33] [pre-commit.ci lite] apply automatic fixes --- .../recorded/contiguousScope/changeComment.yml | 10 +++++----- .../recorded/contiguousScope/changeComment2.yml | 10 +++++----- .../recorded/contiguousScope/changeComment3.yml | 10 +++++----- .../recorded/contiguousScope/changeComment4.yml | 10 +++++----- .../recorded/contiguousScope/changeComment5.yml | 10 +++++----- .../recorded/contiguousScope/changeComment6.yml | 10 +++++----- .../recorded/contiguousScope/changeComment7.yml | 10 +++++----- .../recorded/contiguousScope/changeComment8.yml | 10 +++++----- 8 files changed, 40 insertions(+), 40 deletions(-) diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment.yml index 08e61a9eb8..1e87859b9b 100644 --- a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment.yml +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment.yml @@ -8,18 +8,18 @@ command: type: primitive modifiers: - type: containingScope - scopeType: {type: comment} + scopeType: { type: comment } usePrePhraseSnapshot: true initialState: documentContents: |- // Hello // World selections: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} + - anchor: { line: 0, character: 0 } + active: { line: 0, character: 0 } marks: {} finalState: documentContents: "" selections: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} + - anchor: { line: 0, character: 0 } + active: { line: 0, character: 0 } diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment2.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment2.yml index 670bb896fa..a1eb8cf21b 100644 --- a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment2.yml +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment2.yml @@ -8,18 +8,18 @@ command: type: primitive modifiers: - type: containingScope - scopeType: {type: comment} + scopeType: { type: comment } usePrePhraseSnapshot: true initialState: documentContents: |- // Hello // World selections: - - anchor: {line: 1, character: 8} - active: {line: 1, character: 8} + - anchor: { line: 1, character: 8 } + active: { line: 1, character: 8 } marks: {} finalState: documentContents: "" selections: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} + - anchor: { line: 0, character: 0 } + active: { line: 0, character: 0 } diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment3.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment3.yml index 9e3ab8cef8..cb31e88d74 100644 --- a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment3.yml +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment3.yml @@ -8,18 +8,18 @@ command: type: primitive modifiers: - type: containingScope - scopeType: {type: comment} + scopeType: { type: comment } usePrePhraseSnapshot: true initialState: documentContents: |- // Hello // World selections: - - anchor: {line: 1, character: 0} - active: {line: 1, character: 0} + - anchor: { line: 1, character: 0 } + active: { line: 1, character: 0 } marks: {} finalState: documentContents: "" selections: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} + - anchor: { line: 0, character: 0 } + active: { line: 0, character: 0 } diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment4.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment4.yml index ea955c8d5c..19286e007f 100644 --- a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment4.yml +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment4.yml @@ -8,7 +8,7 @@ command: type: primitive modifiers: - type: containingScope - scopeType: {type: comment} + scopeType: { type: comment } usePrePhraseSnapshot: true initialState: documentContents: |- @@ -16,8 +16,8 @@ initialState: // World selections: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} + - anchor: { line: 0, character: 0 } + active: { line: 0, character: 0 } marks: {} finalState: documentContents: |- @@ -25,5 +25,5 @@ finalState: // World selections: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} + - anchor: { line: 0, character: 0 } + active: { line: 0, character: 0 } diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment5.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment5.yml index ad8dd1d273..70ed4afb60 100644 --- a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment5.yml +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment5.yml @@ -8,18 +8,18 @@ command: type: primitive modifiers: - type: containingScope - scopeType: {type: comment} + scopeType: { type: comment } usePrePhraseSnapshot: true initialState: documentContents: |- # Hello # World selections: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} + - anchor: { line: 0, character: 0 } + active: { line: 0, character: 0 } marks: {} finalState: documentContents: "" selections: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} + - anchor: { line: 0, character: 0 } + active: { line: 0, character: 0 } diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment6.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment6.yml index caacfd20b1..16007f2c08 100644 --- a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment6.yml +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment6.yml @@ -8,18 +8,18 @@ command: type: primitive modifiers: - type: containingScope - scopeType: {type: comment} + scopeType: { type: comment } usePrePhraseSnapshot: true initialState: documentContents: |- // Hello // World selections: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} + - anchor: { line: 0, character: 0 } + active: { line: 0, character: 0 } marks: {} finalState: documentContents: "" selections: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} + - anchor: { line: 0, character: 0 } + active: { line: 0, character: 0 } diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment7.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment7.yml index a49a209eab..d6be6a8fbe 100644 --- a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment7.yml +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment7.yml @@ -8,20 +8,20 @@ command: type: primitive modifiers: - type: containingScope - scopeType: {type: comment} + scopeType: { type: comment } usePrePhraseSnapshot: true initialState: documentContents: |- /* Hello */ /* Wold */ selections: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} + - anchor: { line: 0, character: 0 } + active: { line: 0, character: 0 } marks: {} finalState: documentContents: |- /* Wold */ selections: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} + - anchor: { line: 0, character: 0 } + active: { line: 0, character: 0 } diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment8.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment8.yml index 971002a4b0..c2cfbdbb1d 100644 --- a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment8.yml +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/contiguousScope/changeComment8.yml @@ -8,20 +8,20 @@ command: type: primitive modifiers: - type: containingScope - scopeType: {type: comment} + scopeType: { type: comment } usePrePhraseSnapshot: true initialState: documentContents: |- /** Hello */ /** World */ selections: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} + - anchor: { line: 0, character: 0 } + active: { line: 0, character: 0 } marks: {} finalState: documentContents: |- /** World */ selections: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} + - anchor: { line: 0, character: 0 } + active: { line: 0, character: 0 }