From 72c46b7edbd8195c24a61b83a6f8f7971347944f Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 18 Sep 2024 08:51:16 +0200 Subject: [PATCH] Don't use multiline pairs for head/tail modifier. (#2659) `change tail` did the wrong thing in this case ```py """|foo bar """ ``` ## Checklist - [x] I have added [tests](https://www.cursorless.org/docs/contributing/test-case-recorder/) - [/] I have updated the [docs](https://github.com/cursorless-dev/cursorless/tree/main/docs) and [cheatsheet](https://github.com/cursorless-dev/cursorless/tree/main/cursorless-talon/src/cheatsheet) - [/] I have not broken the cheatsheet --- .../recorded/headTail/changeTail3.yml | 28 +++++++++++++++++++ .../command/PartialTargetDescriptor.types.ts | 2 ++ .../processTargets/modifiers/HeadTailStage.ts | 1 + .../SurroundingPairInteriorScopeHandler.ts | 28 +++++++++++-------- 4 files changed, 47 insertions(+), 12 deletions(-) create mode 100644 data/fixtures/recorded/headTail/changeTail3.yml diff --git a/data/fixtures/recorded/headTail/changeTail3.yml b/data/fixtures/recorded/headTail/changeTail3.yml new file mode 100644 index 0000000000..ae6e6412a2 --- /dev/null +++ b/data/fixtures/recorded/headTail/changeTail3.yml @@ -0,0 +1,28 @@ +languageId: python +command: + version: 7 + spokenForm: change tail + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - {type: extendThroughEndOf} + usePrePhraseSnapshot: true +initialState: + documentContents: |- + """foo + bar + """ + selections: + - anchor: {line: 0, character: 3} + active: {line: 0, character: 3} + marks: {} +finalState: + documentContents: |- + """ + bar + """ + selections: + - anchor: {line: 0, character: 3} + active: {line: 0, character: 3} diff --git a/packages/common/src/types/command/PartialTargetDescriptor.types.ts b/packages/common/src/types/command/PartialTargetDescriptor.types.ts index 507068286a..a382bc9dc2 100644 --- a/packages/common/src/types/command/PartialTargetDescriptor.types.ts +++ b/packages/common/src/types/command/PartialTargetDescriptor.types.ts @@ -251,6 +251,8 @@ export interface SurroundingPairScopeType { export interface SurroundingPairInteriorScopeType { type: "surroundingPairInterior"; delimiter: SurroundingPairName; + // If true don't yield multiline pairs + requireSingleLine?: boolean; } export interface OneOfScopeType { diff --git a/packages/cursorless-engine/src/processTargets/modifiers/HeadTailStage.ts b/packages/cursorless-engine/src/processTargets/modifiers/HeadTailStage.ts index 91981e977c..71af22afa9 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/HeadTailStage.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/HeadTailStage.ts @@ -27,6 +27,7 @@ export class HeadTailStage implements ModifierStage { { type: "surroundingPairInterior", delimiter: "any", + requireSingleLine: true, }, ], }, diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/SurroundingPairScopeHandler/SurroundingPairInteriorScopeHandler.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/SurroundingPairScopeHandler/SurroundingPairInteriorScopeHandler.ts index 850979e86c..f6be0ac0df 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/SurroundingPairScopeHandler/SurroundingPairInteriorScopeHandler.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/SurroundingPairScopeHandler/SurroundingPairInteriorScopeHandler.ts @@ -5,7 +5,6 @@ import type { TargetScope } from "../scope.types"; import type { ScopeIteratorRequirements } from "../scopeHandler.types"; import { type ScopeHandler } from "../scopeHandler.types"; import type { ScopeHandlerFactory } from "../ScopeHandlerFactory"; -import { map } from "itertools"; export class SurroundingPairInteriorScopeHandler extends BaseScopeHandler { protected isHierarchical = true; @@ -32,20 +31,25 @@ export class SurroundingPairInteriorScopeHandler extends BaseScopeHandler { return this.surroundingPairScopeHandler.iterationScopeType; } - generateScopeCandidates( + *generateScopeCandidates( editor: TextEditor, position: Position, direction: Direction, hints: ScopeIteratorRequirements, ): Iterable { - return map( - this.surroundingPairScopeHandler.generateScopes( - editor, - position, - direction, - hints, - ), - (scope) => ({ + const scopes = this.surroundingPairScopeHandler.generateScopes( + editor, + position, + direction, + hints, + ); + + for (const scope of scopes) { + if (this.scopeType.requireSingleLine && !scope.domain.isSingleLine) { + continue; + } + + yield { editor, domain: scope.domain, getTargets(isReversed) { @@ -53,7 +57,7 @@ export class SurroundingPairInteriorScopeHandler extends BaseScopeHandler { .getTargets(isReversed) .flatMap((target) => target.getInterior()!); }, - }), - ); + }; + } } }