From 206d882b22b0c40d2fa62d70d1d94007744b617d Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Tue, 7 Jun 2022 19:48:19 +0100 Subject: [PATCH 01/17] Implemented head tail modifier that works on multiple scope types --- src/processTargets/modifiers/HeadTailStage.ts | 36 ++++++++++++++----- .../modifiers/OrdinalRangeSubTokenStage.ts | 1 + .../modifiers/SurroundingPairStage.ts | 1 + .../ContainingSyntaxScopeStage.ts | 5 ++- .../scopeTypeStages/DocumentStage.ts | 1 + .../modifiers/scopeTypeStages/LineStage.ts | 11 +++--- .../scopeTypeStages/ParagraphStage.ts | 14 ++++---- .../modifiers/scopeTypeStages/RegexStage.ts | 8 ++++- src/processTargets/targets/BaseTarget.ts | 6 ++++ .../targets/SurroundingPairTarget.ts | 1 + .../compoundTargets/takeLineVestAndAir.yml | 2 ++ .../recorded/selectionTypes/clearHeadCore.yml | 26 ++++++++++++++ .../recorded/selectionTypes/clearHeadFunk.yml | 32 +++++++++++++++++ src/typings/target.types.ts | 2 ++ 14 files changed, 124 insertions(+), 22 deletions(-) create mode 100644 src/test/suite/fixtures/recorded/selectionTypes/clearHeadCore.yml create mode 100644 src/test/suite/fixtures/recorded/selectionTypes/clearHeadFunk.yml diff --git a/src/processTargets/modifiers/HeadTailStage.ts b/src/processTargets/modifiers/HeadTailStage.ts index 175eaceb64..ff0d3bcbd1 100644 --- a/src/processTargets/modifiers/HeadTailStage.ts +++ b/src/processTargets/modifiers/HeadTailStage.ts @@ -1,4 +1,4 @@ -import { Position, Range, TextEditor } from "vscode"; +import { Range, TextEditor } from "vscode"; import { Target } from "../../typings/target.types"; import { HeadModifier, @@ -6,17 +6,35 @@ import { } from "../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; -import TokenTarget from "../targets/TokenTarget"; +import PlainTarget from "../targets/PlainTarget"; +import { toLineTarget } from "./scopeTypeStages/LineStage"; abstract class HeadTailStage implements ModifierStage { - abstract update(editor: TextEditor, range: Range): Range; + abstract update( + editor: TextEditor, + previousRange: Range, + nextRange: Range + ): Range; constructor(private isReversed: boolean) {} run(context: ProcessedTargetsContext, target: Target): Target[] { - const contentRange = this.update(target.editor, target.contentRange); + const { previousRange, nextRange } = (() => { + if (target.previousTarget != null) { + return { + previousRange: target.previousTarget.contentRange, + nextRange: target.contentRange, + }; + } + return { + previousRange: target.contentRange, + nextRange: toLineTarget(target).contentRange, + }; + })(); + + const contentRange = this.update(target.editor, previousRange, nextRange); return [ - new TokenTarget({ + new PlainTarget({ editor: target.editor, isReversed: this.isReversed, contentRange, @@ -30,8 +48,8 @@ export class HeadStage extends HeadTailStage { super(true); } - update(editor: TextEditor, range: Range) { - return new Range(new Position(range.start.line, 0), range.end); + update(editor: TextEditor, previousRange: Range, nextRange: Range) { + return new Range(nextRange.start, previousRange.end); } } @@ -40,7 +58,7 @@ export class TailStage extends HeadTailStage { super(false); } - update(editor: TextEditor, range: Range) { - return new Range(range.start, editor.document.lineAt(range.end).range.end); + update(editor: TextEditor, previousRange: Range, nextRange: Range) { + return new Range(previousRange.start, nextRange.end); } } diff --git a/src/processTargets/modifiers/OrdinalRangeSubTokenStage.ts b/src/processTargets/modifiers/OrdinalRangeSubTokenStage.ts index ac1d14855b..0f5f5dd595 100644 --- a/src/processTargets/modifiers/OrdinalRangeSubTokenStage.ts +++ b/src/processTargets/modifiers/OrdinalRangeSubTokenStage.ts @@ -130,6 +130,7 @@ export default class OrdinalRangeSubTokenStage implements ModifierStage { insertionDelimiter, leadingDelimiterRange, trailingDelimiterRange, + previousTarget: target, }), ]; } diff --git a/src/processTargets/modifiers/SurroundingPairStage.ts b/src/processTargets/modifiers/SurroundingPairStage.ts index bb92ef29b1..6abf99b820 100644 --- a/src/processTargets/modifiers/SurroundingPairStage.ts +++ b/src/processTargets/modifiers/SurroundingPairStage.ts @@ -50,6 +50,7 @@ function processedSurroundingPairTarget( ...pairInfo, editor: target.editor, isReversed: target.isReversed, + previousTarget: target, }), ]; } diff --git a/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts b/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts index 5844e86b7d..f4b43f9350 100644 --- a/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts @@ -32,10 +32,12 @@ export default class implements ModifierStage { ) {} run(context: ProcessedTargetsContext, target: Target): ScopeTypeTarget[] { + const isEveryScope = this.modifier.type === "everyScope"; + const nodeMatcher = getNodeMatcher( target.editor.document.languageId, this.modifier.scopeType.type, - this.modifier.type === "everyScope" + isEveryScope ); const node: SyntaxNode | null = context.getNodeAtLocation( @@ -82,6 +84,7 @@ export default class implements ModifierStage { delimiter: containingListDelimiter, leadingDelimiterRange, trailingDelimiterRange, + previousTarget: isEveryScope ? undefined : target, }); }); } diff --git a/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts b/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts index ebd7dcd39c..5aedd633a1 100644 --- a/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts @@ -17,6 +17,7 @@ export default class implements ModifierStage { editor: target.editor, isReversed: target.isReversed, contentRange: getDocumentRange(target.editor), + previousTarget: target, }), ]; } diff --git a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts index 2e8afefcfa..f02716b9ec 100644 --- a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts @@ -47,11 +47,12 @@ export default class implements ModifierStage { } export function toLineTarget(target: Target): LineTarget { - return createLineTarget( - target.editor, - target.contentRange, - target.isReversed - ); + return new LineTarget({ + editor: target.editor, + isReversed: target.isReversed, + contentRange: fitRangeToLineContent(target.editor, target.contentRange), + previousTarget: target, + }); } export function createLineTarget( diff --git a/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts b/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts index cac90e429a..91cd6b6a5c 100644 --- a/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts @@ -72,14 +72,16 @@ export default class implements ModifierStage { } getSingleTarget(target: Target): ParagraphTarget { - return this.getTargetFromRange(target); + const range = calculateRange(target); + return new ParagraphTarget({ + editor: target.editor, + isReversed: target.isReversed, + contentRange: fitRangeToLineContent(target.editor, range), + previousTarget: target, + }); } - getTargetFromRange(target: Target, range?: Range): ParagraphTarget { - if (range == null) { - range = calculateRange(target); - } - + getTargetFromRange(target: Target, range: Range): ParagraphTarget { return new ParagraphTarget({ editor: target.editor, isReversed: target.isReversed, diff --git a/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts b/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts index a0b7bf86cd..f7e1254ffc 100644 --- a/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts @@ -60,7 +60,13 @@ class RegexStage implements ModifierStage { const start = this.getMatchForPos(editor, target.contentRange.start).start; const end = this.getMatchForPos(editor, target.contentRange.end).end; const contentRange = new Range(start, end); - return this.getTargetFromRange(target, contentRange); + return new ScopeTypeTarget({ + scopeTypeType: this.modifier.scopeType.type, + editor: target.editor, + isReversed: target.isReversed, + contentRange, + previousTarget: target, + }); } getTargetFromRange(target: Target, range: Range): ScopeTypeTarget { diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index 3c1a7a1fcd..9ebf780baa 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -15,6 +15,7 @@ export interface CommonTargetParameters { readonly isReversed: boolean; readonly contentRange: Range; readonly thatTarget?: Target; + readonly previousTarget?: Target; } export interface CloneWithParameters { @@ -35,6 +36,7 @@ export default abstract class BaseTarget implements Target { isReversed: parameters.isReversed, contentRange: parameters.contentRange, thatTarget: parameters.thatTarget, + previousTarget: parameters.previousTarget, }; } @@ -51,6 +53,10 @@ export default abstract class BaseTarget implements Target { : this; } + get previousTarget(): Target | undefined { + return this.state.previousTarget; + } + get contentText(): string { return this.editor.document.getText(this.contentRange); } diff --git a/src/processTargets/targets/SurroundingPairTarget.ts b/src/processTargets/targets/SurroundingPairTarget.ts index c3bc151d74..992da22633 100644 --- a/src/processTargets/targets/SurroundingPairTarget.ts +++ b/src/processTargets/targets/SurroundingPairTarget.ts @@ -52,6 +52,7 @@ export default class SurroundingPairTarget extends BaseTarget { editor: this.editor, isReversed: this.isReversed, contentRange: this.interiorRange_, + previousTarget: this.previousTarget, }), ]; } diff --git a/src/test/suite/fixtures/recorded/compoundTargets/takeLineVestAndAir.yml b/src/test/suite/fixtures/recorded/compoundTargets/takeLineVestAndAir.yml index 6782ffba97..815e70ec28 100644 --- a/src/test/suite/fixtures/recorded/compoundTargets/takeLineVestAndAir.yml +++ b/src/test/suite/fixtures/recorded/compoundTargets/takeLineVestAndAir.yml @@ -31,4 +31,6 @@ finalState: thatMark: - anchor: {line: 0, character: 4} active: {line: 0, character: 17} + - anchor: {line: 0, character: 4} + active: {line: 0, character: 17} fullTargets: [{type: list, elements: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: v}, selectionType: line, position: contents, insideOutsideType: inside, modifier: {type: identity}}, {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: a}, selectionType: line, position: contents, insideOutsideType: inside, modifier: {type: identity}}]}] diff --git a/src/test/suite/fixtures/recorded/selectionTypes/clearHeadCore.yml b/src/test/suite/fixtures/recorded/selectionTypes/clearHeadCore.yml new file mode 100644 index 0000000000..6fc3624883 --- /dev/null +++ b/src/test/suite/fixtures/recorded/selectionTypes/clearHeadCore.yml @@ -0,0 +1,26 @@ +languageId: plaintext +command: + spokenForm: clear head core + version: 2 + targets: + - type: primitive + modifiers: + - {type: head} + - {type: interiorOnly} + usePrePhraseSnapshot: true + action: {name: clearAndSetSelection} +initialState: + documentContents: foo(bar baz) + selections: + - anchor: {line: 0, character: 10} + active: {line: 0, character: 10} + marks: {} +finalState: + documentContents: foo(z) + selections: + - anchor: {line: 0, character: 4} + active: {line: 0, character: 4} + thatMark: + - anchor: {line: 0, character: 4} + active: {line: 0, character: 4} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: head}, {type: interiorOnly}]}] diff --git a/src/test/suite/fixtures/recorded/selectionTypes/clearHeadFunk.yml b/src/test/suite/fixtures/recorded/selectionTypes/clearHeadFunk.yml new file mode 100644 index 0000000000..594bc7023d --- /dev/null +++ b/src/test/suite/fixtures/recorded/selectionTypes/clearHeadFunk.yml @@ -0,0 +1,32 @@ +languageId: typescript +command: + spokenForm: clear head funk + version: 2 + targets: + - type: primitive + modifiers: + - {type: head} + - type: containingScope + scopeType: {type: namedFunction} + usePrePhraseSnapshot: true + action: {name: clearAndSetSelection} +initialState: + documentContents: |- + function whatever() { + + } + selections: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} + marks: {} +finalState: + documentContents: |- + + } + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: head}, {type: containingScope, scopeType: {type: namedFunction}}]}] diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 080e571a21..2ad2dc3f7c 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -46,6 +46,8 @@ export interface Target { /** Internal target that should be used for the that mark */ readonly thatTarget: Target; + readonly previousTarget: Target | undefined; + getInteriorStrict(): Target[]; getBoundaryStrict(): Target[]; /** The range of the delimiter before the content selection */ From 2d0fe2b8ea90a79174f369bc3ca24100d4530e5d Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 13 Jun 2022 12:20:01 +0200 Subject: [PATCH 02/17] Fixed test that broke in merge --- src/processTargets/targets/BaseTarget.ts | 5 ++++- .../fixtures/recorded/compoundTargets/takeLineVestAndAir.yml | 2 -- .../suite/fixtures/recorded/selectionTypes/clearHeadCore.yml | 4 ++-- .../suite/fixtures/recorded/selectionTypes/clearHeadFunk.yml | 4 ++-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index 9ebf780baa..3f0516224e 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -159,7 +159,10 @@ export default abstract class BaseTarget implements Target { isEqual(target: Target): boolean { return ( target instanceof BaseTarget && - isEqual(this.getCloneParameters(), target.getCloneParameters()) + isEqual( + { ...this.getCloneParameters(), previousTarget: null }, + { ...target.getCloneParameters(), previousTarget: null } + ) ); } diff --git a/src/test/suite/fixtures/recorded/compoundTargets/takeLineVestAndAir.yml b/src/test/suite/fixtures/recorded/compoundTargets/takeLineVestAndAir.yml index 815e70ec28..6782ffba97 100644 --- a/src/test/suite/fixtures/recorded/compoundTargets/takeLineVestAndAir.yml +++ b/src/test/suite/fixtures/recorded/compoundTargets/takeLineVestAndAir.yml @@ -31,6 +31,4 @@ finalState: thatMark: - anchor: {line: 0, character: 4} active: {line: 0, character: 17} - - anchor: {line: 0, character: 4} - active: {line: 0, character: 17} fullTargets: [{type: list, elements: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: v}, selectionType: line, position: contents, insideOutsideType: inside, modifier: {type: identity}}, {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: a}, selectionType: line, position: contents, insideOutsideType: inside, modifier: {type: identity}}]}] diff --git a/src/test/suite/fixtures/recorded/selectionTypes/clearHeadCore.yml b/src/test/suite/fixtures/recorded/selectionTypes/clearHeadCore.yml index 6fc3624883..f6e8970b90 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/clearHeadCore.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/clearHeadCore.yml @@ -5,7 +5,7 @@ command: targets: - type: primitive modifiers: - - {type: head} + - {type: extendThroughStartOf} - {type: interiorOnly} usePrePhraseSnapshot: true action: {name: clearAndSetSelection} @@ -23,4 +23,4 @@ finalState: thatMark: - anchor: {line: 0, character: 4} active: {line: 0, character: 4} -fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: head}, {type: interiorOnly}]}] +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: extendThroughStartOf}, {type: interiorOnly}]}] diff --git a/src/test/suite/fixtures/recorded/selectionTypes/clearHeadFunk.yml b/src/test/suite/fixtures/recorded/selectionTypes/clearHeadFunk.yml index 594bc7023d..2efa59e231 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/clearHeadFunk.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/clearHeadFunk.yml @@ -5,7 +5,7 @@ command: targets: - type: primitive modifiers: - - {type: head} + - {type: extendThroughStartOf} - type: containingScope scopeType: {type: namedFunction} usePrePhraseSnapshot: true @@ -29,4 +29,4 @@ finalState: thatMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 0} -fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: head}, {type: containingScope, scopeType: {type: namedFunction}}]}] +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: extendThroughStartOf}, {type: containingScope, scopeType: {type: namedFunction}}]}] From 372952e67db6b06b3fbfd944b78bef02fd50bbcc Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 16 Jun 2022 15:36:27 +0200 Subject: [PATCH 03/17] Cleanup --- cursorless-talon/src/modifiers/head_tail.py | 10 ++++++++++ cursorless-talon/src/modifiers/modifiers.py | 11 +---------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/cursorless-talon/src/modifiers/head_tail.py b/cursorless-talon/src/modifiers/head_tail.py index 2d32c432e4..1c31b5d3f2 100644 --- a/cursorless-talon/src/modifiers/head_tail.py +++ b/cursorless-talon/src/modifiers/head_tail.py @@ -1,7 +1,17 @@ from talon import Module +head_tail_modifiers = { + "head": "extendThroughStartOf", + "tail": "extendThroughEndOf", +} + mod = Module() +mod.list( + "cursorless_head_tail_modifier", + desc="Cursorless head and tail modifiers", +) + @mod.capture(rule="{user.cursorless_head_tail_modifier} []") def cursorless_head_tail_modifier(m) -> dict[str, str]: diff --git a/cursorless-talon/src/modifiers/modifiers.py b/cursorless-talon/src/modifiers/modifiers.py index 1192a8f7d0..771c6d6acf 100644 --- a/cursorless-talon/src/modifiers/modifiers.py +++ b/cursorless-talon/src/modifiers/modifiers.py @@ -2,6 +2,7 @@ from ..csv_overrides import init_csv_and_watch_changes from .range_type import range_types +from .head_tail import head_tail_modifiers mod = Module() @@ -15,21 +16,11 @@ "trailing": "trailing", } -head_tail_modifiers = { - "head": "extendThroughStartOf", - "tail": "extendThroughEndOf", -} - mod.list( "cursorless_simple_modifier", desc="Simple cursorless modifiers that only need to specify their type", ) -mod.list( - "cursorless_head_tail_modifier", - desc="Cursorless head and tail modifiers", -) - @mod.capture(rule="{user.cursorless_simple_modifier}") def cursorless_simple_modifier(m) -> dict[str, str]: From fa3087935336d30e28f4c68cd0960f76e9a006ff Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 16 Jun 2022 13:37:15 +0000 Subject: [PATCH 04/17] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- cursorless-talon/src/modifiers/modifiers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cursorless-talon/src/modifiers/modifiers.py b/cursorless-talon/src/modifiers/modifiers.py index 771c6d6acf..b4481808fd 100644 --- a/cursorless-talon/src/modifiers/modifiers.py +++ b/cursorless-talon/src/modifiers/modifiers.py @@ -1,8 +1,8 @@ from talon import Module, app from ..csv_overrides import init_csv_and_watch_changes -from .range_type import range_types from .head_tail import head_tail_modifiers +from .range_type import range_types mod = Module() From 406c5f95fa2b1cb9f4448a21264fcb5a9784ffec Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 16 Jun 2022 15:45:14 +0200 Subject: [PATCH 05/17] More cleanup --- src/processTargets/marks/LineNumberStage.ts | 2 +- .../ContainingSyntaxScopeStage.ts | 4 +--- .../modifiers/scopeTypeStages/LineStage.ts | 16 +++++++------- .../scopeTypeStages/ParagraphStage.ts | 13 ++++------- .../modifiers/scopeTypeStages/RegexStage.ts | 22 +++++++++---------- 5 files changed, 24 insertions(+), 33 deletions(-) diff --git a/src/processTargets/marks/LineNumberStage.ts b/src/processTargets/marks/LineNumberStage.ts index 955264936f..68a180b02c 100644 --- a/src/processTargets/marks/LineNumberStage.ts +++ b/src/processTargets/marks/LineNumberStage.ts @@ -22,7 +22,7 @@ export default class implements MarkStage { const activeRange = editor.document.lineAt(activeLine).range; const contentRange = anchorRange.union(activeRange); const isReversed = this.modifier.anchor < this.modifier.active; - return [createLineTarget(editor, contentRange, isReversed)]; + return [createLineTarget(editor, isReversed, contentRange)]; } } diff --git a/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts b/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts index bace6d1b5e..5844e86b7d 100644 --- a/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts @@ -32,12 +32,10 @@ export default class implements ModifierStage { ) {} run(context: ProcessedTargetsContext, target: Target): ScopeTypeTarget[] { - const isEveryScope = this.modifier.type === "everyScope"; - const nodeMatcher = getNodeMatcher( target.editor.document.languageId, this.modifier.scopeType.type, - isEveryScope + this.modifier.type === "everyScope" ); const node: SyntaxNode | null = context.getNodeAtLocation( diff --git a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts index 072332b557..e1c1a5a4a6 100644 --- a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts @@ -31,7 +31,7 @@ export default class implements ModifierStage { const line = editor.document.lineAt(i); if (!line.isEmptyOrWhitespace) { targets.push( - createLineTarget(target.editor, line.range, target.isReversed) + createLineTarget(target.editor, target.isReversed, line.range) ); } } @@ -47,17 +47,17 @@ export default class implements ModifierStage { } export function toLineTarget(target: Target): LineTarget { - return new LineTarget({ - editor: target.editor, - isReversed: target.isReversed, - contentRange: fitRangeToLineContent(target.editor, target.contentRange), - }); + return createLineTarget( + target.editor, + target.isReversed, + target.contentRange + ); } export function createLineTarget( editor: TextEditor, - range: Range, - isReversed: boolean + isReversed: boolean, + range: Range ) { return new LineTarget({ editor, diff --git a/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts b/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts index 5c7a253e6a..2b6e2ede0b 100644 --- a/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts @@ -19,7 +19,7 @@ export default class implements ModifierStage { return [this.getSingleTarget(target)]; } - getEveryTarget(target: Target): ParagraphTarget[] { + private getEveryTarget(target: Target): ParagraphTarget[] { const { contentRange, editor } = target; const { isEmpty } = contentRange; const { lineCount } = editor.document; @@ -71,16 +71,11 @@ export default class implements ModifierStage { return targets; } - getSingleTarget(target: Target): ParagraphTarget { - const range = calculateRange(target); - return new ParagraphTarget({ - editor: target.editor, - isReversed: target.isReversed, - contentRange: fitRangeToLineContent(target.editor, range), - }); + private getSingleTarget(target: Target): ParagraphTarget { + return this.getTargetFromRange(target, calculateRange(target)); } - getTargetFromRange(target: Target, range: Range): ParagraphTarget { + private getTargetFromRange(target: Target, range: Range): ParagraphTarget { return new ParagraphTarget({ editor: target.editor, isReversed: target.isReversed, diff --git a/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts b/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts index a8c3f7d550..301c45c927 100644 --- a/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts @@ -24,7 +24,7 @@ class RegexStage implements ModifierStage { return [this.getSingleTarget(target)]; } - getEveryTarget(target: Target): ScopeTypeTarget[] { + private getEveryTarget(target: Target): ScopeTypeTarget[] { const { contentRange, editor } = target; const { isEmpty } = contentRange; const start = isEmpty @@ -55,29 +55,27 @@ class RegexStage implements ModifierStage { return targets; } - getSingleTarget(target: Target): ScopeTypeTarget { + private getSingleTarget(target: Target): ScopeTypeTarget { const { editor } = target; const start = this.getMatchForPos(editor, target.contentRange.start).start; const end = this.getMatchForPos(editor, target.contentRange.end).end; const contentRange = new Range(start, end); - return new ScopeTypeTarget({ - scopeTypeType: this.modifier.scopeType.type, - editor: target.editor, - isReversed: target.isReversed, - contentRange, - }); + return this.getTargetFromRange(target, contentRange); } - getTargetFromRange(target: Target, range: Range): ScopeTypeTarget { + private getTargetFromRange( + target: Target, + contentRange: Range + ): ScopeTypeTarget { return new ScopeTypeTarget({ scopeTypeType: this.modifier.scopeType.type, editor: target.editor, isReversed: target.isReversed, - contentRange: range, + contentRange, }); } - getMatchForPos(editor: TextEditor, position: Position) { + private getMatchForPos(editor: TextEditor, position: Position) { const match = this.getMatchesForLine(editor, position.line).find((range) => range.contains(position) ); @@ -91,7 +89,7 @@ class RegexStage implements ModifierStage { return match; } - getMatchesForLine(editor: TextEditor, lineNum: number) { + private getMatchesForLine(editor: TextEditor, lineNum: number) { const line = editor.document.lineAt(lineNum); const result = [...line.text.matchAll(this.regex)].map( (match) => From 2aa822298dc6ce467bfe30d344da44519d8ead7f Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 16 Jun 2022 15:48:20 +0200 Subject: [PATCH 06/17] More cleanup --- src/processTargets/modifiers/scopeTypeStages/LineStage.ts | 2 +- src/processTargets/modifiers/scopeTypeStages/TokenStage.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts index e1c1a5a4a6..fd523f2724 100644 --- a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts @@ -18,7 +18,7 @@ export default class implements ModifierStage { return [toLineTarget(target)]; } - getEveryTarget(target: Target): LineTarget[] { + private getEveryTarget(target: Target): LineTarget[] { const { contentRange, editor } = target; const { isEmpty } = contentRange; const startLine = isEmpty ? 0 : contentRange.start.line; diff --git a/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts index be7f943683..bcd15861f2 100644 --- a/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts @@ -19,7 +19,7 @@ export default class implements ModifierStage { return [this.getSingleTarget(target)]; } - getEveryTarget( + private getEveryTarget( context: ProcessedTargetsContext, target: Target ): TokenTarget[] { @@ -46,11 +46,11 @@ export default class implements ModifierStage { return targets; } - getSingleTarget(target: Target): TokenTarget { + private getSingleTarget(target: Target): TokenTarget { return this.getTargetFromRange(target, target.contentRange); } - getTargetFromRange(target: Target, range: Range): TokenTarget { + private getTargetFromRange(target: Target, range: Range): TokenTarget { const contentRange = getTokenRangeForSelection(target.editor, range); return new TokenTarget({ editor: target.editor, From 00d0ed547a675eaa5953aee9ae52c7ea62e9f9a2 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 16 Jun 2022 15:51:30 +0200 Subject: [PATCH 07/17] More cleanup --- src/processTargets/modifiers/scopeTypeStages/LineStage.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts index fd523f2724..66f8389f68 100644 --- a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts @@ -46,7 +46,7 @@ export default class implements ModifierStage { } } -export function toLineTarget(target: Target): LineTarget { +function toLineTarget(target: Target): LineTarget { return createLineTarget( target.editor, target.isReversed, From 9277be8d4709e220c2d909ecb632c74e548864df Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 16 Jun 2022 15:55:16 +0200 Subject: [PATCH 08/17] Fixed line endings --- .../suite/fixtures/recorded/languages/php/changeClass.yml | 4 +++- .../suite/fixtures/recorded/languages/php/changeComment.yml | 4 +++- .../suite/fixtures/recorded/languages/php/changeFunk.yml | 4 +++- .../suite/fixtures/recorded/languages/php/changeIfState.yml | 4 +++- .../suite/fixtures/recorded/languages/php/changeType6.yml | 4 ++-- src/test/suite/fixtures/recorded/languages/php/chuckFunk.yml | 4 +++- .../suite/fixtures/recorded/languages/php/chuckFunk2.yml | 4 +++- src/test/suite/fixtures/recorded/languages/php/chuckPair.yml | 5 ++++- 8 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/test/suite/fixtures/recorded/languages/php/changeClass.yml b/src/test/suite/fixtures/recorded/languages/php/changeClass.yml index f52f64ba74..d9b8d3f42b 100644 --- a/src/test/suite/fixtures/recorded/languages/php/changeClass.yml +++ b/src/test/suite/fixtures/recorded/languages/php/changeClass.yml @@ -19,7 +19,9 @@ initialState: active: {line: 4, character: 0} marks: {} finalState: - documentContents: " Date: Thu, 16 Jun 2022 16:00:40 +0200 Subject: [PATCH 09/17] Updated tests --- .../fixtures/recorded/selectionTypes/clearHeadCore.yml | 5 +++-- .../fixtures/recorded/selectionTypes/clearHeadFunk.yml | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/test/suite/fixtures/recorded/selectionTypes/clearHeadCore.yml b/src/test/suite/fixtures/recorded/selectionTypes/clearHeadCore.yml index f6e8970b90..f1bf5179dc 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/clearHeadCore.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/clearHeadCore.yml @@ -5,8 +5,9 @@ command: targets: - type: primitive modifiers: - - {type: extendThroughStartOf} - - {type: interiorOnly} + - type: extendThroughStartOf + modifier: + type: interiorOnly usePrePhraseSnapshot: true action: {name: clearAndSetSelection} initialState: diff --git a/src/test/suite/fixtures/recorded/selectionTypes/clearHeadFunk.yml b/src/test/suite/fixtures/recorded/selectionTypes/clearHeadFunk.yml index 2efa59e231..7d1de7c787 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/clearHeadFunk.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/clearHeadFunk.yml @@ -5,9 +5,10 @@ command: targets: - type: primitive modifiers: - - {type: extendThroughStartOf} - - type: containingScope - scopeType: {type: namedFunction} + - type: extendThroughStartOf + modifier: + type: containingScope + scopeType: {type: namedFunction} usePrePhraseSnapshot: true action: {name: clearAndSetSelection} initialState: From 9f8eac10cdc6ee2389357224192ab1a5de7038de Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 16 Jun 2022 16:02:54 +0200 Subject: [PATCH 10/17] Updated tests --- .../suite/fixtures/recorded/selectionTypes/clearHeadCore.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/suite/fixtures/recorded/selectionTypes/clearHeadCore.yml b/src/test/suite/fixtures/recorded/selectionTypes/clearHeadCore.yml index f1bf5179dc..38757b5e5a 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/clearHeadCore.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/clearHeadCore.yml @@ -6,8 +6,7 @@ command: - type: primitive modifiers: - type: extendThroughStartOf - modifier: - type: interiorOnly + modifier: {type: interiorOnly} usePrePhraseSnapshot: true action: {name: clearAndSetSelection} initialState: From 01242804341978f3098dbd2fcbd3d91891db3119 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Fri, 17 Jun 2022 18:13:20 +0200 Subject: [PATCH 11/17] Head and tail modifiers swallow all following modifiers --- cursorless-talon/src/modifiers/head_tail.py | 4 +-- src/processTargets/modifiers/HeadTailStage.ts | 24 ++++++++----- src/processTargets/processTargets.ts | 25 +++++++------- .../selectionTypes/clearHeadCoreCurly.yml | 34 +++++++++++++++++++ src/typings/targetDescriptor.types.ts | 2 +- 5 files changed, 65 insertions(+), 24 deletions(-) create mode 100644 src/test/suite/fixtures/recorded/selectionTypes/clearHeadCoreCurly.yml diff --git a/cursorless-talon/src/modifiers/head_tail.py b/cursorless-talon/src/modifiers/head_tail.py index 1c31b5d3f2..85dcff2731 100644 --- a/cursorless-talon/src/modifiers/head_tail.py +++ b/cursorless-talon/src/modifiers/head_tail.py @@ -13,14 +13,14 @@ ) -@mod.capture(rule="{user.cursorless_head_tail_modifier} []") +@mod.capture(rule="{user.cursorless_head_tail_modifier} *") def cursorless_head_tail_modifier(m) -> dict[str, str]: """Cursorless head and tail modifier""" result = { "type": m.cursorless_head_tail_modifier, } try: - result["modifier"] = m.cursorless_modifier + result["modifiers"] = m.cursorless_modifier_list except AttributeError: pass return result diff --git a/src/processTargets/modifiers/HeadTailStage.ts b/src/processTargets/modifiers/HeadTailStage.ts index 1242298cbb..a49c6712ea 100644 --- a/src/processTargets/modifiers/HeadTailStage.ts +++ b/src/processTargets/modifiers/HeadTailStage.ts @@ -7,18 +7,24 @@ import { import { ProcessedTargetsContext } from "../../typings/Types"; import getModifierStage from "../getModifierStage"; import { ModifierStage } from "../PipelineStages.types"; +import { processModifierStages } from "../processTargets"; import PlainTarget from "../targets/PlainTarget"; abstract class HeadTailStage implements ModifierStage { - constructor(private isReversed: boolean, private modifier?: Modifier) {} + constructor(private isReversed: boolean, private modifiers?: Modifier[]) {} run(context: ProcessedTargetsContext, target: Target): Target[] { - const modifier = this.modifier ?? { - type: "containingScope", - scopeType: { type: "line" }, - }; - const modifierStage = getModifierStage(modifier); - const previousTargets = modifierStage.run(context, target); + const modifiers = this.modifiers ?? [ + { + type: "containingScope", + scopeType: { type: "line" }, + }, + ]; + + const modifierStages = modifiers.map(getModifierStage).reverse(); + const previousTargets = processModifierStages(context, modifierStages, [ + target, + ]); return previousTargets.map((previousTarget) => { const contentRange = this.update( @@ -43,7 +49,7 @@ abstract class HeadTailStage implements ModifierStage { export class HeadStage extends HeadTailStage { constructor(modifier: HeadTailModifier) { - super(true, modifier.modifier); + super(true, modifier.modifiers); } protected update(editor: TextEditor, previousRange: Range, nextRange: Range) { @@ -53,7 +59,7 @@ export class HeadStage extends HeadTailStage { export class TailStage extends HeadTailStage { constructor(modifier: HeadTailModifier) { - super(false, modifier.modifier); + super(false, modifier.modifiers); } protected update(editor: TextEditor, previousRange: Range, nextRange: Range) { diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index 922bd7371d..42dfdf6036 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -10,6 +10,7 @@ import { ProcessedTargetsContext } from "../typings/Types"; import { ensureSingleEditor } from "../util/targetUtils"; import getMarkStage from "./getMarkStage"; import getModifierStage from "./getModifierStage"; +import { ModifierStage } from "./PipelineStages.types"; import PlainTarget from "./targets/PlainTarget"; import PositionTarget from "./targets/PositionTarget"; @@ -193,9 +194,7 @@ function processPrimitiveTarget( const markStage = getMarkStage(targetDescriptor.mark); const markOutputTargets = markStage.run(context); - /** - * The modifier pipeline that will be applied to construct our final targets - */ + // The modifier pipeline that will be applied to construct our final targets const modifierStages = [ // Reverse target modifiers because they are returned in reverse order from // the api, to match the order in which they are spoken. @@ -203,23 +202,25 @@ function processPrimitiveTarget( ...context.finalStages, ]; - /** - * Intermediate variable to store the output of the current pipeline stage. - * We initialise it to start with the outputs from the mark. - */ - let currentTargets = markOutputTargets; + // Run all targets through the modifier stages + return processModifierStages(context, modifierStages, markOutputTargets); +} +/** Run all targets through the modifier stages */ +export function processModifierStages( + context: ProcessedTargetsContext, + modifierStages: ModifierStage[], + targets: Target[] +) { // Then we apply each stage in sequence, letting each stage see the targets // one-by-one and concatenating the results before passing them on to the // next stage. modifierStages.forEach((stage) => { - currentTargets = currentTargets.flatMap((target) => - stage.run(context, target) - ); + targets = targets.flatMap((target) => stage.run(context, target)); }); // Then return the output from the final stage - return currentTargets; + return targets; } function calcIsReversed(anchor: Target, active: Target) { diff --git a/src/test/suite/fixtures/recorded/selectionTypes/clearHeadCoreCurly.yml b/src/test/suite/fixtures/recorded/selectionTypes/clearHeadCoreCurly.yml new file mode 100644 index 0000000000..eba314f3a4 --- /dev/null +++ b/src/test/suite/fixtures/recorded/selectionTypes/clearHeadCoreCurly.yml @@ -0,0 +1,34 @@ +languageId: plaintext +command: + spokenForm: clear head core curly + version: 2 + targets: + - type: primitive + modifiers: + - type: extendThroughStartOf + modifiers: + - {type: interiorOnly} + - type: containingScope + scopeType: {type: surroundingPair, delimiter: curlyBrackets} + usePrePhraseSnapshot: true + action: {name: clearAndSetSelection} +initialState: + documentContents: |- + { + foo(bar baz) + } + selections: + - anchor: {line: 1, character: 14} + active: {line: 1, character: 14} + marks: {} +finalState: + documentContents: |- + {z) + } + selections: + - anchor: {line: 0, character: 1} + active: {line: 0, character: 1} + thatMark: + - anchor: {line: 0, character: 1} + active: {line: 0, character: 1} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: extendThroughStartOf, modifiers: [{type: interiorOnly}, {type: containingScope, scopeType: {type: surroundingPair, delimiter: curlyBrackets}}]}]}] diff --git a/src/typings/targetDescriptor.types.ts b/src/typings/targetDescriptor.types.ts index 4b6e5eb07c..82f02666ad 100644 --- a/src/typings/targetDescriptor.types.ts +++ b/src/typings/targetDescriptor.types.ts @@ -188,7 +188,7 @@ export interface PartialPrimitiveTargetDescriptor { export interface HeadTailModifier { type: "extendThroughStartOf" | "extendThroughEndOf"; - modifier?: Modifier; + modifiers?: Modifier[]; } export type Modifier = From db9068931b5c188f266e3b571ba90aaa4e4e02a8 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Fri, 17 Jun 2022 18:17:55 +0200 Subject: [PATCH 12/17] Updated tests --- src/processTargets/processTargets.ts | 2 +- .../fixtures/recorded/selectionTypes/clearHeadCore.yml | 3 ++- .../fixtures/recorded/selectionTypes/clearHeadFunk.yml | 6 +++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index 42dfdf6036..f3133be62c 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -212,7 +212,7 @@ export function processModifierStages( modifierStages: ModifierStage[], targets: Target[] ) { - // Then we apply each stage in sequence, letting each stage see the targets + // First we apply each stage in sequence, letting each stage see the targets // one-by-one and concatenating the results before passing them on to the // next stage. modifierStages.forEach((stage) => { diff --git a/src/test/suite/fixtures/recorded/selectionTypes/clearHeadCore.yml b/src/test/suite/fixtures/recorded/selectionTypes/clearHeadCore.yml index 38757b5e5a..0b72f224e8 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/clearHeadCore.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/clearHeadCore.yml @@ -6,7 +6,8 @@ command: - type: primitive modifiers: - type: extendThroughStartOf - modifier: {type: interiorOnly} + modifiers: + - {type: interiorOnly} usePrePhraseSnapshot: true action: {name: clearAndSetSelection} initialState: diff --git a/src/test/suite/fixtures/recorded/selectionTypes/clearHeadFunk.yml b/src/test/suite/fixtures/recorded/selectionTypes/clearHeadFunk.yml index 7d1de7c787..829932f0cb 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/clearHeadFunk.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/clearHeadFunk.yml @@ -6,9 +6,9 @@ command: - type: primitive modifiers: - type: extendThroughStartOf - modifier: - type: containingScope - scopeType: {type: namedFunction} + modifiers: + - type: containingScope + scopeType: {type: namedFunction} usePrePhraseSnapshot: true action: {name: clearAndSetSelection} initialState: From 31a77b73ee1883f318330e5af3d1378aa9d359cd Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 18 Jun 2022 09:58:31 +0200 Subject: [PATCH 13/17] Cleanup --- src/processTargets/modifiers/HeadTailStage.ts | 8 +++++--- src/processTargets/processTargets.ts | 14 +++++++++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/processTargets/modifiers/HeadTailStage.ts b/src/processTargets/modifiers/HeadTailStage.ts index a49c6712ea..d9bb5de81d 100644 --- a/src/processTargets/modifiers/HeadTailStage.ts +++ b/src/processTargets/modifiers/HeadTailStage.ts @@ -5,9 +5,11 @@ import { Modifier, } from "../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../typings/Types"; -import getModifierStage from "../getModifierStage"; import { ModifierStage } from "../PipelineStages.types"; -import { processModifierStages } from "../processTargets"; +import { + getModifierStagesFromTargetModifiers, + processModifierStages, +} from "../processTargets"; import PlainTarget from "../targets/PlainTarget"; abstract class HeadTailStage implements ModifierStage { @@ -21,7 +23,7 @@ abstract class HeadTailStage implements ModifierStage { }, ]; - const modifierStages = modifiers.map(getModifierStage).reverse(); + const modifierStages = getModifierStagesFromTargetModifiers(modifiers); const previousTargets = processModifierStages(context, modifierStages, [ target, ]); diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index f3133be62c..819921e945 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -2,6 +2,7 @@ import { uniqWith, zip } from "lodash"; import { Range } from "vscode"; import { Target } from "../typings/target.types"; import { + Modifier, PrimitiveTargetDescriptor, RangeTargetDescriptor, TargetDescriptor, @@ -196,9 +197,7 @@ function processPrimitiveTarget( // The modifier pipeline that will be applied to construct our final targets const modifierStages = [ - // Reverse target modifiers because they are returned in reverse order from - // the api, to match the order in which they are spoken. - ...targetDescriptor.modifiers.map(getModifierStage).reverse(), + ...getModifierStagesFromTargetModifiers(targetDescriptor.modifiers), ...context.finalStages, ]; @@ -206,6 +205,15 @@ function processPrimitiveTarget( return processModifierStages(context, modifierStages, markOutputTargets); } +/** Convert a list of target modifiers to modifier stages */ +export function getModifierStagesFromTargetModifiers( + targetModifiers: Modifier[] +) { + // Reverse target modifiers because they are returned in reverse order from + // the api, to match the order in which they are spoken. + return targetModifiers.map(getModifierStage).reverse(); +} + /** Run all targets through the modifier stages */ export function processModifierStages( context: ProcessedTargetsContext, From a97be060dfee6c9f7bff6f1e33dcc4b195d80ea4 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 18 Jun 2022 10:00:37 +0200 Subject: [PATCH 14/17] Cleanup --- src/processTargets/modifiers/HeadTailStage.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/processTargets/modifiers/HeadTailStage.ts b/src/processTargets/modifiers/HeadTailStage.ts index d9bb5de81d..f8c981f155 100644 --- a/src/processTargets/modifiers/HeadTailStage.ts +++ b/src/processTargets/modifiers/HeadTailStage.ts @@ -24,15 +24,15 @@ abstract class HeadTailStage implements ModifierStage { ]; const modifierStages = getModifierStagesFromTargetModifiers(modifiers); - const previousTargets = processModifierStages(context, modifierStages, [ + const modifiedTargets = processModifierStages(context, modifierStages, [ target, ]); - return previousTargets.map((previousTarget) => { + return modifiedTargets.map((modifiedTarget) => { const contentRange = this.update( target.editor, target.contentRange, - previousTarget.contentRange + modifiedTarget.contentRange ); return new PlainTarget({ editor: target.editor, From 2f0438478b61456e3f107eaa69acc02d1bb61dcd Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Mon, 20 Jun 2022 18:43:25 +0100 Subject: [PATCH 15/17] Switch head tail stage to use token target instead of plane target --- src/processTargets/modifiers/HeadTailStage.ts | 4 +-- .../recorded/headTail/chuckHeadAir.yml | 29 +++++++++++++++++++ .../recorded/headTail/chuckHeadWhale.yml | 29 +++++++++++++++++++ .../recorded/headTail/chuckTailHarp.yml | 29 +++++++++++++++++++ .../recorded/headTail/chuckTailWhale.yml | 29 +++++++++++++++++++ .../recorded/headTail/clearHeadAir.yml | 29 +++++++++++++++++++ .../recorded/headTail/clearTailHarp.yml | 29 +++++++++++++++++++ 7 files changed, 176 insertions(+), 2 deletions(-) create mode 100644 src/test/suite/fixtures/recorded/headTail/chuckHeadAir.yml create mode 100644 src/test/suite/fixtures/recorded/headTail/chuckHeadWhale.yml create mode 100644 src/test/suite/fixtures/recorded/headTail/chuckTailHarp.yml create mode 100644 src/test/suite/fixtures/recorded/headTail/chuckTailWhale.yml create mode 100644 src/test/suite/fixtures/recorded/headTail/clearHeadAir.yml create mode 100644 src/test/suite/fixtures/recorded/headTail/clearTailHarp.yml diff --git a/src/processTargets/modifiers/HeadTailStage.ts b/src/processTargets/modifiers/HeadTailStage.ts index f8c981f155..fe7ade3978 100644 --- a/src/processTargets/modifiers/HeadTailStage.ts +++ b/src/processTargets/modifiers/HeadTailStage.ts @@ -10,7 +10,7 @@ import { getModifierStagesFromTargetModifiers, processModifierStages, } from "../processTargets"; -import PlainTarget from "../targets/PlainTarget"; +import { TokenTarget } from "../targets"; abstract class HeadTailStage implements ModifierStage { constructor(private isReversed: boolean, private modifiers?: Modifier[]) {} @@ -34,7 +34,7 @@ abstract class HeadTailStage implements ModifierStage { target.contentRange, modifiedTarget.contentRange ); - return new PlainTarget({ + return new TokenTarget({ editor: target.editor, isReversed: this.isReversed, contentRange, diff --git a/src/test/suite/fixtures/recorded/headTail/chuckHeadAir.yml b/src/test/suite/fixtures/recorded/headTail/chuckHeadAir.yml new file mode 100644 index 0000000000..65db463cdc --- /dev/null +++ b/src/test/suite/fixtures/recorded/headTail/chuckHeadAir.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: chuck head air + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: a} + modifiers: + - {type: extendThroughStartOf} + usePrePhraseSnapshot: true + action: {name: remove} +initialState: + documentContents: " hello world whatever" + selections: + - anchor: {line: 0, character: 24} + active: {line: 0, character: 24} + marks: + default.a: + start: {line: 0, character: 16} + end: {line: 0, character: 24} +finalState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: a}, modifiers: [{type: extendThroughStartOf}]}] diff --git a/src/test/suite/fixtures/recorded/headTail/chuckHeadWhale.yml b/src/test/suite/fixtures/recorded/headTail/chuckHeadWhale.yml new file mode 100644 index 0000000000..eebc2a927e --- /dev/null +++ b/src/test/suite/fixtures/recorded/headTail/chuckHeadWhale.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: chuck head whale + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: w} + modifiers: + - {type: extendThroughStartOf} + usePrePhraseSnapshot: true + action: {name: remove} +initialState: + documentContents: " hello world whatever" + selections: + - anchor: {line: 0, character: 24} + active: {line: 0, character: 24} + marks: + default.w: + start: {line: 0, character: 10} + end: {line: 0, character: 15} +finalState: + documentContents: " whatever" + selections: + - anchor: {line: 0, character: 12} + active: {line: 0, character: 12} + thatMark: + - anchor: {line: 0, character: 4} + active: {line: 0, character: 4} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: w}, modifiers: [{type: extendThroughStartOf}]}] diff --git a/src/test/suite/fixtures/recorded/headTail/chuckTailHarp.yml b/src/test/suite/fixtures/recorded/headTail/chuckTailHarp.yml new file mode 100644 index 0000000000..abadc44913 --- /dev/null +++ b/src/test/suite/fixtures/recorded/headTail/chuckTailHarp.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: chuck tail harp + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: h} + modifiers: + - {type: extendThroughEndOf} + usePrePhraseSnapshot: true + action: {name: remove} +initialState: + documentContents: " hello world whatever" + selections: + - anchor: {line: 0, character: 24} + active: {line: 0, character: 24} + marks: + default.h: + start: {line: 0, character: 4} + end: {line: 0, character: 9} +finalState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: h}, modifiers: [{type: extendThroughEndOf}]}] diff --git a/src/test/suite/fixtures/recorded/headTail/chuckTailWhale.yml b/src/test/suite/fixtures/recorded/headTail/chuckTailWhale.yml new file mode 100644 index 0000000000..8810148298 --- /dev/null +++ b/src/test/suite/fixtures/recorded/headTail/chuckTailWhale.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: chuck tail whale + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: w} + modifiers: + - {type: extendThroughEndOf} + usePrePhraseSnapshot: true + action: {name: remove} +initialState: + documentContents: " hello world whatever" + selections: + - anchor: {line: 0, character: 24} + active: {line: 0, character: 24} + marks: + default.w: + start: {line: 0, character: 10} + end: {line: 0, character: 15} +finalState: + documentContents: " hello" + selections: + - anchor: {line: 0, character: 9} + active: {line: 0, character: 9} + thatMark: + - anchor: {line: 0, character: 9} + active: {line: 0, character: 9} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: w}, modifiers: [{type: extendThroughEndOf}]}] diff --git a/src/test/suite/fixtures/recorded/headTail/clearHeadAir.yml b/src/test/suite/fixtures/recorded/headTail/clearHeadAir.yml new file mode 100644 index 0000000000..f5983e014f --- /dev/null +++ b/src/test/suite/fixtures/recorded/headTail/clearHeadAir.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: clear head air + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: a} + modifiers: + - {type: extendThroughStartOf} + usePrePhraseSnapshot: true + action: {name: clearAndSetSelection} +initialState: + documentContents: " hello world whatever" + selections: + - anchor: {line: 0, character: 24} + active: {line: 0, character: 24} + marks: + default.a: + start: {line: 0, character: 16} + end: {line: 0, character: 24} +finalState: + documentContents: " " + selections: + - anchor: {line: 0, character: 4} + active: {line: 0, character: 4} + thatMark: + - anchor: {line: 0, character: 4} + active: {line: 0, character: 4} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: a}, modifiers: [{type: extendThroughStartOf}]}] diff --git a/src/test/suite/fixtures/recorded/headTail/clearTailHarp.yml b/src/test/suite/fixtures/recorded/headTail/clearTailHarp.yml new file mode 100644 index 0000000000..f4b9b0c5eb --- /dev/null +++ b/src/test/suite/fixtures/recorded/headTail/clearTailHarp.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: clear tail harp + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: h} + modifiers: + - {type: extendThroughEndOf} + usePrePhraseSnapshot: true + action: {name: clearAndSetSelection} +initialState: + documentContents: " hello world whatever" + selections: + - anchor: {line: 0, character: 24} + active: {line: 0, character: 24} + marks: + default.h: + start: {line: 0, character: 4} + end: {line: 0, character: 9} +finalState: + documentContents: " " + selections: + - anchor: {line: 0, character: 4} + active: {line: 0, character: 4} + thatMark: + - anchor: {line: 0, character: 4} + active: {line: 0, character: 4} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: h}, modifiers: [{type: extendThroughEndOf}]}] From 075db77c05e2b4dc741c68eef3fc5677d5eb20bd Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Mon, 20 Jun 2022 18:50:12 +0100 Subject: [PATCH 16/17] Cleanup head tail stage --- src/processTargets/modifiers/HeadTailStage.ts | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/processTargets/modifiers/HeadTailStage.ts b/src/processTargets/modifiers/HeadTailStage.ts index fe7ade3978..1b246a436b 100644 --- a/src/processTargets/modifiers/HeadTailStage.ts +++ b/src/processTargets/modifiers/HeadTailStage.ts @@ -29,11 +29,11 @@ abstract class HeadTailStage implements ModifierStage { ]); return modifiedTargets.map((modifiedTarget) => { - const contentRange = this.update( - target.editor, + const contentRange = this.constructContentRange( target.contentRange, modifiedTarget.contentRange ); + return new TokenTarget({ editor: target.editor, isReversed: this.isReversed, @@ -42,10 +42,9 @@ abstract class HeadTailStage implements ModifierStage { }); } - protected abstract update( - editor: TextEditor, - previousRange: Range, - nextRange: Range + protected abstract constructContentRange( + originalRange: Range, + modifiedRange: Range ): Range; } @@ -54,8 +53,8 @@ export class HeadStage extends HeadTailStage { super(true, modifier.modifiers); } - protected update(editor: TextEditor, previousRange: Range, nextRange: Range) { - return new Range(nextRange.start, previousRange.end); + protected constructContentRange(originalRange: Range, modifiedRange: Range) { + return new Range(modifiedRange.start, originalRange.end); } } @@ -64,7 +63,7 @@ export class TailStage extends HeadTailStage { super(false, modifier.modifiers); } - protected update(editor: TextEditor, previousRange: Range, nextRange: Range) { - return new Range(previousRange.start, nextRange.end); + protected constructContentRange(originalRange: Range, modifiedRange: Range) { + return new Range(originalRange.start, modifiedRange.end); } } From fc8550fa182c92c4eaa8137b8576dd5669e619ad Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Mon, 20 Jun 2022 18:58:00 +0100 Subject: [PATCH 17/17] Reinstate doc string --- src/processTargets/processTargets.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index 819921e945..24bdeb0264 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -195,7 +195,7 @@ function processPrimitiveTarget( const markStage = getMarkStage(targetDescriptor.mark); const markOutputTargets = markStage.run(context); - // The modifier pipeline that will be applied to construct our final targets + /** The modifier pipeline that will be applied to construct our final targets */ const modifierStages = [ ...getModifierStagesFromTargetModifiers(targetDescriptor.modifiers), ...context.finalStages,