From f98806da17ddab5ab4b78267e8575826b7dfe629 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Thu, 12 May 2022 14:24:02 +0300 Subject: [PATCH 001/314] Support fully compositional modifiers Fixes #69 --- cursorless-talon/src/marks/lines_number.py | 15 ++++--- cursorless-talon/src/marks/mark.py | 20 +++++----- .../src/modifiers/containing_scope.py | 10 ++--- cursorless-talon/src/modifiers/head_tail.py | 7 ++-- cursorless-talon/src/modifiers/position.py | 6 ++- .../src/modifiers/selection_type.py | 7 +++- cursorless-talon/src/modifiers/sub_token.py | 13 +++--- .../src/modifiers/surrounding_pair.py | 40 +++++++++---------- .../src/modifiers/to_raw_selection.py | 6 ++- cursorless-talon/src/primitive_target.py | 11 +++-- src/typings/Types.ts | 8 ++++ 11 files changed, 77 insertions(+), 66 deletions(-) diff --git a/cursorless-talon/src/marks/lines_number.py b/cursorless-talon/src/marks/lines_number.py index 4c8e9049ba..ac02618042 100644 --- a/cursorless-talon/src/marks/lines_number.py +++ b/cursorless-talon/src/marks/lines_number.py @@ -1,4 +1,5 @@ from dataclasses import dataclass +from typing import Any, Callable from talon import Context, Module @@ -13,7 +14,7 @@ class CustomizableTerm: defaultSpokenForm: str cursorlessIdentifier: str type: str - formatter: callable + formatter: Callable # NOTE: Please do not change these dicts. Use the CSVs for customization. @@ -33,18 +34,16 @@ class CustomizableTerm: @mod.capture(rule="{user.cursorless_line_direction} ") -def cursorless_line_number(m) -> str: +def cursorless_line_number(m) -> dict[str, Any]: direction = directions_map[m.cursorless_line_direction] line_number = m.number_small line = { "lineNumber": direction.formatter(line_number), "type": direction.type, } + # TODO: Make sure to spit out a line in the case of a line number mark return { - "selectionType": "line", - "mark": { - "type": "lineNumber", - "anchor": line, - "active": line, - }, + "type": "lineNumber", + "anchor": line, + "active": line, } diff --git a/cursorless-talon/src/marks/mark.py b/cursorless-talon/src/marks/mark.py index 999ceb8a62..83b951fbde 100644 --- a/cursorless-talon/src/marks/mark.py +++ b/cursorless-talon/src/marks/mark.py @@ -43,7 +43,7 @@ @mod.capture( rule="[{user.cursorless_hat_color}] [{user.cursorless_hat_shape}] " ) -def cursorless_decorated_symbol(m) -> dict[str, dict[str, Any]]: +def cursorless_decorated_symbol(m) -> dict[str, Any]: """A decorated symbol""" hat_color = getattr(m, "cursorless_hat_color", "default") try: @@ -51,11 +51,9 @@ def cursorless_decorated_symbol(m) -> dict[str, dict[str, Any]]: except AttributeError: hat_style_name = hat_color return { - "mark": { - "type": "decoratedSymbol", - "symbolColor": hat_style_name, - "character": m.any_alphanumeric_key, - } + "type": "decoratedSymbol", + "symbolColor": hat_style_name, + "character": m.any_alphanumeric_key, } @@ -69,10 +67,10 @@ class CustomizableTerm: # NOTE: Please do not change these dicts. Use the CSVs for customization. # See https://www.cursorless.org/docs/user/customization/ special_marks = [ - CustomizableTerm("this", "currentSelection", {"mark": {"type": "cursor"}}), - CustomizableTerm("that", "previousTarget", {"mark": {"type": "that"}}), - CustomizableTerm("source", "previousSource", {"mark": {"type": "source"}}), - CustomizableTerm("nothing", "nothing", {"mark": {"type": "nothing"}}), + CustomizableTerm("this", "currentSelection", {"type": "cursor"}), + CustomizableTerm("that", "previousTarget", {"type": "that"}), + CustomizableTerm("source", "previousSource", {"type": "source"}), + CustomizableTerm("nothing", "nothing", {"type": "nothing"}), # "last cursor": {"mark": {"type": "lastCursorPosition"}} # Not implemented ] @@ -93,7 +91,7 @@ class CustomizableTerm: "" # row (ie absolute mod 100), up, down ) ) -def cursorless_mark(m) -> str: +def cursorless_mark(m) -> dict[str, Any]: try: return m.cursorless_decorated_symbol except AttributeError: diff --git a/cursorless-talon/src/modifiers/containing_scope.py b/cursorless-talon/src/modifiers/containing_scope.py index 17956d9019..40f935a4cf 100644 --- a/cursorless-talon/src/modifiers/containing_scope.py +++ b/cursorless-talon/src/modifiers/containing_scope.py @@ -50,14 +50,12 @@ @mod.capture(rule="[every] {user.cursorless_scope_type}") -def cursorless_containing_scope(m) -> dict[str, dict[str, Any]]: +def cursorless_containing_scope(m) -> dict[str, Any]: """Expand to containing scope""" return { - "modifier": { - "type": "containingScope", - "scopeType": m.cursorless_scope_type, - "includeSiblings": m[0] == "every", - } + "type": "containingScope", + "scopeType": m.cursorless_scope_type, + "includeSiblings": m[0] == "every", } diff --git a/cursorless-talon/src/modifiers/head_tail.py b/cursorless-talon/src/modifiers/head_tail.py index 8049a1e637..9d8dd07b49 100644 --- a/cursorless-talon/src/modifiers/head_tail.py +++ b/cursorless-talon/src/modifiers/head_tail.py @@ -1,4 +1,5 @@ from dataclasses import dataclass +from typing import Any from talon import Module @@ -22,9 +23,7 @@ class HeadTail: @mod.capture(rule="{user.cursorless_head_tail}") -def cursorless_head_tail(m) -> dict: +def cursorless_head_tail(m) -> dict[str, Any]: return { - "modifier": { - "type": head_tail_map[m.cursorless_head_tail], - } + "type": head_tail_map[m.cursorless_head_tail], } diff --git a/cursorless-talon/src/modifiers/position.py b/cursorless-talon/src/modifiers/position.py index 830d00b68a..5ed41492eb 100644 --- a/cursorless-talon/src/modifiers/position.py +++ b/cursorless-talon/src/modifiers/position.py @@ -1,3 +1,5 @@ +from typing import Any + from talon import Context, Module mod = Module() @@ -19,5 +21,5 @@ @mod.capture(rule="{user.cursorless_position}") -def cursorless_position(m) -> str: - return positions[m.cursorless_position] +def cursorless_position(m) -> dict[str, Any]: + return {"type": "position", **positions[m.cursorless_position]} diff --git a/cursorless-talon/src/modifiers/selection_type.py b/cursorless-talon/src/modifiers/selection_type.py index ec2296cd22..8733773d2f 100644 --- a/cursorless-talon/src/modifiers/selection_type.py +++ b/cursorless-talon/src/modifiers/selection_type.py @@ -1,3 +1,5 @@ +from typing import Any + from talon import Module mod = Module() @@ -7,5 +9,6 @@ @mod.capture(rule="{user.cursorless_selection_type}") -def cursorless_selection_type(m) -> str: - return {"selectionType": m.cursorless_selection_type} +def cursorless_selection_type(m) -> dict[str, Any]: + # TODO: Change this to containing scope next + return {"type": "selectionType", "selectionType": m.cursorless_selection_type} diff --git a/cursorless-talon/src/modifiers/sub_token.py b/cursorless-talon/src/modifiers/sub_token.py index 08ba72ad8f..7f63675db7 100644 --- a/cursorless-talon/src/modifiers/sub_token.py +++ b/cursorless-talon/src/modifiers/sub_token.py @@ -1,3 +1,5 @@ +from typing import Any + from talon import Module from ..compound_targets import is_active_included, is_anchor_included @@ -51,17 +53,14 @@ def cursorless_first_last_range(m) -> str: "{user.cursorless_subtoken_scope_type}" ) ) -def cursorless_subtoken_scope(m) -> str: +def cursorless_subtoken_scope(m) -> dict[str, Any]: """Subtoken ranges such as subwords or characters""" try: range = m.cursorless_ordinal_range except AttributeError: range = m.cursorless_first_last_range return { - "selectionType": "token", - "modifier": { - "type": "subpiece", - "pieceType": m.cursorless_subtoken_scope_type, - **range, - }, + "type": "subpiece", + "pieceType": m.cursorless_subtoken_scope_type, + **range, } diff --git a/cursorless-talon/src/modifiers/surrounding_pair.py b/cursorless-talon/src/modifiers/surrounding_pair.py index 8fbf236179..bf170718dc 100644 --- a/cursorless-talon/src/modifiers/surrounding_pair.py +++ b/cursorless-talon/src/modifiers/surrounding_pair.py @@ -1,3 +1,5 @@ +from typing import Any + from talon import Context, Module from ..paired_delimiter import paired_delimiters_map @@ -28,13 +30,29 @@ ) +@mod.capture( + rule=( + " |" + "{user.cursorless_surrounding_pair_scope_type}" + ) +) +def cursorless_surrounding_pair_scope_type(m) -> str: + """Surrounding pair scope type""" + try: + return m.cursorless_surrounding_pair_scope_type + except AttributeError: + return paired_delimiters_map[ + m.cursorless_selectable_paired_delimiter + ].cursorlessIdentifier + + @mod.capture( rule=( "[{user.cursorless_delimiter_inclusion}] [{user.cursorless_delimiter_force_direction}] | " "{user.cursorless_delimiter_inclusion} [{user.cursorless_delimiter_force_direction}]" ) ) -def cursorless_surrounding_pair(m) -> str: +def cursorless_surrounding_pair(m) -> dict[str, Any]: """Surrounding pair modifier""" try: surrounding_pair_scope_type = m.cursorless_surrounding_pair_scope_type @@ -56,22 +74,4 @@ def cursorless_surrounding_pair(m) -> str: except AttributeError: pass - return { - "modifier": modifier, - } - - -@mod.capture( - rule=( - " |" - "{user.cursorless_surrounding_pair_scope_type}" - ) -) -def cursorless_surrounding_pair_scope_type(m) -> str: - """Surrounding pair scope type""" - try: - return m.cursorless_surrounding_pair_scope_type - except AttributeError: - return paired_delimiters_map[ - m.cursorless_selectable_paired_delimiter - ].cursorlessIdentifier + return modifier diff --git a/cursorless-talon/src/modifiers/to_raw_selection.py b/cursorless-talon/src/modifiers/to_raw_selection.py index 791f775745..fc2b6d14ea 100644 --- a/cursorless-talon/src/modifiers/to_raw_selection.py +++ b/cursorless-talon/src/modifiers/to_raw_selection.py @@ -1,3 +1,5 @@ +from typing import Any + from talon import Module mod = Module() @@ -10,5 +12,5 @@ @mod.capture(rule="{user.cursorless_to_raw_selection}") -def cursorless_to_raw_selection(m) -> dict: - return {"modifier": {"type": "toRawSelection"}} +def cursorless_to_raw_selection(m) -> dict[str, Any]: + return {"type": "toRawSelection"} diff --git a/cursorless-talon/src/primitive_target.py b/cursorless-talon/src/primitive_target.py index 714e19de64..47768f9eed 100644 --- a/cursorless-talon/src/primitive_target.py +++ b/cursorless-talon/src/primitive_target.py @@ -1,8 +1,10 @@ +from typing import Any + from talon import Module mod = Module() -BASE_TARGET = {"type": "primitive"} +BASE_TARGET: dict[str, Any] = {"type": "primitive"} IMPLICIT_TARGET = {"type": "primitive", "isImplicit": True} @@ -27,9 +29,10 @@ def cursorless_modifier(m) -> str: @mod.capture( rule="+ [] | " ) -def cursorless_primitive_target(m) -> str: +def cursorless_primitive_target(m) -> dict[str, Any]: """Supported extents for cursorless navigation""" result = BASE_TARGET.copy() - for capture in m: - result.update(capture) + + result["stages"] = list(m) + return result diff --git a/src/typings/Types.ts b/src/typings/Types.ts index 4a47ceb11f..aad0f76d30 100644 --- a/src/typings/Types.ts +++ b/src/typings/Types.ts @@ -214,6 +214,7 @@ export type InsideOutsideType = "inside" | "outside" | null; export interface PartialPrimitiveTarget { type: "primitive"; + stages: PipelineDescriptor[]; mark?: Mark; modifier?: Modifier; selectionType?: SelectionType; @@ -222,6 +223,13 @@ export interface PartialPrimitiveTarget { isImplicit?: boolean; } +type PipelineDescriptor = + | Mark + | Modifier + | SelectionType + | Position + | InsideOutsideType; + export interface PartialRangeTarget { type: "range"; start: PartialPrimitiveTarget; From d7af9189bcfbcfcba29ee4b752ec325b10872b77 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Fri, 13 May 2022 18:01:01 +0300 Subject: [PATCH 002/314] Start moving some migration files around --- .../src/cheatsheet/sections/scopes.py | 2 +- cursorless-talon/src/command.py | 2 +- .../src/modifiers/containing_scope.py | 24 +- cursorless-talon/src/modifiers/position.py | 6 +- .../src/modifiers/selection_type.py | 14 - cursorless-talon/src/primitive_target.py | 1 - src/core/commandRunner/CommandRunner.ts | 33 +-- .../{types.ts => command.types.ts} | 34 +-- .../canonicalizeActionName.ts | 2 +- .../canonicalizeAndValidateCommand.ts | 58 ++-- .../canonicalizeTargets.ts | 32 +-- .../upgradeV0ToV1/index.ts | 1 + .../upgradeV0ToV1/upgradeV0ToV1.ts | 5 + .../upgradeV1ToV2/commandV1.types.ts | 208 ++++++++++++++ .../upgradeV1ToV2/index.ts | 1 + .../upgradeV1ToV2/upgradeStrictHere.ts | 19 ++ .../upgradeV1ToV2/upgradeV1ToV2.ts | 19 ++ src/core/inferFullTargets.ts | 6 +- src/languages/clojure.ts | 2 +- src/languages/cpp.ts | 3 +- src/languages/csharp.ts | 3 +- src/languages/getNodeMatcher.ts | 2 +- src/languages/go.ts | 3 +- src/languages/html.ts | 2 +- src/languages/java.ts | 3 +- src/languages/json.ts | 2 +- src/languages/markdown.ts | 2 +- src/languages/php.ts | 2 +- src/languages/python.ts | 3 +- src/languages/ruby.ts | 2 +- src/languages/scala.ts | 3 +- src/languages/scss.ts | 2 +- src/languages/typescript.ts | 2 +- src/processTargets/index.ts | 7 +- .../modifiers/processModifier.ts | 10 +- .../surroundingPair/delimiterMaps.ts | 4 +- ...ractSelectionFromSurroundingPairOffsets.ts | 2 +- .../findDelimiterPairContainingSelection.ts | 2 +- .../surroundingPair/findOppositeDelimiter.ts | 2 +- .../findSurroundingPairCore.ts | 2 +- .../findSurroundingPairParseTreeBased.ts | 4 +- .../findSurroundingPairTextBased.ts | 4 +- .../generateUnmatchedDelimiters.ts | 2 +- .../getIndividualDelimiters.ts | 2 +- .../modifiers/surroundingPair/index.ts | 3 +- .../modifiers/surroundingPair/types.ts | 2 +- src/processTargets/processMark.ts | 10 +- src/processTargets/processPosition.ts | 2 +- src/processTargets/processSelectionType.ts | 9 +- .../updateSurroundingPairTest.ts | 4 +- .../transformations/upgradeFromVersion0.ts | 2 +- .../fixtures/inferFullTargets.fixture.ts | 6 +- src/testUtil/TestCase.ts | 7 +- src/testUtil/TestCaseRecorder.ts | 3 +- src/testUtil/extractTargetedMarks.ts | 3 +- src/typings/Types.ts | 264 +----------------- src/typings/snippet.ts | 2 +- src/typings/target.types.ts | 232 +++++++++++++++ src/util/getPrimitiveTargets.ts | 4 +- src/util/nodeMatchers.ts | 2 +- src/util/performInsideOutsideAdjustment.ts | 3 +- src/util/selectionType.ts | 2 +- 62 files changed, 658 insertions(+), 446 deletions(-) delete mode 100644 cursorless-talon/src/modifiers/selection_type.py rename src/core/commandRunner/{types.ts => command.types.ts} (55%) rename src/{util => core/commandVersionUpgrades}/canonicalizeActionName.ts (95%) rename src/{util => core/commandVersionUpgrades}/canonicalizeAndValidateCommand.ts (78%) rename src/{util => core/commandVersionUpgrades}/canonicalizeTargets.ts (59%) create mode 100644 src/core/commandVersionUpgrades/upgradeV0ToV1/index.ts create mode 100644 src/core/commandVersionUpgrades/upgradeV0ToV1/upgradeV0ToV1.ts create mode 100644 src/core/commandVersionUpgrades/upgradeV1ToV2/commandV1.types.ts create mode 100644 src/core/commandVersionUpgrades/upgradeV1ToV2/index.ts create mode 100644 src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeStrictHere.ts create mode 100644 src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts create mode 100644 src/typings/target.types.ts diff --git a/cursorless-talon/src/cheatsheet/sections/scopes.py b/cursorless-talon/src/cheatsheet/sections/scopes.py index a9df0cd2a5..1df251ac69 100644 --- a/cursorless-talon/src/cheatsheet/sections/scopes.py +++ b/cursorless-talon/src/cheatsheet/sections/scopes.py @@ -4,7 +4,7 @@ def get_scopes(): return { **get_lists( - ["scope_type", "selection_type", "subtoken_scope_type"], + ["scope_type", "subtoken_scope_type"], {"argumentOrParameter": "Argument"}, ), "

": "Paired delimiter", diff --git a/cursorless-talon/src/command.py b/cursorless-talon/src/command.py index 95d8d69a17..757c78a7a4 100644 --- a/cursorless-talon/src/command.py +++ b/cursorless-talon/src/command.py @@ -127,7 +127,7 @@ def construct_cursorless_command_argument( use_pre_phrase_snapshot = False return { - "version": 1, + "version": 2, "spokenForm": get_spoken_form(), "action": action, "targets": targets, diff --git a/cursorless-talon/src/modifiers/containing_scope.py b/cursorless-talon/src/modifiers/containing_scope.py index 40f935a4cf..da1829103c 100644 --- a/cursorless-talon/src/modifiers/containing_scope.py +++ b/cursorless-talon/src/modifiers/containing_scope.py @@ -46,6 +46,14 @@ "tags": "xmlBothTags", "start tag": "xmlStartTag", "end tag": "xmlEndTag", + # Text-based scope types + "block": "paragraph", + "cell": "notebookCell", + "file": "document", + "line": "line", + "paint": "nonWhitespaceSequence", + "link": "url", + "token": "token", } @@ -53,24 +61,11 @@ def cursorless_containing_scope(m) -> dict[str, Any]: """Expand to containing scope""" return { - "type": "containingScope", + "type": "everyScope" if m[0] == "every" else "containingScope", "scopeType": m.cursorless_scope_type, - "includeSiblings": m[0] == "every", } -# NOTE: Please do not change these dicts. Use the CSVs for customization. -# See https://www.cursorless.org/docs/user/customization/ -selection_types = { - "block": "paragraph", - "cell": "notebookCell", - "file": "document", - "line": "line", - "paint": "nonWhitespaceSequence", - "link": "url", - "token": "token", -} - # NOTE: Please do not change these dicts. Use the CSVs for customization. # See https://www.cursorless.org/docs/user/customization/ subtoken_scope_types = { @@ -88,7 +83,6 @@ def cursorless_containing_scope(m) -> dict[str, Any]: default_values = { "scope_type": scope_types, - "selection_type": selection_types, "subtoken_scope_type": subtoken_scope_types, "surrounding_pair_scope_type": surrounding_pair_scope_types, } diff --git a/cursorless-talon/src/modifiers/position.py b/cursorless-talon/src/modifiers/position.py index 5ed41492eb..b4f9da56a1 100644 --- a/cursorless-talon/src/modifiers/position.py +++ b/cursorless-talon/src/modifiers/position.py @@ -7,10 +7,10 @@ positions = { - "after": {"position": "after"}, "before": {"position": "before"}, - "start of": {"position": "before", "insideOutsideType": "inside"}, - "end of": {"position": "after", "insideOutsideType": "inside"}, + "after": {"position": "after"}, + "start of": {"position": "start"}, + "end of": {"position": "end"}, # Disabled for now because "below" can misrecognize with "blue" and we may move away from allowing positional modifiers in arbitrary places anyway # "above": {"position": "before", **LINE.json_repr}, # "below": {"position": "after", **LINE.json_repr} diff --git a/cursorless-talon/src/modifiers/selection_type.py b/cursorless-talon/src/modifiers/selection_type.py deleted file mode 100644 index 8733773d2f..0000000000 --- a/cursorless-talon/src/modifiers/selection_type.py +++ /dev/null @@ -1,14 +0,0 @@ -from typing import Any - -from talon import Module - -mod = Module() - - -mod.list("cursorless_selection_type", desc="Types of selection_types") - - -@mod.capture(rule="{user.cursorless_selection_type}") -def cursorless_selection_type(m) -> dict[str, Any]: - # TODO: Change this to containing scope next - return {"type": "selectionType", "selectionType": m.cursorless_selection_type} diff --git a/cursorless-talon/src/primitive_target.py b/cursorless-talon/src/primitive_target.py index 47768f9eed..af9a5eb296 100644 --- a/cursorless-talon/src/primitive_target.py +++ b/cursorless-talon/src/primitive_target.py @@ -10,7 +10,6 @@ modifiers = [ "", # before, end of - "", # token, line, file "", # head, tail "", # funk, state, class "", # first past second word diff --git a/src/core/commandRunner/CommandRunner.ts b/src/core/commandRunner/CommandRunner.ts index b93b23559e..88a6a0e994 100644 --- a/src/core/commandRunner/CommandRunner.ts +++ b/src/core/commandRunner/CommandRunner.ts @@ -4,14 +4,14 @@ import processTargets from "../../processTargets"; import { ActionType, Graph, - PartialTarget, ProcessedTargetsContext, } from "../../typings/Types"; +import { PartialTarget } from "../../typings/target.types"; import { ThatMark } from "../ThatMark"; -import { canonicalizeAndValidateCommand } from "../../util/canonicalizeAndValidateCommand"; -import { CommandArgument } from "./types"; +import { Command } from "./command.types"; import { isString } from "../../util/type"; import { ActionableError } from "../../errors"; +import { canonicalizeAndValidateCommand } from "../commandVersionUpgrades/canonicalizeAndValidateCommand"; // TODO: Do this using the graph once we migrate its dependencies onto the graph export default class CommandRunner { @@ -58,11 +58,11 @@ export default class CommandRunner { * action, and returns the desired return value indicated by the action, if * it has one. */ - async runCommand(commandArgument: CommandArgument) { + async runCommand(command: Command) { try { if (this.graph.debug.active) { - this.graph.debug.log(`commandArgument:`); - this.graph.debug.log(JSON.stringify(commandArgument, null, 3)); + this.graph.debug.log(`command:`); + this.graph.debug.log(JSON.stringify(command, null, 3)); } const { @@ -71,7 +71,7 @@ export default class CommandRunner { targets: partialTargets, extraArgs, usePrePhraseSnapshot, - } = canonicalizeAndValidateCommand(commandArgument); + } = canonicalizeAndValidateCommand(command); const readableHatMap = await this.graph.hatTokenMap.getReadableMap( usePrePhraseSnapshot @@ -116,10 +116,7 @@ export default class CommandRunner { hatTokenMap: readableHatMap, spokenForm, }; - await this.graph.testCaseRecorder.preCommandHook( - commandArgument, - context - ); + await this.graph.testCaseRecorder.preCommandHook(command, context); } const { @@ -151,20 +148,20 @@ export default class CommandRunner { } private runCommandBackwardCompatible( - spokenFormOrCommandArgument: string | CommandArgument, + spokenFormOrCommand: string | Command, ...rest: unknown[] ) { - let commandArgument: CommandArgument; + let command: Command; - if (isString(spokenFormOrCommandArgument)) { - const spokenForm = spokenFormOrCommandArgument; + if (isString(spokenFormOrCommand)) { + const spokenForm = spokenFormOrCommand; const [action, targets, ...extraArgs] = rest as [ ActionType, PartialTarget[], ...unknown[] ]; - commandArgument = { + command = { version: 0, spokenForm, action, @@ -173,10 +170,10 @@ export default class CommandRunner { usePrePhraseSnapshot: false, }; } else { - commandArgument = spokenFormOrCommandArgument; + command = spokenFormOrCommand; } - return this.runCommand(commandArgument); + return this.runCommand(command); } dispose() { diff --git a/src/core/commandRunner/types.ts b/src/core/commandRunner/command.types.ts similarity index 55% rename from src/core/commandRunner/types.ts rename to src/core/commandRunner/command.types.ts index b70e169f78..82bea9450c 100644 --- a/src/core/commandRunner/types.ts +++ b/src/core/commandRunner/command.types.ts @@ -1,32 +1,26 @@ -import { ActionType, PartialTarget } from "../../typings/Types"; +import { ActionType } from "../../typings/Types"; +import { PartialPrimitiveTarget } from "../../typings/target.types"; +import { + CommandV0, + CommandV1, +} from "../commandVersionUpgrades/upgradeV1ToV2/commandV1.types"; -export type CommandArgumentComplete = Required< - Omit -> & - Pick; +export type CommandComplete = Required> & + Pick; export const LATEST_VERSION = 1 as const; -export type CommandArgumentLatest = CommandArgument & { +export type CommandLatest = Command & { version: typeof LATEST_VERSION; }; -export type CommandArgument = CommandArgumentV0 | CommandArgumentV1; +export type Command = CommandV0 | CommandV1 | CommandV2; -interface CommandArgumentV1 extends CommandArgumentV0V1 { - version: 1; -} - -interface CommandArgumentV0 extends CommandArgumentV0V1 { - version: 0; - usePrePhraseSnapshot?: false; -} - -interface CommandArgumentV0V1 { +interface CommandV2 { /** * The version number of the command API */ - version: 0 | 1; + version: 2; /** * The spoken form of the command if issued from a voice command system @@ -39,7 +33,7 @@ interface CommandArgumentV0V1 { * voice command system issues a pre phrase signal at the start of every * phrase. */ - usePrePhraseSnapshot?: boolean; + usePrePhraseSnapshot: boolean; /** * The action to run @@ -50,7 +44,7 @@ interface CommandArgumentV0V1 { * A list of targets expected by the action. Inference will be run on the * targets */ - targets: PartialTarget[]; + targets: PartialPrimitiveTarget[]; /** * A list of extra arguments expected by the given action. diff --git a/src/util/canonicalizeActionName.ts b/src/core/commandVersionUpgrades/canonicalizeActionName.ts similarity index 95% rename from src/util/canonicalizeActionName.ts rename to src/core/commandVersionUpgrades/canonicalizeActionName.ts index 983ce9c332..b7111cd521 100644 --- a/src/util/canonicalizeActionName.ts +++ b/src/core/commandVersionUpgrades/canonicalizeActionName.ts @@ -1,4 +1,4 @@ -import { ActionType } from "../typings/Types"; +import { ActionType } from "../../typings/Types"; const actionAliasToCanonicalName: Record = { bring: "replaceWithTarget", diff --git a/src/util/canonicalizeAndValidateCommand.ts b/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts similarity index 78% rename from src/util/canonicalizeAndValidateCommand.ts rename to src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts index 5036475373..0b3aeaf3ab 100644 --- a/src/util/canonicalizeAndValidateCommand.ts +++ b/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts @@ -3,23 +3,26 @@ import canonicalizeTargets from "./canonicalizeTargets"; import { ActionType, PartialTarget, SelectionType } from "../typings/Types"; import { getPartialPrimitiveTargets } from "./getPrimitiveTargets"; import { - CommandArgument, - CommandArgumentComplete, + Command, + CommandComplete, LATEST_VERSION, } from "../core/commandRunner/types"; import { ActionableError } from "../errors"; import { commands } from "vscode"; +import { upgradeV0ToV1 } from "./upgradeV0ToV1"; +import { upgradeV1ToV2 } from "./upgradeV1ToV2"; /** * Given a command argument which comes from the client, normalize it so that it * conforms to the latest version of the expected cursorless command argument. * - * @param commandArgument The command argument to normalize + * @param command The command argument to normalize * @returns The normalized command argument */ export function canonicalizeAndValidateCommand( - commandArgument: CommandArgument -): CommandArgumentComplete { + command: Command +): CommandComplete { + const commandUpgraded = upgradeCommand(command); const { action: inputActionName, targets: inputPartialTargets, @@ -27,22 +30,7 @@ export function canonicalizeAndValidateCommand( usePrePhraseSnapshot = false, version, ...rest - } = commandArgument; - - if (version > LATEST_VERSION) { - throw new ActionableError( - "Cursorless Talon version is ahead of Cursorless VSCode extension version. Please update Cursorless VSCode.", - [ - { - name: "Check for updates", - action: () => - commands.executeCommand( - "workbench.extensions.action.checkForUpdates" - ), - }, - ] - ); - } + } = commandUpgraded; const actionName = canonicalizeActionName(inputActionName); const partialTargets = canonicalizeTargets(inputPartialTargets); @@ -60,6 +48,34 @@ export function canonicalizeAndValidateCommand( }; } +function upgradeCommand(command: Command) { + if (command.version > LATEST_VERSION) { + throw new ActionableError( + "Cursorless Talon version is ahead of Cursorless VSCode extension version. Please update Cursorless VSCode.", + [ + { + name: "Check for updates", + action: () => + commands.executeCommand( + "workbench.extensions.action.checkForUpdates" + ), + }, + ] + ); + } + + while (command.version < LATEST_VERSION) { + switch (command.version) { + case 0: + command = upgradeV0ToV1(command); + break; + case 1: + command = upgradeV1ToV2(command); + break; + } + } +} + export function validateCommand( actionName: ActionType, partialTargets: PartialTarget[] diff --git a/src/util/canonicalizeTargets.ts b/src/core/commandVersionUpgrades/canonicalizeTargets.ts similarity index 59% rename from src/util/canonicalizeTargets.ts rename to src/core/commandVersionUpgrades/canonicalizeTargets.ts index f2efb50eb8..b3dc0767b8 100644 --- a/src/util/canonicalizeTargets.ts +++ b/src/core/commandVersionUpgrades/canonicalizeTargets.ts @@ -1,13 +1,8 @@ -import { - PartialPrimitiveTarget, - PartialTarget, - ScopeType, -} from "../typings/Types"; import update from "immutability-helper"; -import { transformPartialPrimitiveTargets } from "./getPrimitiveTargets"; -import { HatStyleName } from "../core/constants"; import { flow } from "lodash"; -import { isDeepStrictEqual } from "util"; +import { ScopeType, PartialPrimitiveTarget, PartialTarget } from "../../typings/target.types"; +import { transformPartialPrimitiveTargets } from "../../util/getPrimitiveTargets"; +import { HatStyleName } from "../constants"; const SCOPE_TYPE_CANONICALIZATION_MAPPING: Record = { arrowFunction: "anonymousFunction", @@ -43,28 +38,9 @@ const canonicalizeColors = ( }) : target; -const STRICT_HERE = { - type: "primitive", - mark: { type: "cursor" }, - selectionType: "token", - position: "contents", - modifier: { type: "identity" }, - insideOutsideType: "inside", -}; - -const IMPLICIT_TARGET: PartialPrimitiveTarget = { - type: "primitive", - isImplicit: true, -}; - -const upgradeStrictHere = ( - target: PartialPrimitiveTarget -): PartialPrimitiveTarget => - isDeepStrictEqual(target, STRICT_HERE) ? IMPLICIT_TARGET : target; - export default function canonicalizeTargets(partialTargets: PartialTarget[]) { return transformPartialPrimitiveTargets( partialTargets, - flow(canonicalizeScopeTypes, canonicalizeColors, upgradeStrictHere) + flow(canonicalizeScopeTypes, canonicalizeColors) ); } diff --git a/src/core/commandVersionUpgrades/upgradeV0ToV1/index.ts b/src/core/commandVersionUpgrades/upgradeV0ToV1/index.ts new file mode 100644 index 0000000000..2a30592649 --- /dev/null +++ b/src/core/commandVersionUpgrades/upgradeV0ToV1/index.ts @@ -0,0 +1 @@ +export * from "./upgradeV0ToV1"; diff --git a/src/core/commandVersionUpgrades/upgradeV0ToV1/upgradeV0ToV1.ts b/src/core/commandVersionUpgrades/upgradeV0ToV1/upgradeV0ToV1.ts new file mode 100644 index 0000000000..b0d572d0e2 --- /dev/null +++ b/src/core/commandVersionUpgrades/upgradeV0ToV1/upgradeV0ToV1.ts @@ -0,0 +1,5 @@ +import { CommandV0, CommandV1 } from "../../commandRunner/command.types"; + +export function upgradeV0ToV1(command: CommandV0): CommandV1 { + return { ...command, version: 1 }; +} diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/commandV1.types.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/commandV1.types.ts new file mode 100644 index 0000000000..51bb75a499 --- /dev/null +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/commandV1.types.ts @@ -0,0 +1,208 @@ +export interface CommandV1 extends CommandV0V1 { + version: 1; +} + +export interface CommandV0 extends CommandV0V1 { + version: 0; + usePrePhraseSnapshot?: false; +} + +interface CommandV0V1 { + /** + * The version number of the command API + */ + version: 0 | 1; + + /** + * The spoken form of the command if issued from a voice command system + */ + spokenForm?: string; + + /** + * If the command is issued from a voice command system, this boolean indicates + * whether we should use the pre phrase snapshot. Only set this to true if the + * voice command system issues a pre phrase signal at the start of every + * phrase. + */ + usePrePhraseSnapshot?: boolean; + + /** + * The action to run + */ + action: string; + + /** + * A list of targets expected by the action. Inference will be run on the + * targets + */ + targets: PartialPrimitiveTarget[]; + + /** + * A list of extra arguments expected by the given action. + */ + extraArgs?: unknown[]; +} + +interface PartialPrimitiveTarget { + type: "primitive"; + mark?: Mark; + modifier?: Modifier; + selectionType?: SelectionType; + position?: Position; + insideOutsideType?: InsideOutsideType; + isImplicit?: boolean; +} + +type SelectionType = + | "token" + | "line" + | "notebookCell" + | "paragraph" + | "document" + | "nonWhitespaceSequence" + | "url"; + +interface CursorMark { + type: "cursor"; +} + +interface CursorMarkToken { + type: "cursorToken"; +} + +interface That { + type: "that"; +} + +interface Source { + type: "source"; +} + +interface Nothing { + type: "nothing"; +} + +interface DecoratedSymbol { + type: "decoratedSymbol"; + // NB: We use the type string instead of the more specific hat style type + // because this will go through a canonicalization mapping anyway + symbolColor: string; + character: string; +} + +type LineNumberType = "absolute" | "relative" | "modulo100"; + +interface LineNumberPosition { + type: LineNumberType; + lineNumber: number; +} + +interface LineNumber { + type: "lineNumber"; + anchor: LineNumberPosition; + active: LineNumberPosition; +} + +type Mark = + | CursorMark + | CursorMarkToken + | That + | Source + | DecoratedSymbol + | Nothing + | LineNumber; + +type SimpleSurroundingPairName = + | "angleBrackets" + | "backtickQuotes" + | "curlyBrackets" + | "doubleQuotes" + | "escapedDoubleQuotes" + | "escapedParentheses" + | "escapedSquareBrackets" + | "escapedSingleQuotes" + | "parentheses" + | "singleQuotes" + | "squareBrackets"; + +type ComplexSurroundingPairName = "string" | "any"; + +type SurroundingPairName = + | SimpleSurroundingPairName + | ComplexSurroundingPairName; + +type ScopeType = string; + +type Position = "before" | "after" | "contents"; + +type InsideOutsideType = "inside" | "outside" | null; + +type SubTokenType = "word" | "character"; + +/** + * Indicates whether to include or exclude delimiters in a surrounding pair + * modifier. In the future, these will become proper modifiers that can be + * applied in many places, such as to restrict to the body of an if statement. + * By default, a surrounding pair modifier refers to the entire surrounding + * range, so if delimiter inclusion is undefined, it's equivalent to not having + * one of these modifiers; ie include the delimiters. + */ + +type DelimiterInclusion = "excludeInterior" | "interiorOnly" | undefined; + +type SurroundingPairDirection = "left" | "right"; + +interface SurroundingPairModifier { + type: "surroundingPair"; + delimiter: SurroundingPairName; + delimiterInclusion: DelimiterInclusion; + forceDirection?: SurroundingPairDirection; +} + +interface ContainingScopeModifier { + type: "containingScope"; + scopeType: ScopeType; + valueOnly?: boolean; + includeSiblings?: boolean; +} + +interface SubTokenModifier { + type: "subpiece"; + pieceType: SubTokenType; + anchor: number; + active: number; + excludeAnchor?: boolean; + excludeActive?: boolean; +} + +interface IdentityModifier { + type: "identity"; +} + +/** + * Converts its input to a raw selection with no type information so for + * example if it is the destination of a bring or move it should inherit the + * type information such as delimiters from its source. + */ + +interface RawSelectionModifier { + type: "toRawSelection"; +} + +interface HeadModifier { + type: "head"; +} + +interface TailModifier { + type: "tail"; +} + +type Modifier = + | IdentityModifier + | SurroundingPairModifier + | ContainingScopeModifier + | SubTokenModifier + // | MatchingPairSymbolModifier Not implemented + | HeadModifier + | TailModifier + | RawSelectionModifier; diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/index.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/index.ts new file mode 100644 index 0000000000..d31a7b40a9 --- /dev/null +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/index.ts @@ -0,0 +1 @@ +export * from "./upgradeV1ToV2"; diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeStrictHere.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeStrictHere.ts new file mode 100644 index 0000000000..cc28e85d79 --- /dev/null +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeStrictHere.ts @@ -0,0 +1,19 @@ +import { PartialPrimitiveTarget } from "../typings/Types"; +import { isDeepStrictEqual } from "util"; + +const STRICT_HERE = { + type: "primitive", + mark: { type: "cursor" }, + selectionType: "token", + position: "contents", + modifier: { type: "identity" }, + insideOutsideType: "inside", +}; +const IMPLICIT_TARGET: PartialPrimitiveTarget = { + type: "primitive", + isImplicit: true, +}; +export const upgradeStrictHere = ( + target: PartialPrimitiveTarget +): PartialPrimitiveTarget => + isDeepStrictEqual(target, STRICT_HERE) ? IMPLICIT_TARGET : target; diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts new file mode 100644 index 0000000000..73d0c01a24 --- /dev/null +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts @@ -0,0 +1,19 @@ +import { flow } from "lodash"; +import { transformPartialPrimitiveTargets } from "../../../util/getPrimitiveTargets"; +import { CommandV0, CommandV1 } from "../../commandRunner/command.types"; +import { upgradeStrictHere } from "./upgradeStrictHere"; + +export function upgradeV1ToV2(command: CommandV1): CommandV2 { + return { + ...command, + targets: upgradeTargets(command.targets), + version: 2, + }; +} + +function upgradeTargets(partialTargets: PartialTarget[]) { + return transformPartialPrimitiveTargets( + partialTargets, + flow(upgradeStrictHere) + ); +} diff --git a/src/core/inferFullTargets.ts b/src/core/inferFullTargets.ts index 84c1eeac3f..969a495877 100644 --- a/src/core/inferFullTargets.ts +++ b/src/core/inferFullTargets.ts @@ -1,13 +1,15 @@ import { ActionPreferences, +} from "../typings/Types"; +import { PartialPrimitiveTarget, PartialRangeTarget, PartialTarget, PrimitiveTarget, RangeTarget, Target, - PartialListTarget, -} from "../typings/Types"; + PartialListTarget +} from "../typings/target.types"; /** * Performs inference on the partial targets provided by the user, using diff --git a/src/languages/clojure.ts b/src/languages/clojure.ts index 7089a01030..90d5045c88 100644 --- a/src/languages/clojure.ts +++ b/src/languages/clojure.ts @@ -6,10 +6,10 @@ import { patternMatcher, } from "../util/nodeMatchers"; import { - ScopeType, NodeMatcherAlternative, NodeFinder, } from "../typings/Types"; +import { ScopeType } from "../typings/target.types"; import { SyntaxNode } from "web-tree-sitter"; import { delimitedSelector } from "../util/nodeSelectors"; import { identity } from "lodash"; diff --git a/src/languages/cpp.ts b/src/languages/cpp.ts index 3ca9b1b7fa..8741e72bf3 100644 --- a/src/languages/cpp.ts +++ b/src/languages/cpp.ts @@ -4,7 +4,8 @@ import { leadingMatcher, trailingMatcher, } from "../util/nodeMatchers"; -import { NodeMatcherAlternative, ScopeType } from "../typings/Types"; +import { NodeMatcherAlternative } from "../typings/Types"; +import { ScopeType } from "../typings/target.types"; // Generated by the following command: // > curl https://raw.githubusercontent.com/tree-sitter/tree-sitter-cpp/master/src/node-types.json | jq '[.[] | select(.type == "compound_statement") | .children.types[].type] + [.[] | select(.type == "_statement") | .subtypes[].type]' diff --git a/src/languages/csharp.ts b/src/languages/csharp.ts index 7ad4ecee17..c1cd010d75 100644 --- a/src/languages/csharp.ts +++ b/src/languages/csharp.ts @@ -8,7 +8,8 @@ import { trailingMatcher, typeMatcher, } from "../util/nodeMatchers"; -import { NodeMatcherAlternative, ScopeType } from "../typings/Types"; +import { NodeMatcherAlternative } from "../typings/Types"; +import { ScopeType } from "../typings/target.types"; import { nodeFinder, typedNodeFinder } from "../util/nodeFinders"; import { delimitedSelector } from "../util/nodeSelectors"; diff --git a/src/languages/getNodeMatcher.ts b/src/languages/getNodeMatcher.ts index eda070ca97..226640da43 100644 --- a/src/languages/getNodeMatcher.ts +++ b/src/languages/getNodeMatcher.ts @@ -4,9 +4,9 @@ import { selectionWithEditorFromRange } from "../util/selectionUtils"; import { NodeMatcher, NodeMatcherValue, - ScopeType, SelectionWithEditor, } from "../typings/Types"; +import { ScopeType } from "../typings/target.types"; import cpp from "./cpp"; import clojure from "./clojure"; import csharp from "./csharp"; diff --git a/src/languages/go.ts b/src/languages/go.ts index 8de97bd28c..1bf68458f8 100644 --- a/src/languages/go.ts +++ b/src/languages/go.ts @@ -5,7 +5,8 @@ import { cascadingMatcher, patternMatcher, } from "../util/nodeMatchers"; -import { NodeMatcherAlternative, ScopeType } from "../typings/Types"; +import { NodeMatcherAlternative } from "../typings/Types"; +import { ScopeType } from "../typings/target.types"; // Generated by the following command: // `curl https://raw.githubusercontent.com/tree-sitter/tree-sitter-go/master/src/node-types.json | jq '[.[] | select(.type == "_statement" or .type == "_simple_statement") | .subtypes[].type]'` diff --git a/src/languages/html.ts b/src/languages/html.ts index 5089206109..786097c4f2 100644 --- a/src/languages/html.ts +++ b/src/languages/html.ts @@ -4,10 +4,10 @@ import { patternMatcher, } from "../util/nodeMatchers"; import { - ScopeType, NodeMatcherAlternative, SelectionWithEditor, } from "../typings/Types"; +import { ScopeType } from "../typings/target.types"; import { SyntaxNode } from "web-tree-sitter"; import { getNodeRange } from "../util/nodeSelectors"; diff --git a/src/languages/java.ts b/src/languages/java.ts index 130aeffbd7..597d52e4ab 100644 --- a/src/languages/java.ts +++ b/src/languages/java.ts @@ -5,7 +5,8 @@ import { conditionMatcher, trailingMatcher, } from "../util/nodeMatchers"; -import { NodeMatcherAlternative, ScopeType } from "../typings/Types"; +import { NodeMatcherAlternative } from "../typings/Types"; +import { ScopeType } from "../typings/target.types"; // Generated by the following command: // > curl https://raw.githubusercontent.com/tree-sitter/tree-sitter-java/master/src/node-types.json | jq '[.[] | select(.type == "statement" or .type == "declaration") | .subtypes[].type]' diff --git a/src/languages/json.ts b/src/languages/json.ts index 45405a8f2f..348a953b5e 100644 --- a/src/languages/json.ts +++ b/src/languages/json.ts @@ -5,10 +5,10 @@ import { trailingMatcher, } from "../util/nodeMatchers"; import { - ScopeType, NodeMatcherAlternative, SelectionWithEditor, } from "../typings/Types"; +import { ScopeType } from "../typings/target.types"; import { SyntaxNode } from "web-tree-sitter"; import { getNodeRange } from "../util/nodeSelectors"; diff --git a/src/languages/markdown.ts b/src/languages/markdown.ts index 3ce9f75071..670f07b622 100644 --- a/src/languages/markdown.ts +++ b/src/languages/markdown.ts @@ -3,9 +3,9 @@ import { SyntaxNode } from "web-tree-sitter"; import { NodeFinder, NodeMatcherAlternative, - ScopeType, SelectionWithContext, } from "../typings/Types"; +import { ScopeType } from "../typings/target.types"; import { leadingSiblingNodeFinder, patternFinder } from "../util/nodeFinders"; import { createPatternMatchers, diff --git a/src/languages/php.ts b/src/languages/php.ts index f59d98ff13..ece2dd9b1b 100644 --- a/src/languages/php.ts +++ b/src/languages/php.ts @@ -2,10 +2,10 @@ import { Selection, TextEditor } from "vscode"; import { SyntaxNode } from "web-tree-sitter"; import { NodeMatcherAlternative, - ScopeType, SelectionWithContext, SelectionWithEditor, } from "../typings/Types"; +import { ScopeType } from "../typings/target.types"; import { patternFinder } from "../util/nodeFinders"; import { argumentMatcher, diff --git a/src/languages/python.ts b/src/languages/python.ts index 42ac0756db..f5eca5cdc7 100644 --- a/src/languages/python.ts +++ b/src/languages/python.ts @@ -10,7 +10,8 @@ import { matcher, } from "../util/nodeMatchers"; import { patternFinder } from "../util/nodeFinders"; -import { NodeMatcherAlternative, ScopeType } from "../typings/Types"; +import { NodeMatcherAlternative } from "../typings/Types"; +import { ScopeType } from "../typings/target.types"; import { childRangeSelector } from "../util/nodeSelectors"; // Generated by the following command: diff --git a/src/languages/ruby.ts b/src/languages/ruby.ts index ec3846b9fb..c7d6837d09 100644 --- a/src/languages/ruby.ts +++ b/src/languages/ruby.ts @@ -11,9 +11,9 @@ import { } from "../util/nodeMatchers"; import { NodeMatcherAlternative, - ScopeType, SelectionWithEditor, } from "../typings/Types"; +import { ScopeType } from "../typings/target.types"; import { SyntaxNode } from "web-tree-sitter"; import { getNodeRange } from "../util/nodeSelectors"; import { patternFinder } from "../util/nodeFinders"; diff --git a/src/languages/scala.ts b/src/languages/scala.ts index a0eddc8583..7bf7806369 100644 --- a/src/languages/scala.ts +++ b/src/languages/scala.ts @@ -4,7 +4,8 @@ import { leadingMatcher, conditionMatcher, } from "../util/nodeMatchers"; -import { NodeMatcherAlternative, ScopeType } from "../typings/Types"; +import { NodeMatcherAlternative } from "../typings/Types"; +import { ScopeType } from "../typings/target.types"; const nodeMatchers: Partial> = { // treating classes = classlike diff --git a/src/languages/scss.ts b/src/languages/scss.ts index 1463d1707a..28e3c9313a 100644 --- a/src/languages/scss.ts +++ b/src/languages/scss.ts @@ -1,9 +1,9 @@ import { SyntaxNode } from "web-tree-sitter"; import { NodeMatcherAlternative, - ScopeType, SelectionWithEditor, } from "../typings/Types"; +import { ScopeType } from "../typings/target.types"; import { patternFinder } from "../util/nodeFinders"; import { cascadingMatcher, diff --git a/src/languages/typescript.ts b/src/languages/typescript.ts index 444144b7bf..d7836d97b3 100644 --- a/src/languages/typescript.ts +++ b/src/languages/typescript.ts @@ -11,9 +11,9 @@ import { import { NodeMatcher, NodeMatcherAlternative, - ScopeType, SelectionWithEditor, } from "../typings/Types"; +import { ScopeType } from "../typings/target.types"; import { getNodeInternalRange, getNodeRange, diff --git a/src/processTargets/index.ts b/src/processTargets/index.ts index 0e9a8b1397..ea81938307 100644 --- a/src/processTargets/index.ts +++ b/src/processTargets/index.ts @@ -2,12 +2,13 @@ import { isEqual, zip } from "lodash"; import { Selection } from "vscode"; import { performInsideOutsideAdjustment } from "../util/performInsideOutsideAdjustment"; import { - PrimitiveTarget, ProcessedTargetsContext, - RangeTarget, - Target, TypedSelection, } from "../typings/Types"; +import { + PrimitiveTarget, RangeTarget, + Target +} from "../typings/target.types"; import processMark from "./processMark"; import processModifier from "./modifiers/processModifier"; import processPosition from "./processPosition"; diff --git a/src/processTargets/modifiers/processModifier.ts b/src/processTargets/modifiers/processModifier.ts index 7116f5ea64..7e019df807 100644 --- a/src/processTargets/modifiers/processModifier.ts +++ b/src/processTargets/modifiers/processModifier.ts @@ -5,16 +5,16 @@ import { SyntaxNode } from "web-tree-sitter"; import { SUBWORD_MATCHER } from "../../core/constants"; import { selectionWithEditorFromRange } from "../../util/selectionUtils"; import { - ContainingScopeModifier, - HeadModifier, NodeMatcher, - PrimitiveTarget, ProcessedTargetsContext, SelectionContext, SelectionWithEditor, - SubTokenModifier, - TailModifier, } from "../../typings/Types"; +import { + ContainingScopeModifier, + HeadModifier, PrimitiveTarget, SubTokenModifier, + TailModifier +} from "../../typings/target.types"; import { processSurroundingPair } from "./surroundingPair"; import { getNodeMatcher } from "../../languages/getNodeMatcher"; diff --git a/src/processTargets/modifiers/surroundingPair/delimiterMaps.ts b/src/processTargets/modifiers/surroundingPair/delimiterMaps.ts index 5204d2c3fb..87987d1791 100644 --- a/src/processTargets/modifiers/surroundingPair/delimiterMaps.ts +++ b/src/processTargets/modifiers/surroundingPair/delimiterMaps.ts @@ -1,7 +1,7 @@ import { ComplexSurroundingPairName, - SimpleSurroundingPairName, -} from "../../../typings/Types"; + SimpleSurroundingPairName +} from "../../../typings/target.types"; type IndividualDelimiterText = string | string[]; diff --git a/src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts b/src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts index 236e0d8c96..c4fc1c464b 100644 --- a/src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts +++ b/src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts @@ -1,8 +1,8 @@ import { Selection, TextDocument } from "vscode"; import { - DelimiterInclusion, SelectionWithContext, } from "../../../typings/Types"; +import { DelimiterInclusion } from "../../../typings/target.types"; import { SurroundingPairOffsets } from "./types"; /** diff --git a/src/processTargets/modifiers/surroundingPair/findDelimiterPairContainingSelection.ts b/src/processTargets/modifiers/surroundingPair/findDelimiterPairContainingSelection.ts index 6d10a5ad3a..68614fba17 100644 --- a/src/processTargets/modifiers/surroundingPair/findDelimiterPairContainingSelection.ts +++ b/src/processTargets/modifiers/surroundingPair/findDelimiterPairContainingSelection.ts @@ -5,7 +5,7 @@ import { Offsets, } from "./types"; import { generateUnmatchedDelimiters } from "./generateUnmatchedDelimiters"; -import { SimpleSurroundingPairName } from "../../../typings/Types"; +import { SimpleSurroundingPairName } from "../../../typings/target.types"; /** * Looks for a surrounding pair that contains the selection, returning null if none is found. diff --git a/src/processTargets/modifiers/surroundingPair/findOppositeDelimiter.ts b/src/processTargets/modifiers/surroundingPair/findOppositeDelimiter.ts index c2e6342725..f7f4d3bad1 100644 --- a/src/processTargets/modifiers/surroundingPair/findOppositeDelimiter.ts +++ b/src/processTargets/modifiers/surroundingPair/findOppositeDelimiter.ts @@ -1,4 +1,4 @@ -import { SurroundingPairDirection } from "../../../typings/Types"; +import { SurroundingPairDirection } from "../../../typings/target.types"; import { findUnmatchedDelimiter } from "./generateUnmatchedDelimiters"; import { DelimiterOccurrence, diff --git a/src/processTargets/modifiers/surroundingPair/findSurroundingPairCore.ts b/src/processTargets/modifiers/surroundingPair/findSurroundingPairCore.ts index 9cf1d883d3..4f569c661e 100644 --- a/src/processTargets/modifiers/surroundingPair/findSurroundingPairCore.ts +++ b/src/processTargets/modifiers/surroundingPair/findSurroundingPairCore.ts @@ -1,5 +1,5 @@ import { sortedIndexBy } from "lodash"; -import { SimpleSurroundingPairName } from "../../../typings/Types"; +import { SimpleSurroundingPairName } from "../../../typings/target.types"; import { findDelimiterPairAdjacentToSelection } from "./findDelimiterPairAdjacentToSelection"; import { findDelimiterPairContainingSelection } from "./findDelimiterPairContainingSelection"; import { diff --git a/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts b/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts index 8e9ee00691..ed664408fc 100644 --- a/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts +++ b/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts @@ -3,8 +3,8 @@ import { SyntaxNode } from "web-tree-sitter"; import { SimpleSurroundingPairName, DelimiterInclusion, - SurroundingPairDirection, -} from "../../../typings/Types"; + SurroundingPairDirection +} from "../../../typings/target.types"; import { getNodeRange } from "../../../util/nodeSelectors"; import { isContainedInErrorNode } from "../../../util/treeSitterUtils"; import { extractSelectionFromSurroundingPairOffsets } from "./extractSelectionFromSurroundingPairOffsets"; diff --git a/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts b/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts index 79abe8962b..dca32a1509 100644 --- a/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts +++ b/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts @@ -4,8 +4,8 @@ import { SimpleSurroundingPairName, DelimiterInclusion, SurroundingPairName, - SurroundingPairDirection, -} from "../../../typings/Types"; + SurroundingPairDirection +} from "../../../typings/target.types"; import { getDocumentRange } from "../../../util/range"; import { matchAll } from "../../../util/regex"; import { extractSelectionFromSurroundingPairOffsets } from "./extractSelectionFromSurroundingPairOffsets"; diff --git a/src/processTargets/modifiers/surroundingPair/generateUnmatchedDelimiters.ts b/src/processTargets/modifiers/surroundingPair/generateUnmatchedDelimiters.ts index d733157d40..4812c943d1 100644 --- a/src/processTargets/modifiers/surroundingPair/generateUnmatchedDelimiters.ts +++ b/src/processTargets/modifiers/surroundingPair/generateUnmatchedDelimiters.ts @@ -1,5 +1,5 @@ import { range } from "lodash"; -import { SimpleSurroundingPairName } from "../../../typings/Types"; +import { SimpleSurroundingPairName } from "../../../typings/target.types"; import { DelimiterOccurrence, DelimiterSide, diff --git a/src/processTargets/modifiers/surroundingPair/getIndividualDelimiters.ts b/src/processTargets/modifiers/surroundingPair/getIndividualDelimiters.ts index 75f78419c6..5998d154f3 100644 --- a/src/processTargets/modifiers/surroundingPair/getIndividualDelimiters.ts +++ b/src/processTargets/modifiers/surroundingPair/getIndividualDelimiters.ts @@ -1,4 +1,4 @@ -import { SimpleSurroundingPairName } from "../../../typings/Types"; +import { SimpleSurroundingPairName } from "../../../typings/target.types"; import { IndividualDelimiter } from "./types"; import { delimiterToText } from "./delimiterMaps"; import { concat, uniq } from "lodash"; diff --git a/src/processTargets/modifiers/surroundingPair/index.ts b/src/processTargets/modifiers/surroundingPair/index.ts index 97d74c5f2f..7f1ecc7364 100644 --- a/src/processTargets/modifiers/surroundingPair/index.ts +++ b/src/processTargets/modifiers/surroundingPair/index.ts @@ -3,11 +3,10 @@ import { SyntaxNode } from "web-tree-sitter"; import { findSurroundingPairParseTreeBased } from "./findSurroundingPairParseTreeBased"; import { findSurroundingPairTextBased } from "./findSurroundingPairTextBased"; import { - ComplexSurroundingPairName, ProcessedTargetsContext, SelectionWithEditor, - SurroundingPairModifier, } from "../../../typings/Types"; +import { ComplexSurroundingPairName, SurroundingPairModifier } from "../../../typings/target.types"; import { SelectionWithEditorWithContext } from "../processModifier"; import { complexDelimiterMap } from "./delimiterMaps"; import getTextFragmentExtractor, { diff --git a/src/processTargets/modifiers/surroundingPair/types.ts b/src/processTargets/modifiers/surroundingPair/types.ts index f8be89b5d6..875a0530b8 100644 --- a/src/processTargets/modifiers/surroundingPair/types.ts +++ b/src/processTargets/modifiers/surroundingPair/types.ts @@ -1,4 +1,4 @@ -import { SimpleSurroundingPairName } from "../../../typings/Types"; +import { SimpleSurroundingPairName } from "../../../typings/target.types"; /** * Used to indicate whether a particular side of the delimiter is left or right diff --git a/src/processTargets/processMark.ts b/src/processTargets/processMark.ts index 6e4c7c56cb..9d743741b0 100644 --- a/src/processTargets/processMark.ts +++ b/src/processTargets/processMark.ts @@ -1,12 +1,14 @@ import { Range, Selection } from "vscode"; import { - DecoratedSymbol, - LineNumber, - LineNumberPosition, - Mark, ProcessedTargetsContext, SelectionWithEditor, } from "../typings/Types"; +import { + DecoratedSymbol, + LineNumber, + LineNumberPosition, + Mark +} from "../typings/target.types"; import { getTokensInRange, PartialToken } from "../util/getTokensInRange"; import { selectionWithEditorFromPositions } from "../util/selectionUtils"; diff --git a/src/processTargets/processPosition.ts b/src/processTargets/processPosition.ts index d45c874430..e03ce654ca 100644 --- a/src/processTargets/processPosition.ts +++ b/src/processTargets/processPosition.ts @@ -1,9 +1,9 @@ import { Selection } from "vscode"; import { - PrimitiveTarget, ProcessedTargetsContext, TypedSelection, } from "../typings/Types"; +import { PrimitiveTarget } from "../typings/target.types"; export default function ( context: ProcessedTargetsContext, diff --git a/src/processTargets/processSelectionType.ts b/src/processTargets/processSelectionType.ts index 2848cd8957..cc8679da7b 100644 --- a/src/processTargets/processSelectionType.ts +++ b/src/processTargets/processSelectionType.ts @@ -5,15 +5,16 @@ import { selectionWithEditorFromRange, } from "../util/selectionUtils"; import { - InsideOutsideType, - Modifier, - PrimitiveTarget, ProcessedTargetsContext, SelectionContext, SelectionWithEditor, TypedSelection, - Position as TargetPosition, } from "../typings/Types"; +import { + InsideOutsideType, + Modifier, + PrimitiveTarget, Position as TargetPosition +} from "../typings/target.types"; import { getDocumentRange } from "../util/range"; // taken from https://regexr.com/3e6m0 diff --git a/src/scripts/transformRecordedTests/transformations/updateSurroundingPairTest.ts b/src/scripts/transformRecordedTests/transformations/updateSurroundingPairTest.ts index e254d16365..a10a7a139b 100644 --- a/src/scripts/transformRecordedTests/transformations/updateSurroundingPairTest.ts +++ b/src/scripts/transformRecordedTests/transformations/updateSurroundingPairTest.ts @@ -2,8 +2,8 @@ import { TestCaseFixture } from "../../../testUtil/TestCase"; import { transformPartialPrimitiveTargets } from "../../../util/getPrimitiveTargets"; import { DelimiterInclusion, - PartialPrimitiveTarget, -} from "../../../typings/Types"; + PartialPrimitiveTarget +} from "../../../typings/target.types"; // Leaving an example here in case it's helpful export function updateSurroundingPairTest(fixture: TestCaseFixture) { diff --git a/src/scripts/transformRecordedTests/transformations/upgradeFromVersion0.ts b/src/scripts/transformRecordedTests/transformations/upgradeFromVersion0.ts index 5e878f4a43..ed55cab58a 100644 --- a/src/scripts/transformRecordedTests/transformations/upgradeFromVersion0.ts +++ b/src/scripts/transformRecordedTests/transformations/upgradeFromVersion0.ts @@ -1,6 +1,6 @@ import { TestCaseFixture } from "../../../testUtil/TestCase"; import { transformPartialPrimitiveTargets } from "../../../util/getPrimitiveTargets"; -import { PartialPrimitiveTarget } from "../../../typings/Types"; +import { PartialPrimitiveTarget } from "../../../typings/target.types"; export function upgradeFromVersion0(fixture: TestCaseFixture) { const { command, spokenForm: oldSpokenForm, ...rest } = fixture as any; diff --git a/src/test/suite/fixtures/inferFullTargets.fixture.ts b/src/test/suite/fixtures/inferFullTargets.fixture.ts index 2c8ceed674..0bb0ff53d1 100644 --- a/src/test/suite/fixtures/inferFullTargets.fixture.ts +++ b/src/test/suite/fixtures/inferFullTargets.fixture.ts @@ -2,9 +2,11 @@ import { ActionPreferences, InferenceContext, - PartialTarget, - Target, } from "../../../typings/Types"; +import { + PartialTarget, + Target +} from "../../../typings/target.types"; interface FixtureInput { context: InferenceContext; diff --git a/src/testUtil/TestCase.ts b/src/testUtil/TestCase.ts index c836d929fc..9dd1033d9e 100644 --- a/src/testUtil/TestCase.ts +++ b/src/testUtil/TestCase.ts @@ -1,6 +1,7 @@ import * as vscode from "vscode"; import { ThatMark } from "../core/ThatMark"; -import { Target, Token } from "../typings/Types"; +import { Token } from "../typings/Types"; +import { Target } from "../typings/target.types"; import { extractTargetedMarks, extractTargetKeys, @@ -14,10 +15,10 @@ import { import serialize from "./serialize"; import { pick } from "lodash"; import { ReadOnlyHatMap } from "../core/IndividualHatMap"; -import { CommandArgument } from "../core/commandRunner/types"; +import { Command } from "../core/commandRunner/command.types"; import { cleanUpTestCaseCommand } from "./cleanUpTestCaseCommand"; -export type TestCaseCommand = CommandArgument; +export type TestCaseCommand = Command; export type TestCaseContext = { thatMark: ThatMark; diff --git a/src/testUtil/TestCaseRecorder.ts b/src/testUtil/TestCaseRecorder.ts index 847b61e013..b4fe7f2138 100644 --- a/src/testUtil/TestCaseRecorder.ts +++ b/src/testUtil/TestCaseRecorder.ts @@ -3,7 +3,8 @@ import { invariant } from "immutability-helper"; import * as path from "path"; import * as vscode from "vscode"; import HatTokenMap from "../core/HatTokenMap"; -import { DecoratedSymbol, Graph } from "../typings/Types"; +import { Graph } from "../typings/Types"; +import { DecoratedSymbol } from "../typings/target.types"; import { getDocumentRange } from "../util/range"; import sleep from "../util/sleep"; import { extractTargetedMarks } from "./extractTargetedMarks"; diff --git a/src/testUtil/extractTargetedMarks.ts b/src/testUtil/extractTargetedMarks.ts index dc4366e089..2f579fe274 100644 --- a/src/testUtil/extractTargetedMarks.ts +++ b/src/testUtil/extractTargetedMarks.ts @@ -1,6 +1,7 @@ import { ReadOnlyHatMap } from "../core/IndividualHatMap"; import HatTokenMap from "../core/HatTokenMap"; -import { PrimitiveTarget, Target, Token } from "../typings/Types"; +import { Token } from "../typings/Types"; +import { PrimitiveTarget, Target } from "../typings/target.types"; function extractPrimitiveTargetKeys(...targets: PrimitiveTarget[]) { const keys: string[] = []; diff --git a/src/typings/Types.ts b/src/typings/Types.ts index aad0f76d30..66b9e0db44 100644 --- a/src/typings/Types.ts +++ b/src/typings/Types.ts @@ -1,7 +1,6 @@ import { SyntaxNode } from "web-tree-sitter"; import * as vscode from "vscode"; import { ExtensionContext, Location, Selection } from "vscode"; -import { HatStyleName } from "../core/constants"; import { EditStyles } from "../core/editStyles"; import HatTokenMap from "../core/HatTokenMap"; import { Snippets } from "../core/Snippets"; @@ -13,6 +12,12 @@ import { CommandServerApi } from "../util/getExtensionApi"; import { ReadOnlyHatMap } from "../core/IndividualHatMap"; import Debug from "../core/Debug"; import { TestCaseRecorder } from "../testUtil/TestCaseRecorder"; +import { + SelectionType, + InsideOutsideType, + Position, + Modifier, +} from "./target.types"; /** * A token within a text editor, including the current display line of the token @@ -22,263 +27,6 @@ export interface Token extends FullRangeInfo { displayLine: number; } -export interface CursorMark { - type: "cursor"; -} - -export interface CursorMarkToken { - type: "cursorToken"; -} - -export interface That { - type: "that"; -} - -export interface Source { - type: "source"; -} - -export interface Nothing { - type: "nothing"; -} - -export interface LastCursorPosition { - type: "lastCursorPosition"; -} - -export interface DecoratedSymbol { - type: "decoratedSymbol"; - symbolColor: HatStyleName; - character: string; -} - -export type LineNumberType = "absolute" | "relative" | "modulo100"; - -export interface LineNumberPosition { - type: LineNumberType; - lineNumber: number; -} - -export interface LineNumber { - type: "lineNumber"; - anchor: LineNumberPosition; - active: LineNumberPosition; -} - -export type Mark = - | CursorMark - | CursorMarkToken - | That - | Source - // | LastCursorPosition Not implemented yet - | DecoratedSymbol - | Nothing - | LineNumber; - -export type SimpleSurroundingPairName = - | "angleBrackets" - | "backtickQuotes" - | "curlyBrackets" - | "doubleQuotes" - | "escapedDoubleQuotes" - | "escapedParentheses" - | "escapedSquareBrackets" - | "escapedSingleQuotes" - | "parentheses" - | "singleQuotes" - | "squareBrackets"; -export type ComplexSurroundingPairName = "string" | "any"; -export type SurroundingPairName = - | SimpleSurroundingPairName - | ComplexSurroundingPairName; - -export type ScopeType = - | "argumentOrParameter" - | "anonymousFunction" - | "attribute" - | "class" - | "className" - | "collectionItem" - | "collectionKey" - | "comment" - | "functionCall" - | "functionName" - | "ifStatement" - | "list" - | "map" - | "name" - | "namedFunction" - | "regularExpression" - | "statement" - | "string" - | "type" - | "value" - | "condition" - | "section" - | "sectionLevelOne" - | "sectionLevelTwo" - | "sectionLevelThree" - | "sectionLevelFour" - | "sectionLevelFive" - | "sectionLevelSix" - | "selector" - | "xmlBothTags" - | "xmlElement" - | "xmlEndTag" - | "xmlStartTag"; - -export type SubTokenType = "word" | "character"; - -/** - * Indicates whether to include or exclude delimiters in a surrounding pair - * modifier. In the future, these will become proper modifiers that can be - * applied in many places, such as to restrict to the body of an if statement. - * By default, a surrounding pair modifier refers to the entire surrounding - * range, so if delimiter inclusion is undefined, it's equivalent to not having - * one of these modifiers; ie include the delimiters. - */ -export type DelimiterInclusion = "excludeInterior" | "interiorOnly" | undefined; - -export type SurroundingPairDirection = "left" | "right"; -export interface SurroundingPairModifier { - type: "surroundingPair"; - delimiter: SurroundingPairName; - delimiterInclusion: DelimiterInclusion; - forceDirection?: SurroundingPairDirection; -} - -export interface ContainingScopeModifier { - type: "containingScope"; - scopeType: ScopeType; - valueOnly?: boolean; - includeSiblings?: boolean; -} - -export interface SubTokenModifier { - type: "subpiece"; - pieceType: SubTokenType; - anchor: number; - active: number; - excludeAnchor?: boolean; - excludeActive?: boolean; -} - -export interface MatchingPairSymbolModifier { - type: "matchingPairSymbol"; -} - -export interface IdentityModifier { - type: "identity"; -} - -/** - * Converts its input to a raw selection with no type information so for - * example if it is the destination of a bring or move it should inherit the - * type information such as delimiters from its source. - */ -export interface RawSelectionModifier { - type: "toRawSelection"; -} - -export interface HeadModifier { - type: "head"; -} - -export interface TailModifier { - type: "tail"; -} - -export type Modifier = - | IdentityModifier - | SurroundingPairModifier - | ContainingScopeModifier - | SubTokenModifier - // | MatchingPairSymbolModifier Not implemented - | HeadModifier - | TailModifier - | RawSelectionModifier; - -export type SelectionType = - // | "character" Not implemented - | "token" - | "line" - | "notebookCell" - | "paragraph" - | "document" - | "nonWhitespaceSequence" - | "url"; - -export type Position = "before" | "after" | "contents"; - -export type InsideOutsideType = "inside" | "outside" | null; - -export interface PartialPrimitiveTarget { - type: "primitive"; - stages: PipelineDescriptor[]; - mark?: Mark; - modifier?: Modifier; - selectionType?: SelectionType; - position?: Position; - insideOutsideType?: InsideOutsideType; - isImplicit?: boolean; -} - -type PipelineDescriptor = - | Mark - | Modifier - | SelectionType - | Position - | InsideOutsideType; - -export interface PartialRangeTarget { - type: "range"; - start: PartialPrimitiveTarget; - end: PartialPrimitiveTarget; - excludeStart?: boolean; - excludeEnd?: boolean; - rangeType?: RangeType; -} - -export interface PartialListTarget { - type: "list"; - elements: (PartialPrimitiveTarget | PartialRangeTarget)[]; -} - -export type PartialTarget = - | PartialPrimitiveTarget - | PartialRangeTarget - | PartialListTarget; - -export interface PrimitiveTarget { - type: "primitive"; - mark: Mark; - modifier: Modifier; - selectionType: SelectionType; - position: Position; - insideOutsideType: InsideOutsideType; - isImplicit: boolean; -} - -export interface RangeTarget { - type: "range"; - anchor: PrimitiveTarget; - active: PrimitiveTarget; - excludeAnchor: boolean; - excludeActive: boolean; - rangeType: RangeType; -} - -// continuous is one single continuous selection between the two targets -// vertical puts a selection on each line vertically between the two targets -export type RangeType = "continuous" | "vertical"; - -export interface ListTarget { - type: "list"; - elements: (PrimitiveTarget | RangeTarget)[]; -} - -export type Target = PrimitiveTarget | RangeTarget | ListTarget; - export interface ProcessedTargetsContext { currentSelections: SelectionWithEditor[]; currentEditor: vscode.TextEditor | undefined; diff --git a/src/typings/snippet.ts b/src/typings/snippet.ts index 4eb7ef3c08..7dd6053146 100644 --- a/src/typings/snippet.ts +++ b/src/typings/snippet.ts @@ -1,4 +1,4 @@ -import { ScopeType } from "./Types"; +import { ScopeType } from "./target.types"; export interface SnippetScope { langIds?: string[]; diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts new file mode 100644 index 0000000000..c515c8aca3 --- /dev/null +++ b/src/typings/target.types.ts @@ -0,0 +1,232 @@ +import { HatStyleName } from "../core/constants"; + +export interface CursorMark { + type: "cursor"; +} + +export interface CursorMarkToken { + type: "cursorToken"; +} + +export interface That { + type: "that"; +} + +export interface Source { + type: "source"; +} + +export interface Nothing { + type: "nothing"; +} + +export interface LastCursorPosition { + type: "lastCursorPosition"; +} + +export interface DecoratedSymbol { + type: "decoratedSymbol"; + symbolColor: HatStyleName; + character: string; +} + +export type LineNumberType = "absolute" | "relative" | "modulo100"; + +export interface LineNumberPosition { + type: LineNumberType; + lineNumber: number; +} + +export interface LineNumber { + type: "lineNumber"; + anchor: LineNumberPosition; + active: LineNumberPosition; +} + +export type Mark = + | CursorMark + | CursorMarkToken + | That + | Source + // | LastCursorPosition Not implemented yet + | DecoratedSymbol + | Nothing + | LineNumber; + +export type SimpleSurroundingPairName = + | "angleBrackets" + | "backtickQuotes" + | "curlyBrackets" + | "doubleQuotes" + | "escapedDoubleQuotes" + | "escapedParentheses" + | "escapedSquareBrackets" + | "escapedSingleQuotes" + | "parentheses" + | "singleQuotes" + | "squareBrackets"; +export type ComplexSurroundingPairName = "string" | "any"; +export type SurroundingPairName = + | SimpleSurroundingPairName + | ComplexSurroundingPairName; + +export type ScopeType = + | "argumentOrParameter" + | "anonymousFunction" + | "attribute" + | "class" + | "className" + | "collectionItem" + | "collectionKey" + | "comment" + | "functionCall" + | "functionName" + | "ifStatement" + | "list" + | "map" + | "name" + | "namedFunction" + | "regularExpression" + | "statement" + | "string" + | "type" + | "value" + | "condition" + | "section" + | "sectionLevelOne" + | "sectionLevelTwo" + | "sectionLevelThree" + | "sectionLevelFour" + | "sectionLevelFive" + | "sectionLevelSix" + | "selector" + | "xmlBothTags" + | "xmlElement" + | "xmlEndTag" + | "xmlStartTag"; + +export type SubTokenType = "word" | "character"; +/** + * Indicates whether to include or exclude delimiters in a surrounding pair + * modifier. In the future, these will become proper modifiers that can be + * applied in many places, such as to restrict to the body of an if statement. + * By default, a surrounding pair modifier refers to the entire surrounding + * range, so if delimiter inclusion is undefined, it's equivalent to not having + * one of these modifiers; ie include the delimiters. + */ + +export type DelimiterInclusion = "excludeInterior" | "interiorOnly" | undefined; + +export type SurroundingPairDirection = "left" | "right"; +export interface SurroundingPairModifier { + type: "surroundingPair"; + delimiter: SurroundingPairName; + delimiterInclusion: DelimiterInclusion; + forceDirection?: SurroundingPairDirection; +} + +export interface ContainingScopeModifier { + type: "containingScope"; + scopeType: ScopeType | SelectionType; + includeSiblings?: boolean; +} + +export interface SubTokenModifier { + type: "subpiece"; + pieceType: SubTokenType; + anchor: number; + active: number; + excludeAnchor?: boolean; + excludeActive?: boolean; +} + +/** + * Converts its input to a raw selection with no type information so for + * example if it is the destination of a bring or move it should inherit the + * type information such as delimiters from its source. + */ + +export interface RawSelectionModifier { + type: "toRawSelection"; +} + +export interface HeadModifier { + type: "head"; +} + +export interface TailModifier { + type: "tail"; +} + +export type SelectionType = + // | "character" Not implemented + | "token" + | "line" + | "notebookCell" + | "paragraph" + | "document" + | "nonWhitespaceSequence" + | "url"; + +export interface Position { + type: "position"; + position: "before" | "after" | "start" | "end"; +} + +export interface PartialPrimitiveTarget { + type: "primitive"; + stages: PipelineStageDescriptor[]; + isImplicit?: boolean; +} +type PipelineStageDescriptor = + | Mark + | Position + | SurroundingPairModifier + | ContainingScopeModifier + | SubTokenModifier + | HeadModifier + | TailModifier + | RawSelectionModifier; + +export interface PartialRangeTarget { + type: "range"; + start: PartialPrimitiveTarget; + end: PartialPrimitiveTarget; + excludeStart?: boolean; + excludeEnd?: boolean; + rangeType?: RangeType; +} + +export interface PartialListTarget { + type: "list"; + elements: (PartialPrimitiveTarget | PartialRangeTarget)[]; +} + +export type PartialTarget = + | PartialPrimitiveTarget + | PartialRangeTarget + | PartialListTarget; + +export interface PrimitiveTarget extends PartialPrimitiveTarget { + isImplicit: boolean; +} + +export interface RangeTarget { + type: "range"; + anchor: PrimitiveTarget; + active: PrimitiveTarget; + excludeAnchor: boolean; + excludeActive: boolean; + rangeType: RangeType; +} +// continuous is one single continuous selection between the two targets +// vertical puts a selection on each line vertically between the two targets + +export type RangeType = "continuous" | "vertical"; + +export interface ListTarget { + type: "list"; + elements: (PrimitiveTarget | RangeTarget)[]; +} + +export type Target = PrimitiveTarget | RangeTarget | ListTarget; diff --git a/src/util/getPrimitiveTargets.ts b/src/util/getPrimitiveTargets.ts index 8206390edf..c5f2039c29 100644 --- a/src/util/getPrimitiveTargets.ts +++ b/src/util/getPrimitiveTargets.ts @@ -3,8 +3,8 @@ import { PartialRangeTarget, PartialTarget, PrimitiveTarget, - Target, -} from "../typings/Types"; + Target +} from "../typings/target.types"; /** * Given a list of targets, recursively descends all targets and returns every diff --git a/src/util/nodeMatchers.ts b/src/util/nodeMatchers.ts index f29ea9197e..ed1fa29fe1 100644 --- a/src/util/nodeMatchers.ts +++ b/src/util/nodeMatchers.ts @@ -4,9 +4,9 @@ import { NodeFinder, SelectionExtractor, NodeMatcherAlternative, - ScopeType, SelectionWithEditor, } from "../typings/Types"; +import { ScopeType } from "../typings/target.types"; import { simpleSelectionExtractor, argumentSelectionExtractor, diff --git a/src/util/performInsideOutsideAdjustment.ts b/src/util/performInsideOutsideAdjustment.ts index 9d8326980e..8dce8c4264 100644 --- a/src/util/performInsideOutsideAdjustment.ts +++ b/src/util/performInsideOutsideAdjustment.ts @@ -1,4 +1,5 @@ -import { InsideOutsideType, TypedSelection } from "../typings/Types"; +import { TypedSelection } from "../typings/Types"; +import { InsideOutsideType } from "../typings/target.types"; import { updateTypedSelectionRange } from "./selectionUtils"; export function performInsideOutsideAdjustment( diff --git a/src/util/selectionType.ts b/src/util/selectionType.ts index a500dffbaf..41734dfc6a 100644 --- a/src/util/selectionType.ts +++ b/src/util/selectionType.ts @@ -1,4 +1,4 @@ -import { SelectionType } from "../typings/Types"; +import { SelectionType } from "../typings/target.types"; export function isLineSelectionType(selectionType: SelectionType) { return selectionType === "line" || selectionType === "paragraph"; From f3e873f450c326080b8ce4ade1f340eb934942c4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 13 May 2022 15:01:39 +0000 Subject: [PATCH 003/314] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/core/commandVersionUpgrades/canonicalizeTargets.ts | 6 +++++- src/core/inferFullTargets.ts | 6 ++---- src/languages/clojure.ts | 5 +---- src/languages/html.ts | 5 +---- src/languages/json.ts | 5 +---- src/languages/ruby.ts | 5 +---- src/languages/scss.ts | 5 +---- src/processTargets/index.ts | 10 ++-------- src/processTargets/modifiers/processModifier.ts | 6 ++++-- .../modifiers/surroundingPair/delimiterMaps.ts | 2 +- .../extractSelectionFromSurroundingPairOffsets.ts | 4 +--- .../findSurroundingPairParseTreeBased.ts | 2 +- .../surroundingPair/findSurroundingPairTextBased.ts | 2 +- src/processTargets/modifiers/surroundingPair/index.ts | 5 ++++- src/processTargets/processMark.ts | 7 ++----- src/processTargets/processPosition.ts | 5 +---- src/processTargets/processSelectionType.ts | 3 ++- .../transformations/updateSurroundingPairTest.ts | 2 +- src/test/suite/fixtures/inferFullTargets.fixture.ts | 10 ++-------- src/util/getPrimitiveTargets.ts | 2 +- 20 files changed, 35 insertions(+), 62 deletions(-) diff --git a/src/core/commandVersionUpgrades/canonicalizeTargets.ts b/src/core/commandVersionUpgrades/canonicalizeTargets.ts index b3dc0767b8..fd12be9f91 100644 --- a/src/core/commandVersionUpgrades/canonicalizeTargets.ts +++ b/src/core/commandVersionUpgrades/canonicalizeTargets.ts @@ -1,6 +1,10 @@ import update from "immutability-helper"; import { flow } from "lodash"; -import { ScopeType, PartialPrimitiveTarget, PartialTarget } from "../../typings/target.types"; +import { + ScopeType, + PartialPrimitiveTarget, + PartialTarget, +} from "../../typings/target.types"; import { transformPartialPrimitiveTargets } from "../../util/getPrimitiveTargets"; import { HatStyleName } from "../constants"; diff --git a/src/core/inferFullTargets.ts b/src/core/inferFullTargets.ts index 969a495877..9eaec15590 100644 --- a/src/core/inferFullTargets.ts +++ b/src/core/inferFullTargets.ts @@ -1,6 +1,4 @@ -import { - ActionPreferences, -} from "../typings/Types"; +import { ActionPreferences } from "../typings/Types"; import { PartialPrimitiveTarget, PartialRangeTarget, @@ -8,7 +6,7 @@ import { PrimitiveTarget, RangeTarget, Target, - PartialListTarget + PartialListTarget, } from "../typings/target.types"; /** diff --git a/src/languages/clojure.ts b/src/languages/clojure.ts index 90d5045c88..a07ff970b2 100644 --- a/src/languages/clojure.ts +++ b/src/languages/clojure.ts @@ -5,10 +5,7 @@ import { matcher, patternMatcher, } from "../util/nodeMatchers"; -import { - NodeMatcherAlternative, - NodeFinder, -} from "../typings/Types"; +import { NodeMatcherAlternative, NodeFinder } from "../typings/Types"; import { ScopeType } from "../typings/target.types"; import { SyntaxNode } from "web-tree-sitter"; import { delimitedSelector } from "../util/nodeSelectors"; diff --git a/src/languages/html.ts b/src/languages/html.ts index 786097c4f2..808803d4d0 100644 --- a/src/languages/html.ts +++ b/src/languages/html.ts @@ -3,10 +3,7 @@ import { leadingMatcher, patternMatcher, } from "../util/nodeMatchers"; -import { - NodeMatcherAlternative, - SelectionWithEditor, -} from "../typings/Types"; +import { NodeMatcherAlternative, SelectionWithEditor } from "../typings/Types"; import { ScopeType } from "../typings/target.types"; import { SyntaxNode } from "web-tree-sitter"; import { getNodeRange } from "../util/nodeSelectors"; diff --git a/src/languages/json.ts b/src/languages/json.ts index 348a953b5e..394a552bf4 100644 --- a/src/languages/json.ts +++ b/src/languages/json.ts @@ -4,10 +4,7 @@ import { leadingMatcher, trailingMatcher, } from "../util/nodeMatchers"; -import { - NodeMatcherAlternative, - SelectionWithEditor, -} from "../typings/Types"; +import { NodeMatcherAlternative, SelectionWithEditor } from "../typings/Types"; import { ScopeType } from "../typings/target.types"; import { SyntaxNode } from "web-tree-sitter"; import { getNodeRange } from "../util/nodeSelectors"; diff --git a/src/languages/ruby.ts b/src/languages/ruby.ts index c7d6837d09..c98c79fcc1 100644 --- a/src/languages/ruby.ts +++ b/src/languages/ruby.ts @@ -9,10 +9,7 @@ import { patternMatcher, trailingMatcher, } from "../util/nodeMatchers"; -import { - NodeMatcherAlternative, - SelectionWithEditor, -} from "../typings/Types"; +import { NodeMatcherAlternative, SelectionWithEditor } from "../typings/Types"; import { ScopeType } from "../typings/target.types"; import { SyntaxNode } from "web-tree-sitter"; import { getNodeRange } from "../util/nodeSelectors"; diff --git a/src/languages/scss.ts b/src/languages/scss.ts index 28e3c9313a..b4412911c8 100644 --- a/src/languages/scss.ts +++ b/src/languages/scss.ts @@ -1,8 +1,5 @@ import { SyntaxNode } from "web-tree-sitter"; -import { - NodeMatcherAlternative, - SelectionWithEditor, -} from "../typings/Types"; +import { NodeMatcherAlternative, SelectionWithEditor } from "../typings/Types"; import { ScopeType } from "../typings/target.types"; import { patternFinder } from "../util/nodeFinders"; import { diff --git a/src/processTargets/index.ts b/src/processTargets/index.ts index ea81938307..71b72cf9a4 100644 --- a/src/processTargets/index.ts +++ b/src/processTargets/index.ts @@ -1,14 +1,8 @@ import { isEqual, zip } from "lodash"; import { Selection } from "vscode"; import { performInsideOutsideAdjustment } from "../util/performInsideOutsideAdjustment"; -import { - ProcessedTargetsContext, - TypedSelection, -} from "../typings/Types"; -import { - PrimitiveTarget, RangeTarget, - Target -} from "../typings/target.types"; +import { ProcessedTargetsContext, TypedSelection } from "../typings/Types"; +import { PrimitiveTarget, RangeTarget, Target } from "../typings/target.types"; import processMark from "./processMark"; import processModifier from "./modifiers/processModifier"; import processPosition from "./processPosition"; diff --git a/src/processTargets/modifiers/processModifier.ts b/src/processTargets/modifiers/processModifier.ts index 7e019df807..d5d1932c2d 100644 --- a/src/processTargets/modifiers/processModifier.ts +++ b/src/processTargets/modifiers/processModifier.ts @@ -12,8 +12,10 @@ import { } from "../../typings/Types"; import { ContainingScopeModifier, - HeadModifier, PrimitiveTarget, SubTokenModifier, - TailModifier + HeadModifier, + PrimitiveTarget, + SubTokenModifier, + TailModifier, } from "../../typings/target.types"; import { processSurroundingPair } from "./surroundingPair"; import { getNodeMatcher } from "../../languages/getNodeMatcher"; diff --git a/src/processTargets/modifiers/surroundingPair/delimiterMaps.ts b/src/processTargets/modifiers/surroundingPair/delimiterMaps.ts index 87987d1791..68c40a19b6 100644 --- a/src/processTargets/modifiers/surroundingPair/delimiterMaps.ts +++ b/src/processTargets/modifiers/surroundingPair/delimiterMaps.ts @@ -1,6 +1,6 @@ import { ComplexSurroundingPairName, - SimpleSurroundingPairName + SimpleSurroundingPairName, } from "../../../typings/target.types"; type IndividualDelimiterText = string | string[]; diff --git a/src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts b/src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts index c4fc1c464b..b949d66a15 100644 --- a/src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts +++ b/src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts @@ -1,7 +1,5 @@ import { Selection, TextDocument } from "vscode"; -import { - SelectionWithContext, -} from "../../../typings/Types"; +import { SelectionWithContext } from "../../../typings/Types"; import { DelimiterInclusion } from "../../../typings/target.types"; import { SurroundingPairOffsets } from "./types"; diff --git a/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts b/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts index ed664408fc..3063be411d 100644 --- a/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts +++ b/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts @@ -3,7 +3,7 @@ import { SyntaxNode } from "web-tree-sitter"; import { SimpleSurroundingPairName, DelimiterInclusion, - SurroundingPairDirection + SurroundingPairDirection, } from "../../../typings/target.types"; import { getNodeRange } from "../../../util/nodeSelectors"; import { isContainedInErrorNode } from "../../../util/treeSitterUtils"; diff --git a/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts b/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts index dca32a1509..f7b025fcf3 100644 --- a/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts +++ b/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts @@ -4,7 +4,7 @@ import { SimpleSurroundingPairName, DelimiterInclusion, SurroundingPairName, - SurroundingPairDirection + SurroundingPairDirection, } from "../../../typings/target.types"; import { getDocumentRange } from "../../../util/range"; import { matchAll } from "../../../util/regex"; diff --git a/src/processTargets/modifiers/surroundingPair/index.ts b/src/processTargets/modifiers/surroundingPair/index.ts index 7f1ecc7364..0124eb6a70 100644 --- a/src/processTargets/modifiers/surroundingPair/index.ts +++ b/src/processTargets/modifiers/surroundingPair/index.ts @@ -6,7 +6,10 @@ import { ProcessedTargetsContext, SelectionWithEditor, } from "../../../typings/Types"; -import { ComplexSurroundingPairName, SurroundingPairModifier } from "../../../typings/target.types"; +import { + ComplexSurroundingPairName, + SurroundingPairModifier, +} from "../../../typings/target.types"; import { SelectionWithEditorWithContext } from "../processModifier"; import { complexDelimiterMap } from "./delimiterMaps"; import getTextFragmentExtractor, { diff --git a/src/processTargets/processMark.ts b/src/processTargets/processMark.ts index 9d743741b0..17e173c128 100644 --- a/src/processTargets/processMark.ts +++ b/src/processTargets/processMark.ts @@ -1,13 +1,10 @@ import { Range, Selection } from "vscode"; -import { - ProcessedTargetsContext, - SelectionWithEditor, -} from "../typings/Types"; +import { ProcessedTargetsContext, SelectionWithEditor } from "../typings/Types"; import { DecoratedSymbol, LineNumber, LineNumberPosition, - Mark + Mark, } from "../typings/target.types"; import { getTokensInRange, PartialToken } from "../util/getTokensInRange"; import { selectionWithEditorFromPositions } from "../util/selectionUtils"; diff --git a/src/processTargets/processPosition.ts b/src/processTargets/processPosition.ts index e03ce654ca..505696e0d9 100644 --- a/src/processTargets/processPosition.ts +++ b/src/processTargets/processPosition.ts @@ -1,8 +1,5 @@ import { Selection } from "vscode"; -import { - ProcessedTargetsContext, - TypedSelection, -} from "../typings/Types"; +import { ProcessedTargetsContext, TypedSelection } from "../typings/Types"; import { PrimitiveTarget } from "../typings/target.types"; export default function ( diff --git a/src/processTargets/processSelectionType.ts b/src/processTargets/processSelectionType.ts index cc8679da7b..8bdca75d1b 100644 --- a/src/processTargets/processSelectionType.ts +++ b/src/processTargets/processSelectionType.ts @@ -13,7 +13,8 @@ import { import { InsideOutsideType, Modifier, - PrimitiveTarget, Position as TargetPosition + PrimitiveTarget, + Position as TargetPosition, } from "../typings/target.types"; import { getDocumentRange } from "../util/range"; diff --git a/src/scripts/transformRecordedTests/transformations/updateSurroundingPairTest.ts b/src/scripts/transformRecordedTests/transformations/updateSurroundingPairTest.ts index a10a7a139b..a7f3c94bc2 100644 --- a/src/scripts/transformRecordedTests/transformations/updateSurroundingPairTest.ts +++ b/src/scripts/transformRecordedTests/transformations/updateSurroundingPairTest.ts @@ -2,7 +2,7 @@ import { TestCaseFixture } from "../../../testUtil/TestCase"; import { transformPartialPrimitiveTargets } from "../../../util/getPrimitiveTargets"; import { DelimiterInclusion, - PartialPrimitiveTarget + PartialPrimitiveTarget, } from "../../../typings/target.types"; // Leaving an example here in case it's helpful diff --git a/src/test/suite/fixtures/inferFullTargets.fixture.ts b/src/test/suite/fixtures/inferFullTargets.fixture.ts index 0bb0ff53d1..931524c6f7 100644 --- a/src/test/suite/fixtures/inferFullTargets.fixture.ts +++ b/src/test/suite/fixtures/inferFullTargets.fixture.ts @@ -1,12 +1,6 @@ // @ts-nocheck -import { - ActionPreferences, - InferenceContext, -} from "../../../typings/Types"; -import { - PartialTarget, - Target -} from "../../../typings/target.types"; +import { ActionPreferences, InferenceContext } from "../../../typings/Types"; +import { PartialTarget, Target } from "../../../typings/target.types"; interface FixtureInput { context: InferenceContext; diff --git a/src/util/getPrimitiveTargets.ts b/src/util/getPrimitiveTargets.ts index c5f2039c29..35a30e5905 100644 --- a/src/util/getPrimitiveTargets.ts +++ b/src/util/getPrimitiveTargets.ts @@ -3,7 +3,7 @@ import { PartialRangeTarget, PartialTarget, PrimitiveTarget, - Target + Target, } from "../typings/target.types"; /** From 18f9d2260f36114ecff6c114203d16db774d860a Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Fri, 13 May 2022 22:53:32 +0200 Subject: [PATCH 004/314] Rename range target start and end to anchor and active --- cursorless-talon/src/compound_targets.py | 8 +- src/core/inferFullTargets.ts | 10 +-- .../fixtures/inferFullTargets.fixture.ts | 80 +++++++++---------- src/typings/target.types.ts | 4 +- src/util/getPrimitiveTargets.ts | 8 +- 5 files changed, 57 insertions(+), 53 deletions(-) diff --git a/cursorless-talon/src/compound_targets.py b/cursorless-talon/src/compound_targets.py index 8c321bd200..ed33648c84 100644 --- a/cursorless-talon/src/compound_targets.py +++ b/cursorless-talon/src/compound_targets.py @@ -44,17 +44,17 @@ def cursorless_range(m) -> str: return primitive_targets[0] if len(primitive_targets) == 1: - start = BASE_TARGET.copy() + anchor = BASE_TARGET.copy() else: - start = primitive_targets[0] + anchor = primitive_targets[0] range_connective = range_connective_with_type["connective"] range_type = range_connective_with_type["type"] range = { "type": "range", - "start": start, - "end": primitive_targets[-1], + "anchor": anchor, + "active": primitive_targets[-1], "excludeStart": not is_anchor_included(range_connective), "excludeEnd": not is_active_included(range_connective), } diff --git a/src/core/inferFullTargets.ts b/src/core/inferFullTargets.ts index 9eaec15590..043638f744 100644 --- a/src/core/inferFullTargets.ts +++ b/src/core/inferFullTargets.ts @@ -87,13 +87,13 @@ function inferRangeTarget( excludeActive: target.excludeEnd ?? false, rangeType: target.rangeType ?? "continuous", anchor: inferPrimitiveTarget( - target.start, + target.anchor, previousTargets, actionPreferences ), active: inferPrimitiveTarget( - target.end, - previousTargets.concat(target.start), + target.active, + previousTargets.concat(target.anchor), actionPreferences ), }; @@ -193,8 +193,8 @@ function getPreviousTarget( } break; case "range": - if (useTarget(target.start)) { - return target.start; + if (useTarget(target.anchor)) { + return target.anchor; } break; case "list": diff --git a/src/test/suite/fixtures/inferFullTargets.fixture.ts b/src/test/suite/fixtures/inferFullTargets.fixture.ts index 931524c6f7..d3bdf2cf9e 100644 --- a/src/test/suite/fixtures/inferFullTargets.fixture.ts +++ b/src/test/suite/fixtures/inferFullTargets.fixture.ts @@ -147,10 +147,10 @@ const fixture: Fixture[] = [ partialTargets: [ { type: "range", - start: { + anchor: { type: "primitive", }, - end: { + active: { type: "primitive", position: "end", modifier: { @@ -200,11 +200,11 @@ const fixture: Fixture[] = [ partialTargets: [ { type: "range", - start: { + anchor: { type: "primitive", selectionType: "line", }, - end: { + active: { type: "primitive", position: "end", modifier: { @@ -254,7 +254,7 @@ const fixture: Fixture[] = [ partialTargets: [ { type: "range", - start: { + anchor: { type: "primitive", modifier: { type: "containingScope", @@ -266,7 +266,7 @@ const fixture: Fixture[] = [ character: "g", }, }, - end: { + active: { type: "primitive", mark: { type: "decoratedSymbol", @@ -321,10 +321,10 @@ const fixture: Fixture[] = [ partialTargets: [ { type: "range", - start: { + anchor: { type: "primitive", }, - end: { + active: { type: "primitive", selectionType: "paragraph", mark: { @@ -1082,7 +1082,7 @@ const fixture: Fixture[] = [ partialTargets: [ { type: "range", - start: { + anchor: { type: "primitive", selectionType: "line", mark: { @@ -1091,7 +1091,7 @@ const fixture: Fixture[] = [ character: "f", }, }, - end: { + active: { type: "primitive", mark: { type: "decoratedSymbol", @@ -1159,7 +1159,7 @@ const fixture: Fixture[] = [ }, { type: "range", - start: { + anchor: { type: "primitive", mark: { type: "decoratedSymbol", @@ -1167,7 +1167,7 @@ const fixture: Fixture[] = [ character: "h", }, }, - end: { + active: { type: "primitive", mark: { type: "decoratedSymbol", @@ -1570,7 +1570,7 @@ const fixture: Fixture[] = [ }, { type: "range", - start: { + anchor: { type: "primitive", mark: { type: "decoratedSymbol", @@ -1578,7 +1578,7 @@ const fixture: Fixture[] = [ character: "g", }, }, - end: { + active: { type: "primitive", mark: { type: "decoratedSymbol", @@ -1657,7 +1657,7 @@ const fixture: Fixture[] = [ elements: [ { type: "range", - start: { + anchor: { type: "primitive", selectionType: "line", modifier: { @@ -1670,7 +1670,7 @@ const fixture: Fixture[] = [ character: "g", }, }, - end: { + active: { type: "primitive", mark: { type: "decoratedSymbol", @@ -1754,10 +1754,10 @@ const fixture: Fixture[] = [ partialTargets: [ { type: "range", - start: { + anchor: { type: "primitive", }, - end: { + active: { type: "primitive", position: "end", selectionType: "line", @@ -1803,11 +1803,11 @@ const fixture: Fixture[] = [ partialTargets: [ { type: "range", - start: { + anchor: { type: "primitive", selectionType: "line", }, - end: { + active: { type: "primitive", position: "end", selectionType: "paragraph", @@ -1853,7 +1853,7 @@ const fixture: Fixture[] = [ partialTargets: [ { type: "range", - start: { + anchor: { type: "primitive", mark: { type: "decoratedSymbol", @@ -1861,7 +1861,7 @@ const fixture: Fixture[] = [ character: "f", }, }, - end: { + active: { type: "primitive", position: "end", selectionType: "line", @@ -1911,7 +1911,7 @@ const fixture: Fixture[] = [ partialTargets: [ { type: "range", - start: { + anchor: { type: "primitive", selectionType: "line", mark: { @@ -1920,7 +1920,7 @@ const fixture: Fixture[] = [ character: "g", }, }, - end: { + active: { type: "primitive", position: "end", modifier: { @@ -1974,7 +1974,7 @@ const fixture: Fixture[] = [ partialTargets: [ { type: "range", - start: { + anchor: { type: "primitive", mark: { type: "decoratedSymbol", @@ -1982,7 +1982,7 @@ const fixture: Fixture[] = [ character: "g", }, }, - end: { + active: { type: "primitive", modifier: { type: "surroundingPair", @@ -2042,7 +2042,7 @@ const fixture: Fixture[] = [ partialTargets: [ { type: "range", - start: { + anchor: { type: "primitive", mark: { type: "decoratedSymbol", @@ -2050,7 +2050,7 @@ const fixture: Fixture[] = [ character: "g", }, }, - end: { + active: { type: "primitive", modifier: { type: "containingScope", @@ -2108,10 +2108,10 @@ const fixture: Fixture[] = [ partialTargets: [ { type: "range", - start: { + anchor: { type: "primitive", }, - end: { + active: { type: "primitive", modifier: { type: "containingScope", @@ -2168,10 +2168,10 @@ const fixture: Fixture[] = [ partialTargets: [ { type: "range", - start: { + anchor: { type: "primitive", }, - end: { + active: { type: "primitive", modifier: { type: "surroundingPair", @@ -2229,7 +2229,7 @@ const fixture: Fixture[] = [ partialTargets: [ { type: "range", - start: { + anchor: { type: "primitive", modifier: { type: "surroundingPair", @@ -2242,7 +2242,7 @@ const fixture: Fixture[] = [ character: "f", }, }, - end: { + active: { type: "primitive", mark: { type: "decoratedSymbol", @@ -2297,7 +2297,7 @@ const fixture: Fixture[] = [ partialTargets: [ { type: "range", - start: { + anchor: { type: "primitive", modifier: { type: "surroundingPair", @@ -2305,7 +2305,7 @@ const fixture: Fixture[] = [ includePairDelimiter: false, }, }, - end: { + active: { type: "primitive", mark: { type: "decoratedSymbol", @@ -2358,7 +2358,7 @@ const fixture: Fixture[] = [ partialTargets: [ { type: "range", - start: { + anchor: { type: "primitive", selectionType: "line", modifier: { @@ -2367,7 +2367,7 @@ const fixture: Fixture[] = [ includePairDelimiter: false, }, }, - end: { + active: { type: "primitive", mark: { type: "decoratedSymbol", @@ -2420,7 +2420,7 @@ const fixture: Fixture[] = [ partialTargets: [ { type: "range", - start: { + anchor: { type: "primitive", selectionType: "line", modifier: { @@ -2428,7 +2428,7 @@ const fixture: Fixture[] = [ scopeType: "namedFunction", }, }, - end: { + active: { type: "primitive", mark: { type: "decoratedSymbol", diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index c515c8aca3..b05724b736 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -190,8 +190,8 @@ type PipelineStageDescriptor = export interface PartialRangeTarget { type: "range"; - start: PartialPrimitiveTarget; - end: PartialPrimitiveTarget; + anchor: PartialPrimitiveTarget; + active: PartialPrimitiveTarget; excludeStart?: boolean; excludeEnd?: boolean; rangeType?: RangeType; diff --git a/src/util/getPrimitiveTargets.ts b/src/util/getPrimitiveTargets.ts index 35a30e5905..aaecaa73dc 100644 --- a/src/util/getPrimitiveTargets.ts +++ b/src/util/getPrimitiveTargets.ts @@ -26,7 +26,7 @@ function getPartialPrimitiveTargetsHelper( case "list": return target.elements.flatMap(getPartialPrimitiveTargetsHelper); case "range": - return [target.start, target.end]; + return [target.anchor, target.active]; } } /** @@ -85,6 +85,10 @@ function transformPartialPrimitiveTargetsHelper( ), }; case "range": - return { ...target, start: func(target.start), end: func(target.end) }; + return { + ...target, + anchor: func(target.anchor), + active: func(target.active), + }; } } From 93b633a2b57a3d966ea3440c20adad59773a041c Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Fri, 13 May 2022 23:34:02 +0200 Subject: [PATCH 005/314] Updated types to resolve command runner problem --- src/core/commandRunner/CommandRunner.ts | 12 +++++----- src/core/commandRunner/command.types.ts | 6 ++--- .../canonicalizeAndValidateCommand.ts | 23 ++++++++++-------- .../canonicalizeTargets.ts | 2 +- .../upgradeV0ToV1/upgradeV0ToV1.ts | 2 +- .../upgradeV1ToV2/commandV1.types.ts | 24 +++++++++++++++++-- 6 files changed, 46 insertions(+), 23 deletions(-) diff --git a/src/core/commandRunner/CommandRunner.ts b/src/core/commandRunner/CommandRunner.ts index 88a6a0e994..62ffe52fbf 100644 --- a/src/core/commandRunner/CommandRunner.ts +++ b/src/core/commandRunner/CommandRunner.ts @@ -1,17 +1,17 @@ import * as vscode from "vscode"; -import inferFullTargets from "../inferFullTargets"; +import { ActionableError } from "../../errors"; import processTargets from "../../processTargets"; import { ActionType, Graph, ProcessedTargetsContext, } from "../../typings/Types"; -import { PartialTarget } from "../../typings/target.types"; -import { ThatMark } from "../ThatMark"; -import { Command } from "./command.types"; import { isString } from "../../util/type"; -import { ActionableError } from "../../errors"; import { canonicalizeAndValidateCommand } from "../commandVersionUpgrades/canonicalizeAndValidateCommand"; +import { PartialTargetV0V1 } from "../commandVersionUpgrades/upgradeV1ToV2/commandV1.types"; +import inferFullTargets from "../inferFullTargets"; +import { ThatMark } from "../ThatMark"; +import { Command } from "./command.types"; // TODO: Do this using the graph once we migrate its dependencies onto the graph export default class CommandRunner { @@ -157,7 +157,7 @@ export default class CommandRunner { const spokenForm = spokenFormOrCommand; const [action, targets, ...extraArgs] = rest as [ ActionType, - PartialTarget[], + PartialTargetV0V1[], ...unknown[] ]; diff --git a/src/core/commandRunner/command.types.ts b/src/core/commandRunner/command.types.ts index 82bea9450c..31add588a4 100644 --- a/src/core/commandRunner/command.types.ts +++ b/src/core/commandRunner/command.types.ts @@ -1,5 +1,5 @@ +import { PartialTarget } from "../../typings/target.types"; import { ActionType } from "../../typings/Types"; -import { PartialPrimitiveTarget } from "../../typings/target.types"; import { CommandV0, CommandV1, @@ -8,7 +8,7 @@ import { export type CommandComplete = Required> & Pick; -export const LATEST_VERSION = 1 as const; +export const LATEST_VERSION = 2 as const; export type CommandLatest = Command & { version: typeof LATEST_VERSION; @@ -44,7 +44,7 @@ interface CommandV2 { * A list of targets expected by the action. Inference will be run on the * targets */ - targets: PartialPrimitiveTarget[]; + targets: PartialTarget[]; /** * A list of extra arguments expected by the given action. diff --git a/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts b/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts index 0b3aeaf3ab..a950eca05c 100644 --- a/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts +++ b/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts @@ -1,14 +1,16 @@ -import canonicalizeActionName from "./canonicalizeActionName"; -import canonicalizeTargets from "./canonicalizeTargets"; -import { ActionType, PartialTarget, SelectionType } from "../typings/Types"; -import { getPartialPrimitiveTargets } from "./getPrimitiveTargets"; +import { commands } from "vscode"; +import { ActionableError } from "../../errors"; +import { PartialTarget, SelectionType } from "../../typings/target.types"; +import { ActionType } from "../../typings/Types"; +import { getPartialPrimitiveTargets } from "../../util/getPrimitiveTargets"; import { Command, CommandComplete, + CommandLatest, LATEST_VERSION, -} from "../core/commandRunner/types"; -import { ActionableError } from "../errors"; -import { commands } from "vscode"; +} from "../commandRunner/command.types"; +import canonicalizeActionName from "./canonicalizeActionName"; +import canonicalizeTargets from "./canonicalizeTargets"; import { upgradeV0ToV1 } from "./upgradeV0ToV1"; import { upgradeV1ToV2 } from "./upgradeV1ToV2"; @@ -34,7 +36,6 @@ export function canonicalizeAndValidateCommand( const actionName = canonicalizeActionName(inputActionName); const partialTargets = canonicalizeTargets(inputPartialTargets); - const extraArgs = inputExtraArgs; validateCommand(actionName, partialTargets); @@ -43,12 +44,12 @@ export function canonicalizeAndValidateCommand( version: LATEST_VERSION, action: actionName, targets: partialTargets, - extraArgs: extraArgs, + extraArgs: inputExtraArgs, usePrePhraseSnapshot, }; } -function upgradeCommand(command: Command) { +function upgradeCommand(command: Command): CommandLatest { if (command.version > LATEST_VERSION) { throw new ActionableError( "Cursorless Talon version is ahead of Cursorless VSCode extension version. Please update Cursorless VSCode.", @@ -74,6 +75,8 @@ function upgradeCommand(command: Command) { break; } } + + return command as CommandLatest; // TODO Better implementation ? } export function validateCommand( diff --git a/src/core/commandVersionUpgrades/canonicalizeTargets.ts b/src/core/commandVersionUpgrades/canonicalizeTargets.ts index fd12be9f91..0fa137acea 100644 --- a/src/core/commandVersionUpgrades/canonicalizeTargets.ts +++ b/src/core/commandVersionUpgrades/canonicalizeTargets.ts @@ -1,9 +1,9 @@ import update from "immutability-helper"; import { flow } from "lodash"; import { - ScopeType, PartialPrimitiveTarget, PartialTarget, + ScopeType, } from "../../typings/target.types"; import { transformPartialPrimitiveTargets } from "../../util/getPrimitiveTargets"; import { HatStyleName } from "../constants"; diff --git a/src/core/commandVersionUpgrades/upgradeV0ToV1/upgradeV0ToV1.ts b/src/core/commandVersionUpgrades/upgradeV0ToV1/upgradeV0ToV1.ts index b0d572d0e2..e46af93053 100644 --- a/src/core/commandVersionUpgrades/upgradeV0ToV1/upgradeV0ToV1.ts +++ b/src/core/commandVersionUpgrades/upgradeV0ToV1/upgradeV0ToV1.ts @@ -1,4 +1,4 @@ -import { CommandV0, CommandV1 } from "../../commandRunner/command.types"; +import { CommandV0, CommandV1 } from "../upgradeV1ToV2/commandV1.types"; export function upgradeV0ToV1(command: CommandV0): CommandV1 { return { ...command, version: 1 }; diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/commandV1.types.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/commandV1.types.ts index 51bb75a499..c073359429 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/commandV1.types.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/commandV1.types.ts @@ -35,7 +35,7 @@ interface CommandV0V1 { * A list of targets expected by the action. Inference will be run on the * targets */ - targets: PartialPrimitiveTarget[]; + targets: PartialTargetV0V1[]; /** * A list of extra arguments expected by the given action. @@ -53,6 +53,27 @@ interface PartialPrimitiveTarget { isImplicit?: boolean; } +interface PartialRangeTarget { + type: "range"; + start: PartialPrimitiveTarget; + end: PartialPrimitiveTarget; + excludeStart?: boolean; + excludeEnd?: boolean; + rangeType?: RangeType; +} + +type RangeType = "continuous" | "vertical"; + +interface PartialListTarget { + type: "list"; + elements: (PartialPrimitiveTarget | PartialRangeTarget)[]; +} + +export type PartialTargetV0V1 = + | PartialPrimitiveTarget + | PartialRangeTarget + | PartialListTarget; + type SelectionType = | "token" | "line" @@ -202,7 +223,6 @@ type Modifier = | SurroundingPairModifier | ContainingScopeModifier | SubTokenModifier - // | MatchingPairSymbolModifier Not implemented | HeadModifier | TailModifier | RawSelectionModifier; From f2ba1c2a8355d722002d043f1653f2d71304b0e1 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 14 May 2022 02:43:16 +0200 Subject: [PATCH 006/314] Added command runner and migrated all marks --- src/core/commandRunner/CommandRunner.ts | 6 - src/processTargets/index.ts | 51 +++-- .../pipelineStages/CursorStage.ts | 17 ++ .../pipelineStages/CursorTokenStage.ts | 120 ++++++++++ .../pipelineStages/DecoratedSymbolStage.ts | 27 +++ .../pipelineStages/LineNumberStage.ts | 65 ++++++ .../pipelineStages/NothingStage.ts | 8 + .../pipelineStages/PipelineStage.ts | 10 + .../pipelineStages/SourceStage.ts | 13 ++ .../pipelineStages/ThatStage.ts | 13 ++ .../pipelineStages/getPipelineStage.ts | 47 ++++ src/processTargets/processMark.ts | 208 ------------------ src/typings/Types.ts | 67 ++++-- src/typings/target.types.ts | 6 +- src/util/selectionUtils.ts | 4 + 15 files changed, 412 insertions(+), 250 deletions(-) create mode 100644 src/processTargets/pipelineStages/CursorStage.ts create mode 100644 src/processTargets/pipelineStages/CursorTokenStage.ts create mode 100644 src/processTargets/pipelineStages/DecoratedSymbolStage.ts create mode 100644 src/processTargets/pipelineStages/LineNumberStage.ts create mode 100644 src/processTargets/pipelineStages/NothingStage.ts create mode 100644 src/processTargets/pipelineStages/PipelineStage.ts create mode 100644 src/processTargets/pipelineStages/SourceStage.ts create mode 100644 src/processTargets/pipelineStages/ThatStage.ts create mode 100644 src/processTargets/pipelineStages/getPipelineStage.ts delete mode 100644 src/processTargets/processMark.ts diff --git a/src/core/commandRunner/CommandRunner.ts b/src/core/commandRunner/CommandRunner.ts index 62ffe52fbf..5f3e7ad526 100644 --- a/src/core/commandRunner/CommandRunner.ts +++ b/src/core/commandRunner/CommandRunner.ts @@ -94,12 +94,6 @@ export default class CommandRunner { } const processedTargetsContext: ProcessedTargetsContext = { - currentSelections: - vscode.window.activeTextEditor?.selections.map((selection) => ({ - selection, - editor: vscode.window.activeTextEditor!, - })) ?? [], - currentEditor: vscode.window.activeTextEditor, hatTokenMap: readableHatMap, thatMark: this.thatMark.exists() ? this.thatMark.get() : [], sourceMark: this.sourceMark.exists() ? this.sourceMark.get() : [], diff --git a/src/processTargets/index.ts b/src/processTargets/index.ts index 71b72cf9a4..bf942a0668 100644 --- a/src/processTargets/index.ts +++ b/src/processTargets/index.ts @@ -3,10 +3,10 @@ import { Selection } from "vscode"; import { performInsideOutsideAdjustment } from "../util/performInsideOutsideAdjustment"; import { ProcessedTargetsContext, TypedSelection } from "../typings/Types"; import { PrimitiveTarget, RangeTarget, Target } from "../typings/target.types"; -import processMark from "./processMark"; import processModifier from "./modifiers/processModifier"; import processPosition from "./processPosition"; import processSelectionType from "./processSelectionType"; +import getPipelineStage from "./pipelineStages/getPipelineStage"; /** * Converts the abstract target descriptions provided by the user to a concrete @@ -77,7 +77,7 @@ function processRangeTarget( throw new Error("anchorTargets and activeTargets lengths don't match"); } - if (anchorTarget.selection.editor !== activeTarget.selection.editor) { + if (anchorTarget.editor !== activeTarget.editor) { throw new Error( "anchorTarget and activeTarget must be in same document" ); @@ -275,24 +275,41 @@ function processPrimitiveTarget( context: ProcessedTargetsContext, target: PrimitiveTarget ): TypedSelection[] { - const markSelections = processMark(context, target.mark); - const modifiedSelections = markSelections.flatMap((markSelection) => - processModifier(context, target, markSelection) - ); - if (target.isImplicit) { - modifiedSelections.forEach((typedSelection) => { - typedSelection.context.isRawSelection = true; - }); + let selections: TypedSelection[] = []; + + for (let i = target.stages.length - 1; i > -1; --i) { + const stageDescriptor = target.stages[i]; + const stage = getPipelineStage(stageDescriptor); + if (selections.length === 0) { + selections = stage(context, stageDescriptor); + } else { + const stageSelections: TypedSelection[] = []; + for (const selection of selections) { + stageSelections.push(...stage(context, stageDescriptor, selection)); + } + selections = stageSelections; + } } - const typedSelections = modifiedSelections.map( - ({ selection, context: selectionContext }) => - processSelectionType(context, target, selection, selectionContext) - ); + return selections; - return typedSelections.map((selection) => - processPosition(context, target, selection) - ); + // TODO + // const markSelections = processMark(context, target.mark); + // const modifiedSelections = markSelections.flatMap((markSelection) => + // processModifier(context, target, markSelection) + // ); + // if (target.isImplicit) { + // modifiedSelections.forEach((typedSelection) => { + // typedSelection.context. = true; + // }); + // } + // const typedSelections = modifiedSelections.map( + // ({ selection, context: selectionContext }) => + // processSelectionType(context, target, selection, selectionContext) + // ); + // return typedSelections.map((selection) => + // processPosition(context, target, selection) + // ); } function filterDuplicateSelections(selections: TypedSelection[]) { diff --git a/src/processTargets/pipelineStages/CursorStage.ts b/src/processTargets/pipelineStages/CursorStage.ts new file mode 100644 index 0000000000..dedb9b7150 --- /dev/null +++ b/src/processTargets/pipelineStages/CursorStage.ts @@ -0,0 +1,17 @@ +import { window } from "vscode"; +import { TypedSelection } from "../../typings/Types"; +import { isReversed } from "../../util/selectionUtils"; +import PipelineStage from "./PipelineStage"; + +export default class implements PipelineStage { + run(): TypedSelection[] { + if (window.activeTextEditor == null) { + return []; + } + return window.activeTextEditor.selections.map((selection) => ({ + editor: window.activeTextEditor!, + isReversed: isReversed(selection), + contentRange: selection, + })); + } +} diff --git a/src/processTargets/pipelineStages/CursorTokenStage.ts b/src/processTargets/pipelineStages/CursorTokenStage.ts new file mode 100644 index 0000000000..61a43ae779 --- /dev/null +++ b/src/processTargets/pipelineStages/CursorTokenStage.ts @@ -0,0 +1,120 @@ +import { Range, window } from "vscode"; +import { SelectionWithEditor, TypedSelection } from "../../typings/Types"; +import { getTokensInRange, PartialToken } from "../../util/getTokensInRange"; +import { isReversed } from "../../util/selectionUtils"; +import PipelineStage from "./PipelineStage"; + +export default class implements PipelineStage { + run(): TypedSelection[] { + const editor = window.activeTextEditor; + if (editor == null) { + return []; + } + return editor.selections.map((selection) => ({ + editor, + isReversed: isReversed(selection), + contentRange: getTokenRangeForSelection({ + editor, + selection, + }), + })); + } +} + +/** + * Given a selection returns a new range which contains the tokens + * intersecting the given selection. Uses heuristics to tie break when the + * given selection is empty and abuts 2 adjacent tokens + * @param selection Selection to operate on + * @returns Modified range + */ +function getTokenRangeForSelection(selection: SelectionWithEditor): Range { + let tokens = getTokenIntersectionsForSelection(selection); + // Use single token for overlapping or adjacent range + if (selection.selection.isEmpty) { + // If multiple matches sort and take the first + tokens.sort(({ token: a }, { token: b }) => { + // First sort on alphanumeric + const aIsAlphaNum = isAlphaNum(a.text); + const bIsAlphaNum = isAlphaNum(b.text); + if (aIsAlphaNum && !bIsAlphaNum) { + return -1; + } + if (bIsAlphaNum && !aIsAlphaNum) { + return 1; + } + // Second sort on length + const lengthDiff = b.text.length - a.text.length; + if (lengthDiff !== 0) { + return lengthDiff; + } + // Lastly sort on start position. ie leftmost + return a.offsets.start - b.offsets.start; + }); + tokens = tokens.slice(0, 1); + } + // Use tokens for overlapping ranges + else { + tokens = tokens.filter((token) => !token.intersection.isEmpty); + tokens.sort((a, b) => a.token.offsets.start - b.token.offsets.start); + } + if (tokens.length < 1) { + throw new Error("Couldn't find token in selection"); + } + const start = tokens[0].token.range.start; + const end = tokens[tokens.length - 1].token.range.end; + return new Range(start, end); +} + +/** + * Returns tokens that intersect with the selection that may be relevant for + * expanding the selection to its containing token. + * @param selection The selection + * @returns All tokens that intersect with the selection and are on the same line as the start or endpoint of the selection + */ +function getTokenIntersectionsForSelection(selection: SelectionWithEditor) { + const tokens = getRelevantTokens(selection); + + const tokenIntersections: { token: PartialToken; intersection: Range }[] = []; + + tokens.forEach((token) => { + const intersection = token.range.intersection(selection.selection); + if (intersection != null) { + tokenIntersections.push({ token, intersection }); + } + }); + + return tokenIntersections; +} + +/** + * Given a selection, finds all tokens that we might use to expand the + * selection. Just looks at tokens on the same line as the start and end of the + * selection, because we assume that a token cannot span multiple lines. + * @param selection The selection we care about + * @returns A list of tokens that we might expand to + */ +function getRelevantTokens(selection: SelectionWithEditor) { + const startLine = selection.selection.start.line; + const endLine = selection.selection.end.line; + + let tokens = getTokensInRange( + selection.editor, + selection.editor.document.lineAt(startLine).range + ); + + if (endLine !== startLine) { + tokens.push( + ...getTokensInRange( + selection.editor, + selection.editor.document.lineAt(endLine).range + ) + ); + } + + return tokens; +} + +function isAlphaNum(text: string) { + return /^\w+$/.test(text); +} diff --git a/src/processTargets/pipelineStages/DecoratedSymbolStage.ts b/src/processTargets/pipelineStages/DecoratedSymbolStage.ts new file mode 100644 index 0000000000..3b759a4139 --- /dev/null +++ b/src/processTargets/pipelineStages/DecoratedSymbolStage.ts @@ -0,0 +1,27 @@ +import { Range } from "vscode"; +import { DecoratedSymbol } from "../../typings/target.types"; +import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import PipelineStage from "./PipelineStage"; + +export default class implements PipelineStage { + run( + context: ProcessedTargetsContext, + stage: DecoratedSymbol + ): TypedSelection[] { + const token = context.hatTokenMap.getToken( + stage.symbolColor, + stage.character + ); + if (token == null) { + throw new Error( + `Couldn't find mark ${stage.symbolColor} '${stage.character}'` + ); + } + return [ + { + editor: token.editor, + contentRange: new Range(token.range.start, token.range.end), + }, + ]; + } +} diff --git a/src/processTargets/pipelineStages/LineNumberStage.ts b/src/processTargets/pipelineStages/LineNumberStage.ts new file mode 100644 index 0000000000..5986131f43 --- /dev/null +++ b/src/processTargets/pipelineStages/LineNumberStage.ts @@ -0,0 +1,65 @@ +import { Range, TextEditor, window } from "vscode"; +import { LineNumber, LineNumberPosition } from "../../typings/target.types"; +import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import PipelineStage from "./PipelineStage"; + +export default class implements PipelineStage { + run(context: ProcessedTargetsContext, stage: LineNumber): TypedSelection[] { + if (window.activeTextEditor == null) { + return []; + } + const editor = window.activeTextEditor; + return [ + { + editor, + contentRange: new Range( + getLine(editor, stage.anchor), + 0, + getLine(editor, stage.active), + 0 + ), + }, + ]; + } +} + +const getLine = (editor: TextEditor, linePosition: LineNumberPosition) => { + switch (linePosition.type) { + case "absolute": + return linePosition.lineNumber; + case "relative": + return editor.selection.active.line + linePosition.lineNumber; + case "modulo100": + const stepSize = 100; + const startLine = editor.visibleRanges[0].start.line; + const endLine = + editor.visibleRanges[editor.visibleRanges.length - 1].end.line; + const base = Math.floor(startLine / stepSize) * stepSize; + const visibleLines = []; + const invisibleLines = []; + let lineNumber = base + linePosition.lineNumber; + while (lineNumber <= endLine) { + if (lineNumber >= startLine) { + const visible = editor.visibleRanges.find( + (r) => lineNumber >= r.start.line && lineNumber <= r.end.line + ); + if (visible) { + visibleLines.push(lineNumber); + } else { + invisibleLines.push(lineNumber); + } + } + lineNumber += stepSize; + } + if (visibleLines.length === 1) { + return visibleLines[0]; + } + if (visibleLines.length + invisibleLines.length > 1) { + throw new Error("Multiple lines matching"); + } + if (invisibleLines.length === 1) { + return invisibleLines[0]; + } + throw new Error("Line is not in viewport"); + } +}; diff --git a/src/processTargets/pipelineStages/NothingStage.ts b/src/processTargets/pipelineStages/NothingStage.ts new file mode 100644 index 0000000000..9ed56126ce --- /dev/null +++ b/src/processTargets/pipelineStages/NothingStage.ts @@ -0,0 +1,8 @@ +import { TypedSelection } from "../../typings/Types"; +import PipelineStage from "./PipelineStage"; + +export default class implements PipelineStage { + run(): TypedSelection[] { + return []; + } +} diff --git a/src/processTargets/pipelineStages/PipelineStage.ts b/src/processTargets/pipelineStages/PipelineStage.ts new file mode 100644 index 0000000000..3f6edea4ba --- /dev/null +++ b/src/processTargets/pipelineStages/PipelineStage.ts @@ -0,0 +1,10 @@ +import { PipelineStageDescriptor } from "../../typings/target.types"; +import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; + +export default interface PipelineStage { + run( + context: ProcessedTargetsContext, + stage: PipelineStageDescriptor, + target?: TypedSelection + ): TypedSelection | TypedSelection[]; +} diff --git a/src/processTargets/pipelineStages/SourceStage.ts b/src/processTargets/pipelineStages/SourceStage.ts new file mode 100644 index 0000000000..4a7b28646a --- /dev/null +++ b/src/processTargets/pipelineStages/SourceStage.ts @@ -0,0 +1,13 @@ +import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import { isReversed } from "../../util/selectionUtils"; +import PipelineStage from "./PipelineStage"; + +export default class implements PipelineStage { + run(context: ProcessedTargetsContext): TypedSelection[] { + return context.sourceMark.map((selection) => ({ + editor: selection.editor, + isReversed: isReversed(selection.selection), + contentRange: selection.selection, + })); + } +} diff --git a/src/processTargets/pipelineStages/ThatStage.ts b/src/processTargets/pipelineStages/ThatStage.ts new file mode 100644 index 0000000000..20404accfe --- /dev/null +++ b/src/processTargets/pipelineStages/ThatStage.ts @@ -0,0 +1,13 @@ +import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import { isReversed } from "../../util/selectionUtils"; +import PipelineStage from "./PipelineStage"; + +export default class implements PipelineStage { + run(context: ProcessedTargetsContext): TypedSelection[] { + return context.thatMark.map((selection) => ({ + editor: selection.editor, + isReversed: isReversed(selection.selection), + contentRange: selection.selection, + })); + } +} diff --git a/src/processTargets/pipelineStages/getPipelineStage.ts b/src/processTargets/pipelineStages/getPipelineStage.ts new file mode 100644 index 0000000000..619f1f2e4d --- /dev/null +++ b/src/processTargets/pipelineStages/getPipelineStage.ts @@ -0,0 +1,47 @@ +import { PipelineStageDescriptor } from "../../typings/target.types"; +import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import CursorStage from "./CursorStage"; +import CursorTokenStage from "./CursorTokenStage"; +import DecoratedSymbolStage from "./DecoratedSymbolStage"; +import LineNumberStage from "./LineNumberStage"; +import NothingStage from "./NothingStage"; +import PipelineStage from "./PipelineStage"; +import SourceStage from "./SourceStage"; +import ThatStage from "./ThatStage"; + +export default (stageDescriptor: PipelineStageDescriptor) => { + const stage = getStage(stageDescriptor); + return ( + context: ProcessedTargetsContext, + stageDescriptor: PipelineStageDescriptor, + selection?: TypedSelection + ) => { + const stageResult = stage.run(context, stageDescriptor, selection); + if (!Array.isArray(stageResult)) { + return [stageResult]; + } + return stageResult; + }; +}; + +const getStage = (stageDescriptor: PipelineStageDescriptor): PipelineStage => { + switch (stageDescriptor.type) { + // Mark/source stages + case "cursor": + return new CursorStage(); + case "that": + return new ThatStage(); + case "source": + return new SourceStage(); + case "cursorToken": + return new CursorTokenStage(); + case "decoratedSymbol": + return new DecoratedSymbolStage(); + case "lineNumber": + return new LineNumberStage(); + case "nothing": + return new NothingStage(); + default: + throw Error("Unknown pipeline stage " + stageDescriptor.type); + } +}; diff --git a/src/processTargets/processMark.ts b/src/processTargets/processMark.ts deleted file mode 100644 index 17e173c128..0000000000 --- a/src/processTargets/processMark.ts +++ /dev/null @@ -1,208 +0,0 @@ -import { Range, Selection } from "vscode"; -import { ProcessedTargetsContext, SelectionWithEditor } from "../typings/Types"; -import { - DecoratedSymbol, - LineNumber, - LineNumberPosition, - Mark, -} from "../typings/target.types"; -import { getTokensInRange, PartialToken } from "../util/getTokensInRange"; -import { selectionWithEditorFromPositions } from "../util/selectionUtils"; - -export default function ( - context: ProcessedTargetsContext, - mark: Mark -): SelectionWithEditor[] { - switch (mark.type) { - case "cursor": - return context.currentSelections; - case "that": - return context.thatMark; - case "source": - return context.sourceMark; - case "cursorToken": - return context.currentSelections.map((selection) => - getTokenSelectionForSelection(context, selection) - ); - case "decoratedSymbol": - return processDecoratedSymbol(context, mark); - case "lineNumber": - return processLineNumber(context, mark); - case "nothing": - return []; - } -} - -/** - * Returns tokens that intersect with the selection that may be relevant for - * expanding the selection to its containing token. - * @param selection The selection - * @returns All tokens that intersect with the selection and are on the same line as the start or endpoint of the selection - */ -function getTokenIntersectionsForSelection(selection: SelectionWithEditor) { - let tokens = getRelevantTokens(selection); - - const tokenIntersections: { token: PartialToken; intersection: Range }[] = []; - - tokens.forEach((token) => { - const intersection = token.range.intersection(selection.selection); - if (intersection != null) { - tokenIntersections.push({ token, intersection }); - } - }); - - return tokenIntersections; -} - -/** - * Given a selection, finds all tokens that we might use to expand the - * selection. Just looks at tokens on the same line as the start and end of the - * selection, because we assume that a token cannot span multiple lines. - * @param selection The selection we care about - * @returns A list of tokens that we might expand to - */ -function getRelevantTokens(selection: SelectionWithEditor) { - const startLine = selection.selection.start.line; - const endLine = selection.selection.end.line; - - let tokens = getTokensInRange( - selection.editor, - selection.editor.document.lineAt(startLine).range - ); - - if (endLine !== startLine) { - tokens.push( - ...getTokensInRange( - selection.editor, - selection.editor.document.lineAt(endLine).range - ) - ); - } - - return tokens; -} - -/** - * Given a selection returns a new selection which contains the tokens - * intersecting the given selection. Uses heuristics to tie break when the - * given selection is empty and abuts 2 adjacent tokens - * @param selection Selection to operate on - * @returns Modified selection - */ -function getTokenSelectionForSelection( - context: ProcessedTargetsContext, - selection: SelectionWithEditor -): SelectionWithEditor { - let tokens = getTokenIntersectionsForSelection(selection); - // Use single token for overlapping or adjacent range - if (selection.selection.isEmpty) { - // If multiple matches sort and take the first - tokens.sort(({ token: a }, { token: b }) => { - // First sort on alphanumeric - const aIsAlphaNum = isAlphaNum(a.text); - const bIsAlphaNum = isAlphaNum(b.text); - if (aIsAlphaNum && !bIsAlphaNum) { - return -1; - } - if (bIsAlphaNum && !aIsAlphaNum) { - return 1; - } - // Second sort on length - const lengthDiff = b.text.length - a.text.length; - if (lengthDiff !== 0) { - return lengthDiff; - } - // Lastly sort on start position. ie leftmost - return a.offsets.start - b.offsets.start; - }); - tokens = tokens.slice(0, 1); - } - // Use tokens for overlapping ranges - else { - tokens = tokens.filter((token) => !token.intersection.isEmpty); - tokens.sort((a, b) => a.token.offsets.start - b.token.offsets.start); - } - if (tokens.length < 1) { - throw new Error("Couldn't find token in selection"); - } - const start = tokens[0].token.range.start; - const end = tokens[tokens.length - 1].token.range.end; - return selectionWithEditorFromPositions(selection, start, end); -} - -function processDecoratedSymbol( - context: ProcessedTargetsContext, - mark: DecoratedSymbol -) { - const token = context.hatTokenMap.getToken(mark.symbolColor, mark.character); - if (token == null) { - throw new Error( - `Couldn't find mark ${mark.symbolColor} '${mark.character}'` - ); - } - return [ - { - selection: new Selection(token.range.start, token.range.end), - editor: token.editor, - }, - ]; -} - -function processLineNumber(context: ProcessedTargetsContext, mark: LineNumber) { - const editor = context.currentEditor!; - const getLine = (linePosition: LineNumberPosition) => { - switch (linePosition.type) { - case "absolute": - return linePosition.lineNumber; - case "relative": - return editor.selection.active.line + linePosition.lineNumber; - case "modulo100": - const stepSize = 100; - const startLine = editor.visibleRanges[0].start.line; - const endLine = - editor.visibleRanges[editor.visibleRanges.length - 1].end.line; - const base = Math.floor(startLine / stepSize) * stepSize; - const visibleLines = []; - const invisibleLines = []; - let lineNumber = base + linePosition.lineNumber; - while (lineNumber <= endLine) { - if (lineNumber >= startLine) { - const visible = editor.visibleRanges.find( - (r) => lineNumber >= r.start.line && lineNumber <= r.end.line - ); - if (visible) { - visibleLines.push(lineNumber); - } else { - invisibleLines.push(lineNumber); - } - } - lineNumber += stepSize; - } - if (visibleLines.length === 1) { - return visibleLines[0]; - } - if (visibleLines.length + invisibleLines.length > 1) { - throw new Error("Multiple lines matching"); - } - if (invisibleLines.length === 1) { - return invisibleLines[0]; - } - throw new Error("Line is not in viewport"); - } - }; - return [ - { - selection: new Selection( - getLine(mark.anchor), - 0, - getLine(mark.active), - 0 - ), - editor: context.currentEditor!, - }, - ]; -} - -function isAlphaNum(text: string) { - return /^\w+$/.test(text); -} diff --git a/src/typings/Types.ts b/src/typings/Types.ts index 66b9e0db44..19cd3a94af 100644 --- a/src/typings/Types.ts +++ b/src/typings/Types.ts @@ -12,12 +12,7 @@ import { CommandServerApi } from "../util/getExtensionApi"; import { ReadOnlyHatMap } from "../core/IndividualHatMap"; import Debug from "../core/Debug"; import { TestCaseRecorder } from "../testUtil/TestCaseRecorder"; -import { - SelectionType, - InsideOutsideType, - Position, - Modifier, -} from "./target.types"; +import { SelectionType, Position } from "./target.types"; /** * A token within a text editor, including the current display line of the token @@ -28,8 +23,6 @@ export interface Token extends FullRangeInfo { } export interface ProcessedTargetsContext { - currentSelections: SelectionWithEditor[]; - currentEditor: vscode.TextEditor | undefined; hatTokenMap: ReadOnlyHatMap; thatMark: SelectionWithEditor[]; sourceMark: SelectionWithEditor[]; @@ -88,24 +81,64 @@ export interface SelectionContext { * Represents a selection in a particular document along with potential rich * context information such as how to remove the given selection */ +// export interface TypedSelection { +// /** +// * The selection. If insideOutsideType is non-null, it will be adjusted to +// * include delimiter if outside +// */ +// selection: SelectionWithEditor; +// selectionContext: SelectionContext; + +// /** +// * Mirrored from the target from which this selection was constructed +// */ +// position: Position; +// } + export interface TypedSelection { /** - * The selection. If insideOutsideType is non-null, it will be adjusted to - * include delimiter if outside + * The text editor used for all ranges */ - selection: SelectionWithEditor; - selectionType: SelectionType; - selectionContext: SelectionContext; + editor: vscode.TextEditor; /** - * Is a boolean if user specifically requested inside or outside + * If true active is before anchor */ - insideOutsideType: InsideOutsideType; + isReversed?: boolean; + + /** + * If this selection has a delimiter. For example, new line for a line or paragraph and comma for a list or argument + */ + delimiter?: string; /** - * Mirrored from the target from which this selection was constructed + * The range of the content + */ + contentRange: vscode.Range; + + /** + * Represents the interior range of this selection. For example, for a + * surrounding pair this would exclude the opening and closing delimiter. For an if + * statement this would be the statements in the body. + */ + interiorRange?: vscode.Range; + + /** + * The range of the delimiter before the content selection + */ + leadingDelimiterRange?: vscode.Range; + + /** + * The range of the delimiter after the content selection + */ + trailingDelimiterRange?: vscode.Range; + + /** + * Represents the boundary ranges of this selection. For example, for a + * surrounding pair this would be the opening and closing delimiter. For an if + * statement this would be the line of the guard as well as the closing brace. */ - position: Position; + boundary?: vscode.Range[]; } export interface ActionPreferences { diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index b05724b736..5c5e220bfe 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -1,4 +1,5 @@ import { HatStyleName } from "../core/constants"; +import { ProcessedTargetsContext, TypedSelection } from "./Types"; export interface CursorMark { type: "cursor"; @@ -106,6 +107,7 @@ export type ScopeType = | "xmlStartTag"; export type SubTokenType = "word" | "character"; + /** * Indicates whether to include or exclude delimiters in a surrounding pair * modifier. In the future, these will become proper modifiers that can be @@ -114,7 +116,6 @@ export type SubTokenType = "word" | "character"; * range, so if delimiter inclusion is undefined, it's equivalent to not having * one of these modifiers; ie include the delimiters. */ - export type DelimiterInclusion = "excludeInterior" | "interiorOnly" | undefined; export type SurroundingPairDirection = "left" | "right"; @@ -178,7 +179,8 @@ export interface PartialPrimitiveTarget { stages: PipelineStageDescriptor[]; isImplicit?: boolean; } -type PipelineStageDescriptor = + +export type PipelineStageDescriptor = | Mark | Position | SurroundingPairModifier diff --git a/src/util/selectionUtils.ts b/src/util/selectionUtils.ts index 6ce7e891fb..a03a5ae5c3 100644 --- a/src/util/selectionUtils.ts +++ b/src/util/selectionUtils.ts @@ -24,6 +24,10 @@ export function isForward(selection: Selection) { return selection.active.isAfterOrEqual(selection.anchor); } +export function isReversed(selection: Selection) { + return selection.active.isBefore(selection.anchor); +} + export function selectionWithEditorFromRange( selection: SelectionWithEditor, range: Range From b9ff80437a05fca4bc5a6974f0438c6cbdde1750 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 14 May 2022 04:13:16 +0200 Subject: [PATCH 007/314] Updated process targets to new formats --- src/processTargets/index.ts | 233 ++++++++++++------------------------ 1 file changed, 77 insertions(+), 156 deletions(-) diff --git a/src/processTargets/index.ts b/src/processTargets/index.ts index bf942a0668..6a6feb0c56 100644 --- a/src/processTargets/index.ts +++ b/src/processTargets/index.ts @@ -1,11 +1,8 @@ import { isEqual, zip } from "lodash"; -import { Selection } from "vscode"; -import { performInsideOutsideAdjustment } from "../util/performInsideOutsideAdjustment"; -import { ProcessedTargetsContext, TypedSelection } from "../typings/Types"; +import { Range } from "vscode"; import { PrimitiveTarget, RangeTarget, Target } from "../typings/target.types"; -import processModifier from "./modifiers/processModifier"; -import processPosition from "./processPosition"; -import processSelectionType from "./processSelectionType"; +import { ProcessedTargetsContext, TypedSelection } from "../typings/Types"; +import { performInsideOutsideAdjustment } from "../util/performInsideOutsideAdjustment"; import getPipelineStage from "./pipelineStages/getPipelineStage"; /** @@ -83,12 +80,9 @@ function processRangeTarget( ); } - const anchorSelection = anchorTarget.selection.selection; - const activeSelection = activeTarget.selection.selection; - - const isForward = anchorSelection.start.isBeforeOrEqual( - activeSelection.start - ); + const anchorRange = anchorTarget.contentRange; + const activeRange = activeTarget.contentRange; + const isForward = anchorRange.start.isBeforeOrEqual(activeRange.start); switch (target.rangeType) { case "continuous": @@ -116,104 +110,99 @@ function processContinuousRangeTarget( activeTarget: TypedSelection, isForward: boolean ): TypedSelection[] { - const anchor = targetToRangeLimitPosition( - anchorTarget, + const { excludeAnchor, excludeActive } = target; + + const contentRange = unionRanges( isForward, - !target.excludeAnchor - ); - const active = targetToRangeLimitPosition( - activeTarget, - !isForward, - !target.excludeActive - ); + excludeAnchor, + excludeActive, + anchorTarget.contentRange, + activeTarget.contentRange + )!; - const outerAnchor = target.excludeAnchor - ? null - : isForward - ? anchorTarget.selectionContext.outerSelection?.start - : anchorTarget.selectionContext.outerSelection?.end; - const outerActive = target.excludeActive - ? null - : isForward - ? activeTarget.selectionContext.outerSelection?.end - : activeTarget.selectionContext.outerSelection?.start; - const outerSelection = - outerAnchor != null || outerActive != null - ? new Selection(outerAnchor ?? anchor, outerActive ?? active) - : null; + const interiorRange = unionRanges( + isForward, + excludeAnchor, + excludeActive, + anchorTarget.interiorRange, + activeTarget.interiorRange + ); - const startSelectionContext = target.excludeAnchor - ? null - : anchorTarget.selectionContext; - const endSelectionContext = target.excludeActive - ? null - : activeTarget.selectionContext; + const anchorContext = excludeAnchor ? undefined : anchorTarget; + const activeContext = excludeActive ? undefined : activeTarget; const leadingDelimiterRange = isForward - ? startSelectionContext?.leadingDelimiterRange - : endSelectionContext?.leadingDelimiterRange; + ? anchorContext?.leadingDelimiterRange + : activeContext?.leadingDelimiterRange; const trailingDelimiterRange = isForward - ? endSelectionContext?.trailingDelimiterRange - : startSelectionContext?.trailingDelimiterRange; + ? activeContext?.trailingDelimiterRange + : anchorContext?.trailingDelimiterRange; return [ { - selection: { - selection: new Selection(anchor, active), - editor: anchorTarget.selection.editor, - }, - selectionType: anchorTarget.selectionType, - selectionContext: { - containingListDelimiter: - anchorTarget.selectionContext.containingListDelimiter, - isInDelimitedList: anchorTarget.selectionContext.isInDelimitedList, - leadingDelimiterRange, - trailingDelimiterRange, - outerSelection, - }, - insideOutsideType: anchorTarget.insideOutsideType, - position: "contents", + editor: activeTarget.editor, + isReversed: !isForward, + delimiter: anchorTarget.delimiter, + contentRange, + interiorRange, + leadingDelimiterRange, + trailingDelimiterRange, }, ]; } +function unionRanges( + isForward: boolean, + excludeAnchor: boolean, + excludeActive: boolean, + anchor?: Range, + active?: Range +) { + if (anchor == null || active == null) { + return anchor == null ? active : anchor; + } + return new Range( + getPosition(anchor, isForward, excludeAnchor), + getPosition(active, !isForward, excludeActive) + ); +} + +function getPosition(range: Range, isStartOfRange: boolean, exclude: boolean) { + if (exclude) { + return isStartOfRange ? range.end : range.start; + } + return isStartOfRange ? range.start : range.end; +} + function processVerticalRangeTarget( target: RangeTarget, anchorTarget: TypedSelection, activeTarget: TypedSelection, isForward: boolean ): TypedSelection[] { - const anchorLine = targetToLineLimitPosition( - anchorTarget, - isForward, - !target.excludeAnchor - ); - const activeLine = targetToLineLimitPosition( - activeTarget, - !isForward, - !target.excludeActive - ); - const anchorSelection = anchorTarget.selection.selection; + const { excludeAnchor, excludeActive } = target; const delta = isForward ? 1 : -1; - const results: TypedSelection[] = []; + const anchorPosition = isForward + ? anchorTarget.contentRange.end + : anchorTarget.contentRange.start; + const anchorLine = anchorPosition.line + (excludeAnchor ? delta : 0); + const activePosition = isForward + ? activeTarget.contentRange.end + : activeTarget.contentRange.start; + const activeLine = activePosition.line - (excludeActive ? delta : 0); + + const results: TypedSelection[] = []; for (let i = anchorLine; true; i += delta) { results.push({ - selection: { - selection: new Selection( - i, - anchorSelection.anchor.character, - i, - anchorSelection.active.character - ), - editor: anchorTarget.selection.editor, - }, - selectionType: anchorTarget.selectionType, - selectionContext: { - containingListDelimiter: - anchorTarget.selectionContext.containingListDelimiter, - }, - insideOutsideType: anchorTarget.insideOutsideType, - position: anchorTarget.position, + editor: anchorTarget.editor, + isReversed: !isForward, + delimiter: anchorTarget.delimiter, + contentRange: new Range( + i, + anchorTarget.contentRange.start.character, + i, + anchorTarget.contentRange.end.character + ), }); if (i === activeLine) { return results; @@ -221,56 +210,6 @@ function processVerticalRangeTarget( } } -/** - * Given a target which forms one end of a range target, do necessary - * adjustments to get the proper position for the output range - * @param target The target to get position from - * @param isStartOfRange If true this position is the start of the range - * @param exclude If true the content of this position should be excluded - */ -function targetToRangeLimitPosition( - target: TypedSelection, - isStartOfRange: boolean, - includeTarget: boolean -) { - const selection = target.selection.selection; - - if (includeTarget) { - return isStartOfRange ? selection.start : selection.end; - } - - const outerSelection = target.selectionContext.outerSelection; - - if (outerSelection != null) { - const delimiterPosition = isStartOfRange - ? target.selectionContext.trailingDelimiterRange?.end - : target.selectionContext.leadingDelimiterRange?.start; - if (delimiterPosition != null) { - return delimiterPosition; - } - return isStartOfRange ? outerSelection.end : outerSelection.start; - } - - return isStartOfRange ? selection.end : selection.start; -} - -// Same as targetToRangeLimitPosition but only operates on and returns line number -function targetToLineLimitPosition( - target: TypedSelection, - isStartOfRange: boolean, - includeTarget: boolean -) { - const position = targetToRangeLimitPosition( - target, - isStartOfRange, - includeTarget - ); - if (includeTarget) { - return position.line; - } - return position.line + (isStartOfRange ? 1 : -1); -} - function processPrimitiveTarget( context: ProcessedTargetsContext, target: PrimitiveTarget @@ -292,24 +231,6 @@ function processPrimitiveTarget( } return selections; - - // TODO - // const markSelections = processMark(context, target.mark); - // const modifiedSelections = markSelections.flatMap((markSelection) => - // processModifier(context, target, markSelection) - // ); - // if (target.isImplicit) { - // modifiedSelections.forEach((typedSelection) => { - // typedSelection.context. = true; - // }); - // } - // const typedSelections = modifiedSelections.map( - // ({ selection, context: selectionContext }) => - // processSelectionType(context, target, selection, selectionContext) - // ); - // return typedSelections.map((selection) => - // processPosition(context, target, selection) - // ); } function filterDuplicateSelections(selections: TypedSelection[]) { From ffaf0a7a0d6e9497de254634b67995ea5c9a9d77 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 14 May 2022 04:32:23 +0200 Subject: [PATCH 008/314] Added position stage --- .../pipelineStages/PositionStage.ts | 33 ++++++++++++++ .../pipelineStages/getPipelineStage.ts | 5 +++ src/processTargets/processPosition.ts | 44 ------------------- src/typings/target.types.ts | 4 +- 4 files changed, 39 insertions(+), 47 deletions(-) create mode 100644 src/processTargets/pipelineStages/PositionStage.ts delete mode 100644 src/processTargets/processPosition.ts diff --git a/src/processTargets/pipelineStages/PositionStage.ts b/src/processTargets/pipelineStages/PositionStage.ts new file mode 100644 index 0000000000..6845c40e5a --- /dev/null +++ b/src/processTargets/pipelineStages/PositionStage.ts @@ -0,0 +1,33 @@ +import * as vscode from "vscode"; +import { Position } from "../../typings/target.types"; +import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import PipelineStage from "./PipelineStage"; + +export default class implements PipelineStage { + run( + context: ProcessedTargetsContext, + stage: Position, + selection: TypedSelection + ): TypedSelection[] { + const res: TypedSelection = { + ...selection, + }; + switch (stage.position) { + case "before": + case "start": + res.contentRange = range(res.contentRange.start)!; + res.interiorRange = range(res.interiorRange?.start); + break; + case "after": + case "end": + res.contentRange = range(res.contentRange.end)!; + res.interiorRange = range(res.interiorRange?.end); + break; + } + return [res]; + } +} + +function range(position?: vscode.Position) { + return position ? new vscode.Range(position, position) : undefined; +} diff --git a/src/processTargets/pipelineStages/getPipelineStage.ts b/src/processTargets/pipelineStages/getPipelineStage.ts index 619f1f2e4d..4bf101a158 100644 --- a/src/processTargets/pipelineStages/getPipelineStage.ts +++ b/src/processTargets/pipelineStages/getPipelineStage.ts @@ -6,6 +6,7 @@ import DecoratedSymbolStage from "./DecoratedSymbolStage"; import LineNumberStage from "./LineNumberStage"; import NothingStage from "./NothingStage"; import PipelineStage from "./PipelineStage"; +import PositionStage from "./PositionStage"; import SourceStage from "./SourceStage"; import ThatStage from "./ThatStage"; @@ -41,6 +42,10 @@ const getStage = (stageDescriptor: PipelineStageDescriptor): PipelineStage => { return new LineNumberStage(); case "nothing": return new NothingStage(); + // Modifiers + case "position": + return new PositionStage(); + default: throw Error("Unknown pipeline stage " + stageDescriptor.type); } diff --git a/src/processTargets/processPosition.ts b/src/processTargets/processPosition.ts deleted file mode 100644 index 505696e0d9..0000000000 --- a/src/processTargets/processPosition.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { Selection } from "vscode"; -import { ProcessedTargetsContext, TypedSelection } from "../typings/Types"; -import { PrimitiveTarget } from "../typings/target.types"; - -export default function ( - context: ProcessedTargetsContext, - target: PrimitiveTarget, - selection: TypedSelection -): TypedSelection { - const { position } = target; - const originalSelection = selection.selection.selection; - let newSelection; - - switch (position) { - case "contents": - newSelection = originalSelection; - break; - - case "before": - newSelection = new Selection( - originalSelection.start, - originalSelection.start - ); - break; - - case "after": - newSelection = new Selection( - originalSelection.end, - originalSelection.end - ); - break; - } - - return { - selection: { - selection: newSelection, - editor: selection.selection.editor, - }, - selectionType: selection.selectionType, - selectionContext: selection.selectionContext, - insideOutsideType: target.insideOutsideType ?? null, - position, - }; -} diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 5c5e220bfe..4dd8c661d0 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -1,5 +1,4 @@ import { HatStyleName } from "../core/constants"; -import { ProcessedTargetsContext, TypedSelection } from "./Types"; export interface CursorMark { type: "cursor"; @@ -146,7 +145,6 @@ export interface SubTokenModifier { * example if it is the destination of a bring or move it should inherit the * type information such as delimiters from its source. */ - export interface RawSelectionModifier { type: "toRawSelection"; } @@ -221,9 +219,9 @@ export interface RangeTarget { excludeActive: boolean; rangeType: RangeType; } + // continuous is one single continuous selection between the two targets // vertical puts a selection on each line vertically between the two targets - export type RangeType = "continuous" | "vertical"; export interface ListTarget { From e3e10c6a9614b9c99eac08e36b1656251ee037a9 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 14 May 2022 04:57:58 +0200 Subject: [PATCH 009/314] Added head tail modifiers --- .../pipelineStages/HeadTailStage.ts | 49 +++++++++++++++++++ .../pipelineStages/getPipelineStage.ts | 11 ++++- 2 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 src/processTargets/pipelineStages/HeadTailStage.ts diff --git a/src/processTargets/pipelineStages/HeadTailStage.ts b/src/processTargets/pipelineStages/HeadTailStage.ts new file mode 100644 index 0000000000..e21410be80 --- /dev/null +++ b/src/processTargets/pipelineStages/HeadTailStage.ts @@ -0,0 +1,49 @@ +import { Position, Range, TextEditor, window } from "vscode"; +import { HeadModifier, TailModifier } from "../../typings/target.types"; +import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import PipelineStage from "./PipelineStage"; + +abstract class HeadTailStage implements PipelineStage { + abstract update(editor: TextEditor, range: Range): Range; + + constructor(private isReversed: boolean) {} + + run( + context: ProcessedTargetsContext, + stage: HeadModifier | TailModifier, + selection: TypedSelection + ): TypedSelection[] { + const editor = window.activeTextEditor; + if (editor == null) { + return []; + } + return [ + { + ...selection, + isReversed: this.isReversed, + contentRange: this.update(editor, selection.contentRange), + interiorRange: selection.interiorRange + ? this.update(editor, selection.interiorRange) + : undefined, + }, + ]; + } +} + +export class HeadStage extends HeadTailStage { + constructor() { + super(true); + } + update(editor: TextEditor, range: Range) { + return new Range(new Position(range.start.line, 0), range.end); + } +} + +export class TailStage extends HeadTailStage { + constructor() { + super(false); + } + update(editor: TextEditor, range: Range) { + return new Range(range.start, editor.document.lineAt(range.end).range.end); + } +} diff --git a/src/processTargets/pipelineStages/getPipelineStage.ts b/src/processTargets/pipelineStages/getPipelineStage.ts index 4bf101a158..3071f1c7e7 100644 --- a/src/processTargets/pipelineStages/getPipelineStage.ts +++ b/src/processTargets/pipelineStages/getPipelineStage.ts @@ -3,6 +3,7 @@ import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; import CursorStage from "./CursorStage"; import CursorTokenStage from "./CursorTokenStage"; import DecoratedSymbolStage from "./DecoratedSymbolStage"; +import { HeadStage, TailStage } from "./HeadTailStage"; import LineNumberStage from "./LineNumberStage"; import NothingStage from "./NothingStage"; import PipelineStage from "./PipelineStage"; @@ -45,8 +46,14 @@ const getStage = (stageDescriptor: PipelineStageDescriptor): PipelineStage => { // Modifiers case "position": return new PositionStage(); + case "head": + return new HeadStage(); + case "tail": + return new TailStage(); - default: - throw Error("Unknown pipeline stage " + stageDescriptor.type); + // case "containingScope": + + // default: + // throw Error("Unknown pipeline stage " + stageDescriptor.type); } }; From 50f271091aa605ed88ea817acf8bbccaf39d78de Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 14 May 2022 05:48:38 +0200 Subject: [PATCH 010/314] Started working on containing scope --- .../pipelineStages/ContainingScopeStage.ts | 82 ++++++++++++++ .../pipelineStages/DecoratedSymbolStage.ts | 12 +- .../pipelineStages/HeadTailStage.ts | 24 ++-- .../pipelineStages/LineNumberStage.ts | 25 +++-- .../pipelineStages/PositionStage.ts | 4 +- .../pipelineStages/RawSelectionStage.ts | 13 +++ .../pipelineStages/SubPieceStage.ts | 100 +++++++++++++++++ .../pipelineStages/SurroundingPairStage.ts | 105 ++++++++++++++++++ .../pipelineStages/getPipelineStage.ts | 22 +++- src/typings/Types.ts | 7 ++ src/typings/target.types.ts | 30 +++-- 11 files changed, 371 insertions(+), 53 deletions(-) create mode 100644 src/processTargets/pipelineStages/ContainingScopeStage.ts create mode 100644 src/processTargets/pipelineStages/RawSelectionStage.ts create mode 100644 src/processTargets/pipelineStages/SubPieceStage.ts create mode 100644 src/processTargets/pipelineStages/SurroundingPairStage.ts diff --git a/src/processTargets/pipelineStages/ContainingScopeStage.ts b/src/processTargets/pipelineStages/ContainingScopeStage.ts new file mode 100644 index 0000000000..8e496efdd6 --- /dev/null +++ b/src/processTargets/pipelineStages/ContainingScopeStage.ts @@ -0,0 +1,82 @@ +import { Location } from "vscode"; +import { SyntaxNode } from "web-tree-sitter"; +import { getNodeMatcher } from "../../languages/getNodeMatcher"; +import { + ContainingScopeModifier, + SurroundingPairModifier, +} from "../../typings/target.types"; +import { + ProcessedTargetsContext, + SelectionWithEditor, + TypedSelection, +} from "../../typings/Types"; +import { + SelectionWithEditorWithContext, + findNearestContainingAncestorNode, +} from "../modifiers/processModifier"; +import PipelineStage from "./PipelineStage"; + +export default class implements PipelineStage { + run( + context: ProcessedTargetsContext, + stage: ContainingScopeModifier, + selection: TypedSelection + ): TypedSelection { + switch (stage.scopeType) { + case "token": + // return processToken(target, selection, selectionContext); + case "notebookCell": + // return processNotebookCell(target, selection, selectionContext); + case "document": + // return processDocument(target, selection, selectionContext); + case "line": + // return processLine(target, selection, selectionContext); + case "paragraph": + // return processParagraph(target, selection, selectionContext); + case "nonWhitespaceSequence": + // return processRegexDefinedScope( + // /\S+/g, + // target, + // selection, + // selectionContext + // ); + case "url": + // return processRegexDefinedScope( + // URL_REGEX, + // target, + // selection, + // selectionContext + // ); + + default: + syntaxBased(context); + } + } +} + +function syntaxBased( + context: ProcessedTargetsContext, + selection: SelectionWithEditor, + modifier: ContainingScopeModifier +): SelectionWithEditorWithContext[] | null { + const nodeMatcher = getNodeMatcher( + selection.editor.document.languageId, + modifier.scopeType, + modifier.includeSiblings ?? false + ); + const node: SyntaxNode | null = context.getNodeAtLocation( + new Location(selection.editor.document.uri, selection.selection) + ); + + const result = findNearestContainingAncestorNode( + node, + nodeMatcher, + selection + ); + + if (result == null) { + throw new Error(`Couldn't find containing ${modifier.scopeType}`); + } + + return result; +} diff --git a/src/processTargets/pipelineStages/DecoratedSymbolStage.ts b/src/processTargets/pipelineStages/DecoratedSymbolStage.ts index 3b759a4139..3eb9bfda6a 100644 --- a/src/processTargets/pipelineStages/DecoratedSymbolStage.ts +++ b/src/processTargets/pipelineStages/DecoratedSymbolStage.ts @@ -7,7 +7,7 @@ export default class implements PipelineStage { run( context: ProcessedTargetsContext, stage: DecoratedSymbol - ): TypedSelection[] { + ): TypedSelection { const token = context.hatTokenMap.getToken( stage.symbolColor, stage.character @@ -17,11 +17,9 @@ export default class implements PipelineStage { `Couldn't find mark ${stage.symbolColor} '${stage.character}'` ); } - return [ - { - editor: token.editor, - contentRange: new Range(token.range.start, token.range.end), - }, - ]; + return { + editor: token.editor, + contentRange: new Range(token.range.start, token.range.end), + }; } } diff --git a/src/processTargets/pipelineStages/HeadTailStage.ts b/src/processTargets/pipelineStages/HeadTailStage.ts index e21410be80..5c5d204e30 100644 --- a/src/processTargets/pipelineStages/HeadTailStage.ts +++ b/src/processTargets/pipelineStages/HeadTailStage.ts @@ -12,21 +12,15 @@ abstract class HeadTailStage implements PipelineStage { context: ProcessedTargetsContext, stage: HeadModifier | TailModifier, selection: TypedSelection - ): TypedSelection[] { - const editor = window.activeTextEditor; - if (editor == null) { - return []; - } - return [ - { - ...selection, - isReversed: this.isReversed, - contentRange: this.update(editor, selection.contentRange), - interiorRange: selection.interiorRange - ? this.update(editor, selection.interiorRange) - : undefined, - }, - ]; + ): TypedSelection | TypedSelection[] { + return { + ...selection, + isReversed: this.isReversed, + contentRange: this.update(selection.editor, selection.contentRange), + interiorRange: selection.interiorRange + ? this.update(selection.editor, selection.interiorRange) + : undefined, + }; } } diff --git a/src/processTargets/pipelineStages/LineNumberStage.ts b/src/processTargets/pipelineStages/LineNumberStage.ts index 5986131f43..aa4fb41a09 100644 --- a/src/processTargets/pipelineStages/LineNumberStage.ts +++ b/src/processTargets/pipelineStages/LineNumberStage.ts @@ -4,22 +4,23 @@ import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; import PipelineStage from "./PipelineStage"; export default class implements PipelineStage { - run(context: ProcessedTargetsContext, stage: LineNumber): TypedSelection[] { + run( + context: ProcessedTargetsContext, + stage: LineNumber + ): TypedSelection | TypedSelection[] { if (window.activeTextEditor == null) { return []; } const editor = window.activeTextEditor; - return [ - { - editor, - contentRange: new Range( - getLine(editor, stage.anchor), - 0, - getLine(editor, stage.active), - 0 - ), - }, - ]; + return { + editor, + contentRange: new Range( + getLine(editor, stage.anchor), + 0, + getLine(editor, stage.active), + 0 + ), + }; } } diff --git a/src/processTargets/pipelineStages/PositionStage.ts b/src/processTargets/pipelineStages/PositionStage.ts index 6845c40e5a..a6c12a21fb 100644 --- a/src/processTargets/pipelineStages/PositionStage.ts +++ b/src/processTargets/pipelineStages/PositionStage.ts @@ -8,7 +8,7 @@ export default class implements PipelineStage { context: ProcessedTargetsContext, stage: Position, selection: TypedSelection - ): TypedSelection[] { + ): TypedSelection { const res: TypedSelection = { ...selection, }; @@ -24,7 +24,7 @@ export default class implements PipelineStage { res.interiorRange = range(res.interiorRange?.end); break; } - return [res]; + return res; } } diff --git a/src/processTargets/pipelineStages/RawSelectionStage.ts b/src/processTargets/pipelineStages/RawSelectionStage.ts new file mode 100644 index 0000000000..de7a76b519 --- /dev/null +++ b/src/processTargets/pipelineStages/RawSelectionStage.ts @@ -0,0 +1,13 @@ +import { RawSelectionModifier } from "../../typings/target.types"; +import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import PipelineStage from "./PipelineStage"; + +export default class implements PipelineStage { + run( + context: ProcessedTargetsContext, + stage: RawSelectionModifier, + selection: TypedSelection + ): TypedSelection { + return { ...selection, isRawSelection: true }; + } +} diff --git a/src/processTargets/pipelineStages/SubPieceStage.ts b/src/processTargets/pipelineStages/SubPieceStage.ts new file mode 100644 index 0000000000..e3717ff71a --- /dev/null +++ b/src/processTargets/pipelineStages/SubPieceStage.ts @@ -0,0 +1,100 @@ +import { range } from "lodash"; +import { Range } from "vscode"; +import { SUBWORD_MATCHER } from "../../core/constants"; +import { SubTokenModifier } from "../../typings/target.types"; +import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import PipelineStage from "./PipelineStage"; + +export default class implements PipelineStage { + run( + context: ProcessedTargetsContext, + stage: SubTokenModifier, + selection: TypedSelection + ): TypedSelection { + const token = selection.editor.document.getText(selection.contentRange); + let pieces: { start: number; end: number }[] = []; + + if (stage.excludeActive || stage.excludeAnchor) { + throw new Error("Subtoken exclusions unsupported"); + } + + if (stage.pieceType === "word") { + pieces = [...token.matchAll(SUBWORD_MATCHER)].map((match) => ({ + start: match.index!, + end: match.index! + match[0].length, + })); + } else if (stage.pieceType === "character") { + pieces = range(token.length).map((index) => ({ + start: index, + end: index + 1, + })); + } + + const anchorIndex = + stage.anchor < 0 ? stage.anchor + pieces.length : stage.anchor; + const activeIndex = + stage.active < 0 ? stage.active + pieces.length : stage.active; + + if ( + anchorIndex < 0 || + activeIndex < 0 || + anchorIndex >= pieces.length || + activeIndex >= pieces.length + ) { + throw new Error("Subtoken index out of range"); + } + + const isReversed = activeIndex < anchorIndex; + + const anchor = selection.contentRange.start.translate( + undefined, + isReversed ? pieces[anchorIndex].end : pieces[anchorIndex].start + ); + const active = selection.contentRange.start.translate( + undefined, + isReversed ? pieces[activeIndex].start : pieces[activeIndex].end + ); + + const startIndex = Math.min(anchorIndex, activeIndex); + const endIndex = Math.max(anchorIndex, activeIndex); + const leadingDelimiterRange = + startIndex > 0 && pieces[startIndex - 1].end < pieces[startIndex].start + ? new Range( + selection.contentRange.start.translate({ + characterDelta: pieces[startIndex - 1].end, + }), + selection.contentRange.start.translate({ + characterDelta: pieces[startIndex].start, + }) + ) + : undefined; + const trailingDelimiterRange = + endIndex + 1 < pieces.length && + pieces[endIndex].end < pieces[endIndex + 1].start + ? new Range( + selection.contentRange.start.translate({ + characterDelta: pieces[endIndex].end, + }), + selection.contentRange.start.translate({ + characterDelta: pieces[endIndex + 1].start, + }) + ) + : undefined; + const isInDelimitedList = + leadingDelimiterRange != null || trailingDelimiterRange != null; + const containingListDelimiter = isInDelimitedList + ? selection.editor.document.getText( + (leadingDelimiterRange ?? trailingDelimiterRange)! + ) + : undefined; + + return { + ...selection, + isReversed, + delimiter: containingListDelimiter ?? undefined, + leadingDelimiterRange, + trailingDelimiterRange, + contentRange: new Range(anchor, active), + }; + } +} diff --git a/src/processTargets/pipelineStages/SurroundingPairStage.ts b/src/processTargets/pipelineStages/SurroundingPairStage.ts new file mode 100644 index 0000000000..b920c190d6 --- /dev/null +++ b/src/processTargets/pipelineStages/SurroundingPairStage.ts @@ -0,0 +1,105 @@ +import * as vscode from "vscode"; +import { Selection } from "vscode"; +import { SyntaxNode } from "web-tree-sitter"; +import getTextFragmentExtractor, { + TextFragmentExtractor, +} from "../../languages/getTextFragmentExtractor"; +import { + ComplexSurroundingPairName, + SurroundingPairModifier, +} from "../../typings/target.types"; +import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import { complexDelimiterMap } from "../modifiers/surroundingPair/delimiterMaps"; +import { findSurroundingPairParseTreeBased } from "../modifiers/surroundingPair/findSurroundingPairParseTreeBased"; +import { findSurroundingPairTextBased } from "../modifiers/surroundingPair/findSurroundingPairTextBased"; +import PipelineStage from "./PipelineStage"; + +/** + * Applies the surrounding pair modifier to the given selection. First looks to + * see if the target is itself adjacent to or contained by a modifier token. If + * so it will expand the selection to the opposite delimiter token. Otherwise, + * or if the opposite token wasn't found, it will proceed by finding the + * smallest pair of delimiters which contains the selection. + * + * @param context Context to be leveraged by modifier + * @param selection The selection to process + * @param modifier The surrounding pair modifier information + * @returns The new selection expanded to the containing surrounding pair or + * `null` if none was found + */ +export default class implements PipelineStage { + run( + context: ProcessedTargetsContext, + modifier: SurroundingPairModifier, + selection: TypedSelection + ): TypedSelection | TypedSelection[] { + const document = selection.editor.document; + const delimiters = complexDelimiterMap[ + modifier.delimiter as ComplexSurroundingPairName + ] ?? [modifier.delimiter]; + + let node: SyntaxNode | null; + let textFragmentExtractor: TextFragmentExtractor; + + try { + node = context.getNodeAtLocation( + new vscode.Location(document.uri, selection.contentRange) + ); + + textFragmentExtractor = getTextFragmentExtractor(document.languageId); + } catch (err) { + if ((err as Error).name === "UnsupportedLanguageError") { + // If we're in a language where we don't have a parse tree we use the text + // based algorithm + return findSurroundingPairTextBased( + selection.editor, + selection.contentRange, + null, + delimiters, + modifier.delimiterInclusion, + modifier.forceDirection + ); + } else { + throw err; + } + } + + const selectionWithEditor = { + editor: selection.editor, + selection: new Selection( + selection.contentRange.start, + selection.contentRange.end + ), + }; + + // If we have a parse tree but we are in a string node or in a comment node, + // then we use the text-based algorithm + const textFragmentRange = textFragmentExtractor(node, selectionWithEditor); + if (textFragmentRange != null) { + const surroundingRange = findSurroundingPairTextBased( + selection.editor, + selection.selection, + textFragmentRange, + delimiters, + modifier.delimiterInclusion, + modifier.forceDirection + ); + + if (surroundingRange != null) { + return surroundingRange; + } + } + + // If we have a parse tree and either we are not in a string or comment or we + // couldn't find a surrounding pair within a string or comment, we use the + // parse tree-based algorithm + return findSurroundingPairParseTreeBased( + selection.editor, + selection.selection, + node, + delimiters, + modifier.delimiterInclusion, + modifier.forceDirection + ); + } +} diff --git a/src/processTargets/pipelineStages/getPipelineStage.ts b/src/processTargets/pipelineStages/getPipelineStage.ts index 3071f1c7e7..16603603af 100644 --- a/src/processTargets/pipelineStages/getPipelineStage.ts +++ b/src/processTargets/pipelineStages/getPipelineStage.ts @@ -8,7 +8,10 @@ import LineNumberStage from "./LineNumberStage"; import NothingStage from "./NothingStage"; import PipelineStage from "./PipelineStage"; import PositionStage from "./PositionStage"; +import RawSelectionStage from "./RawSelectionStage"; import SourceStage from "./SourceStage"; +import SubPieceStage from "./SubPieceStage"; +import SurroundingPairStage from "./SurroundingPairStage"; import ThatStage from "./ThatStage"; export default (stageDescriptor: PipelineStageDescriptor) => { @@ -31,18 +34,19 @@ const getStage = (stageDescriptor: PipelineStageDescriptor): PipelineStage => { // Mark/source stages case "cursor": return new CursorStage(); + case "cursorToken": + return new CursorTokenStage(); case "that": return new ThatStage(); case "source": return new SourceStage(); - case "cursorToken": - return new CursorTokenStage(); case "decoratedSymbol": return new DecoratedSymbolStage(); case "lineNumber": return new LineNumberStage(); case "nothing": return new NothingStage(); + // Modifiers case "position": return new PositionStage(); @@ -50,10 +54,18 @@ const getStage = (stageDescriptor: PipelineStageDescriptor): PipelineStage => { return new HeadStage(); case "tail": return new TailStage(); + case "toRawSelection": + return new RawSelectionStage(); + case "subpiece": + return new SubPieceStage(); + case "surroundingPair": + return SurroundingPairStage(); - // case "containingScope": + case "containingScope": + case "everyScope": - // default: - // throw Error("Unknown pipeline stage " + stageDescriptor.type); + default: + // Make sure we haven't missed any cases + const _neverCheck: never = stageDescriptor.type; } }; diff --git a/src/typings/Types.ts b/src/typings/Types.ts index 19cd3a94af..84205df222 100644 --- a/src/typings/Types.ts +++ b/src/typings/Types.ts @@ -106,6 +106,13 @@ export interface TypedSelection { */ isReversed?: boolean; + /** + * Indicates that this is a raw selection with no type information so for + * example if it is the destination of a bring or move it should inherit the + * type information such as delimiters from its source + */ + isRawSelection?: boolean; + /** * If this selection has a delimiter. For example, new line for a line or paragraph and comma for a list or argument */ diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 4dd8c661d0..89e01363cb 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -103,7 +103,16 @@ export type ScopeType = | "xmlBothTags" | "xmlElement" | "xmlEndTag" - | "xmlStartTag"; + | "xmlStartTag" + // Text based scopes + // | "character" Not implemented + | "token" + | "line" + | "notebookCell" + | "paragraph" + | "document" + | "nonWhitespaceSequence" + | "url"; export type SubTokenType = "word" | "character"; @@ -127,7 +136,13 @@ export interface SurroundingPairModifier { export interface ContainingScopeModifier { type: "containingScope"; - scopeType: ScopeType | SelectionType; + scopeType: ScopeType; + includeSiblings?: boolean; +} + +export interface EveryScopeModifier { + type: "everyScope"; + scopeType: ScopeType; includeSiblings?: boolean; } @@ -157,16 +172,6 @@ export interface TailModifier { type: "tail"; } -export type SelectionType = - // | "character" Not implemented - | "token" - | "line" - | "notebookCell" - | "paragraph" - | "document" - | "nonWhitespaceSequence" - | "url"; - export interface Position { type: "position"; position: "before" | "after" | "start" | "end"; @@ -183,6 +188,7 @@ export type PipelineStageDescriptor = | Position | SurroundingPairModifier | ContainingScopeModifier + | EveryScopeModifier | SubTokenModifier | HeadModifier | TailModifier From 24f68b1eab21dcd440ff5f068da74dc168f04c3c Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 14 May 2022 05:58:03 +0200 Subject: [PATCH 011/314] Started adding selection types --- .../pipelineStages/ContainingScopeStage.ts | 3 +++ src/processTargets/pipelineStages/TokenStage.ts | 11 +++++++++++ src/processTargets/pipelineStages/getPipelineStage.ts | 5 +++-- 3 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 src/processTargets/pipelineStages/TokenStage.ts diff --git a/src/processTargets/pipelineStages/ContainingScopeStage.ts b/src/processTargets/pipelineStages/ContainingScopeStage.ts index 8e496efdd6..bbdd28240f 100644 --- a/src/processTargets/pipelineStages/ContainingScopeStage.ts +++ b/src/processTargets/pipelineStages/ContainingScopeStage.ts @@ -15,6 +15,7 @@ import { findNearestContainingAncestorNode, } from "../modifiers/processModifier"; import PipelineStage from "./PipelineStage"; +import TokenStage from "./TokenStage"; export default class implements PipelineStage { run( @@ -24,6 +25,8 @@ export default class implements PipelineStage { ): TypedSelection { switch (stage.scopeType) { case "token": + // TODO better solution? + return new TokenStage().run(context, stage, selection); // return processToken(target, selection, selectionContext); case "notebookCell": // return processNotebookCell(target, selection, selectionContext); diff --git a/src/processTargets/pipelineStages/TokenStage.ts b/src/processTargets/pipelineStages/TokenStage.ts new file mode 100644 index 0000000000..1909042b6f --- /dev/null +++ b/src/processTargets/pipelineStages/TokenStage.ts @@ -0,0 +1,11 @@ +import { ContainingScopeModifier, Position } from "../../typings/target.types"; +import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import PipelineStage from "./PipelineStage"; + +export default class implements PipelineStage { + run( + context: ProcessedTargetsContext, + stage: ContainingScopeModifier, + selection: TypedSelection + ): TypedSelection {} +} diff --git a/src/processTargets/pipelineStages/getPipelineStage.ts b/src/processTargets/pipelineStages/getPipelineStage.ts index 16603603af..e2504fb027 100644 --- a/src/processTargets/pipelineStages/getPipelineStage.ts +++ b/src/processTargets/pipelineStages/getPipelineStage.ts @@ -1,5 +1,6 @@ import { PipelineStageDescriptor } from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import ContainingScopeStage from "./ContainingScopeStage"; import CursorStage from "./CursorStage"; import CursorTokenStage from "./CursorTokenStage"; import DecoratedSymbolStage from "./DecoratedSymbolStage"; @@ -60,9 +61,9 @@ const getStage = (stageDescriptor: PipelineStageDescriptor): PipelineStage => { return new SubPieceStage(); case "surroundingPair": return SurroundingPairStage(); - case "containingScope": - case "everyScope": + return new ContainingScopeStage(); + // case "everyScope": default: // Make sure we haven't missed any cases From 2ce6fadef778c23a4ccbd5151bc80dc4cff82267 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 14 May 2022 10:46:48 +0200 Subject: [PATCH 012/314] Added token stage --- .../pipelineStages/PositionStage.ts | 4 +- .../pipelineStages/TokenStage.ts | 55 ++++++++++++++++++- src/typings/target.types.ts | 6 +- 3 files changed, 60 insertions(+), 5 deletions(-) diff --git a/src/processTargets/pipelineStages/PositionStage.ts b/src/processTargets/pipelineStages/PositionStage.ts index a6c12a21fb..ead4b5a647 100644 --- a/src/processTargets/pipelineStages/PositionStage.ts +++ b/src/processTargets/pipelineStages/PositionStage.ts @@ -1,12 +1,12 @@ import * as vscode from "vscode"; -import { Position } from "../../typings/target.types"; +import { PositionModifier } from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; import PipelineStage from "./PipelineStage"; export default class implements PipelineStage { run( context: ProcessedTargetsContext, - stage: Position, + stage: PositionModifier, selection: TypedSelection ): TypedSelection { const res: TypedSelection = { diff --git a/src/processTargets/pipelineStages/TokenStage.ts b/src/processTargets/pipelineStages/TokenStage.ts index 1909042b6f..08b182c6df 100644 --- a/src/processTargets/pipelineStages/TokenStage.ts +++ b/src/processTargets/pipelineStages/TokenStage.ts @@ -1,3 +1,4 @@ +import { Range } from "vscode"; import { ContainingScopeModifier, Position } from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; import PipelineStage from "./PipelineStage"; @@ -7,5 +8,57 @@ export default class implements PipelineStage { context: ProcessedTargetsContext, stage: ContainingScopeModifier, selection: TypedSelection - ): TypedSelection {} + ): TypedSelection { + return { + ...selection, + delimiter: " ", + ...getDelimiterRanges(selection), + }; + } +} + +function getDelimiterRanges(selection: TypedSelection) { + const document = selection.editor.document; + const { start, end } = selection.contentRange; + const endLine = document.lineAt(end); + let leadingDelimiterRange, trailingDelimiterRange; + + const startLine = document.lineAt(start); + const leadingText = startLine.text.slice(0, start.character); + const leadingDelimiters = leadingText.match(/\s+$/); + leadingDelimiterRange = + leadingDelimiters != null + ? new Range( + start.line, + start.character - leadingDelimiters[0].length, + start.line, + start.character + ) + : undefined; + + const trailingText = endLine.text.slice(end.character); + const trailingDelimiters = trailingText.match(/^\s+/); + trailingDelimiterRange = + trailingDelimiters != null + ? new Range( + end.line, + end.character, + end.line, + end.character + trailingDelimiters[0].length + ) + : undefined; + + const isInDelimitedList = + (leadingDelimiterRange != null || trailingDelimiterRange != null) && + (leadingDelimiterRange != null || start.character === 0) && + (trailingDelimiterRange != null || end.isEqual(endLine.range.end)); + + return { + leadingDelimiterRange: isInDelimitedList + ? leadingDelimiterRange + : undefined, + trailingDelimiterRange: isInDelimitedList + ? trailingDelimiterRange + : undefined, + }; } diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 89e01363cb..21256a7b28 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -172,7 +172,9 @@ export interface TailModifier { type: "tail"; } -export interface Position { +export type Position = "before" | "after" | "start" | "end"; + +export interface PositionModifier { type: "position"; position: "before" | "after" | "start" | "end"; } @@ -185,7 +187,7 @@ export interface PartialPrimitiveTarget { export type PipelineStageDescriptor = | Mark - | Position + | PositionModifier | SurroundingPairModifier | ContainingScopeModifier | EveryScopeModifier From 224cf58043ae9d2d2ccd6428d9eecf64c864f862 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 14 May 2022 11:59:26 +0200 Subject: [PATCH 013/314] Added document stage --- .../pipelineStages/ContainingScopeStage.ts | 103 ++++++------------ .../pipelineStages/DocumentStage.ts | 19 ++++ .../pipelineStages/TokenStage.ts | 2 +- .../pipelineStages/getPipelineStage.ts | 45 +++++++- 4 files changed, 94 insertions(+), 75 deletions(-) create mode 100644 src/processTargets/pipelineStages/DocumentStage.ts diff --git a/src/processTargets/pipelineStages/ContainingScopeStage.ts b/src/processTargets/pipelineStages/ContainingScopeStage.ts index bbdd28240f..7377eb0b54 100644 --- a/src/processTargets/pipelineStages/ContainingScopeStage.ts +++ b/src/processTargets/pipelineStages/ContainingScopeStage.ts @@ -1,85 +1,46 @@ -import { Location } from "vscode"; +import { Location, Selection } from "vscode"; import { SyntaxNode } from "web-tree-sitter"; import { getNodeMatcher } from "../../languages/getNodeMatcher"; -import { - ContainingScopeModifier, - SurroundingPairModifier, -} from "../../typings/target.types"; -import { - ProcessedTargetsContext, - SelectionWithEditor, - TypedSelection, -} from "../../typings/Types"; -import { - SelectionWithEditorWithContext, - findNearestContainingAncestorNode, -} from "../modifiers/processModifier"; +import { ContainingScopeModifier } from "../../typings/target.types"; +import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import { findNearestContainingAncestorNode } from "../modifiers/processModifier"; import PipelineStage from "./PipelineStage"; -import TokenStage from "./TokenStage"; export default class implements PipelineStage { run( context: ProcessedTargetsContext, stage: ContainingScopeModifier, selection: TypedSelection - ): TypedSelection { - switch (stage.scopeType) { - case "token": - // TODO better solution? - return new TokenStage().run(context, stage, selection); - // return processToken(target, selection, selectionContext); - case "notebookCell": - // return processNotebookCell(target, selection, selectionContext); - case "document": - // return processDocument(target, selection, selectionContext); - case "line": - // return processLine(target, selection, selectionContext); - case "paragraph": - // return processParagraph(target, selection, selectionContext); - case "nonWhitespaceSequence": - // return processRegexDefinedScope( - // /\S+/g, - // target, - // selection, - // selectionContext - // ); - case "url": - // return processRegexDefinedScope( - // URL_REGEX, - // target, - // selection, - // selectionContext - // ); + ): TypedSelection[] { + const nodeMatcher = getNodeMatcher( + selection.editor.document.languageId, + stage.scopeType, + stage.includeSiblings ?? false + ); + const node: SyntaxNode | null = context.getNodeAtLocation( + new Location(selection.editor.document.uri, selection.contentRange.start) + ); - default: - syntaxBased(context); - } - } -} + const result = findNearestContainingAncestorNode(node, nodeMatcher, { + editor: selection.editor, + selection: new Selection( + selection.contentRange.start, + selection.contentRange.end + ), + }); -function syntaxBased( - context: ProcessedTargetsContext, - selection: SelectionWithEditor, - modifier: ContainingScopeModifier -): SelectionWithEditorWithContext[] | null { - const nodeMatcher = getNodeMatcher( - selection.editor.document.languageId, - modifier.scopeType, - modifier.includeSiblings ?? false - ); - const node: SyntaxNode | null = context.getNodeAtLocation( - new Location(selection.editor.document.uri, selection.selection) - ); - - const result = findNearestContainingAncestorNode( - node, - nodeMatcher, - selection - ); + if (result == null) { + throw new Error(`Couldn't find containing ${stage.scopeType}`); + } - if (result == null) { - throw new Error(`Couldn't find containing ${modifier.scopeType}`); + return result.map((selection) => ({ + editor: selection.selection.editor, + contentRange: selection.selection.selection, + delimiter: selection.context.containingListDelimiter ?? undefined, + leadingDelimiterRange: + selection.context.leadingDelimiterRange ?? undefined, + trailingDelimiterRange: + selection.context.trailingDelimiterRange ?? undefined, + })); } - - return result; } diff --git a/src/processTargets/pipelineStages/DocumentStage.ts b/src/processTargets/pipelineStages/DocumentStage.ts new file mode 100644 index 0000000000..4b91f50cb2 --- /dev/null +++ b/src/processTargets/pipelineStages/DocumentStage.ts @@ -0,0 +1,19 @@ +import { ContainingScopeModifier } from "../../typings/target.types"; +import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import { getDocumentRange } from "../../util/range"; +import PipelineStage from "./PipelineStage"; + +export default class implements PipelineStage { + run( + context: ProcessedTargetsContext, + stage: ContainingScopeModifier, + selection: TypedSelection + ): TypedSelection { + return { + editor: selection.editor, + isReversed: selection.isReversed, + delimiter: "\n", + contentRange: getDocumentRange(selection.editor.document), + }; + } +} diff --git a/src/processTargets/pipelineStages/TokenStage.ts b/src/processTargets/pipelineStages/TokenStage.ts index 08b182c6df..2a3aa9f13e 100644 --- a/src/processTargets/pipelineStages/TokenStage.ts +++ b/src/processTargets/pipelineStages/TokenStage.ts @@ -1,5 +1,5 @@ import { Range } from "vscode"; -import { ContainingScopeModifier, Position } from "../../typings/target.types"; +import { ContainingScopeModifier } from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; import PipelineStage from "./PipelineStage"; diff --git a/src/processTargets/pipelineStages/getPipelineStage.ts b/src/processTargets/pipelineStages/getPipelineStage.ts index e2504fb027..d77efe3989 100644 --- a/src/processTargets/pipelineStages/getPipelineStage.ts +++ b/src/processTargets/pipelineStages/getPipelineStage.ts @@ -1,9 +1,13 @@ -import { PipelineStageDescriptor } from "../../typings/target.types"; +import { + ContainingScopeModifier, + PipelineStageDescriptor, +} from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; import ContainingScopeStage from "./ContainingScopeStage"; import CursorStage from "./CursorStage"; import CursorTokenStage from "./CursorTokenStage"; import DecoratedSymbolStage from "./DecoratedSymbolStage"; +import DocumentStage from "./DocumentStage"; import { HeadStage, TailStage } from "./HeadTailStage"; import LineNumberStage from "./LineNumberStage"; import NothingStage from "./NothingStage"; @@ -14,6 +18,7 @@ import SourceStage from "./SourceStage"; import SubPieceStage from "./SubPieceStage"; import SurroundingPairStage from "./SurroundingPairStage"; import ThatStage from "./ThatStage"; +import TokenStage from "./TokenStage"; export default (stageDescriptor: PipelineStageDescriptor) => { const stage = getStage(stageDescriptor); @@ -60,9 +65,9 @@ const getStage = (stageDescriptor: PipelineStageDescriptor): PipelineStage => { case "subpiece": return new SubPieceStage(); case "surroundingPair": - return SurroundingPairStage(); + return new SurroundingPairStage(); case "containingScope": - return new ContainingScopeStage(); + return getContainingScopeStage(stageDescriptor); // case "everyScope": default: @@ -70,3 +75,37 @@ const getStage = (stageDescriptor: PipelineStageDescriptor): PipelineStage => { const _neverCheck: never = stageDescriptor.type; } }; + +const getContainingScopeStage = ( + stage: ContainingScopeModifier +): PipelineStage => { + switch (stage.scopeType) { + case "token": + return new TokenStage(); + case "notebookCell": + // return processNotebookCell(target, selection, selectionContext); + case "document": + return new DocumentStage(); + case "line": + // return processLine(target, selection, selectionContext); + case "paragraph": + // return processParagraph(target, selection, selectionContext); + case "nonWhitespaceSequence": + // return processRegexDefinedScope( + // /\S+/g, + // target, + // selection, + // selectionContext + // ); + case "url": + // return processRegexDefinedScope( + // URL_REGEX, + // target, + // selection, + // selectionContext + // ); + + default: + syntaxBased(context); + } +}; From dcd52289bd4465552b477ddb0c0ad40f1eff1dd9 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 14 May 2022 12:21:01 +0200 Subject: [PATCH 014/314] Added line stage --- .../pipelineStages/ContainingScopeStage.ts | 1 + .../pipelineStages/LineStage.ts | 54 +++++++++++++++++++ .../pipelineStages/getPipelineStage.ts | 3 +- src/typings/Types.ts | 5 ++ 4 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 src/processTargets/pipelineStages/LineStage.ts diff --git a/src/processTargets/pipelineStages/ContainingScopeStage.ts b/src/processTargets/pipelineStages/ContainingScopeStage.ts index 7377eb0b54..1cc8551cc9 100644 --- a/src/processTargets/pipelineStages/ContainingScopeStage.ts +++ b/src/processTargets/pipelineStages/ContainingScopeStage.ts @@ -36,6 +36,7 @@ export default class implements PipelineStage { return result.map((selection) => ({ editor: selection.selection.editor, contentRange: selection.selection.selection, + removalRange: selection.context.outerSelection ?? undefined, delimiter: selection.context.containingListDelimiter ?? undefined, leadingDelimiterRange: selection.context.leadingDelimiterRange ?? undefined, diff --git a/src/processTargets/pipelineStages/LineStage.ts b/src/processTargets/pipelineStages/LineStage.ts new file mode 100644 index 0000000000..1902c77218 --- /dev/null +++ b/src/processTargets/pipelineStages/LineStage.ts @@ -0,0 +1,54 @@ +import { Position, Range } from "vscode"; +import { ContainingScopeModifier } from "../../typings/target.types"; +import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import PipelineStage from "./PipelineStage"; + +export default class implements PipelineStage { + run( + context: ProcessedTargetsContext, + stage: ContainingScopeModifier, + selection: TypedSelection + ): TypedSelection { + const { document } = selection.editor; + const startLine = document.lineAt(selection.contentRange.start); + const endLine = document.lineAt(selection.contentRange.end); + const start = new Position( + startLine.lineNumber, + startLine.firstNonWhitespaceCharacterIndex + ); + const end = endLine.range.end; + + return { + editor: selection.editor, + isReversed: selection.isReversed, + delimiter: "\n", + contentRange: new Range(start, end), + ...getLineContext(selection), + }; + } +} + +function getLineContext(selection: TypedSelection) { + const { document } = selection.editor; + const { start, end } = selection.contentRange; + + const removalRange = new Range( + new Position(start.line, 0), + selection.editor.document.lineAt(end).range.end + ); + + const leadingDelimiterRange = + start.line > 0 + ? new Range(document.lineAt(start.line - 1).range.end, removalRange.start) + : undefined; + const trailingDelimiterRange = + end.line + 1 < document.lineCount + ? new Range(removalRange.end, new Position(end.line + 1, 0)) + : undefined; + + return { + leadingDelimiterRange, + trailingDelimiterRange, + removalRange, + }; +} diff --git a/src/processTargets/pipelineStages/getPipelineStage.ts b/src/processTargets/pipelineStages/getPipelineStage.ts index d77efe3989..23520997e7 100644 --- a/src/processTargets/pipelineStages/getPipelineStage.ts +++ b/src/processTargets/pipelineStages/getPipelineStage.ts @@ -10,6 +10,7 @@ import DecoratedSymbolStage from "./DecoratedSymbolStage"; import DocumentStage from "./DocumentStage"; import { HeadStage, TailStage } from "./HeadTailStage"; import LineNumberStage from "./LineNumberStage"; +import LineStage from "./LineStage"; import NothingStage from "./NothingStage"; import PipelineStage from "./PipelineStage"; import PositionStage from "./PositionStage"; @@ -87,7 +88,7 @@ const getContainingScopeStage = ( case "document": return new DocumentStage(); case "line": - // return processLine(target, selection, selectionContext); + return new LineStage(); case "paragraph": // return processParagraph(target, selection, selectionContext); case "nonWhitespaceSequence": diff --git a/src/typings/Types.ts b/src/typings/Types.ts index 84205df222..b4305df88d 100644 --- a/src/typings/Types.ts +++ b/src/typings/Types.ts @@ -130,6 +130,11 @@ export interface TypedSelection { */ interiorRange?: vscode.Range; + /** + * The range that needs to be removed + */ + removalRange?: vscode.Range; + /** * The range of the delimiter before the content selection */ From b04697162d8414f73f6edc92a464d50f0d75f9f5 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 14 May 2022 12:39:39 +0200 Subject: [PATCH 015/314] Added paragraph stage --- .../pipelineStages/LineStage.ts | 47 ++++---- .../pipelineStages/ParagraphStage.ts | 108 ++++++++++++++++++ .../pipelineStages/getPipelineStage.ts | 2 + 3 files changed, 131 insertions(+), 26 deletions(-) create mode 100644 src/processTargets/pipelineStages/ParagraphStage.ts diff --git a/src/processTargets/pipelineStages/LineStage.ts b/src/processTargets/pipelineStages/LineStage.ts index 1902c77218..e5e9625a94 100644 --- a/src/processTargets/pipelineStages/LineStage.ts +++ b/src/processTargets/pipelineStages/LineStage.ts @@ -10,6 +10,7 @@ export default class implements PipelineStage { selection: TypedSelection ): TypedSelection { const { document } = selection.editor; + const startLine = document.lineAt(selection.contentRange.start); const endLine = document.lineAt(selection.contentRange.end); const start = new Position( @@ -18,37 +19,31 @@ export default class implements PipelineStage { ); const end = endLine.range.end; + const removalRange = new Range( + new Position(start.line, 0), + selection.editor.document.lineAt(end).range.end + ); + + const leadingDelimiterRange = + start.line > 0 + ? new Range( + document.lineAt(start.line - 1).range.end, + removalRange.start + ) + : undefined; + const trailingDelimiterRange = + end.line + 1 < document.lineCount + ? new Range(removalRange.end, new Position(end.line + 1, 0)) + : undefined; + return { editor: selection.editor, isReversed: selection.isReversed, delimiter: "\n", contentRange: new Range(start, end), - ...getLineContext(selection), + removalRange, + leadingDelimiterRange, + trailingDelimiterRange, }; } } - -function getLineContext(selection: TypedSelection) { - const { document } = selection.editor; - const { start, end } = selection.contentRange; - - const removalRange = new Range( - new Position(start.line, 0), - selection.editor.document.lineAt(end).range.end - ); - - const leadingDelimiterRange = - start.line > 0 - ? new Range(document.lineAt(start.line - 1).range.end, removalRange.start) - : undefined; - const trailingDelimiterRange = - end.line + 1 < document.lineCount - ? new Range(removalRange.end, new Position(end.line + 1, 0)) - : undefined; - - return { - leadingDelimiterRange, - trailingDelimiterRange, - removalRange, - }; -} diff --git a/src/processTargets/pipelineStages/ParagraphStage.ts b/src/processTargets/pipelineStages/ParagraphStage.ts new file mode 100644 index 0000000000..e5c0633a7c --- /dev/null +++ b/src/processTargets/pipelineStages/ParagraphStage.ts @@ -0,0 +1,108 @@ +import { Position, Range, TextDocument } from "vscode"; +import { ContainingScopeModifier } from "../../typings/target.types"; +import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import PipelineStage from "./PipelineStage"; + +export default class implements PipelineStage { + run( + context: ProcessedTargetsContext, + stage: ContainingScopeModifier, + selection: TypedSelection + ): TypedSelection { + const { document } = selection.editor; + + let startLine = document.lineAt(selection.contentRange.start); + if (!startLine.isEmptyOrWhitespace) { + while (startLine.lineNumber > 0) { + const line = document.lineAt(startLine.lineNumber - 1); + if (line.isEmptyOrWhitespace) { + break; + } + startLine = line; + } + } + const lineCount = document.lineCount; + let endLine = document.lineAt(selection.contentRange.end); + if (!endLine.isEmptyOrWhitespace) { + while (endLine.lineNumber + 1 < lineCount) { + const line = document.lineAt(endLine.lineNumber + 1); + if (line.isEmptyOrWhitespace) { + break; + } + endLine = line; + } + } + + const start = new Position( + startLine.lineNumber, + startLine.firstNonWhitespaceCharacterIndex + ); + const end = endLine.range.end; + + const removalRange = new Range( + new Position(start.line, 0), + selection.editor.document.lineAt(end).range.end + ); + + const leadingLine = getPreviousNonEmptyLine(document, start.line); + const trailingLine = getNextNonEmptyLine(document, end.line); + + const leadingDelimiterStart = + leadingLine != null + ? leadingLine.range.end + : start.line > 0 + ? new Position(0, 0) + : undefined; + const trailingDelimiterEnd = + trailingLine != null + ? trailingLine.range.start + : end.line < document.lineCount - 1 + ? document.lineAt(document.lineCount - 1).range.end + : undefined; + const leadingDelimiterRange = + leadingDelimiterStart != null + ? new Range(leadingDelimiterStart, removalRange.start) + : undefined; + const trailingDelimiterRange = + trailingDelimiterEnd != null + ? new Range(removalRange.end, trailingDelimiterEnd) + : undefined; + + return { + editor: selection.editor, + isReversed: selection.isReversed, + delimiter: "\n\n", + contentRange: new Range(start, end), + removalRange, + leadingDelimiterRange, + trailingDelimiterRange, + }; + } +} + +function getPreviousNonEmptyLine( + document: TextDocument, + startLineNumber: number +) { + let line = document.lineAt(startLineNumber); + while (line.lineNumber > 0) { + const previousLine = document.lineAt(line.lineNumber - 1); + if (!previousLine.isEmptyOrWhitespace) { + return previousLine; + } + line = previousLine; + } + return null; +} + +function getNextNonEmptyLine(document: TextDocument, startLineNumber: number) { + let line = document.lineAt(startLineNumber); + while (line.lineNumber + 1 < document.lineCount) { + const nextLine = document.lineAt(line.lineNumber + 1); + if (!nextLine.isEmptyOrWhitespace) { + return nextLine; + } + line = nextLine; + } + return null; +} diff --git a/src/processTargets/pipelineStages/getPipelineStage.ts b/src/processTargets/pipelineStages/getPipelineStage.ts index 23520997e7..6ed9bc8f39 100644 --- a/src/processTargets/pipelineStages/getPipelineStage.ts +++ b/src/processTargets/pipelineStages/getPipelineStage.ts @@ -12,6 +12,7 @@ import { HeadStage, TailStage } from "./HeadTailStage"; import LineNumberStage from "./LineNumberStage"; import LineStage from "./LineStage"; import NothingStage from "./NothingStage"; +import ParagraphStage from "./ParagraphStage"; import PipelineStage from "./PipelineStage"; import PositionStage from "./PositionStage"; import RawSelectionStage from "./RawSelectionStage"; @@ -90,6 +91,7 @@ const getContainingScopeStage = ( case "line": return new LineStage(); case "paragraph": + return new ParagraphStage(); // return processParagraph(target, selection, selectionContext); case "nonWhitespaceSequence": // return processRegexDefinedScope( From a2fc653d08cf6246ffa25ac0719ab40b7fda4ca8 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 14 May 2022 13:02:35 +0200 Subject: [PATCH 016/314] Added regex stages --- .../pipelineStages/RegexStage.ts | 67 ++++++++++++++ .../pipelineStages/TokenStage.ts | 88 +++++++++---------- .../pipelineStages/getPipelineStage.ts | 17 +--- 3 files changed, 114 insertions(+), 58 deletions(-) create mode 100644 src/processTargets/pipelineStages/RegexStage.ts diff --git a/src/processTargets/pipelineStages/RegexStage.ts b/src/processTargets/pipelineStages/RegexStage.ts new file mode 100644 index 0000000000..f6b55dfff8 --- /dev/null +++ b/src/processTargets/pipelineStages/RegexStage.ts @@ -0,0 +1,67 @@ +import { Position, Range } from "vscode"; +import { ContainingScopeModifier } from "../../typings/target.types"; +import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import TokenStage from "./TokenStage"; + +class RegexStage extends TokenStage { + constructor(private regex: RegExp, private name?: string) { + super(); + } + + run( + context: ProcessedTargetsContext, + stage: ContainingScopeModifier, + selection: TypedSelection + ): TypedSelection { + const getMatch = (position: Position) => { + const line = selection.editor.document.lineAt(position); + const result = [...line.text.matchAll(this.regex)] + .map( + (match) => + new Range( + position.line, + match.index!, + position.line, + match.index! + match[0].length + ) + ) + .find((range) => range.contains(position)); + if (result == null) { + if (this.name) { + throw new Error(`Couldn't find containing ${this.name}`); + } else { + throw new Error( + `Cannot find sequence defined by regex: ${this.regex}` + ); + } + } + return result; + }; + + const start = getMatch(selection.contentRange.start).start; + const end = getMatch(selection.contentRange.end).end; + const contentRange = new Range(start, end); + + return { + ...selection, + contentRange, + ...this.getDelimiterRanges(selection.editor, contentRange), + }; + } +} + +export class NonWhitespaceSequenceStage extends RegexStage { + constructor() { + super(/\S+/g, "Non whitespace sequence"); + } +} + +// taken from https://regexr.com/3e6m0 +const URL_REGEX = + /(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/g; + +export class UrlStage extends RegexStage { + constructor() { + super(URL_REGEX, "URL"); + } +} diff --git a/src/processTargets/pipelineStages/TokenStage.ts b/src/processTargets/pipelineStages/TokenStage.ts index 2a3aa9f13e..9eba93bf62 100644 --- a/src/processTargets/pipelineStages/TokenStage.ts +++ b/src/processTargets/pipelineStages/TokenStage.ts @@ -1,4 +1,4 @@ -import { Range } from "vscode"; +import { Range, TextEditor } from "vscode"; import { ContainingScopeModifier } from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; import PipelineStage from "./PipelineStage"; @@ -11,54 +11,54 @@ export default class implements PipelineStage { ): TypedSelection { return { ...selection, - delimiter: " ", - ...getDelimiterRanges(selection), + ...this.getDelimiterRanges(selection.editor, selection.contentRange), }; } -} -function getDelimiterRanges(selection: TypedSelection) { - const document = selection.editor.document; - const { start, end } = selection.contentRange; - const endLine = document.lineAt(end); - let leadingDelimiterRange, trailingDelimiterRange; + getDelimiterRanges(editor: TextEditor, range: Range) { + const document = editor.document; + const { start, end } = range; + const endLine = document.lineAt(end); + let leadingDelimiterRange, trailingDelimiterRange; - const startLine = document.lineAt(start); - const leadingText = startLine.text.slice(0, start.character); - const leadingDelimiters = leadingText.match(/\s+$/); - leadingDelimiterRange = - leadingDelimiters != null - ? new Range( - start.line, - start.character - leadingDelimiters[0].length, - start.line, - start.character - ) - : undefined; + const startLine = document.lineAt(start); + const leadingText = startLine.text.slice(0, start.character); + const leadingDelimiters = leadingText.match(/\s+$/); + leadingDelimiterRange = + leadingDelimiters != null + ? new Range( + start.line, + start.character - leadingDelimiters[0].length, + start.line, + start.character + ) + : undefined; - const trailingText = endLine.text.slice(end.character); - const trailingDelimiters = trailingText.match(/^\s+/); - trailingDelimiterRange = - trailingDelimiters != null - ? new Range( - end.line, - end.character, - end.line, - end.character + trailingDelimiters[0].length - ) - : undefined; + const trailingText = endLine.text.slice(end.character); + const trailingDelimiters = trailingText.match(/^\s+/); + trailingDelimiterRange = + trailingDelimiters != null + ? new Range( + end.line, + end.character, + end.line, + end.character + trailingDelimiters[0].length + ) + : undefined; - const isInDelimitedList = - (leadingDelimiterRange != null || trailingDelimiterRange != null) && - (leadingDelimiterRange != null || start.character === 0) && - (trailingDelimiterRange != null || end.isEqual(endLine.range.end)); + const isInDelimitedList = + (leadingDelimiterRange != null || trailingDelimiterRange != null) && + (leadingDelimiterRange != null || start.character === 0) && + (trailingDelimiterRange != null || end.isEqual(endLine.range.end)); - return { - leadingDelimiterRange: isInDelimitedList - ? leadingDelimiterRange - : undefined, - trailingDelimiterRange: isInDelimitedList - ? trailingDelimiterRange - : undefined, - }; + return { + delimiter: " ", + leadingDelimiterRange: isInDelimitedList + ? leadingDelimiterRange + : undefined, + trailingDelimiterRange: isInDelimitedList + ? trailingDelimiterRange + : undefined, + }; + } } diff --git a/src/processTargets/pipelineStages/getPipelineStage.ts b/src/processTargets/pipelineStages/getPipelineStage.ts index 6ed9bc8f39..282ff201b9 100644 --- a/src/processTargets/pipelineStages/getPipelineStage.ts +++ b/src/processTargets/pipelineStages/getPipelineStage.ts @@ -3,7 +3,6 @@ import { PipelineStageDescriptor, } from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; -import ContainingScopeStage from "./ContainingScopeStage"; import CursorStage from "./CursorStage"; import CursorTokenStage from "./CursorTokenStage"; import DecoratedSymbolStage from "./DecoratedSymbolStage"; @@ -16,6 +15,7 @@ import ParagraphStage from "./ParagraphStage"; import PipelineStage from "./PipelineStage"; import PositionStage from "./PositionStage"; import RawSelectionStage from "./RawSelectionStage"; +import { NonWhitespaceSequenceStage, UrlStage } from "./RegexStage"; import SourceStage from "./SourceStage"; import SubPieceStage from "./SubPieceStage"; import SurroundingPairStage from "./SurroundingPairStage"; @@ -92,21 +92,10 @@ const getContainingScopeStage = ( return new LineStage(); case "paragraph": return new ParagraphStage(); - // return processParagraph(target, selection, selectionContext); case "nonWhitespaceSequence": - // return processRegexDefinedScope( - // /\S+/g, - // target, - // selection, - // selectionContext - // ); + return new NonWhitespaceSequenceStage(); case "url": - // return processRegexDefinedScope( - // URL_REGEX, - // target, - // selection, - // selectionContext - // ); + return new UrlStage(); default: syntaxBased(context); From cf0176980eff83bcdb84c0546db82ffdc7c7f736 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 14 May 2022 13:25:33 +0200 Subject: [PATCH 017/314] Cleanup --- .../modifiers/processModifier.ts | 266 ----------- .../pipelineStages/ContainingScopeStage.ts | 43 +- .../pipelineStages/NotebookCellStage.ts | 16 + .../pipelineStages/SurroundingPairStage.ts | 6 +- .../pipelineStages/getPipelineStage.ts | 16 +- src/processTargets/processSelectionType.ts | 431 ------------------ .../surroundingPair/delimiterMaps.ts | 2 +- ...ractSelectionFromSurroundingPairOffsets.ts | 4 +- .../findDelimiterPairAdjacentToSelection.ts | 0 .../findDelimiterPairContainingSelection.ts | 2 +- .../surroundingPair/findOppositeDelimiter.ts | 2 +- .../findSurroundingPairCore.ts | 2 +- .../findSurroundingPairParseTreeBased.ts | 6 +- .../findSurroundingPairTextBased.ts | 6 +- .../generateUnmatchedDelimiters.ts | 2 +- .../getIndividualDelimiters.ts | 4 +- .../getSurroundingPairOffsets.ts | 0 .../{modifiers => }/surroundingPair/index.ts | 22 +- .../{modifiers => }/surroundingPair/types.ts | 2 +- src/typings/Types.ts | 28 +- src/typings/target.types.ts | 2 - 21 files changed, 110 insertions(+), 752 deletions(-) delete mode 100644 src/processTargets/modifiers/processModifier.ts create mode 100644 src/processTargets/pipelineStages/NotebookCellStage.ts delete mode 100644 src/processTargets/processSelectionType.ts rename src/processTargets/{modifiers => }/surroundingPair/delimiterMaps.ts (96%) rename src/processTargets/{modifiers => }/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts (94%) rename src/processTargets/{modifiers => }/surroundingPair/findDelimiterPairAdjacentToSelection.ts (100%) rename src/processTargets/{modifiers => }/surroundingPair/findDelimiterPairContainingSelection.ts (98%) rename src/processTargets/{modifiers => }/surroundingPair/findOppositeDelimiter.ts (96%) rename src/processTargets/{modifiers => }/surroundingPair/findSurroundingPairCore.ts (97%) rename src/processTargets/{modifiers => }/surroundingPair/findSurroundingPairParseTreeBased.ts (98%) rename src/processTargets/{modifiers => }/surroundingPair/findSurroundingPairTextBased.ts (98%) rename src/processTargets/{modifiers => }/surroundingPair/generateUnmatchedDelimiters.ts (98%) rename src/processTargets/{modifiers => }/surroundingPair/getIndividualDelimiters.ts (92%) rename src/processTargets/{modifiers => }/surroundingPair/getSurroundingPairOffsets.ts (100%) rename src/processTargets/{modifiers => }/surroundingPair/index.ts (94%) rename src/processTargets/{modifiers => }/surroundingPair/types.ts (95%) diff --git a/src/processTargets/modifiers/processModifier.ts b/src/processTargets/modifiers/processModifier.ts deleted file mode 100644 index d5d1932c2d..0000000000 --- a/src/processTargets/modifiers/processModifier.ts +++ /dev/null @@ -1,266 +0,0 @@ -import update from "immutability-helper"; -import { range } from "lodash"; -import { Location, Position, Range, Selection } from "vscode"; -import { SyntaxNode } from "web-tree-sitter"; -import { SUBWORD_MATCHER } from "../../core/constants"; -import { selectionWithEditorFromRange } from "../../util/selectionUtils"; -import { - NodeMatcher, - ProcessedTargetsContext, - SelectionContext, - SelectionWithEditor, -} from "../../typings/Types"; -import { - ContainingScopeModifier, - HeadModifier, - PrimitiveTarget, - SubTokenModifier, - TailModifier, -} from "../../typings/target.types"; -import { processSurroundingPair } from "./surroundingPair"; -import { getNodeMatcher } from "../../languages/getNodeMatcher"; - -export type SelectionWithEditorWithContext = { - selection: SelectionWithEditor; - context: SelectionContext; -}; - -/** - * Processes a single modifier in the {@link processTargets} pipeline. - * @param context Context created in {@link CommandRunner#run} - * @param target Target description, including information about the modifier - * to apply - * @param selection Selection to apply the modifier to, as output by previous - * stages of pipeline, such as the mark. - * @returns Modified selection including additional rich context information - */ -export default function ( - context: ProcessedTargetsContext, - target: PrimitiveTarget, - selection: SelectionWithEditor -): SelectionWithEditorWithContext[] { - const { modifier } = target; - let result; - - switch (modifier.type) { - case "identity": - result = [{ selection, context: {} }]; - break; - - case "containingScope": - result = processScopeType(context, selection, modifier); - break; - - case "subpiece": - result = processSubToken(context, selection, modifier); - break; - - case "head": - case "tail": - result = processHeadTail(context, selection, modifier); - break; - - case "surroundingPair": - result = processSurroundingPair(context, selection, modifier); - break; - - case "toRawSelection": - result = processRawSelectionModifier(context, selection); - break; - - default: - // Make sure we haven't missed any cases - const _neverCheck: never = modifier; - } - - if (result == null) { - throw new Error(`Couldn't find containing`); - } - - return result; -} - -function processScopeType( - context: ProcessedTargetsContext, - selection: SelectionWithEditor, - modifier: ContainingScopeModifier -): SelectionWithEditorWithContext[] | null { - const nodeMatcher = getNodeMatcher( - selection.editor.document.languageId, - modifier.scopeType, - modifier.includeSiblings ?? false - ); - const node: SyntaxNode | null = context.getNodeAtLocation( - new Location(selection.editor.document.uri, selection.selection) - ); - - const result = findNearestContainingAncestorNode( - node, - nodeMatcher, - selection - ); - - if (result == null) { - throw new Error(`Couldn't find containing ${modifier.scopeType}`); - } - - return result; -} - -function processSubToken( - context: ProcessedTargetsContext, - selection: SelectionWithEditor, - modifier: SubTokenModifier -): SelectionWithEditorWithContext[] | null { - const token = selection.editor.document.getText(selection.selection); - let pieces: { start: number; end: number }[] = []; - - if (modifier.excludeActive || modifier.excludeAnchor) { - throw new Error("Subtoken exclusions unsupported"); - } - - if (modifier.pieceType === "word") { - pieces = [...token.matchAll(SUBWORD_MATCHER)].map((match) => ({ - start: match.index!, - end: match.index! + match[0].length, - })); - } else if (modifier.pieceType === "character") { - pieces = range(token.length).map((index) => ({ - start: index, - end: index + 1, - })); - } - - const anchorIndex = - modifier.anchor < 0 ? modifier.anchor + pieces.length : modifier.anchor; - const activeIndex = - modifier.active < 0 ? modifier.active + pieces.length : modifier.active; - - if ( - anchorIndex < 0 || - activeIndex < 0 || - anchorIndex >= pieces.length || - activeIndex >= pieces.length - ) { - throw new Error("Subtoken index out of range"); - } - - const isReversed = activeIndex < anchorIndex; - - const anchor = selection.selection.start.translate( - undefined, - isReversed ? pieces[anchorIndex].end : pieces[anchorIndex].start - ); - const active = selection.selection.start.translate( - undefined, - isReversed ? pieces[activeIndex].start : pieces[activeIndex].end - ); - - const startIndex = Math.min(anchorIndex, activeIndex); - const endIndex = Math.max(anchorIndex, activeIndex); - const leadingDelimiterRange = - startIndex > 0 && pieces[startIndex - 1].end < pieces[startIndex].start - ? new Range( - selection.selection.start.translate({ - characterDelta: pieces[startIndex - 1].end, - }), - selection.selection.start.translate({ - characterDelta: pieces[startIndex].start, - }) - ) - : null; - const trailingDelimiterRange = - endIndex + 1 < pieces.length && - pieces[endIndex].end < pieces[endIndex + 1].start - ? new Range( - selection.selection.start.translate({ - characterDelta: pieces[endIndex].end, - }), - selection.selection.start.translate({ - characterDelta: pieces[endIndex + 1].start, - }) - ) - : null; - const isInDelimitedList = - leadingDelimiterRange != null || trailingDelimiterRange != null; - const containingListDelimiter = isInDelimitedList - ? selection.editor.document.getText( - (leadingDelimiterRange ?? trailingDelimiterRange)! - ) - : null; - - return [ - { - selection: update(selection, { - selection: () => new Selection(anchor, active), - }), - context: { - isInDelimitedList, - containingListDelimiter: containingListDelimiter ?? undefined, - leadingDelimiterRange, - trailingDelimiterRange, - }, - }, - ]; -} - -function processHeadTail( - context: ProcessedTargetsContext, - selection: SelectionWithEditor, - modifier: HeadModifier | TailModifier -): SelectionWithEditorWithContext[] | null { - let anchor: Position, active: Position; - if (modifier.type === "head") { - anchor = selection.selection.end; - active = new Position(selection.selection.start.line, 0); - } else { - anchor = selection.selection.start; - active = selection.editor.document.lineAt(selection.selection.end).range - .end; - } - return [ - { - selection: update(selection, { - selection: () => new Selection(anchor, active), - }), - context: {}, - }, - ]; -} - -export function findNearestContainingAncestorNode( - startNode: SyntaxNode, - nodeMatcher: NodeMatcher, - selection: SelectionWithEditor -) { - let node: SyntaxNode | null = startNode; - while (node != null) { - const matches = nodeMatcher(selection, node); - if (matches != null) { - return matches - .map((match) => match.selection) - .map((matchedSelection) => ({ - selection: selectionWithEditorFromRange( - selection, - matchedSelection.selection - ), - context: matchedSelection.context, - })); - } - node = node.parent; - } - - return null; -} - -function processRawSelectionModifier( - context: ProcessedTargetsContext, - selection: SelectionWithEditor -): SelectionWithEditorWithContext[] | null { - return [ - { - selection, - context: { isRawSelection: true }, - }, - ]; -} diff --git a/src/processTargets/pipelineStages/ContainingScopeStage.ts b/src/processTargets/pipelineStages/ContainingScopeStage.ts index 1cc8551cc9..f1f97f4b3e 100644 --- a/src/processTargets/pipelineStages/ContainingScopeStage.ts +++ b/src/processTargets/pipelineStages/ContainingScopeStage.ts @@ -1,21 +1,29 @@ import { Location, Selection } from "vscode"; import { SyntaxNode } from "web-tree-sitter"; import { getNodeMatcher } from "../../languages/getNodeMatcher"; -import { ContainingScopeModifier } from "../../typings/target.types"; -import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; -import { findNearestContainingAncestorNode } from "../modifiers/processModifier"; +import { + ContainingScopeModifier, + EveryScopeModifier, +} from "../../typings/target.types"; +import { + NodeMatcher, + ProcessedTargetsContext, + SelectionWithEditor, + TypedSelection, +} from "../../typings/Types"; +import { selectionWithEditorFromRange } from "../../util/selectionUtils"; import PipelineStage from "./PipelineStage"; export default class implements PipelineStage { run( context: ProcessedTargetsContext, - stage: ContainingScopeModifier, + stage: ContainingScopeModifier | EveryScopeModifier, selection: TypedSelection ): TypedSelection[] { const nodeMatcher = getNodeMatcher( selection.editor.document.languageId, stage.scopeType, - stage.includeSiblings ?? false + stage.type === "everyScope" ); const node: SyntaxNode | null = context.getNodeAtLocation( new Location(selection.editor.document.uri, selection.contentRange.start) @@ -45,3 +53,28 @@ export default class implements PipelineStage { })); } } + +export function findNearestContainingAncestorNode( + startNode: SyntaxNode, + nodeMatcher: NodeMatcher, + selection: SelectionWithEditor +) { + let node: SyntaxNode | null = startNode; + while (node != null) { + const matches = nodeMatcher(selection, node); + if (matches != null) { + return matches + .map((match) => match.selection) + .map((matchedSelection) => ({ + selection: selectionWithEditorFromRange( + selection, + matchedSelection.selection + ), + context: matchedSelection.context, + })); + } + node = node.parent; + } + + return null; +} diff --git a/src/processTargets/pipelineStages/NotebookCellStage.ts b/src/processTargets/pipelineStages/NotebookCellStage.ts new file mode 100644 index 0000000000..7c3a2652e8 --- /dev/null +++ b/src/processTargets/pipelineStages/NotebookCellStage.ts @@ -0,0 +1,16 @@ +import { ContainingScopeModifier } from "../../typings/target.types"; +import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import PipelineStage from "./PipelineStage"; + +export default class implements PipelineStage { + run( + context: ProcessedTargetsContext, + stage: ContainingScopeModifier, + selection: TypedSelection + ): TypedSelection { + return { + ...selection, + isNotebookCell: true, + }; + } +} diff --git a/src/processTargets/pipelineStages/SurroundingPairStage.ts b/src/processTargets/pipelineStages/SurroundingPairStage.ts index b920c190d6..11739fc885 100644 --- a/src/processTargets/pipelineStages/SurroundingPairStage.ts +++ b/src/processTargets/pipelineStages/SurroundingPairStage.ts @@ -9,9 +9,9 @@ import { SurroundingPairModifier, } from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; -import { complexDelimiterMap } from "../modifiers/surroundingPair/delimiterMaps"; -import { findSurroundingPairParseTreeBased } from "../modifiers/surroundingPair/findSurroundingPairParseTreeBased"; -import { findSurroundingPairTextBased } from "../modifiers/surroundingPair/findSurroundingPairTextBased"; +import { complexDelimiterMap } from "../surroundingPair/delimiterMaps"; +import { findSurroundingPairParseTreeBased } from "../surroundingPair/findSurroundingPairParseTreeBased"; +import { findSurroundingPairTextBased } from "../surroundingPair/findSurroundingPairTextBased"; import PipelineStage from "./PipelineStage"; /** diff --git a/src/processTargets/pipelineStages/getPipelineStage.ts b/src/processTargets/pipelineStages/getPipelineStage.ts index 282ff201b9..509aa94365 100644 --- a/src/processTargets/pipelineStages/getPipelineStage.ts +++ b/src/processTargets/pipelineStages/getPipelineStage.ts @@ -1,8 +1,10 @@ import { ContainingScopeModifier, + EveryScopeModifier, PipelineStageDescriptor, } from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import ContainingScopeStage from "./ContainingScopeStage"; import CursorStage from "./CursorStage"; import CursorTokenStage from "./CursorTokenStage"; import DecoratedSymbolStage from "./DecoratedSymbolStage"; @@ -10,6 +12,7 @@ import DocumentStage from "./DocumentStage"; import { HeadStage, TailStage } from "./HeadTailStage"; import LineNumberStage from "./LineNumberStage"; import LineStage from "./LineStage"; +import NotebookCellStage from "./NotebookCellStage"; import NothingStage from "./NothingStage"; import ParagraphStage from "./ParagraphStage"; import PipelineStage from "./PipelineStage"; @@ -69,23 +72,19 @@ const getStage = (stageDescriptor: PipelineStageDescriptor): PipelineStage => { case "surroundingPair": return new SurroundingPairStage(); case "containingScope": + case "everyScope": return getContainingScopeStage(stageDescriptor); - // case "everyScope": - - default: - // Make sure we haven't missed any cases - const _neverCheck: never = stageDescriptor.type; } }; const getContainingScopeStage = ( - stage: ContainingScopeModifier + stage: ContainingScopeModifier | EveryScopeModifier ): PipelineStage => { switch (stage.scopeType) { case "token": return new TokenStage(); case "notebookCell": - // return processNotebookCell(target, selection, selectionContext); + return new NotebookCellStage(); case "document": return new DocumentStage(); case "line": @@ -96,8 +95,7 @@ const getContainingScopeStage = ( return new NonWhitespaceSequenceStage(); case "url": return new UrlStage(); - default: - syntaxBased(context); + return new ContainingScopeStage(); } }; diff --git a/src/processTargets/processSelectionType.ts b/src/processTargets/processSelectionType.ts deleted file mode 100644 index 8bdca75d1b..0000000000 --- a/src/processTargets/processSelectionType.ts +++ /dev/null @@ -1,431 +0,0 @@ -import { Position, Range, TextDocument } from "vscode"; -import { - selectionFromPositions, - selectionWithEditorFromPositions, - selectionWithEditorFromRange, -} from "../util/selectionUtils"; -import { - ProcessedTargetsContext, - SelectionContext, - SelectionWithEditor, - TypedSelection, -} from "../typings/Types"; -import { - InsideOutsideType, - Modifier, - PrimitiveTarget, - Position as TargetPosition, -} from "../typings/target.types"; -import { getDocumentRange } from "../util/range"; - -// taken from https://regexr.com/3e6m0 -const URL_REGEX = - /(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/g; - -export default function ( - context: ProcessedTargetsContext, - target: PrimitiveTarget, - selection: SelectionWithEditor, - selectionContext: SelectionContext -): TypedSelection { - switch (target.selectionType) { - case "token": - return processToken(target, selection, selectionContext); - case "notebookCell": - return processNotebookCell(target, selection, selectionContext); - case "document": - return processDocument(target, selection, selectionContext); - case "line": - return processLine(target, selection, selectionContext); - case "paragraph": - return processParagraph(target, selection, selectionContext); - case "nonWhitespaceSequence": - return processRegexDefinedScope( - /\S+/g, - target, - selection, - selectionContext - ); - case "url": - return processRegexDefinedScope( - URL_REGEX, - target, - selection, - selectionContext - ); - } -} - -function processNotebookCell( - target: PrimitiveTarget, - selection: SelectionWithEditor, - selectionContext: SelectionContext -): TypedSelection { - const { selectionType, insideOutsideType, position } = target; - return { - selection, - selectionType, - position, - insideOutsideType, - selectionContext: { ...selectionContext, isNotebookCell: true }, - }; -} - -function processToken( - target: PrimitiveTarget, - selection: SelectionWithEditor, - selectionContext: SelectionContext -) { - const { selectionType, insideOutsideType, position, modifier } = target; - return { - selection, - selectionType, - position, - insideOutsideType, - // NB: This is a hack to work around the fact that it's not currently - // possible to apply a modifier after processing the selection type. We - // would really prefer that the user be able to say "just" and have that be - // processed after we've processed the selection type, which would strip - // away the type information and turn it into a raw target. Until that's - // possible using the new pipelines, we instead just check for it here when - // we're doing the selection type and bail out if it is a raw target. - selectionContext: selectionContext.isRawSelection - ? selectionContext - : getTokenSelectionContext( - selection, - modifier, - position, - insideOutsideType, - selectionContext - ), - }; -} - -function processDocument( - target: PrimitiveTarget, - selection: SelectionWithEditor, - selectionContext: SelectionContext -) { - const { selectionType, insideOutsideType, position } = target; - const newSelection = selectionWithEditorFromRange( - selection, - getDocumentRange(selection.editor.document) - ); - - return { - selection: newSelection, - selectionType, - position, - insideOutsideType, - selectionContext, - }; -} - -function processLine( - target: PrimitiveTarget, - selection: SelectionWithEditor, - _selectionContext: SelectionContext -) { - const { selectionType, insideOutsideType, position } = target; - const { document } = selection.editor; - const startLine = document.lineAt(selection.selection.start); - const endLine = document.lineAt(selection.selection.end); - const start = new Position( - startLine.lineNumber, - startLine.firstNonWhitespaceCharacterIndex - ); - const end = endLine.range.end; - - const newSelection = selectionWithEditorFromPositions(selection, start, end); - - return { - selection: newSelection, - selectionType, - position, - insideOutsideType, - selectionContext: getLineSelectionContext(newSelection), - }; -} - -function processParagraph( - target: PrimitiveTarget, - selection: SelectionWithEditor, - _selectionContext: SelectionContext -) { - const { selectionType, insideOutsideType, position } = target; - const { document } = selection.editor; - let startLine = document.lineAt(selection.selection.start); - if (!startLine.isEmptyOrWhitespace) { - while (startLine.lineNumber > 0) { - const line = document.lineAt(startLine.lineNumber - 1); - if (line.isEmptyOrWhitespace) { - break; - } - startLine = line; - } - } - const lineCount = document.lineCount; - let endLine = document.lineAt(selection.selection.end); - if (!endLine.isEmptyOrWhitespace) { - while (endLine.lineNumber + 1 < lineCount) { - const line = document.lineAt(endLine.lineNumber + 1); - if (line.isEmptyOrWhitespace) { - break; - } - endLine = line; - } - } - - const start = new Position( - startLine.lineNumber, - startLine.firstNonWhitespaceCharacterIndex - ); - const end = endLine.range.end; - - const newSelection = selectionWithEditorFromPositions(selection, start, end); - - return { - selection: newSelection, - position, - selectionType, - insideOutsideType, - selectionContext: getParagraphSelectionContext(newSelection), - }; -} - -function processRegexDefinedScope( - regex: RegExp, - target: PrimitiveTarget, - selection: SelectionWithEditor, - selectionContext: SelectionContext -) { - const { selectionType, insideOutsideType, position, modifier } = target; - - const getMatch = (position: Position) => { - const line = selection.editor.document.lineAt(position); - const result = [...line.text.matchAll(regex)] - .map( - (match) => - new Range( - position.line, - match.index!, - position.line, - match.index! + match[0].length - ) - ) - .find((range) => range.contains(position)); - if (result == null) { - throw new Error(`Cannot find sequence defined by regex: ${regex}`); - } - return result; - }; - - const start = getMatch(selection.selection.start).start; - const end = getMatch(selection.selection.end).end; - const newSelection = selectionWithEditorFromPositions(selection, start, end); - - return { - selection: newSelection, - position, - selectionType, - insideOutsideType, - selectionContext: getTokenSelectionContext( - newSelection, - modifier, - position, - insideOutsideType, - selectionContext - ), - }; -} - -function getTokenSelectionContext( - selection: SelectionWithEditor, - modifier: Modifier, - position: TargetPosition, - insideOutsideType: InsideOutsideType, - selectionContext: SelectionContext -): SelectionContext { - if (!isSelectionContextEmpty(selectionContext)) { - return selectionContext; - } - if (modifier.type === "subpiece") { - return selectionContext; - } - - const document = selection.editor.document; - const { start, end } = selection.selection; - const endLine = document.lineAt(end); - let leadingDelimiterRange, trailingDelimiterRange; - - // Positions start/end of has no delimiters - if (position !== "before" || insideOutsideType !== "inside") { - const startLine = document.lineAt(start); - const leadingText = startLine.text.slice(0, start.character); - const leadingDelimiters = leadingText.match(/\s+$/); - leadingDelimiterRange = - leadingDelimiters != null - ? new Range( - start.line, - start.character - leadingDelimiters[0].length, - start.line, - start.character - ) - : null; - } - - if (position !== "after" || insideOutsideType !== "inside") { - const trailingText = endLine.text.slice(end.character); - const trailingDelimiters = trailingText.match(/^\s+/); - trailingDelimiterRange = - trailingDelimiters != null - ? new Range( - end.line, - end.character, - end.line, - end.character + trailingDelimiters[0].length - ) - : null; - } - - let isInDelimitedList; - if (position === "contents") { - isInDelimitedList = - (leadingDelimiterRange != null || trailingDelimiterRange != null) && - (leadingDelimiterRange != null || start.character === 0) && - (trailingDelimiterRange != null || end.isEqual(endLine.range.end)); - } else { - isInDelimitedList = - leadingDelimiterRange != null || trailingDelimiterRange != null; - } - - return { - ...selectionContext, - isInDelimitedList, - containingListDelimiter: " ", - leadingDelimiterRange: isInDelimitedList ? leadingDelimiterRange : null, - trailingDelimiterRange: isInDelimitedList ? trailingDelimiterRange : null, - }; -} - -// TODO Clean this up once we have rich targets and better polymorphic -// selection contexts that indicate their type -function isSelectionContextEmpty(selectionContext: SelectionContext) { - return ( - selectionContext.isInDelimitedList == null && - selectionContext.containingListDelimiter == null && - selectionContext.leadingDelimiterRange == null && - selectionContext.trailingDelimiterRange == null - ); -} - -function getLineSelectionContext( - selection: SelectionWithEditor -): SelectionContext { - const { document } = selection.editor; - const { start, end } = selection.selection; - const outerSelection = getOuterSelection(selection, start, end); - - const leadingDelimiterRange = - start.line > 0 - ? new Range( - document.lineAt(start.line - 1).range.end, - outerSelection.start - ) - : null; - const trailingDelimiterRange = - end.line + 1 < document.lineCount - ? new Range(outerSelection.end, new Position(end.line + 1, 0)) - : null; - const isInDelimitedList = - leadingDelimiterRange != null || trailingDelimiterRange != null; - - return { - isInDelimitedList, - containingListDelimiter: "\n", - leadingDelimiterRange, - trailingDelimiterRange, - outerSelection, - }; -} - -function getParagraphSelectionContext( - selection: SelectionWithEditor -): SelectionContext { - const { document } = selection.editor; - const { start, end } = selection.selection; - const outerSelection = getOuterSelection(selection, start, end); - const leadingLine = getPreviousNonEmptyLine(document, start.line); - const trailingLine = getNextNonEmptyLine(document, end.line); - - const leadingDelimiterStart = - leadingLine != null - ? leadingLine.range.end - : start.line > 0 - ? new Position(0, 0) - : null; - const trailingDelimiterEnd = - trailingLine != null - ? trailingLine.range.start - : end.line < document.lineCount - 1 - ? document.lineAt(document.lineCount - 1).range.end - : null; - const leadingDelimiterRange = - leadingDelimiterStart != null - ? new Range(leadingDelimiterStart, outerSelection.start) - : null; - const trailingDelimiterRange = - trailingDelimiterEnd != null - ? new Range(outerSelection.end, trailingDelimiterEnd) - : null; - const isInDelimitedList = - leadingDelimiterRange != null || trailingDelimiterRange != null; - - return { - isInDelimitedList, - containingListDelimiter: "\n\n", - leadingDelimiterRange, - trailingDelimiterRange, - outerSelection, - }; -} - -function getOuterSelection( - selection: SelectionWithEditor, - start: Position, - end: Position -) { - // Outer selection contains the entire lines - return selectionFromPositions( - selection.selection, - new Position(start.line, 0), - selection.editor.document.lineAt(end).range.end - ); -} - -function getPreviousNonEmptyLine( - document: TextDocument, - startLineNumber: number -) { - let line = document.lineAt(startLineNumber); - while (line.lineNumber > 0) { - const previousLine = document.lineAt(line.lineNumber - 1); - if (!previousLine.isEmptyOrWhitespace) { - return previousLine; - } - line = previousLine; - } - return null; -} - -function getNextNonEmptyLine(document: TextDocument, startLineNumber: number) { - let line = document.lineAt(startLineNumber); - while (line.lineNumber + 1 < document.lineCount) { - const nextLine = document.lineAt(line.lineNumber + 1); - if (!nextLine.isEmptyOrWhitespace) { - return nextLine; - } - line = nextLine; - } - return null; -} diff --git a/src/processTargets/modifiers/surroundingPair/delimiterMaps.ts b/src/processTargets/surroundingPair/delimiterMaps.ts similarity index 96% rename from src/processTargets/modifiers/surroundingPair/delimiterMaps.ts rename to src/processTargets/surroundingPair/delimiterMaps.ts index 68c40a19b6..7a1615d3ff 100644 --- a/src/processTargets/modifiers/surroundingPair/delimiterMaps.ts +++ b/src/processTargets/surroundingPair/delimiterMaps.ts @@ -1,7 +1,7 @@ import { ComplexSurroundingPairName, SimpleSurroundingPairName, -} from "../../../typings/target.types"; +} from "../../typings/target.types"; type IndividualDelimiterText = string | string[]; diff --git a/src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts b/src/processTargets/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts similarity index 94% rename from src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts rename to src/processTargets/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts index b949d66a15..d071877bf0 100644 --- a/src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts +++ b/src/processTargets/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts @@ -1,6 +1,6 @@ import { Selection, TextDocument } from "vscode"; -import { SelectionWithContext } from "../../../typings/Types"; -import { DelimiterInclusion } from "../../../typings/target.types"; +import { SelectionWithContext } from "../../typings/Types"; +import { DelimiterInclusion } from "../../typings/target.types"; import { SurroundingPairOffsets } from "./types"; /** diff --git a/src/processTargets/modifiers/surroundingPair/findDelimiterPairAdjacentToSelection.ts b/src/processTargets/surroundingPair/findDelimiterPairAdjacentToSelection.ts similarity index 100% rename from src/processTargets/modifiers/surroundingPair/findDelimiterPairAdjacentToSelection.ts rename to src/processTargets/surroundingPair/findDelimiterPairAdjacentToSelection.ts diff --git a/src/processTargets/modifiers/surroundingPair/findDelimiterPairContainingSelection.ts b/src/processTargets/surroundingPair/findDelimiterPairContainingSelection.ts similarity index 98% rename from src/processTargets/modifiers/surroundingPair/findDelimiterPairContainingSelection.ts rename to src/processTargets/surroundingPair/findDelimiterPairContainingSelection.ts index 68614fba17..29ba759d77 100644 --- a/src/processTargets/modifiers/surroundingPair/findDelimiterPairContainingSelection.ts +++ b/src/processTargets/surroundingPair/findDelimiterPairContainingSelection.ts @@ -5,7 +5,7 @@ import { Offsets, } from "./types"; import { generateUnmatchedDelimiters } from "./generateUnmatchedDelimiters"; -import { SimpleSurroundingPairName } from "../../../typings/target.types"; +import { SimpleSurroundingPairName } from "../../typings/target.types"; /** * Looks for a surrounding pair that contains the selection, returning null if none is found. diff --git a/src/processTargets/modifiers/surroundingPair/findOppositeDelimiter.ts b/src/processTargets/surroundingPair/findOppositeDelimiter.ts similarity index 96% rename from src/processTargets/modifiers/surroundingPair/findOppositeDelimiter.ts rename to src/processTargets/surroundingPair/findOppositeDelimiter.ts index f7f4d3bad1..7d00871f8c 100644 --- a/src/processTargets/modifiers/surroundingPair/findOppositeDelimiter.ts +++ b/src/processTargets/surroundingPair/findOppositeDelimiter.ts @@ -1,4 +1,4 @@ -import { SurroundingPairDirection } from "../../../typings/target.types"; +import { SurroundingPairDirection } from "../../typings/target.types"; import { findUnmatchedDelimiter } from "./generateUnmatchedDelimiters"; import { DelimiterOccurrence, diff --git a/src/processTargets/modifiers/surroundingPair/findSurroundingPairCore.ts b/src/processTargets/surroundingPair/findSurroundingPairCore.ts similarity index 97% rename from src/processTargets/modifiers/surroundingPair/findSurroundingPairCore.ts rename to src/processTargets/surroundingPair/findSurroundingPairCore.ts index 4f569c661e..c28215e41a 100644 --- a/src/processTargets/modifiers/surroundingPair/findSurroundingPairCore.ts +++ b/src/processTargets/surroundingPair/findSurroundingPairCore.ts @@ -1,5 +1,5 @@ import { sortedIndexBy } from "lodash"; -import { SimpleSurroundingPairName } from "../../../typings/target.types"; +import { SimpleSurroundingPairName } from "../../typings/target.types"; import { findDelimiterPairAdjacentToSelection } from "./findDelimiterPairAdjacentToSelection"; import { findDelimiterPairContainingSelection } from "./findDelimiterPairContainingSelection"; import { diff --git a/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts b/src/processTargets/surroundingPair/findSurroundingPairParseTreeBased.ts similarity index 98% rename from src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts rename to src/processTargets/surroundingPair/findSurroundingPairParseTreeBased.ts index 3063be411d..54a6a16d9e 100644 --- a/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts +++ b/src/processTargets/surroundingPair/findSurroundingPairParseTreeBased.ts @@ -4,9 +4,9 @@ import { SimpleSurroundingPairName, DelimiterInclusion, SurroundingPairDirection, -} from "../../../typings/target.types"; -import { getNodeRange } from "../../../util/nodeSelectors"; -import { isContainedInErrorNode } from "../../../util/treeSitterUtils"; +} from "../../typings/target.types"; +import { getNodeRange } from "../../util/nodeSelectors"; +import { isContainedInErrorNode } from "../../util/treeSitterUtils"; import { extractSelectionFromSurroundingPairOffsets } from "./extractSelectionFromSurroundingPairOffsets"; import { findSurroundingPairCore } from "./findSurroundingPairCore"; import { getIndividualDelimiters } from "./getIndividualDelimiters"; diff --git a/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts b/src/processTargets/surroundingPair/findSurroundingPairTextBased.ts similarity index 98% rename from src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts rename to src/processTargets/surroundingPair/findSurroundingPairTextBased.ts index f7b025fcf3..37e196713f 100644 --- a/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts +++ b/src/processTargets/surroundingPair/findSurroundingPairTextBased.ts @@ -5,9 +5,9 @@ import { DelimiterInclusion, SurroundingPairName, SurroundingPairDirection, -} from "../../../typings/target.types"; -import { getDocumentRange } from "../../../util/range"; -import { matchAll } from "../../../util/regex"; +} from "../../typings/target.types"; +import { getDocumentRange } from "../../util/range"; +import { matchAll } from "../../util/regex"; import { extractSelectionFromSurroundingPairOffsets } from "./extractSelectionFromSurroundingPairOffsets"; import { findSurroundingPairCore } from "./findSurroundingPairCore"; import { getIndividualDelimiters } from "./getIndividualDelimiters"; diff --git a/src/processTargets/modifiers/surroundingPair/generateUnmatchedDelimiters.ts b/src/processTargets/surroundingPair/generateUnmatchedDelimiters.ts similarity index 98% rename from src/processTargets/modifiers/surroundingPair/generateUnmatchedDelimiters.ts rename to src/processTargets/surroundingPair/generateUnmatchedDelimiters.ts index 4812c943d1..ecf239a569 100644 --- a/src/processTargets/modifiers/surroundingPair/generateUnmatchedDelimiters.ts +++ b/src/processTargets/surroundingPair/generateUnmatchedDelimiters.ts @@ -1,5 +1,5 @@ import { range } from "lodash"; -import { SimpleSurroundingPairName } from "../../../typings/target.types"; +import { SimpleSurroundingPairName } from "../../typings/target.types"; import { DelimiterOccurrence, DelimiterSide, diff --git a/src/processTargets/modifiers/surroundingPair/getIndividualDelimiters.ts b/src/processTargets/surroundingPair/getIndividualDelimiters.ts similarity index 92% rename from src/processTargets/modifiers/surroundingPair/getIndividualDelimiters.ts rename to src/processTargets/surroundingPair/getIndividualDelimiters.ts index 5998d154f3..b2c6890a21 100644 --- a/src/processTargets/modifiers/surroundingPair/getIndividualDelimiters.ts +++ b/src/processTargets/surroundingPair/getIndividualDelimiters.ts @@ -1,8 +1,8 @@ -import { SimpleSurroundingPairName } from "../../../typings/target.types"; +import { SimpleSurroundingPairName } from "../../typings/target.types"; import { IndividualDelimiter } from "./types"; import { delimiterToText } from "./delimiterMaps"; import { concat, uniq } from "lodash"; -import { isString } from "../../../util/type"; +import { isString } from "../../util/type"; /** * Given a list of delimiters, returns a list where each element corresponds to diff --git a/src/processTargets/modifiers/surroundingPair/getSurroundingPairOffsets.ts b/src/processTargets/surroundingPair/getSurroundingPairOffsets.ts similarity index 100% rename from src/processTargets/modifiers/surroundingPair/getSurroundingPairOffsets.ts rename to src/processTargets/surroundingPair/getSurroundingPairOffsets.ts diff --git a/src/processTargets/modifiers/surroundingPair/index.ts b/src/processTargets/surroundingPair/index.ts similarity index 94% rename from src/processTargets/modifiers/surroundingPair/index.ts rename to src/processTargets/surroundingPair/index.ts index 0124eb6a70..37db124e8f 100644 --- a/src/processTargets/modifiers/surroundingPair/index.ts +++ b/src/processTargets/surroundingPair/index.ts @@ -1,20 +1,20 @@ import { Location } from "vscode"; import { SyntaxNode } from "web-tree-sitter"; -import { findSurroundingPairParseTreeBased } from "./findSurroundingPairParseTreeBased"; -import { findSurroundingPairTextBased } from "./findSurroundingPairTextBased"; -import { - ProcessedTargetsContext, - SelectionWithEditor, -} from "../../../typings/Types"; +import getTextFragmentExtractor, { + TextFragmentExtractor, +} from "../../languages/getTextFragmentExtractor"; import { ComplexSurroundingPairName, SurroundingPairModifier, -} from "../../../typings/target.types"; -import { SelectionWithEditorWithContext } from "../processModifier"; +} from "../../typings/target.types"; +import { + ProcessedTargetsContext, + SelectionWithEditor, + SelectionWithEditorWithContext, +} from "../../typings/Types"; import { complexDelimiterMap } from "./delimiterMaps"; -import getTextFragmentExtractor, { - TextFragmentExtractor, -} from "../../../languages/getTextFragmentExtractor"; +import { findSurroundingPairParseTreeBased } from "./findSurroundingPairParseTreeBased"; +import { findSurroundingPairTextBased } from "./findSurroundingPairTextBased"; /** * Applies the surrounding pair modifier to the given selection. First looks to diff --git a/src/processTargets/modifiers/surroundingPair/types.ts b/src/processTargets/surroundingPair/types.ts similarity index 95% rename from src/processTargets/modifiers/surroundingPair/types.ts rename to src/processTargets/surroundingPair/types.ts index 875a0530b8..8a3d93cde4 100644 --- a/src/processTargets/modifiers/surroundingPair/types.ts +++ b/src/processTargets/surroundingPair/types.ts @@ -1,4 +1,4 @@ -import { SimpleSurroundingPairName } from "../../../typings/target.types"; +import { SimpleSurroundingPairName } from "../../typings/target.types"; /** * Used to indicate whether a particular side of the delimiter is left or right diff --git a/src/typings/Types.ts b/src/typings/Types.ts index b4305df88d..a500f52a3d 100644 --- a/src/typings/Types.ts +++ b/src/typings/Types.ts @@ -1,18 +1,18 @@ -import { SyntaxNode } from "web-tree-sitter"; import * as vscode from "vscode"; -import { ExtensionContext, Location, Selection } from "vscode"; +import { ExtensionContext, Location } from "vscode"; +import { SyntaxNode } from "web-tree-sitter"; +import Debug from "../core/Debug"; +import Decorations from "../core/Decorations"; import { EditStyles } from "../core/editStyles"; +import FontMeasurements from "../core/FontMeasurements"; import HatTokenMap from "../core/HatTokenMap"; +import { ReadOnlyHatMap } from "../core/IndividualHatMap"; import { Snippets } from "../core/Snippets"; import { RangeUpdater } from "../core/updateSelections/RangeUpdater"; -import { FullRangeInfo } from "./updateSelections"; -import Decorations from "../core/Decorations"; -import FontMeasurements from "../core/FontMeasurements"; -import { CommandServerApi } from "../util/getExtensionApi"; -import { ReadOnlyHatMap } from "../core/IndividualHatMap"; -import Debug from "../core/Debug"; import { TestCaseRecorder } from "../testUtil/TestCaseRecorder"; -import { SelectionType, Position } from "./target.types"; +import { CommandServerApi } from "../util/getExtensionApi"; +import { Position } from "./target.types"; +import { FullRangeInfo } from "./updateSelections"; /** * A token within a text editor, including the current display line of the token @@ -113,6 +113,11 @@ export interface TypedSelection { */ isRawSelection?: boolean; + /** + * If true this selection is part of a notebook cell + */ + isNotebookCell?: boolean; + /** * If this selection has a delimiter. For example, new line for a line or paragraph and comma for a list or argument */ @@ -160,6 +165,11 @@ export interface ActionPreferences { modifier?: Modifier; } +export type SelectionWithEditorWithContext = { + selection: SelectionWithEditor; + context: SelectionContext; +}; + export interface SelectionWithContext { selection: vscode.Selection; context: SelectionContext; diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 21256a7b28..5c41a81892 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -137,13 +137,11 @@ export interface SurroundingPairModifier { export interface ContainingScopeModifier { type: "containingScope"; scopeType: ScopeType; - includeSiblings?: boolean; } export interface EveryScopeModifier { type: "everyScope"; scopeType: ScopeType; - includeSiblings?: boolean; } export interface SubTokenModifier { From 63c73c9fe4f2fc317bf099375e3389f25522dc7c Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 14 May 2022 13:59:27 +0200 Subject: [PATCH 018/314] Started working on inference --- src/core/inferFullTargets.ts | 23 ++++++++++++++++------- src/typings/target.types.ts | 5 +++-- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/core/inferFullTargets.ts b/src/core/inferFullTargets.ts index 043638f744..73782bf79b 100644 --- a/src/core/inferFullTargets.ts +++ b/src/core/inferFullTargets.ts @@ -1,13 +1,13 @@ -import { ActionPreferences } from "../typings/Types"; import { + PartialListTarget, PartialPrimitiveTarget, PartialRangeTarget, PartialTarget, PrimitiveTarget, RangeTarget, Target, - PartialListTarget, } from "../typings/target.types"; +import { ActionPreferences } from "../typings/Types"; /** * Performs inference on the partial targets provided by the user, using @@ -214,9 +214,18 @@ function getPreviousTarget( * @returns A boolean indicating whether the target has content */ function hasContent(target: PartialPrimitiveTarget) { - return ( - target.selectionType != null || - target.modifier != null || - target.insideOutsideType != null - ); + return !!target.stages.find((stage) => { + switch (stage.type) { + case "head": + case "tail": + case "toRawSelection": + case "subpiece": + case "surroundingPair": + case "containingScope": + case "everyScope": + return true; + default: + return false; + } + }); } diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 5c41a81892..1ec0dda620 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -183,8 +183,7 @@ export interface PartialPrimitiveTarget { isImplicit?: boolean; } -export type PipelineStageDescriptor = - | Mark +export type PipelineStageModifiers = | PositionModifier | SurroundingPairModifier | ContainingScopeModifier @@ -194,6 +193,8 @@ export type PipelineStageDescriptor = | TailModifier | RawSelectionModifier; +export type PipelineStageDescriptor = Mark | PipelineStageModifiers; + export interface PartialRangeTarget { type: "range"; anchor: PartialPrimitiveTarget; From 216ecb891aadad5b3c130e7fb885dad52c852d81 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 14 May 2022 15:37:38 +0200 Subject: [PATCH 019/314] Separate mark and modifier stages --- cursorless-talon/src/primitive_target.py | 10 +- src/core/inferFullTargets.ts | 93 +++------------- src/processTargets/PipelineStages.types.ts | 14 +++ src/processTargets/getMarkStage.ts | 28 +++++ src/processTargets/getModifierStage.ts | 61 +++++++++++ src/processTargets/index.ts | 27 ++--- .../{pipelineStages => marks}/CursorStage.ts | 4 +- .../CursorTokenStage.ts | 4 +- .../DecoratedSymbolStage.ts | 16 +-- .../LineNumberStage.ts | 29 +++-- .../{pipelineStages => marks}/NothingStage.ts | 2 +- .../{pipelineStages => marks}/SourceStage.ts | 4 +- .../{pipelineStages => marks}/ThatStage.ts | 4 +- .../ContainingScopeStage.ts | 4 +- .../DocumentStage.ts | 4 +- .../HeadTailStage.ts | 8 +- .../LineStage.ts | 4 +- .../NotebookCellStage.ts | 4 +- .../ParagraphStage.ts | 4 +- .../PositionStage.ts | 4 +- .../RawSelectionStage.ts | 4 +- .../RegexStage.ts | 0 .../SubPieceStage.ts | 4 +- .../SurroundingPairStage.ts | 10 +- .../TokenStage.ts | 4 +- .../surroundingPair/delimiterMaps.ts | 2 +- ...ractSelectionFromSurroundingPairOffsets.ts | 4 +- .../findDelimiterPairAdjacentToSelection.ts | 0 .../findDelimiterPairContainingSelection.ts | 2 +- .../surroundingPair/findOppositeDelimiter.ts | 2 +- .../findSurroundingPairCore.ts | 2 +- .../findSurroundingPairParseTreeBased.ts | 6 +- .../findSurroundingPairTextBased.ts | 6 +- .../generateUnmatchedDelimiters.ts | 2 +- .../getIndividualDelimiters.ts | 4 +- .../getSurroundingPairOffsets.ts | 0 .../{ => modifiers}/surroundingPair/index.ts | 6 +- .../{ => modifiers}/surroundingPair/types.ts | 2 +- .../pipelineStages/PipelineStage.ts | 10 -- .../pipelineStages/getPipelineStage.ts | 101 ------------------ src/typings/target.types.ts | 11 +- 41 files changed, 223 insertions(+), 287 deletions(-) create mode 100644 src/processTargets/PipelineStages.types.ts create mode 100644 src/processTargets/getMarkStage.ts create mode 100644 src/processTargets/getModifierStage.ts rename src/processTargets/{pipelineStages => marks}/CursorStage.ts (81%) rename src/processTargets/{pipelineStages => marks}/CursorTokenStage.ts (97%) rename src/processTargets/{pipelineStages => marks}/DecoratedSymbolStage.ts (65%) rename src/processTargets/{pipelineStages => marks}/LineNumberStage.ts (81%) rename src/processTargets/{pipelineStages => marks}/NothingStage.ts (74%) rename src/processTargets/{pipelineStages => marks}/SourceStage.ts (79%) rename src/processTargets/{pipelineStages => marks}/ThatStage.ts (79%) rename src/processTargets/{pipelineStages => modifiers}/ContainingScopeStage.ts (95%) rename src/processTargets/{pipelineStages => modifiers}/DocumentStage.ts (83%) rename src/processTargets/{pipelineStages => modifiers}/HeadTailStage.ts (84%) rename src/processTargets/{pipelineStages => modifiers}/LineStage.ts (92%) rename src/processTargets/{pipelineStages => modifiers}/NotebookCellStage.ts (77%) rename src/processTargets/{pipelineStages => modifiers}/ParagraphStage.ts (96%) rename src/processTargets/{pipelineStages => modifiers}/PositionStage.ts (89%) rename src/processTargets/{pipelineStages => modifiers}/RawSelectionStage.ts (76%) rename src/processTargets/{pipelineStages => modifiers}/RegexStage.ts (100%) rename src/processTargets/{pipelineStages => modifiers}/SubPieceStage.ts (96%) rename src/processTargets/{pipelineStages => modifiers}/SurroundingPairStage.ts (89%) rename src/processTargets/{pipelineStages => modifiers}/TokenStage.ts (94%) rename src/processTargets/{ => modifiers}/surroundingPair/delimiterMaps.ts (96%) rename src/processTargets/{ => modifiers}/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts (94%) rename src/processTargets/{ => modifiers}/surroundingPair/findDelimiterPairAdjacentToSelection.ts (100%) rename src/processTargets/{ => modifiers}/surroundingPair/findDelimiterPairContainingSelection.ts (98%) rename src/processTargets/{ => modifiers}/surroundingPair/findOppositeDelimiter.ts (96%) rename src/processTargets/{ => modifiers}/surroundingPair/findSurroundingPairCore.ts (97%) rename src/processTargets/{ => modifiers}/surroundingPair/findSurroundingPairParseTreeBased.ts (98%) rename src/processTargets/{ => modifiers}/surroundingPair/findSurroundingPairTextBased.ts (98%) rename src/processTargets/{ => modifiers}/surroundingPair/generateUnmatchedDelimiters.ts (98%) rename src/processTargets/{ => modifiers}/surroundingPair/getIndividualDelimiters.ts (92%) rename src/processTargets/{ => modifiers}/surroundingPair/getSurroundingPairOffsets.ts (100%) rename src/processTargets/{ => modifiers}/surroundingPair/index.ts (96%) rename src/processTargets/{ => modifiers}/surroundingPair/types.ts (95%) delete mode 100644 src/processTargets/pipelineStages/PipelineStage.ts delete mode 100644 src/processTargets/pipelineStages/getPipelineStage.ts diff --git a/cursorless-talon/src/primitive_target.py b/cursorless-talon/src/primitive_target.py index af9a5eb296..91eac64292 100644 --- a/cursorless-talon/src/primitive_target.py +++ b/cursorless-talon/src/primitive_target.py @@ -32,6 +32,14 @@ def cursorless_primitive_target(m) -> dict[str, Any]: """Supported extents for cursorless navigation""" result = BASE_TARGET.copy() - result["stages"] = list(m) + try: + result["mark"] = m.cursorless_mark + except AttributeError: + pass + + try: + result["modifiers"] = m.cursorless_modifier_list + except AttributeError: + pass return result diff --git a/src/core/inferFullTargets.ts b/src/core/inferFullTargets.ts index 73782bf79b..f62c2631aa 100644 --- a/src/core/inferFullTargets.ts +++ b/src/core/inferFullTargets.ts @@ -104,78 +104,31 @@ function inferPrimitiveTarget( previousTargets: PartialTarget[], actionPreferences: ActionPreferences ): PrimitiveTarget { - const doAttributeInference = !hasContent(target) && !target.isImplicit; - - const previousTargetsForAttributes = doAttributeInference - ? previousTargets - : []; - - const maybeSelectionType = - target.selectionType ?? - getPreviousAttribute(previousTargetsForAttributes, "selectionType"); - const mark = target.mark ?? - (target.position === "before" || target.position === "after" - ? getPreviousMark(previousTargets) - : null) ?? { - type: maybeSelectionType === "token" ? "cursorToken" : "cursor", - }; - - const position = - target.position ?? - getPreviousPosition(previousTargets) ?? - actionPreferences.position ?? - "contents"; - - const selectionType = - maybeSelectionType ?? - (doAttributeInference ? actionPreferences.selectionType : null) ?? - "token"; - - const insideOutsideType = - target.insideOutsideType ?? - getPreviousAttribute(previousTargetsForAttributes, "insideOutsideType") ?? - actionPreferences.insideOutsideType; + getPreviousAttribute(previousTargets, "mark") ?? { type: "cursor" }; + const modifiers = + target.modifiers ?? + getPreviousAttribute(previousTargets, "modifiers") ?? + []; - const modifier = target.modifier ?? - getPreviousAttribute(previousTargetsForAttributes, "modifier") ?? - (doAttributeInference ? actionPreferences.modifier : null) ?? { - type: "identity", - }; + // TODO ActionPreferences return { type: target.type, mark, - selectionType, - position, - insideOutsideType, - modifier, + modifiers, isImplicit: target.isImplicit ?? false, }; } -function getPreviousMark(previousTargets: PartialTarget[]) { - return getPreviousAttribute( - previousTargets, - "mark", - (target) => target["mark"] != null - ); -} - -function getPreviousPosition(previousTargets: PartialTarget[]) { - return getPreviousAttribute( - previousTargets, - "position", - (target) => target["position"] != null - ); -} - function getPreviousAttribute( previousTargets: PartialTarget[], - attributeName: T, - useTarget: (target: PartialPrimitiveTarget) => boolean = hasContent + attributeName: T ) { - const target = getPreviousTarget(previousTargets, useTarget); + const target = getPreviousTarget( + previousTargets, + (target: PartialPrimitiveTarget) => !!target[attributeName] + ); return target != null ? target[attributeName] : null; } @@ -207,25 +160,3 @@ function getPreviousTarget( } return null; } - -/** - * Determine whether the target has content, so that we shouldn't do inference - * @param target The target to inspect - * @returns A boolean indicating whether the target has content - */ -function hasContent(target: PartialPrimitiveTarget) { - return !!target.stages.find((stage) => { - switch (stage.type) { - case "head": - case "tail": - case "toRawSelection": - case "subpiece": - case "surroundingPair": - case "containingScope": - case "everyScope": - return true; - default: - return false; - } - }); -} diff --git a/src/processTargets/PipelineStages.types.ts b/src/processTargets/PipelineStages.types.ts new file mode 100644 index 0000000000..7430f1e7af --- /dev/null +++ b/src/processTargets/PipelineStages.types.ts @@ -0,0 +1,14 @@ +import { Mark, Modifier } from "../typings/target.types"; +import { ProcessedTargetsContext, TypedSelection } from "../typings/Types"; + +export interface MarkStage { + run(context: ProcessedTargetsContext, mark: Mark): TypedSelection[]; +} + +export interface ModifierStage { + run( + context: ProcessedTargetsContext, + modifier: Modifier, + target?: TypedSelection + ): TypedSelection | TypedSelection[]; +} diff --git a/src/processTargets/getMarkStage.ts b/src/processTargets/getMarkStage.ts new file mode 100644 index 0000000000..7319398aac --- /dev/null +++ b/src/processTargets/getMarkStage.ts @@ -0,0 +1,28 @@ +import { Mark } from "../typings/target.types"; +import CursorStage from "./marks/CursorStage"; +import CursorTokenStage from "./marks/CursorTokenStage"; +import DecoratedSymbolStage from "./marks/DecoratedSymbolStage"; +import LineNumberStage from "./marks/LineNumberStage"; +import NothingStage from "./marks/NothingStage"; +import SourceStage from "./marks/SourceStage"; +import ThatStage from "./marks/ThatStage"; +import { MarkStage } from "./PipelineStages.types"; + +export default (mark: Mark): MarkStage => { + switch (mark.type) { + case "cursor": + return new CursorStage(); + case "cursorToken": + return new CursorTokenStage(); + case "that": + return new ThatStage(); + case "source": + return new SourceStage(); + case "decoratedSymbol": + return new DecoratedSymbolStage(); + case "lineNumber": + return new LineNumberStage(); + case "nothing": + return new NothingStage(); + } +}; diff --git a/src/processTargets/getModifierStage.ts b/src/processTargets/getModifierStage.ts new file mode 100644 index 0000000000..2110381023 --- /dev/null +++ b/src/processTargets/getModifierStage.ts @@ -0,0 +1,61 @@ +import { + ContainingScopeModifier, + EveryScopeModifier, + Modifier, +} from "../typings/target.types"; +import ContainingScopeStage from "./modifiers/ContainingScopeStage"; +import DocumentStage from "./modifiers/DocumentStage"; +import { HeadStage, TailStage } from "./modifiers/HeadTailStage"; +import LineStage from "./modifiers/LineStage"; +import NotebookCellStage from "./modifiers/NotebookCellStage"; +import ParagraphStage from "./modifiers/ParagraphStage"; +import PositionStage from "./modifiers/PositionStage"; +import RawSelectionStage from "./modifiers/RawSelectionStage"; +import { NonWhitespaceSequenceStage, UrlStage } from "./modifiers/RegexStage"; +import SubPieceStage from "./modifiers/SubPieceStage"; +import SurroundingPairStage from "./modifiers/SurroundingPairStage"; +import TokenStage from "./modifiers/TokenStage"; +import { ModifierStage } from "./PipelineStages.types"; + +export default (modifier: Modifier): ModifierStage => { + switch (modifier.type) { + case "position": + return new PositionStage(); + case "head": + return new HeadStage(); + case "tail": + return new TailStage(); + case "toRawSelection": + return new RawSelectionStage(); + case "subpiece": + return new SubPieceStage(); + case "surroundingPair": + return new SurroundingPairStage(); + case "containingScope": + case "everyScope": + return getContainingScopeStage(modifier); + } +}; + +const getContainingScopeStage = ( + stage: ContainingScopeModifier | EveryScopeModifier +): ModifierStage => { + switch (stage.scopeType) { + case "token": + return new TokenStage(); + case "notebookCell": + return new NotebookCellStage(); + case "document": + return new DocumentStage(); + case "line": + return new LineStage(); + case "paragraph": + return new ParagraphStage(); + case "nonWhitespaceSequence": + return new NonWhitespaceSequenceStage(); + case "url": + return new UrlStage(); + default: + return new ContainingScopeStage(); + } +}; diff --git a/src/processTargets/index.ts b/src/processTargets/index.ts index 6a6feb0c56..766368998c 100644 --- a/src/processTargets/index.ts +++ b/src/processTargets/index.ts @@ -3,7 +3,8 @@ import { Range } from "vscode"; import { PrimitiveTarget, RangeTarget, Target } from "../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../typings/Types"; import { performInsideOutsideAdjustment } from "../util/performInsideOutsideAdjustment"; -import getPipelineStage from "./pipelineStages/getPipelineStage"; +import getMarkStage from "./getMarkStage"; +import getModifierStage from "./getModifierStage"; /** * Converts the abstract target descriptions provided by the user to a concrete @@ -214,17 +215,19 @@ function processPrimitiveTarget( context: ProcessedTargetsContext, target: PrimitiveTarget ): TypedSelection[] { - let selections: TypedSelection[] = []; - - for (let i = target.stages.length - 1; i > -1; --i) { - const stageDescriptor = target.stages[i]; - const stage = getPipelineStage(stageDescriptor); - if (selections.length === 0) { - selections = stage(context, stageDescriptor); - } else { - const stageSelections: TypedSelection[] = []; - for (const selection of selections) { - stageSelections.push(...stage(context, stageDescriptor, selection)); + const markStage = getMarkStage(target.mark); + let selections: TypedSelection[] = markStage.run(context, target.mark); + + for (let i = target.modifiers.length - 1; i > -1; --i) { + const stageDescriptor = target.modifiers[i]; + const stage = getModifierStage(stageDescriptor); + const stageSelections: TypedSelection[] = []; + for (const selection of selections) { + const stageResult = stage.run(context, stageDescriptor, selection); + if (Array.isArray(stageResult)) { + stageSelections.push(...stageResult); + } else { + stageSelections.push(stageResult); } selections = stageSelections; } diff --git a/src/processTargets/pipelineStages/CursorStage.ts b/src/processTargets/marks/CursorStage.ts similarity index 81% rename from src/processTargets/pipelineStages/CursorStage.ts rename to src/processTargets/marks/CursorStage.ts index dedb9b7150..0188b27c2e 100644 --- a/src/processTargets/pipelineStages/CursorStage.ts +++ b/src/processTargets/marks/CursorStage.ts @@ -1,9 +1,9 @@ import { window } from "vscode"; import { TypedSelection } from "../../typings/Types"; import { isReversed } from "../../util/selectionUtils"; -import PipelineStage from "./PipelineStage"; +import { MarkStage } from "../PipelineStages.types"; -export default class implements PipelineStage { +export default class implements MarkStage { run(): TypedSelection[] { if (window.activeTextEditor == null) { return []; diff --git a/src/processTargets/pipelineStages/CursorTokenStage.ts b/src/processTargets/marks/CursorTokenStage.ts similarity index 97% rename from src/processTargets/pipelineStages/CursorTokenStage.ts rename to src/processTargets/marks/CursorTokenStage.ts index 61a43ae779..c582f7c059 100644 --- a/src/processTargets/pipelineStages/CursorTokenStage.ts +++ b/src/processTargets/marks/CursorTokenStage.ts @@ -2,9 +2,9 @@ import { Range, window } from "vscode"; import { SelectionWithEditor, TypedSelection } from "../../typings/Types"; import { getTokensInRange, PartialToken } from "../../util/getTokensInRange"; import { isReversed } from "../../util/selectionUtils"; -import PipelineStage from "./PipelineStage"; +import { MarkStage } from "../PipelineStages.types"; -export default class implements PipelineStage { +export default class implements MarkStage { run(): TypedSelection[] { const editor = window.activeTextEditor; if (editor == null) { diff --git a/src/processTargets/pipelineStages/DecoratedSymbolStage.ts b/src/processTargets/marks/DecoratedSymbolStage.ts similarity index 65% rename from src/processTargets/pipelineStages/DecoratedSymbolStage.ts rename to src/processTargets/marks/DecoratedSymbolStage.ts index 3eb9bfda6a..fb77a07db5 100644 --- a/src/processTargets/pipelineStages/DecoratedSymbolStage.ts +++ b/src/processTargets/marks/DecoratedSymbolStage.ts @@ -1,13 +1,13 @@ import { Range } from "vscode"; import { DecoratedSymbol } from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; -import PipelineStage from "./PipelineStage"; +import { MarkStage } from "../PipelineStages.types"; -export default class implements PipelineStage { +export default class implements MarkStage { run( context: ProcessedTargetsContext, stage: DecoratedSymbol - ): TypedSelection { + ): TypedSelection[] { const token = context.hatTokenMap.getToken( stage.symbolColor, stage.character @@ -17,9 +17,11 @@ export default class implements PipelineStage { `Couldn't find mark ${stage.symbolColor} '${stage.character}'` ); } - return { - editor: token.editor, - contentRange: new Range(token.range.start, token.range.end), - }; + return [ + { + editor: token.editor, + contentRange: new Range(token.range.start, token.range.end), + }, + ]; } } diff --git a/src/processTargets/pipelineStages/LineNumberStage.ts b/src/processTargets/marks/LineNumberStage.ts similarity index 81% rename from src/processTargets/pipelineStages/LineNumberStage.ts rename to src/processTargets/marks/LineNumberStage.ts index aa4fb41a09..20ef7cd2c6 100644 --- a/src/processTargets/pipelineStages/LineNumberStage.ts +++ b/src/processTargets/marks/LineNumberStage.ts @@ -1,26 +1,25 @@ import { Range, TextEditor, window } from "vscode"; import { LineNumber, LineNumberPosition } from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; -import PipelineStage from "./PipelineStage"; +import { MarkStage } from "../PipelineStages.types"; -export default class implements PipelineStage { - run( - context: ProcessedTargetsContext, - stage: LineNumber - ): TypedSelection | TypedSelection[] { +export default class implements MarkStage { + run(context: ProcessedTargetsContext, stage: LineNumber): TypedSelection[] { if (window.activeTextEditor == null) { return []; } const editor = window.activeTextEditor; - return { - editor, - contentRange: new Range( - getLine(editor, stage.anchor), - 0, - getLine(editor, stage.active), - 0 - ), - }; + return [ + { + editor, + contentRange: new Range( + getLine(editor, stage.anchor), + 0, + getLine(editor, stage.active), + 0 + ), + }, + ]; } } diff --git a/src/processTargets/pipelineStages/NothingStage.ts b/src/processTargets/marks/NothingStage.ts similarity index 74% rename from src/processTargets/pipelineStages/NothingStage.ts rename to src/processTargets/marks/NothingStage.ts index 9ed56126ce..593af612dd 100644 --- a/src/processTargets/pipelineStages/NothingStage.ts +++ b/src/processTargets/marks/NothingStage.ts @@ -1,5 +1,5 @@ import { TypedSelection } from "../../typings/Types"; -import PipelineStage from "./PipelineStage"; +import PipelineStage from "../PipelineStages.types"; export default class implements PipelineStage { run(): TypedSelection[] { diff --git a/src/processTargets/pipelineStages/SourceStage.ts b/src/processTargets/marks/SourceStage.ts similarity index 79% rename from src/processTargets/pipelineStages/SourceStage.ts rename to src/processTargets/marks/SourceStage.ts index 4a7b28646a..33f5617df6 100644 --- a/src/processTargets/pipelineStages/SourceStage.ts +++ b/src/processTargets/marks/SourceStage.ts @@ -1,8 +1,8 @@ import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; import { isReversed } from "../../util/selectionUtils"; -import PipelineStage from "./PipelineStage"; +import { MarkStage } from "../PipelineStages.types"; -export default class implements PipelineStage { +export default class implements MarkStage { run(context: ProcessedTargetsContext): TypedSelection[] { return context.sourceMark.map((selection) => ({ editor: selection.editor, diff --git a/src/processTargets/pipelineStages/ThatStage.ts b/src/processTargets/marks/ThatStage.ts similarity index 79% rename from src/processTargets/pipelineStages/ThatStage.ts rename to src/processTargets/marks/ThatStage.ts index 20404accfe..ed10dfd9f7 100644 --- a/src/processTargets/pipelineStages/ThatStage.ts +++ b/src/processTargets/marks/ThatStage.ts @@ -1,8 +1,8 @@ import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; import { isReversed } from "../../util/selectionUtils"; -import PipelineStage from "./PipelineStage"; +import { MarkStage } from "../PipelineStages.types"; -export default class implements PipelineStage { +export default class implements MarkStage { run(context: ProcessedTargetsContext): TypedSelection[] { return context.thatMark.map((selection) => ({ editor: selection.editor, diff --git a/src/processTargets/pipelineStages/ContainingScopeStage.ts b/src/processTargets/modifiers/ContainingScopeStage.ts similarity index 95% rename from src/processTargets/pipelineStages/ContainingScopeStage.ts rename to src/processTargets/modifiers/ContainingScopeStage.ts index f1f97f4b3e..a37c025b5d 100644 --- a/src/processTargets/pipelineStages/ContainingScopeStage.ts +++ b/src/processTargets/modifiers/ContainingScopeStage.ts @@ -12,9 +12,9 @@ import { TypedSelection, } from "../../typings/Types"; import { selectionWithEditorFromRange } from "../../util/selectionUtils"; -import PipelineStage from "./PipelineStage"; +import { ModifierStage } from "../PipelineStages.types"; -export default class implements PipelineStage { +export default class implements ModifierStage { run( context: ProcessedTargetsContext, stage: ContainingScopeModifier | EveryScopeModifier, diff --git a/src/processTargets/pipelineStages/DocumentStage.ts b/src/processTargets/modifiers/DocumentStage.ts similarity index 83% rename from src/processTargets/pipelineStages/DocumentStage.ts rename to src/processTargets/modifiers/DocumentStage.ts index 4b91f50cb2..7f6e3dfa76 100644 --- a/src/processTargets/pipelineStages/DocumentStage.ts +++ b/src/processTargets/modifiers/DocumentStage.ts @@ -1,9 +1,9 @@ import { ContainingScopeModifier } from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; import { getDocumentRange } from "../../util/range"; -import PipelineStage from "./PipelineStage"; +import { ModifierStage } from "../PipelineStages.types"; -export default class implements PipelineStage { +export default class implements ModifierStage { run( context: ProcessedTargetsContext, stage: ContainingScopeModifier, diff --git a/src/processTargets/pipelineStages/HeadTailStage.ts b/src/processTargets/modifiers/HeadTailStage.ts similarity index 84% rename from src/processTargets/pipelineStages/HeadTailStage.ts rename to src/processTargets/modifiers/HeadTailStage.ts index 5c5d204e30..f62ae3288d 100644 --- a/src/processTargets/pipelineStages/HeadTailStage.ts +++ b/src/processTargets/modifiers/HeadTailStage.ts @@ -1,9 +1,9 @@ -import { Position, Range, TextEditor, window } from "vscode"; +import { Position, Range, TextEditor } from "vscode"; import { HeadModifier, TailModifier } from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; -import PipelineStage from "./PipelineStage"; +import { ModifierStage } from "../PipelineStages.types"; -abstract class HeadTailStage implements PipelineStage { +abstract class HeadTailStage implements ModifierStage { abstract update(editor: TextEditor, range: Range): Range; constructor(private isReversed: boolean) {} @@ -12,7 +12,7 @@ abstract class HeadTailStage implements PipelineStage { context: ProcessedTargetsContext, stage: HeadModifier | TailModifier, selection: TypedSelection - ): TypedSelection | TypedSelection[] { + ): TypedSelection { return { ...selection, isReversed: this.isReversed, diff --git a/src/processTargets/pipelineStages/LineStage.ts b/src/processTargets/modifiers/LineStage.ts similarity index 92% rename from src/processTargets/pipelineStages/LineStage.ts rename to src/processTargets/modifiers/LineStage.ts index e5e9625a94..ac347daff1 100644 --- a/src/processTargets/pipelineStages/LineStage.ts +++ b/src/processTargets/modifiers/LineStage.ts @@ -1,9 +1,9 @@ import { Position, Range } from "vscode"; import { ContainingScopeModifier } from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; -import PipelineStage from "./PipelineStage"; +import { ModifierStage } from "../PipelineStages.types"; -export default class implements PipelineStage { +export default class implements ModifierStage { run( context: ProcessedTargetsContext, stage: ContainingScopeModifier, diff --git a/src/processTargets/pipelineStages/NotebookCellStage.ts b/src/processTargets/modifiers/NotebookCellStage.ts similarity index 77% rename from src/processTargets/pipelineStages/NotebookCellStage.ts rename to src/processTargets/modifiers/NotebookCellStage.ts index 7c3a2652e8..9efc23d5f1 100644 --- a/src/processTargets/pipelineStages/NotebookCellStage.ts +++ b/src/processTargets/modifiers/NotebookCellStage.ts @@ -1,8 +1,8 @@ import { ContainingScopeModifier } from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; -import PipelineStage from "./PipelineStage"; +import { ModifierStage } from "../PipelineStages.types"; -export default class implements PipelineStage { +export default class implements ModifierStage { run( context: ProcessedTargetsContext, stage: ContainingScopeModifier, diff --git a/src/processTargets/pipelineStages/ParagraphStage.ts b/src/processTargets/modifiers/ParagraphStage.ts similarity index 96% rename from src/processTargets/pipelineStages/ParagraphStage.ts rename to src/processTargets/modifiers/ParagraphStage.ts index e5c0633a7c..42441e8e1a 100644 --- a/src/processTargets/pipelineStages/ParagraphStage.ts +++ b/src/processTargets/modifiers/ParagraphStage.ts @@ -1,9 +1,9 @@ import { Position, Range, TextDocument } from "vscode"; import { ContainingScopeModifier } from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; -import PipelineStage from "./PipelineStage"; +import { ModifierStage } from "../PipelineStages.types"; -export default class implements PipelineStage { +export default class implements ModifierStage { run( context: ProcessedTargetsContext, stage: ContainingScopeModifier, diff --git a/src/processTargets/pipelineStages/PositionStage.ts b/src/processTargets/modifiers/PositionStage.ts similarity index 89% rename from src/processTargets/pipelineStages/PositionStage.ts rename to src/processTargets/modifiers/PositionStage.ts index ead4b5a647..fb47397886 100644 --- a/src/processTargets/pipelineStages/PositionStage.ts +++ b/src/processTargets/modifiers/PositionStage.ts @@ -1,9 +1,9 @@ import * as vscode from "vscode"; import { PositionModifier } from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; -import PipelineStage from "./PipelineStage"; +import { ModifierStage } from "../PipelineStages.types"; -export default class implements PipelineStage { +export default class implements ModifierStage { run( context: ProcessedTargetsContext, stage: PositionModifier, diff --git a/src/processTargets/pipelineStages/RawSelectionStage.ts b/src/processTargets/modifiers/RawSelectionStage.ts similarity index 76% rename from src/processTargets/pipelineStages/RawSelectionStage.ts rename to src/processTargets/modifiers/RawSelectionStage.ts index de7a76b519..43bc9743dc 100644 --- a/src/processTargets/pipelineStages/RawSelectionStage.ts +++ b/src/processTargets/modifiers/RawSelectionStage.ts @@ -1,8 +1,8 @@ import { RawSelectionModifier } from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; -import PipelineStage from "./PipelineStage"; +import { ModifierStage } from "../PipelineStages.types"; -export default class implements PipelineStage { +export default class implements ModifierStage { run( context: ProcessedTargetsContext, stage: RawSelectionModifier, diff --git a/src/processTargets/pipelineStages/RegexStage.ts b/src/processTargets/modifiers/RegexStage.ts similarity index 100% rename from src/processTargets/pipelineStages/RegexStage.ts rename to src/processTargets/modifiers/RegexStage.ts diff --git a/src/processTargets/pipelineStages/SubPieceStage.ts b/src/processTargets/modifiers/SubPieceStage.ts similarity index 96% rename from src/processTargets/pipelineStages/SubPieceStage.ts rename to src/processTargets/modifiers/SubPieceStage.ts index e3717ff71a..daaf28ed66 100644 --- a/src/processTargets/pipelineStages/SubPieceStage.ts +++ b/src/processTargets/modifiers/SubPieceStage.ts @@ -3,9 +3,9 @@ import { Range } from "vscode"; import { SUBWORD_MATCHER } from "../../core/constants"; import { SubTokenModifier } from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; -import PipelineStage from "./PipelineStage"; +import { ModifierStage } from "../PipelineStages.types"; -export default class implements PipelineStage { +export default class implements ModifierStage { run( context: ProcessedTargetsContext, stage: SubTokenModifier, diff --git a/src/processTargets/pipelineStages/SurroundingPairStage.ts b/src/processTargets/modifiers/SurroundingPairStage.ts similarity index 89% rename from src/processTargets/pipelineStages/SurroundingPairStage.ts rename to src/processTargets/modifiers/SurroundingPairStage.ts index 11739fc885..e6f1c2e474 100644 --- a/src/processTargets/pipelineStages/SurroundingPairStage.ts +++ b/src/processTargets/modifiers/SurroundingPairStage.ts @@ -9,10 +9,10 @@ import { SurroundingPairModifier, } from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; -import { complexDelimiterMap } from "../surroundingPair/delimiterMaps"; -import { findSurroundingPairParseTreeBased } from "../surroundingPair/findSurroundingPairParseTreeBased"; -import { findSurroundingPairTextBased } from "../surroundingPair/findSurroundingPairTextBased"; -import PipelineStage from "./PipelineStage"; +import { ModifierStage } from "../PipelineStages.types"; +import { complexDelimiterMap } from "./surroundingPair/delimiterMaps"; +import { findSurroundingPairParseTreeBased } from "./surroundingPair/findSurroundingPairParseTreeBased"; +import { findSurroundingPairTextBased } from "./surroundingPair/findSurroundingPairTextBased"; /** * Applies the surrounding pair modifier to the given selection. First looks to @@ -27,7 +27,7 @@ import PipelineStage from "./PipelineStage"; * @returns The new selection expanded to the containing surrounding pair or * `null` if none was found */ -export default class implements PipelineStage { +export default class implements ModifierStage { run( context: ProcessedTargetsContext, modifier: SurroundingPairModifier, diff --git a/src/processTargets/pipelineStages/TokenStage.ts b/src/processTargets/modifiers/TokenStage.ts similarity index 94% rename from src/processTargets/pipelineStages/TokenStage.ts rename to src/processTargets/modifiers/TokenStage.ts index 9eba93bf62..412ad83ecb 100644 --- a/src/processTargets/pipelineStages/TokenStage.ts +++ b/src/processTargets/modifiers/TokenStage.ts @@ -1,9 +1,9 @@ import { Range, TextEditor } from "vscode"; import { ContainingScopeModifier } from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; -import PipelineStage from "./PipelineStage"; +import { ModifierStage } from "../PipelineStages.types"; -export default class implements PipelineStage { +export default class implements ModifierStage { run( context: ProcessedTargetsContext, stage: ContainingScopeModifier, diff --git a/src/processTargets/surroundingPair/delimiterMaps.ts b/src/processTargets/modifiers/surroundingPair/delimiterMaps.ts similarity index 96% rename from src/processTargets/surroundingPair/delimiterMaps.ts rename to src/processTargets/modifiers/surroundingPair/delimiterMaps.ts index 7a1615d3ff..68c40a19b6 100644 --- a/src/processTargets/surroundingPair/delimiterMaps.ts +++ b/src/processTargets/modifiers/surroundingPair/delimiterMaps.ts @@ -1,7 +1,7 @@ import { ComplexSurroundingPairName, SimpleSurroundingPairName, -} from "../../typings/target.types"; +} from "../../../typings/target.types"; type IndividualDelimiterText = string | string[]; diff --git a/src/processTargets/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts b/src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts similarity index 94% rename from src/processTargets/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts rename to src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts index d071877bf0..b949d66a15 100644 --- a/src/processTargets/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts +++ b/src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts @@ -1,6 +1,6 @@ import { Selection, TextDocument } from "vscode"; -import { SelectionWithContext } from "../../typings/Types"; -import { DelimiterInclusion } from "../../typings/target.types"; +import { SelectionWithContext } from "../../../typings/Types"; +import { DelimiterInclusion } from "../../../typings/target.types"; import { SurroundingPairOffsets } from "./types"; /** diff --git a/src/processTargets/surroundingPair/findDelimiterPairAdjacentToSelection.ts b/src/processTargets/modifiers/surroundingPair/findDelimiterPairAdjacentToSelection.ts similarity index 100% rename from src/processTargets/surroundingPair/findDelimiterPairAdjacentToSelection.ts rename to src/processTargets/modifiers/surroundingPair/findDelimiterPairAdjacentToSelection.ts diff --git a/src/processTargets/surroundingPair/findDelimiterPairContainingSelection.ts b/src/processTargets/modifiers/surroundingPair/findDelimiterPairContainingSelection.ts similarity index 98% rename from src/processTargets/surroundingPair/findDelimiterPairContainingSelection.ts rename to src/processTargets/modifiers/surroundingPair/findDelimiterPairContainingSelection.ts index 29ba759d77..68614fba17 100644 --- a/src/processTargets/surroundingPair/findDelimiterPairContainingSelection.ts +++ b/src/processTargets/modifiers/surroundingPair/findDelimiterPairContainingSelection.ts @@ -5,7 +5,7 @@ import { Offsets, } from "./types"; import { generateUnmatchedDelimiters } from "./generateUnmatchedDelimiters"; -import { SimpleSurroundingPairName } from "../../typings/target.types"; +import { SimpleSurroundingPairName } from "../../../typings/target.types"; /** * Looks for a surrounding pair that contains the selection, returning null if none is found. diff --git a/src/processTargets/surroundingPair/findOppositeDelimiter.ts b/src/processTargets/modifiers/surroundingPair/findOppositeDelimiter.ts similarity index 96% rename from src/processTargets/surroundingPair/findOppositeDelimiter.ts rename to src/processTargets/modifiers/surroundingPair/findOppositeDelimiter.ts index 7d00871f8c..f7f4d3bad1 100644 --- a/src/processTargets/surroundingPair/findOppositeDelimiter.ts +++ b/src/processTargets/modifiers/surroundingPair/findOppositeDelimiter.ts @@ -1,4 +1,4 @@ -import { SurroundingPairDirection } from "../../typings/target.types"; +import { SurroundingPairDirection } from "../../../typings/target.types"; import { findUnmatchedDelimiter } from "./generateUnmatchedDelimiters"; import { DelimiterOccurrence, diff --git a/src/processTargets/surroundingPair/findSurroundingPairCore.ts b/src/processTargets/modifiers/surroundingPair/findSurroundingPairCore.ts similarity index 97% rename from src/processTargets/surroundingPair/findSurroundingPairCore.ts rename to src/processTargets/modifiers/surroundingPair/findSurroundingPairCore.ts index c28215e41a..4f569c661e 100644 --- a/src/processTargets/surroundingPair/findSurroundingPairCore.ts +++ b/src/processTargets/modifiers/surroundingPair/findSurroundingPairCore.ts @@ -1,5 +1,5 @@ import { sortedIndexBy } from "lodash"; -import { SimpleSurroundingPairName } from "../../typings/target.types"; +import { SimpleSurroundingPairName } from "../../../typings/target.types"; import { findDelimiterPairAdjacentToSelection } from "./findDelimiterPairAdjacentToSelection"; import { findDelimiterPairContainingSelection } from "./findDelimiterPairContainingSelection"; import { diff --git a/src/processTargets/surroundingPair/findSurroundingPairParseTreeBased.ts b/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts similarity index 98% rename from src/processTargets/surroundingPair/findSurroundingPairParseTreeBased.ts rename to src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts index 54a6a16d9e..3063be411d 100644 --- a/src/processTargets/surroundingPair/findSurroundingPairParseTreeBased.ts +++ b/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts @@ -4,9 +4,9 @@ import { SimpleSurroundingPairName, DelimiterInclusion, SurroundingPairDirection, -} from "../../typings/target.types"; -import { getNodeRange } from "../../util/nodeSelectors"; -import { isContainedInErrorNode } from "../../util/treeSitterUtils"; +} from "../../../typings/target.types"; +import { getNodeRange } from "../../../util/nodeSelectors"; +import { isContainedInErrorNode } from "../../../util/treeSitterUtils"; import { extractSelectionFromSurroundingPairOffsets } from "./extractSelectionFromSurroundingPairOffsets"; import { findSurroundingPairCore } from "./findSurroundingPairCore"; import { getIndividualDelimiters } from "./getIndividualDelimiters"; diff --git a/src/processTargets/surroundingPair/findSurroundingPairTextBased.ts b/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts similarity index 98% rename from src/processTargets/surroundingPair/findSurroundingPairTextBased.ts rename to src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts index 37e196713f..f7b025fcf3 100644 --- a/src/processTargets/surroundingPair/findSurroundingPairTextBased.ts +++ b/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts @@ -5,9 +5,9 @@ import { DelimiterInclusion, SurroundingPairName, SurroundingPairDirection, -} from "../../typings/target.types"; -import { getDocumentRange } from "../../util/range"; -import { matchAll } from "../../util/regex"; +} from "../../../typings/target.types"; +import { getDocumentRange } from "../../../util/range"; +import { matchAll } from "../../../util/regex"; import { extractSelectionFromSurroundingPairOffsets } from "./extractSelectionFromSurroundingPairOffsets"; import { findSurroundingPairCore } from "./findSurroundingPairCore"; import { getIndividualDelimiters } from "./getIndividualDelimiters"; diff --git a/src/processTargets/surroundingPair/generateUnmatchedDelimiters.ts b/src/processTargets/modifiers/surroundingPair/generateUnmatchedDelimiters.ts similarity index 98% rename from src/processTargets/surroundingPair/generateUnmatchedDelimiters.ts rename to src/processTargets/modifiers/surroundingPair/generateUnmatchedDelimiters.ts index ecf239a569..4812c943d1 100644 --- a/src/processTargets/surroundingPair/generateUnmatchedDelimiters.ts +++ b/src/processTargets/modifiers/surroundingPair/generateUnmatchedDelimiters.ts @@ -1,5 +1,5 @@ import { range } from "lodash"; -import { SimpleSurroundingPairName } from "../../typings/target.types"; +import { SimpleSurroundingPairName } from "../../../typings/target.types"; import { DelimiterOccurrence, DelimiterSide, diff --git a/src/processTargets/surroundingPair/getIndividualDelimiters.ts b/src/processTargets/modifiers/surroundingPair/getIndividualDelimiters.ts similarity index 92% rename from src/processTargets/surroundingPair/getIndividualDelimiters.ts rename to src/processTargets/modifiers/surroundingPair/getIndividualDelimiters.ts index b2c6890a21..5998d154f3 100644 --- a/src/processTargets/surroundingPair/getIndividualDelimiters.ts +++ b/src/processTargets/modifiers/surroundingPair/getIndividualDelimiters.ts @@ -1,8 +1,8 @@ -import { SimpleSurroundingPairName } from "../../typings/target.types"; +import { SimpleSurroundingPairName } from "../../../typings/target.types"; import { IndividualDelimiter } from "./types"; import { delimiterToText } from "./delimiterMaps"; import { concat, uniq } from "lodash"; -import { isString } from "../../util/type"; +import { isString } from "../../../util/type"; /** * Given a list of delimiters, returns a list where each element corresponds to diff --git a/src/processTargets/surroundingPair/getSurroundingPairOffsets.ts b/src/processTargets/modifiers/surroundingPair/getSurroundingPairOffsets.ts similarity index 100% rename from src/processTargets/surroundingPair/getSurroundingPairOffsets.ts rename to src/processTargets/modifiers/surroundingPair/getSurroundingPairOffsets.ts diff --git a/src/processTargets/surroundingPair/index.ts b/src/processTargets/modifiers/surroundingPair/index.ts similarity index 96% rename from src/processTargets/surroundingPair/index.ts rename to src/processTargets/modifiers/surroundingPair/index.ts index 37db124e8f..1305f02b28 100644 --- a/src/processTargets/surroundingPair/index.ts +++ b/src/processTargets/modifiers/surroundingPair/index.ts @@ -2,16 +2,16 @@ import { Location } from "vscode"; import { SyntaxNode } from "web-tree-sitter"; import getTextFragmentExtractor, { TextFragmentExtractor, -} from "../../languages/getTextFragmentExtractor"; +} from "../../../languages/getTextFragmentExtractor"; import { ComplexSurroundingPairName, SurroundingPairModifier, -} from "../../typings/target.types"; +} from "../../../typings/target.types"; import { ProcessedTargetsContext, SelectionWithEditor, SelectionWithEditorWithContext, -} from "../../typings/Types"; +} from "../../../typings/Types"; import { complexDelimiterMap } from "./delimiterMaps"; import { findSurroundingPairParseTreeBased } from "./findSurroundingPairParseTreeBased"; import { findSurroundingPairTextBased } from "./findSurroundingPairTextBased"; diff --git a/src/processTargets/surroundingPair/types.ts b/src/processTargets/modifiers/surroundingPair/types.ts similarity index 95% rename from src/processTargets/surroundingPair/types.ts rename to src/processTargets/modifiers/surroundingPair/types.ts index 8a3d93cde4..875a0530b8 100644 --- a/src/processTargets/surroundingPair/types.ts +++ b/src/processTargets/modifiers/surroundingPair/types.ts @@ -1,4 +1,4 @@ -import { SimpleSurroundingPairName } from "../../typings/target.types"; +import { SimpleSurroundingPairName } from "../../../typings/target.types"; /** * Used to indicate whether a particular side of the delimiter is left or right diff --git a/src/processTargets/pipelineStages/PipelineStage.ts b/src/processTargets/pipelineStages/PipelineStage.ts deleted file mode 100644 index 3f6edea4ba..0000000000 --- a/src/processTargets/pipelineStages/PipelineStage.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { PipelineStageDescriptor } from "../../typings/target.types"; -import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; - -export default interface PipelineStage { - run( - context: ProcessedTargetsContext, - stage: PipelineStageDescriptor, - target?: TypedSelection - ): TypedSelection | TypedSelection[]; -} diff --git a/src/processTargets/pipelineStages/getPipelineStage.ts b/src/processTargets/pipelineStages/getPipelineStage.ts deleted file mode 100644 index 509aa94365..0000000000 --- a/src/processTargets/pipelineStages/getPipelineStage.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { - ContainingScopeModifier, - EveryScopeModifier, - PipelineStageDescriptor, -} from "../../typings/target.types"; -import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; -import ContainingScopeStage from "./ContainingScopeStage"; -import CursorStage from "./CursorStage"; -import CursorTokenStage from "./CursorTokenStage"; -import DecoratedSymbolStage from "./DecoratedSymbolStage"; -import DocumentStage from "./DocumentStage"; -import { HeadStage, TailStage } from "./HeadTailStage"; -import LineNumberStage from "./LineNumberStage"; -import LineStage from "./LineStage"; -import NotebookCellStage from "./NotebookCellStage"; -import NothingStage from "./NothingStage"; -import ParagraphStage from "./ParagraphStage"; -import PipelineStage from "./PipelineStage"; -import PositionStage from "./PositionStage"; -import RawSelectionStage from "./RawSelectionStage"; -import { NonWhitespaceSequenceStage, UrlStage } from "./RegexStage"; -import SourceStage from "./SourceStage"; -import SubPieceStage from "./SubPieceStage"; -import SurroundingPairStage from "./SurroundingPairStage"; -import ThatStage from "./ThatStage"; -import TokenStage from "./TokenStage"; - -export default (stageDescriptor: PipelineStageDescriptor) => { - const stage = getStage(stageDescriptor); - return ( - context: ProcessedTargetsContext, - stageDescriptor: PipelineStageDescriptor, - selection?: TypedSelection - ) => { - const stageResult = stage.run(context, stageDescriptor, selection); - if (!Array.isArray(stageResult)) { - return [stageResult]; - } - return stageResult; - }; -}; - -const getStage = (stageDescriptor: PipelineStageDescriptor): PipelineStage => { - switch (stageDescriptor.type) { - // Mark/source stages - case "cursor": - return new CursorStage(); - case "cursorToken": - return new CursorTokenStage(); - case "that": - return new ThatStage(); - case "source": - return new SourceStage(); - case "decoratedSymbol": - return new DecoratedSymbolStage(); - case "lineNumber": - return new LineNumberStage(); - case "nothing": - return new NothingStage(); - - // Modifiers - case "position": - return new PositionStage(); - case "head": - return new HeadStage(); - case "tail": - return new TailStage(); - case "toRawSelection": - return new RawSelectionStage(); - case "subpiece": - return new SubPieceStage(); - case "surroundingPair": - return new SurroundingPairStage(); - case "containingScope": - case "everyScope": - return getContainingScopeStage(stageDescriptor); - } -}; - -const getContainingScopeStage = ( - stage: ContainingScopeModifier | EveryScopeModifier -): PipelineStage => { - switch (stage.scopeType) { - case "token": - return new TokenStage(); - case "notebookCell": - return new NotebookCellStage(); - case "document": - return new DocumentStage(); - case "line": - return new LineStage(); - case "paragraph": - return new ParagraphStage(); - case "nonWhitespaceSequence": - return new NonWhitespaceSequenceStage(); - case "url": - return new UrlStage(); - default: - return new ContainingScopeStage(); - } -}; diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 1ec0dda620..194c0143a3 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -174,16 +174,17 @@ export type Position = "before" | "after" | "start" | "end"; export interface PositionModifier { type: "position"; - position: "before" | "after" | "start" | "end"; + position: Position; } export interface PartialPrimitiveTarget { type: "primitive"; - stages: PipelineStageDescriptor[]; + mark?: Mark; + modifiers?: Modifier[]; isImplicit?: boolean; } -export type PipelineStageModifiers = +export type Modifier = | PositionModifier | SurroundingPairModifier | ContainingScopeModifier @@ -193,8 +194,6 @@ export type PipelineStageModifiers = | TailModifier | RawSelectionModifier; -export type PipelineStageDescriptor = Mark | PipelineStageModifiers; - export interface PartialRangeTarget { type: "range"; anchor: PartialPrimitiveTarget; @@ -216,6 +215,8 @@ export type PartialTarget = export interface PrimitiveTarget extends PartialPrimitiveTarget { isImplicit: boolean; + mark: Mark; + modifiers: Modifier[]; } export interface RangeTarget { From effad175def71f99e56196acfa41640863f08c61 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 14 May 2022 16:01:35 +0200 Subject: [PATCH 020/314] Fixed type errors in surrounding pair --- .../modifiers/SurroundingPairStage.ts | 130 +++++++++++------- .../findSurroundingPairParseTreeBased.ts | 6 +- .../findSurroundingPairTextBased.ts | 12 +- 3 files changed, 87 insertions(+), 61 deletions(-) diff --git a/src/processTargets/modifiers/SurroundingPairStage.ts b/src/processTargets/modifiers/SurroundingPairStage.ts index e6f1c2e474..45bf330c2a 100644 --- a/src/processTargets/modifiers/SurroundingPairStage.ts +++ b/src/processTargets/modifiers/SurroundingPairStage.ts @@ -33,73 +33,99 @@ export default class implements ModifierStage { modifier: SurroundingPairModifier, selection: TypedSelection ): TypedSelection | TypedSelection[] { - const document = selection.editor.document; - const delimiters = complexDelimiterMap[ - modifier.delimiter as ComplexSurroundingPairName - ] ?? [modifier.delimiter]; + const pairs = processSurroundingPair(context, modifier, selection); + if (pairs == null) { + throw new Error("Couldn't find containing pair"); + } + return pairs.map((pair) => ({ + ...selection, + editor: pair.selection.editor, + contentRange: pair.selection.selection, + removalRange: pair.context.outerSelection ?? undefined, + isRawSelection: pair.context.isRawSelection, + isNotebookCell: pair.context.isNotebookCell, + delimiter: pair.context.containingListDelimiter ?? undefined, + interiorRange: pair.context.interior + ? pair.context.interior[0].selection + : undefined, + boundary: pair.context.boundary?.map((bound) => bound.selection), + leadingDelimiterRange: pair.context.leadingDelimiterRange ?? undefined, + trailingDelimiterRange: pair.context.trailingDelimiterRange ?? undefined, + })); + } +} - let node: SyntaxNode | null; - let textFragmentExtractor: TextFragmentExtractor; +function processSurroundingPair( + context: ProcessedTargetsContext, + modifier: SurroundingPairModifier, + selection: TypedSelection +) { + const document = selection.editor.document; + const delimiters = complexDelimiterMap[ + modifier.delimiter as ComplexSurroundingPairName + ] ?? [modifier.delimiter]; - try { - node = context.getNodeAtLocation( - new vscode.Location(document.uri, selection.contentRange) - ); + let node: SyntaxNode | null; + let textFragmentExtractor: TextFragmentExtractor; - textFragmentExtractor = getTextFragmentExtractor(document.languageId); - } catch (err) { - if ((err as Error).name === "UnsupportedLanguageError") { - // If we're in a language where we don't have a parse tree we use the text - // based algorithm - return findSurroundingPairTextBased( - selection.editor, - selection.contentRange, - null, - delimiters, - modifier.delimiterInclusion, - modifier.forceDirection - ); - } else { - throw err; - } - } - - const selectionWithEditor = { - editor: selection.editor, - selection: new Selection( - selection.contentRange.start, - selection.contentRange.end - ), - }; + try { + node = context.getNodeAtLocation( + new vscode.Location(document.uri, selection.contentRange) + ); - // If we have a parse tree but we are in a string node or in a comment node, - // then we use the text-based algorithm - const textFragmentRange = textFragmentExtractor(node, selectionWithEditor); - if (textFragmentRange != null) { - const surroundingRange = findSurroundingPairTextBased( + textFragmentExtractor = getTextFragmentExtractor(document.languageId); + } catch (err) { + if ((err as Error).name === "UnsupportedLanguageError") { + // If we're in a language where we don't have a parse tree we use the text + // based algorithm + return findSurroundingPairTextBased( selection.editor, - selection.selection, - textFragmentRange, + selection.contentRange, + null, delimiters, modifier.delimiterInclusion, modifier.forceDirection ); - - if (surroundingRange != null) { - return surroundingRange; - } + } else { + throw err; } + } + + const selectionWithEditor = { + editor: selection.editor, + selection: new Selection( + selection.contentRange.start, + selection.contentRange.end + ), + }; - // If we have a parse tree and either we are not in a string or comment or we - // couldn't find a surrounding pair within a string or comment, we use the - // parse tree-based algorithm - return findSurroundingPairParseTreeBased( + // If we have a parse tree but we are in a string node or in a comment node, + // then we use the text-based algorithm + const textFragmentRange = textFragmentExtractor(node, selectionWithEditor); + if (textFragmentRange != null) { + const surroundingRange = findSurroundingPairTextBased( selection.editor, - selection.selection, - node, + selection.contentRange, + textFragmentRange, delimiters, modifier.delimiterInclusion, modifier.forceDirection ); + + if (surroundingRange != null) { + return surroundingRange; + } } + + // If we have a parse tree and either we are not in a string or comment or we + // couldn't find a surrounding pair within a string or comment, we use the + // parse tree-based algorithm + return findSurroundingPairParseTreeBased( + selection.editor, + selection.contentRange, + node, + delimiters, + modifier.delimiterInclusion, + modifier.forceDirection + ); } diff --git a/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts b/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts index 3063be411d..c118d0e0f1 100644 --- a/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts +++ b/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts @@ -1,8 +1,8 @@ -import { Selection, TextDocument, TextEditor } from "vscode"; +import { Range, TextDocument, TextEditor } from "vscode"; import { SyntaxNode } from "web-tree-sitter"; import { - SimpleSurroundingPairName, DelimiterInclusion, + SimpleSurroundingPairName, SurroundingPairDirection, } from "../../../typings/target.types"; import { getNodeRange } from "../../../util/nodeSelectors"; @@ -61,7 +61,7 @@ import { */ export function findSurroundingPairParseTreeBased( editor: TextEditor, - selection: Selection, + selection: Range, node: SyntaxNode, delimiters: SimpleSurroundingPairName[], delimiterInclusion: DelimiterInclusion, diff --git a/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts b/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts index f7b025fcf3..a83e5f48b0 100644 --- a/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts +++ b/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts @@ -1,10 +1,10 @@ import { escapeRegExp, findLast, uniq } from "lodash"; -import { Range, Selection, TextDocument, TextEditor } from "vscode"; +import { Range, TextDocument, TextEditor } from "vscode"; import { - SimpleSurroundingPairName, DelimiterInclusion, - SurroundingPairName, + SimpleSurroundingPairName, SurroundingPairDirection, + SurroundingPairName, } from "../../../typings/target.types"; import { getDocumentRange } from "../../../util/range"; import { matchAll } from "../../../util/regex"; @@ -12,10 +12,10 @@ import { extractSelectionFromSurroundingPairOffsets } from "./extractSelectionFr import { findSurroundingPairCore } from "./findSurroundingPairCore"; import { getIndividualDelimiters } from "./getIndividualDelimiters"; import { + IndividualDelimiter, Offsets, - SurroundingPairOffsets, PossibleDelimiterOccurrence, - IndividualDelimiter, + SurroundingPairOffsets, } from "./types"; /** @@ -69,7 +69,7 @@ const SCAN_EXPANSION_FACTOR = 3; */ export function findSurroundingPairTextBased( editor: TextEditor, - selection: Selection, + selection: Range, allowableRange: Range | null, delimiters: SimpleSurroundingPairName[], delimiterInclusion: DelimiterInclusion, From c86da0804916140847d7a0b977fc21e404b421fc Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 14 May 2022 16:13:58 +0200 Subject: [PATCH 021/314] Prepare migration --- src/core/commandRunner/command.types.ts | 2 +- .../upgradeV1ToV2/upgradeStrictHere.ts | 2 +- .../upgradeV1ToV2/upgradeV1ToV2.ts | 21 +++++++++++++++---- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/core/commandRunner/command.types.ts b/src/core/commandRunner/command.types.ts index 31add588a4..5f6e6df241 100644 --- a/src/core/commandRunner/command.types.ts +++ b/src/core/commandRunner/command.types.ts @@ -16,7 +16,7 @@ export type CommandLatest = Command & { export type Command = CommandV0 | CommandV1 | CommandV2; -interface CommandV2 { +export interface CommandV2 { /** * The version number of the command API */ diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeStrictHere.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeStrictHere.ts index cc28e85d79..829e718bb0 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeStrictHere.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeStrictHere.ts @@ -1,5 +1,5 @@ -import { PartialPrimitiveTarget } from "../typings/Types"; import { isDeepStrictEqual } from "util"; +import { PartialPrimitiveTarget } from "../../../typings/target.types"; const STRICT_HERE = { type: "primitive", diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts index 73d0c01a24..6ea9e58a31 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts @@ -1,19 +1,32 @@ import { flow } from "lodash"; +import { PartialTarget } from "../../../typings/target.types"; +import { ActionType } from "../../../typings/Types"; import { transformPartialPrimitiveTargets } from "../../../util/getPrimitiveTargets"; -import { CommandV0, CommandV1 } from "../../commandRunner/command.types"; +import { CommandV2 } from "../../commandRunner/command.types"; +import { CommandV1, PartialTargetV0V1 } from "./commandV1.types"; import { upgradeStrictHere } from "./upgradeStrictHere"; export function upgradeV1ToV2(command: CommandV1): CommandV2 { return { - ...command, + spokenForm: command.spokenForm, + action: command.action as ActionType, targets: upgradeTargets(command.targets), + extraArgs: command.extraArgs, + usePrePhraseSnapshot: command.usePrePhraseSnapshot ?? false, version: 2, }; } -function upgradeTargets(partialTargets: PartialTarget[]) { +function upgradeTargets(partialTargets: PartialTargetV0V1[]) { + // const partialTargetsV2: PartialTarget[] = partialTargets.map( + // (target) => ({ + + // }) + // ); + // TODO do target migration + const partialTargetsV2: PartialTarget[] = []; return transformPartialPrimitiveTargets( - partialTargets, + partialTargetsV2, flow(upgradeStrictHere) ); } From 28d9af2dd3748c0cdb3bbb86079abf00dcaea896 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 14 May 2022 16:40:48 +0200 Subject: [PATCH 022/314] Make sure marks have context --- src/processTargets/marks/CursorStage.ts | 2 + src/processTargets/marks/CursorTokenStage.ts | 17 ++-- .../marks/DecoratedSymbolStage.ts | 5 +- src/processTargets/marks/LineNumberStage.ts | 15 +-- src/processTargets/marks/NothingStage.ts | 4 +- src/processTargets/marks/SourceStage.ts | 2 + src/processTargets/marks/ThatStage.ts | 2 + src/processTargets/modifiers/LineStage.ts | 62 +++++++------ src/processTargets/modifiers/RegexStage.ts | 11 +-- src/processTargets/modifiers/TokenStage.ts | 93 ++++++++++--------- 10 files changed, 122 insertions(+), 91 deletions(-) diff --git a/src/processTargets/marks/CursorStage.ts b/src/processTargets/marks/CursorStage.ts index 0188b27c2e..27be9721ff 100644 --- a/src/processTargets/marks/CursorStage.ts +++ b/src/processTargets/marks/CursorStage.ts @@ -1,6 +1,7 @@ import { window } from "vscode"; import { TypedSelection } from "../../typings/Types"; import { isReversed } from "../../util/selectionUtils"; +import { getTokenContext } from "../modifiers/TokenStage"; import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { @@ -12,6 +13,7 @@ export default class implements MarkStage { editor: window.activeTextEditor!, isReversed: isReversed(selection), contentRange: selection, + ...getTokenContext(window.activeTextEditor!, selection), })); } } diff --git a/src/processTargets/marks/CursorTokenStage.ts b/src/processTargets/marks/CursorTokenStage.ts index c582f7c059..000c2d6560 100644 --- a/src/processTargets/marks/CursorTokenStage.ts +++ b/src/processTargets/marks/CursorTokenStage.ts @@ -2,6 +2,7 @@ import { Range, window } from "vscode"; import { SelectionWithEditor, TypedSelection } from "../../typings/Types"; import { getTokensInRange, PartialToken } from "../../util/getTokensInRange"; import { isReversed } from "../../util/selectionUtils"; +import { getTokenContext } from "../modifiers/TokenStage"; import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { @@ -10,14 +11,18 @@ export default class implements MarkStage { if (editor == null) { return []; } - return editor.selections.map((selection) => ({ - editor, - isReversed: isReversed(selection), - contentRange: getTokenRangeForSelection({ + return editor.selections.map((selection) => { + const contentRange = getTokenRangeForSelection({ editor, selection, - }), - })); + }); + return { + editor, + isReversed: isReversed(selection), + contentRange, + ...getTokenContext(editor, contentRange), + }; + }); } } diff --git a/src/processTargets/marks/DecoratedSymbolStage.ts b/src/processTargets/marks/DecoratedSymbolStage.ts index fb77a07db5..1e64217d17 100644 --- a/src/processTargets/marks/DecoratedSymbolStage.ts +++ b/src/processTargets/marks/DecoratedSymbolStage.ts @@ -1,6 +1,6 @@ -import { Range } from "vscode"; import { DecoratedSymbol } from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import { getTokenContext } from "../modifiers/TokenStage"; import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { @@ -20,7 +20,8 @@ export default class implements MarkStage { return [ { editor: token.editor, - contentRange: new Range(token.range.start, token.range.end), + contentRange: token.range, + ...getTokenContext(token.editor, token.range), }, ]; } diff --git a/src/processTargets/marks/LineNumberStage.ts b/src/processTargets/marks/LineNumberStage.ts index 20ef7cd2c6..870da19e9f 100644 --- a/src/processTargets/marks/LineNumberStage.ts +++ b/src/processTargets/marks/LineNumberStage.ts @@ -1,6 +1,7 @@ import { Range, TextEditor, window } from "vscode"; import { LineNumber, LineNumberPosition } from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import { getLineContext } from "../modifiers/LineStage"; import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { @@ -9,15 +10,17 @@ export default class implements MarkStage { return []; } const editor = window.activeTextEditor; + const contentRange = new Range( + getLine(editor, stage.anchor), + 0, + getLine(editor, stage.active), + 0 + ); return [ { editor, - contentRange: new Range( - getLine(editor, stage.anchor), - 0, - getLine(editor, stage.active), - 0 - ), + contentRange, + ...getLineContext(editor, contentRange), }, ]; } diff --git a/src/processTargets/marks/NothingStage.ts b/src/processTargets/marks/NothingStage.ts index 593af612dd..4e9411ac12 100644 --- a/src/processTargets/marks/NothingStage.ts +++ b/src/processTargets/marks/NothingStage.ts @@ -1,7 +1,7 @@ import { TypedSelection } from "../../typings/Types"; -import PipelineStage from "../PipelineStages.types"; +import { MarkStage } from "../PipelineStages.types"; -export default class implements PipelineStage { +export default class implements MarkStage { run(): TypedSelection[] { return []; } diff --git a/src/processTargets/marks/SourceStage.ts b/src/processTargets/marks/SourceStage.ts index 33f5617df6..7715e2be22 100644 --- a/src/processTargets/marks/SourceStage.ts +++ b/src/processTargets/marks/SourceStage.ts @@ -1,5 +1,6 @@ import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; import { isReversed } from "../../util/selectionUtils"; +import { getTokenContext } from "../modifiers/TokenStage"; import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { @@ -8,6 +9,7 @@ export default class implements MarkStage { editor: selection.editor, isReversed: isReversed(selection.selection), contentRange: selection.selection, + ...getTokenContext(selection.editor, selection.selection), })); } } diff --git a/src/processTargets/marks/ThatStage.ts b/src/processTargets/marks/ThatStage.ts index ed10dfd9f7..1abd9721bf 100644 --- a/src/processTargets/marks/ThatStage.ts +++ b/src/processTargets/marks/ThatStage.ts @@ -1,5 +1,6 @@ import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; import { isReversed } from "../../util/selectionUtils"; +import { getTokenContext } from "../modifiers/TokenStage"; import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { @@ -8,6 +9,7 @@ export default class implements MarkStage { editor: selection.editor, isReversed: isReversed(selection.selection), contentRange: selection.selection, + ...getTokenContext(selection.editor, selection.selection), })); } } diff --git a/src/processTargets/modifiers/LineStage.ts b/src/processTargets/modifiers/LineStage.ts index ac347daff1..f223709f23 100644 --- a/src/processTargets/modifiers/LineStage.ts +++ b/src/processTargets/modifiers/LineStage.ts @@ -1,4 +1,4 @@ -import { Position, Range } from "vscode"; +import { Position, Range, TextEditor } from "vscode"; import { ContainingScopeModifier } from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; @@ -10,7 +10,6 @@ export default class implements ModifierStage { selection: TypedSelection ): TypedSelection { const { document } = selection.editor; - const startLine = document.lineAt(selection.contentRange.start); const endLine = document.lineAt(selection.contentRange.end); const start = new Position( @@ -18,32 +17,43 @@ export default class implements ModifierStage { startLine.firstNonWhitespaceCharacterIndex ); const end = endLine.range.end; - - const removalRange = new Range( - new Position(start.line, 0), - selection.editor.document.lineAt(end).range.end - ); - - const leadingDelimiterRange = - start.line > 0 - ? new Range( - document.lineAt(start.line - 1).range.end, - removalRange.start - ) - : undefined; - const trailingDelimiterRange = - end.line + 1 < document.lineCount - ? new Range(removalRange.end, new Position(end.line + 1, 0)) - : undefined; + const contentRange = new Range(start, end); return { - editor: selection.editor, - isReversed: selection.isReversed, - delimiter: "\n", - contentRange: new Range(start, end), - removalRange, - leadingDelimiterRange, - trailingDelimiterRange, + ...selection, + ...getLineContext(selection.editor, contentRange), }; } } + +export function getLineContext( + editor: TextEditor, + range: Range +): Partial { + const { document } = editor; + const { start, end } = range; + + const removalRange = new Range( + new Position(start.line, 0), + editor.document.lineAt(end).range.end + ); + + const leadingDelimiterRange = + start.line > 0 + ? new Range(document.lineAt(start.line - 1).range.end, removalRange.start) + : undefined; + const trailingDelimiterRange = + end.line + 1 < document.lineCount + ? new Range(removalRange.end, new Position(end.line + 1, 0)) + : undefined; + + return { + delimiter: "\n", + interiorRange: undefined, + boundary: undefined, + isRawSelection: undefined, + removalRange, + leadingDelimiterRange, + trailingDelimiterRange, + }; +} diff --git a/src/processTargets/modifiers/RegexStage.ts b/src/processTargets/modifiers/RegexStage.ts index f6b55dfff8..35560c4375 100644 --- a/src/processTargets/modifiers/RegexStage.ts +++ b/src/processTargets/modifiers/RegexStage.ts @@ -1,12 +1,11 @@ import { Position, Range } from "vscode"; import { ContainingScopeModifier } from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; -import TokenStage from "./TokenStage"; +import { ModifierStage } from "../PipelineStages.types"; +import { getTokenContext } from "./TokenStage"; -class RegexStage extends TokenStage { - constructor(private regex: RegExp, private name?: string) { - super(); - } +class RegexStage implements ModifierStage { + constructor(private regex: RegExp, private name?: string) {} run( context: ProcessedTargetsContext, @@ -45,7 +44,7 @@ class RegexStage extends TokenStage { return { ...selection, contentRange, - ...this.getDelimiterRanges(selection.editor, contentRange), + ...getTokenContext(selection.editor, contentRange), }; } } diff --git a/src/processTargets/modifiers/TokenStage.ts b/src/processTargets/modifiers/TokenStage.ts index 412ad83ecb..9c8f1cd35b 100644 --- a/src/processTargets/modifiers/TokenStage.ts +++ b/src/processTargets/modifiers/TokenStage.ts @@ -11,54 +11,61 @@ export default class implements ModifierStage { ): TypedSelection { return { ...selection, - ...this.getDelimiterRanges(selection.editor, selection.contentRange), + ...getTokenContext(selection.editor, selection.contentRange), }; } +} - getDelimiterRanges(editor: TextEditor, range: Range) { - const document = editor.document; - const { start, end } = range; - const endLine = document.lineAt(end); - let leadingDelimiterRange, trailingDelimiterRange; +export function getTokenContext( + editor: TextEditor, + range: Range +): Partial { + const document = editor.document; + const { start, end } = range; + const endLine = document.lineAt(end); + let leadingDelimiterRange, trailingDelimiterRange; - const startLine = document.lineAt(start); - const leadingText = startLine.text.slice(0, start.character); - const leadingDelimiters = leadingText.match(/\s+$/); - leadingDelimiterRange = - leadingDelimiters != null - ? new Range( - start.line, - start.character - leadingDelimiters[0].length, - start.line, - start.character - ) - : undefined; + const startLine = document.lineAt(start); + const leadingText = startLine.text.slice(0, start.character); + const leadingDelimiters = leadingText.match(/\s+$/); + leadingDelimiterRange = + leadingDelimiters != null + ? new Range( + start.line, + start.character - leadingDelimiters[0].length, + start.line, + start.character + ) + : undefined; - const trailingText = endLine.text.slice(end.character); - const trailingDelimiters = trailingText.match(/^\s+/); - trailingDelimiterRange = - trailingDelimiters != null - ? new Range( - end.line, - end.character, - end.line, - end.character + trailingDelimiters[0].length - ) - : undefined; + const trailingText = endLine.text.slice(end.character); + const trailingDelimiters = trailingText.match(/^\s+/); + trailingDelimiterRange = + trailingDelimiters != null + ? new Range( + end.line, + end.character, + end.line, + end.character + trailingDelimiters[0].length + ) + : undefined; - const isInDelimitedList = - (leadingDelimiterRange != null || trailingDelimiterRange != null) && - (leadingDelimiterRange != null || start.character === 0) && - (trailingDelimiterRange != null || end.isEqual(endLine.range.end)); + const isInDelimitedList = + (leadingDelimiterRange != null || trailingDelimiterRange != null) && + (leadingDelimiterRange != null || start.character === 0) && + (trailingDelimiterRange != null || end.isEqual(endLine.range.end)); - return { - delimiter: " ", - leadingDelimiterRange: isInDelimitedList - ? leadingDelimiterRange - : undefined, - trailingDelimiterRange: isInDelimitedList - ? trailingDelimiterRange - : undefined, - }; - } + return { + delimiter: " ", + removalRange: undefined, + interiorRange: undefined, + boundary: undefined, + isRawSelection: undefined, + leadingDelimiterRange: isInDelimitedList + ? leadingDelimiterRange + : undefined, + trailingDelimiterRange: isInDelimitedList + ? trailingDelimiterRange + : undefined, + }; } From 078ec9358a880dba1872f412e4e9c63b91988e41 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 14 May 2022 17:07:55 +0200 Subject: [PATCH 023/314] Updated modifier context --- .../modifiers/ContainingScopeStage.ts | 25 +++++++------- src/processTargets/modifiers/DocumentStage.ts | 33 ++++++++++++++++++- .../modifiers/ParagraphStage.ts | 5 +-- src/processTargets/modifiers/PositionStage.ts | 4 +++ src/processTargets/modifiers/SubPieceStage.ts | 4 ++- .../modifiers/SurroundingPairStage.ts | 4 +-- 6 files changed, 57 insertions(+), 18 deletions(-) diff --git a/src/processTargets/modifiers/ContainingScopeStage.ts b/src/processTargets/modifiers/ContainingScopeStage.ts index a37c025b5d..b8b3bcce8a 100644 --- a/src/processTargets/modifiers/ContainingScopeStage.ts +++ b/src/processTargets/modifiers/ContainingScopeStage.ts @@ -29,7 +29,7 @@ export default class implements ModifierStage { new Location(selection.editor.document.uri, selection.contentRange.start) ); - const result = findNearestContainingAncestorNode(node, nodeMatcher, { + const scopeNodes = findNearestContainingAncestorNode(node, nodeMatcher, { editor: selection.editor, selection: new Selection( selection.contentRange.start, @@ -37,19 +37,22 @@ export default class implements ModifierStage { ), }); - if (result == null) { + if (scopeNodes == null) { throw new Error(`Couldn't find containing ${stage.scopeType}`); } - return result.map((selection) => ({ - editor: selection.selection.editor, - contentRange: selection.selection.selection, - removalRange: selection.context.outerSelection ?? undefined, - delimiter: selection.context.containingListDelimiter ?? undefined, - leadingDelimiterRange: - selection.context.leadingDelimiterRange ?? undefined, - trailingDelimiterRange: - selection.context.trailingDelimiterRange ?? undefined, + return scopeNodes.map((scope) => ({ + ...selection, + editor: scope.selection.editor, + contentRange: scope.selection.selection, + interiorRange: scope.context.interior?.at(0)?.selection, + removalRange: scope.context.outerSelection ?? undefined, + isRawSelection: scope.context.isRawSelection, + isNotebookCell: scope.context.isNotebookCell, + delimiter: scope.context.containingListDelimiter ?? undefined, + boundary: scope.context.boundary?.map((bound) => bound.selection), + leadingDelimiterRange: scope.context.leadingDelimiterRange ?? undefined, + trailingDelimiterRange: scope.context.trailingDelimiterRange ?? undefined, })); } } diff --git a/src/processTargets/modifiers/DocumentStage.ts b/src/processTargets/modifiers/DocumentStage.ts index 7f6e3dfa76..0b9505d01d 100644 --- a/src/processTargets/modifiers/DocumentStage.ts +++ b/src/processTargets/modifiers/DocumentStage.ts @@ -1,3 +1,4 @@ +import { Range, TextDocument } from "vscode"; import { ContainingScopeModifier } from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; import { getDocumentRange } from "../../util/range"; @@ -10,10 +11,40 @@ export default class implements ModifierStage { selection: TypedSelection ): TypedSelection { return { + ...selection, editor: selection.editor, isReversed: selection.isReversed, + contentRange: getDocumentContentRange(selection.editor.document), + removalRange: getDocumentRange(selection.editor.document), delimiter: "\n", - contentRange: getDocumentRange(selection.editor.document), + interiorRange: undefined, + boundary: undefined, + leadingDelimiterRange: undefined, + trailingDelimiterRange: undefined, }; } } + +function getDocumentContentRange(document: TextDocument) { + let firstLineNum = 0; + let lastLineNum = document.lineCount - 1; + + for (let i = firstLineNum; i < document.lineCount; ++i) { + if (!document.lineAt(i).isEmptyOrWhitespace) { + break; + } + firstLineNum = i; + } + + for (let i = lastLineNum; i > -1; --i) { + if (!document.lineAt(i).isEmptyOrWhitespace) { + break; + } + lastLineNum = i; + } + + const firstLine = document.lineAt(firstLineNum); + const lastLine = document.lineAt(lastLineNum); + + return new Range(firstLine.range.start, lastLine.range.end); +} diff --git a/src/processTargets/modifiers/ParagraphStage.ts b/src/processTargets/modifiers/ParagraphStage.ts index 42441e8e1a..01b56a6f82 100644 --- a/src/processTargets/modifiers/ParagraphStage.ts +++ b/src/processTargets/modifiers/ParagraphStage.ts @@ -69,13 +69,14 @@ export default class implements ModifierStage { : undefined; return { - editor: selection.editor, - isReversed: selection.isReversed, + ...selection, delimiter: "\n\n", contentRange: new Range(start, end), removalRange, leadingDelimiterRange, trailingDelimiterRange, + interiorRange: undefined, + boundary: undefined, }; } } diff --git a/src/processTargets/modifiers/PositionStage.ts b/src/processTargets/modifiers/PositionStage.ts index fb47397886..4b605abc71 100644 --- a/src/processTargets/modifiers/PositionStage.ts +++ b/src/processTargets/modifiers/PositionStage.ts @@ -11,17 +11,21 @@ export default class implements ModifierStage { ): TypedSelection { const res: TypedSelection = { ...selection, + leadingDelimiterRange: undefined, + trailingDelimiterRange: undefined, }; switch (stage.position) { case "before": case "start": res.contentRange = range(res.contentRange.start)!; res.interiorRange = range(res.interiorRange?.start); + res.removalRange = range(res.removalRange?.start); break; case "after": case "end": res.contentRange = range(res.contentRange.end)!; res.interiorRange = range(res.interiorRange?.end); + res.removalRange = range(res.removalRange?.end); break; } return res; diff --git a/src/processTargets/modifiers/SubPieceStage.ts b/src/processTargets/modifiers/SubPieceStage.ts index daaf28ed66..6bc6dbd4a9 100644 --- a/src/processTargets/modifiers/SubPieceStage.ts +++ b/src/processTargets/modifiers/SubPieceStage.ts @@ -91,10 +91,12 @@ export default class implements ModifierStage { return { ...selection, isReversed, + contentRange: new Range(anchor, active), + interiorRange: undefined, + removalRange: undefined, delimiter: containingListDelimiter ?? undefined, leadingDelimiterRange, trailingDelimiterRange, - contentRange: new Range(anchor, active), }; } } diff --git a/src/processTargets/modifiers/SurroundingPairStage.ts b/src/processTargets/modifiers/SurroundingPairStage.ts index 45bf330c2a..4b62a1a3a3 100644 --- a/src/processTargets/modifiers/SurroundingPairStage.ts +++ b/src/processTargets/modifiers/SurroundingPairStage.ts @@ -41,13 +41,11 @@ export default class implements ModifierStage { ...selection, editor: pair.selection.editor, contentRange: pair.selection.selection, + interiorRange: pair.context.interior?.at(0)?.selection, removalRange: pair.context.outerSelection ?? undefined, isRawSelection: pair.context.isRawSelection, isNotebookCell: pair.context.isNotebookCell, delimiter: pair.context.containingListDelimiter ?? undefined, - interiorRange: pair.context.interior - ? pair.context.interior[0].selection - : undefined, boundary: pair.context.boundary?.map((bound) => bound.selection), leadingDelimiterRange: pair.context.leadingDelimiterRange ?? undefined, trailingDelimiterRange: pair.context.trailingDelimiterRange ?? undefined, From b019ff09fac6d5fe7f70d674dac2d1663a56175f Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 14 May 2022 19:40:59 +0200 Subject: [PATCH 024/314] Add mark and modifier to stage constructors --- src/processTargets/PipelineStages.types.ts | 4 +-- src/processTargets/getMarkStage.ts | 14 ++++---- src/processTargets/getModifierStage.ts | 32 +++++++++---------- src/processTargets/index.ts | 10 +++--- src/processTargets/marks/CursorStage.ts | 3 ++ src/processTargets/marks/CursorTokenStage.ts | 3 ++ .../marks/DecoratedSymbolStage.ts | 15 ++++----- src/processTargets/marks/LineNumberStage.ts | 12 ++++--- src/processTargets/marks/NothingStage.ts | 3 ++ src/processTargets/marks/SourceStage.ts | 3 ++ src/processTargets/marks/ThatStage.ts | 3 ++ .../modifiers/ContainingScopeStage.ts | 9 +++--- src/processTargets/modifiers/DocumentStage.ts | 8 +++-- src/processTargets/modifiers/HeadTailStage.ts | 7 ++-- src/processTargets/modifiers/LineStage.ts | 8 +++-- .../modifiers/NotebookCellStage.ts | 8 +++-- .../modifiers/ParagraphStage.ts | 8 +++-- src/processTargets/modifiers/PositionStage.ts | 5 +-- .../modifiers/RawSelectionStage.ts | 3 +- src/processTargets/modifiers/RegexStage.ts | 10 +++--- src/processTargets/modifiers/SubPieceStage.ts | 17 ++++++---- .../modifiers/SurroundingPairStage.ts | 5 +-- src/processTargets/modifiers/TokenStage.ts | 8 +++-- src/testUtil/TestCaseRecorder.ts | 4 +-- src/typings/target.types.ts | 28 ++++++++-------- 25 files changed, 138 insertions(+), 92 deletions(-) diff --git a/src/processTargets/PipelineStages.types.ts b/src/processTargets/PipelineStages.types.ts index 7430f1e7af..6fd33ccb87 100644 --- a/src/processTargets/PipelineStages.types.ts +++ b/src/processTargets/PipelineStages.types.ts @@ -1,14 +1,12 @@ -import { Mark, Modifier } from "../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../typings/Types"; export interface MarkStage { - run(context: ProcessedTargetsContext, mark: Mark): TypedSelection[]; + run(context: ProcessedTargetsContext): TypedSelection[]; } export interface ModifierStage { run( context: ProcessedTargetsContext, - modifier: Modifier, target?: TypedSelection ): TypedSelection | TypedSelection[]; } diff --git a/src/processTargets/getMarkStage.ts b/src/processTargets/getMarkStage.ts index 7319398aac..b8650f0711 100644 --- a/src/processTargets/getMarkStage.ts +++ b/src/processTargets/getMarkStage.ts @@ -11,18 +11,18 @@ import { MarkStage } from "./PipelineStages.types"; export default (mark: Mark): MarkStage => { switch (mark.type) { case "cursor": - return new CursorStage(); + return new CursorStage(mark); case "cursorToken": - return new CursorTokenStage(); + return new CursorTokenStage(mark); case "that": - return new ThatStage(); + return new ThatStage(mark); case "source": - return new SourceStage(); + return new SourceStage(mark); case "decoratedSymbol": - return new DecoratedSymbolStage(); + return new DecoratedSymbolStage(mark); case "lineNumber": - return new LineNumberStage(); + return new LineNumberStage(mark); case "nothing": - return new NothingStage(); + return new NothingStage(mark); } }; diff --git a/src/processTargets/getModifierStage.ts b/src/processTargets/getModifierStage.ts index 2110381023..5fc5f09d59 100644 --- a/src/processTargets/getModifierStage.ts +++ b/src/processTargets/getModifierStage.ts @@ -20,17 +20,17 @@ import { ModifierStage } from "./PipelineStages.types"; export default (modifier: Modifier): ModifierStage => { switch (modifier.type) { case "position": - return new PositionStage(); + return new PositionStage(modifier); case "head": - return new HeadStage(); + return new HeadStage(modifier); case "tail": - return new TailStage(); + return new TailStage(modifier); case "toRawSelection": - return new RawSelectionStage(); + return new RawSelectionStage(modifier); case "subpiece": - return new SubPieceStage(); + return new SubPieceStage(modifier); case "surroundingPair": - return new SurroundingPairStage(); + return new SurroundingPairStage(modifier); case "containingScope": case "everyScope": return getContainingScopeStage(modifier); @@ -38,24 +38,24 @@ export default (modifier: Modifier): ModifierStage => { }; const getContainingScopeStage = ( - stage: ContainingScopeModifier | EveryScopeModifier + modifier: ContainingScopeModifier | EveryScopeModifier ): ModifierStage => { - switch (stage.scopeType) { + switch (modifier.scopeType) { case "token": - return new TokenStage(); + return new TokenStage(modifier); case "notebookCell": - return new NotebookCellStage(); + return new NotebookCellStage(modifier); case "document": - return new DocumentStage(); + return new DocumentStage(modifier); case "line": - return new LineStage(); + return new LineStage(modifier); case "paragraph": - return new ParagraphStage(); + return new ParagraphStage(modifier); case "nonWhitespaceSequence": - return new NonWhitespaceSequenceStage(); + return new NonWhitespaceSequenceStage(modifier); case "url": - return new UrlStage(); + return new UrlStage(modifier); default: - return new ContainingScopeStage(); + return new ContainingScopeStage(modifier); } }; diff --git a/src/processTargets/index.ts b/src/processTargets/index.ts index 766368998c..f45b4cf644 100644 --- a/src/processTargets/index.ts +++ b/src/processTargets/index.ts @@ -216,21 +216,21 @@ function processPrimitiveTarget( target: PrimitiveTarget ): TypedSelection[] { const markStage = getMarkStage(target.mark); - let selections: TypedSelection[] = markStage.run(context, target.mark); + let selections: TypedSelection[] = markStage.run(context); for (let i = target.modifiers.length - 1; i > -1; --i) { - const stageDescriptor = target.modifiers[i]; - const stage = getModifierStage(stageDescriptor); + const modifier = target.modifiers[i]; + const stage = getModifierStage(modifier); const stageSelections: TypedSelection[] = []; for (const selection of selections) { - const stageResult = stage.run(context, stageDescriptor, selection); + const stageResult = stage.run(context, selection); if (Array.isArray(stageResult)) { stageSelections.push(...stageResult); } else { stageSelections.push(stageResult); } - selections = stageSelections; } + selections = stageSelections; } return selections; diff --git a/src/processTargets/marks/CursorStage.ts b/src/processTargets/marks/CursorStage.ts index 27be9721ff..0833aefc17 100644 --- a/src/processTargets/marks/CursorStage.ts +++ b/src/processTargets/marks/CursorStage.ts @@ -1,10 +1,13 @@ import { window } from "vscode"; +import { CursorMark } from "../../typings/target.types"; import { TypedSelection } from "../../typings/Types"; import { isReversed } from "../../util/selectionUtils"; import { getTokenContext } from "../modifiers/TokenStage"; import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { + constructor(private modifier: CursorMark) {} + run(): TypedSelection[] { if (window.activeTextEditor == null) { return []; diff --git a/src/processTargets/marks/CursorTokenStage.ts b/src/processTargets/marks/CursorTokenStage.ts index 000c2d6560..11dc298e13 100644 --- a/src/processTargets/marks/CursorTokenStage.ts +++ b/src/processTargets/marks/CursorTokenStage.ts @@ -1,4 +1,5 @@ import { Range, window } from "vscode"; +import { CursorTokenMark } from "../../typings/target.types"; import { SelectionWithEditor, TypedSelection } from "../../typings/Types"; import { getTokensInRange, PartialToken } from "../../util/getTokensInRange"; import { isReversed } from "../../util/selectionUtils"; @@ -6,6 +7,8 @@ import { getTokenContext } from "../modifiers/TokenStage"; import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { + constructor(private modifier: CursorTokenMark) {} + run(): TypedSelection[] { const editor = window.activeTextEditor; if (editor == null) { diff --git a/src/processTargets/marks/DecoratedSymbolStage.ts b/src/processTargets/marks/DecoratedSymbolStage.ts index 1e64217d17..10324ba2ea 100644 --- a/src/processTargets/marks/DecoratedSymbolStage.ts +++ b/src/processTargets/marks/DecoratedSymbolStage.ts @@ -1,20 +1,19 @@ -import { DecoratedSymbol } from "../../typings/target.types"; +import { DecoratedSymbolMark } from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; import { getTokenContext } from "../modifiers/TokenStage"; import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { - run( - context: ProcessedTargetsContext, - stage: DecoratedSymbol - ): TypedSelection[] { + constructor(private modifier: DecoratedSymbolMark) {} + + run(context: ProcessedTargetsContext): TypedSelection[] { const token = context.hatTokenMap.getToken( - stage.symbolColor, - stage.character + this.modifier.symbolColor, + this.modifier.character ); if (token == null) { throw new Error( - `Couldn't find mark ${stage.symbolColor} '${stage.character}'` + `Couldn't find mark ${this.modifier.symbolColor} '${this.modifier.character}'` ); } return [ diff --git a/src/processTargets/marks/LineNumberStage.ts b/src/processTargets/marks/LineNumberStage.ts index 870da19e9f..efd500b2e0 100644 --- a/src/processTargets/marks/LineNumberStage.ts +++ b/src/processTargets/marks/LineNumberStage.ts @@ -1,19 +1,21 @@ import { Range, TextEditor, window } from "vscode"; -import { LineNumber, LineNumberPosition } from "../../typings/target.types"; -import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import { LineNumberMark, LineNumberPosition } from "../../typings/target.types"; +import { TypedSelection } from "../../typings/Types"; import { getLineContext } from "../modifiers/LineStage"; import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { - run(context: ProcessedTargetsContext, stage: LineNumber): TypedSelection[] { + constructor(private modifier: LineNumberMark) {} + + run(): TypedSelection[] { if (window.activeTextEditor == null) { return []; } const editor = window.activeTextEditor; const contentRange = new Range( - getLine(editor, stage.anchor), + getLine(editor, this.modifier.anchor), 0, - getLine(editor, stage.active), + getLine(editor, this.modifier.active), 0 ); return [ diff --git a/src/processTargets/marks/NothingStage.ts b/src/processTargets/marks/NothingStage.ts index 4e9411ac12..28689d2edf 100644 --- a/src/processTargets/marks/NothingStage.ts +++ b/src/processTargets/marks/NothingStage.ts @@ -1,7 +1,10 @@ +import { NothingMark } from "../../typings/target.types"; import { TypedSelection } from "../../typings/Types"; import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { + constructor(private modifier: NothingMark) {} + run(): TypedSelection[] { return []; } diff --git a/src/processTargets/marks/SourceStage.ts b/src/processTargets/marks/SourceStage.ts index 7715e2be22..b54b39b25c 100644 --- a/src/processTargets/marks/SourceStage.ts +++ b/src/processTargets/marks/SourceStage.ts @@ -1,9 +1,12 @@ +import { SourceMark } from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; import { isReversed } from "../../util/selectionUtils"; import { getTokenContext } from "../modifiers/TokenStage"; import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { + constructor(private modifier: SourceMark) {} + run(context: ProcessedTargetsContext): TypedSelection[] { return context.sourceMark.map((selection) => ({ editor: selection.editor, diff --git a/src/processTargets/marks/ThatStage.ts b/src/processTargets/marks/ThatStage.ts index 1abd9721bf..3528d6bd3e 100644 --- a/src/processTargets/marks/ThatStage.ts +++ b/src/processTargets/marks/ThatStage.ts @@ -1,9 +1,12 @@ +import { ThatMark } from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; import { isReversed } from "../../util/selectionUtils"; import { getTokenContext } from "../modifiers/TokenStage"; import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { + constructor(private modifier: ThatMark) {} + run(context: ProcessedTargetsContext): TypedSelection[] { return context.thatMark.map((selection) => ({ editor: selection.editor, diff --git a/src/processTargets/modifiers/ContainingScopeStage.ts b/src/processTargets/modifiers/ContainingScopeStage.ts index b8b3bcce8a..096b537994 100644 --- a/src/processTargets/modifiers/ContainingScopeStage.ts +++ b/src/processTargets/modifiers/ContainingScopeStage.ts @@ -15,15 +15,16 @@ import { selectionWithEditorFromRange } from "../../util/selectionUtils"; import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { + constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} + run( context: ProcessedTargetsContext, - stage: ContainingScopeModifier | EveryScopeModifier, selection: TypedSelection ): TypedSelection[] { const nodeMatcher = getNodeMatcher( selection.editor.document.languageId, - stage.scopeType, - stage.type === "everyScope" + this.modifier.scopeType, + this.modifier.type === "everyScope" ); const node: SyntaxNode | null = context.getNodeAtLocation( new Location(selection.editor.document.uri, selection.contentRange.start) @@ -38,7 +39,7 @@ export default class implements ModifierStage { }); if (scopeNodes == null) { - throw new Error(`Couldn't find containing ${stage.scopeType}`); + throw new Error(`Couldn't find containing ${this.modifier.scopeType}`); } return scopeNodes.map((scope) => ({ diff --git a/src/processTargets/modifiers/DocumentStage.ts b/src/processTargets/modifiers/DocumentStage.ts index 0b9505d01d..26b4e2773d 100644 --- a/src/processTargets/modifiers/DocumentStage.ts +++ b/src/processTargets/modifiers/DocumentStage.ts @@ -1,13 +1,17 @@ import { Range, TextDocument } from "vscode"; -import { ContainingScopeModifier } from "../../typings/target.types"; +import { + ContainingScopeModifier, + EveryScopeModifier, +} from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; import { getDocumentRange } from "../../util/range"; import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { + constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} + run( context: ProcessedTargetsContext, - stage: ContainingScopeModifier, selection: TypedSelection ): TypedSelection { return { diff --git a/src/processTargets/modifiers/HeadTailStage.ts b/src/processTargets/modifiers/HeadTailStage.ts index f62ae3288d..e04486a1e7 100644 --- a/src/processTargets/modifiers/HeadTailStage.ts +++ b/src/processTargets/modifiers/HeadTailStage.ts @@ -10,7 +10,6 @@ abstract class HeadTailStage implements ModifierStage { run( context: ProcessedTargetsContext, - stage: HeadModifier | TailModifier, selection: TypedSelection ): TypedSelection { return { @@ -25,18 +24,20 @@ abstract class HeadTailStage implements ModifierStage { } export class HeadStage extends HeadTailStage { - constructor() { + constructor(private modifier: HeadModifier) { super(true); } + update(editor: TextEditor, range: Range) { return new Range(new Position(range.start.line, 0), range.end); } } export class TailStage extends HeadTailStage { - constructor() { + constructor(private modifier: TailModifier) { super(false); } + update(editor: TextEditor, range: Range) { return new Range(range.start, editor.document.lineAt(range.end).range.end); } diff --git a/src/processTargets/modifiers/LineStage.ts b/src/processTargets/modifiers/LineStage.ts index f223709f23..96c51bc23f 100644 --- a/src/processTargets/modifiers/LineStage.ts +++ b/src/processTargets/modifiers/LineStage.ts @@ -1,12 +1,16 @@ import { Position, Range, TextEditor } from "vscode"; -import { ContainingScopeModifier } from "../../typings/target.types"; +import { + ContainingScopeModifier, + EveryScopeModifier, +} from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { + constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} + run( context: ProcessedTargetsContext, - stage: ContainingScopeModifier, selection: TypedSelection ): TypedSelection { const { document } = selection.editor; diff --git a/src/processTargets/modifiers/NotebookCellStage.ts b/src/processTargets/modifiers/NotebookCellStage.ts index 9efc23d5f1..70a7db3bf4 100644 --- a/src/processTargets/modifiers/NotebookCellStage.ts +++ b/src/processTargets/modifiers/NotebookCellStage.ts @@ -1,11 +1,15 @@ -import { ContainingScopeModifier } from "../../typings/target.types"; +import { + ContainingScopeModifier, + EveryScopeModifier, +} from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { + constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} + run( context: ProcessedTargetsContext, - stage: ContainingScopeModifier, selection: TypedSelection ): TypedSelection { return { diff --git a/src/processTargets/modifiers/ParagraphStage.ts b/src/processTargets/modifiers/ParagraphStage.ts index 01b56a6f82..672d1bea7f 100644 --- a/src/processTargets/modifiers/ParagraphStage.ts +++ b/src/processTargets/modifiers/ParagraphStage.ts @@ -1,12 +1,16 @@ import { Position, Range, TextDocument } from "vscode"; -import { ContainingScopeModifier } from "../../typings/target.types"; +import { + ContainingScopeModifier, + EveryScopeModifier, +} from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { + constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} + run( context: ProcessedTargetsContext, - stage: ContainingScopeModifier, selection: TypedSelection ): TypedSelection { const { document } = selection.editor; diff --git a/src/processTargets/modifiers/PositionStage.ts b/src/processTargets/modifiers/PositionStage.ts index 4b605abc71..4b052879c8 100644 --- a/src/processTargets/modifiers/PositionStage.ts +++ b/src/processTargets/modifiers/PositionStage.ts @@ -4,9 +4,10 @@ import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { + constructor(private modifier: PositionModifier) {} + run( context: ProcessedTargetsContext, - stage: PositionModifier, selection: TypedSelection ): TypedSelection { const res: TypedSelection = { @@ -14,7 +15,7 @@ export default class implements ModifierStage { leadingDelimiterRange: undefined, trailingDelimiterRange: undefined, }; - switch (stage.position) { + switch (this.modifier.position) { case "before": case "start": res.contentRange = range(res.contentRange.start)!; diff --git a/src/processTargets/modifiers/RawSelectionStage.ts b/src/processTargets/modifiers/RawSelectionStage.ts index 43bc9743dc..c9a73f53ba 100644 --- a/src/processTargets/modifiers/RawSelectionStage.ts +++ b/src/processTargets/modifiers/RawSelectionStage.ts @@ -3,9 +3,10 @@ import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { + constructor(private modifier: RawSelectionModifier) {} + run( context: ProcessedTargetsContext, - stage: RawSelectionModifier, selection: TypedSelection ): TypedSelection { return { ...selection, isRawSelection: true }; diff --git a/src/processTargets/modifiers/RegexStage.ts b/src/processTargets/modifiers/RegexStage.ts index 35560c4375..f24617c4fb 100644 --- a/src/processTargets/modifiers/RegexStage.ts +++ b/src/processTargets/modifiers/RegexStage.ts @@ -1,5 +1,8 @@ import { Position, Range } from "vscode"; -import { ContainingScopeModifier } from "../../typings/target.types"; +import { + ContainingScopeModifier, + EveryScopeModifier, +} from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; import { getTokenContext } from "./TokenStage"; @@ -9,7 +12,6 @@ class RegexStage implements ModifierStage { run( context: ProcessedTargetsContext, - stage: ContainingScopeModifier, selection: TypedSelection ): TypedSelection { const getMatch = (position: Position) => { @@ -50,7 +52,7 @@ class RegexStage implements ModifierStage { } export class NonWhitespaceSequenceStage extends RegexStage { - constructor() { + constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) { super(/\S+/g, "Non whitespace sequence"); } } @@ -60,7 +62,7 @@ const URL_REGEX = /(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/g; export class UrlStage extends RegexStage { - constructor() { + constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) { super(URL_REGEX, "URL"); } } diff --git a/src/processTargets/modifiers/SubPieceStage.ts b/src/processTargets/modifiers/SubPieceStage.ts index 6bc6dbd4a9..5c8f99a6c0 100644 --- a/src/processTargets/modifiers/SubPieceStage.ts +++ b/src/processTargets/modifiers/SubPieceStage.ts @@ -6,24 +6,25 @@ import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { + constructor(private modifier: SubTokenModifier) {} + run( context: ProcessedTargetsContext, - stage: SubTokenModifier, selection: TypedSelection ): TypedSelection { const token = selection.editor.document.getText(selection.contentRange); let pieces: { start: number; end: number }[] = []; - if (stage.excludeActive || stage.excludeAnchor) { + if (this.modifier.excludeActive || this.modifier.excludeAnchor) { throw new Error("Subtoken exclusions unsupported"); } - if (stage.pieceType === "word") { + if (this.modifier.pieceType === "word") { pieces = [...token.matchAll(SUBWORD_MATCHER)].map((match) => ({ start: match.index!, end: match.index! + match[0].length, })); - } else if (stage.pieceType === "character") { + } else if (this.modifier.pieceType === "character") { pieces = range(token.length).map((index) => ({ start: index, end: index + 1, @@ -31,9 +32,13 @@ export default class implements ModifierStage { } const anchorIndex = - stage.anchor < 0 ? stage.anchor + pieces.length : stage.anchor; + this.modifier.anchor < 0 + ? this.modifier.anchor + pieces.length + : this.modifier.anchor; const activeIndex = - stage.active < 0 ? stage.active + pieces.length : stage.active; + this.modifier.active < 0 + ? this.modifier.active + pieces.length + : this.modifier.active; if ( anchorIndex < 0 || diff --git a/src/processTargets/modifiers/SurroundingPairStage.ts b/src/processTargets/modifiers/SurroundingPairStage.ts index 4b62a1a3a3..be9263341f 100644 --- a/src/processTargets/modifiers/SurroundingPairStage.ts +++ b/src/processTargets/modifiers/SurroundingPairStage.ts @@ -28,12 +28,13 @@ import { findSurroundingPairTextBased } from "./surroundingPair/findSurroundingP * `null` if none was found */ export default class implements ModifierStage { + constructor(private modifier: SurroundingPairModifier) {} + run( context: ProcessedTargetsContext, - modifier: SurroundingPairModifier, selection: TypedSelection ): TypedSelection | TypedSelection[] { - const pairs = processSurroundingPair(context, modifier, selection); + const pairs = processSurroundingPair(context, this.modifier, selection); if (pairs == null) { throw new Error("Couldn't find containing pair"); } diff --git a/src/processTargets/modifiers/TokenStage.ts b/src/processTargets/modifiers/TokenStage.ts index 9c8f1cd35b..63f3dc9458 100644 --- a/src/processTargets/modifiers/TokenStage.ts +++ b/src/processTargets/modifiers/TokenStage.ts @@ -1,12 +1,16 @@ import { Range, TextEditor } from "vscode"; -import { ContainingScopeModifier } from "../../typings/target.types"; +import { + ContainingScopeModifier, + EveryScopeModifier, +} from "../../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { + constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} + run( context: ProcessedTargetsContext, - stage: ContainingScopeModifier, selection: TypedSelection ): TypedSelection { return { diff --git a/src/testUtil/TestCaseRecorder.ts b/src/testUtil/TestCaseRecorder.ts index b4fe7f2138..ed7f86dcbe 100644 --- a/src/testUtil/TestCaseRecorder.ts +++ b/src/testUtil/TestCaseRecorder.ts @@ -4,7 +4,7 @@ import * as path from "path"; import * as vscode from "vscode"; import HatTokenMap from "../core/HatTokenMap"; import { Graph } from "../typings/Types"; -import { DecoratedSymbol } from "../typings/target.types"; +import { DecoratedSymbolMark } from "../typings/target.types"; import { getDocumentRange } from "../util/range"; import sleep from "../util/sleep"; import { extractTargetedMarks } from "./extractTargetedMarks"; @@ -124,7 +124,7 @@ export class TestCaseRecorder { async ( outPath: string, metadata: unknown, - targetedMarks: DecoratedSymbol[], + targetedMarks: DecoratedSymbolMark[], usePrePhraseSnapshot: boolean ) => { let marks: SerializedMarks | undefined; diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 194c0143a3..3a39c14518 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -4,27 +4,27 @@ export interface CursorMark { type: "cursor"; } -export interface CursorMarkToken { +export interface CursorTokenMark { type: "cursorToken"; } -export interface That { +export interface ThatMark { type: "that"; } -export interface Source { +export interface SourceMark { type: "source"; } -export interface Nothing { +export interface NothingMark { type: "nothing"; } -export interface LastCursorPosition { +export interface LastCursorPositionMark { type: "lastCursorPosition"; } -export interface DecoratedSymbol { +export interface DecoratedSymbolMark { type: "decoratedSymbol"; symbolColor: HatStyleName; character: string; @@ -37,7 +37,7 @@ export interface LineNumberPosition { lineNumber: number; } -export interface LineNumber { +export interface LineNumberMark { type: "lineNumber"; anchor: LineNumberPosition; active: LineNumberPosition; @@ -45,13 +45,13 @@ export interface LineNumber { export type Mark = | CursorMark - | CursorMarkToken - | That - | Source - // | LastCursorPosition Not implemented yet - | DecoratedSymbol - | Nothing - | LineNumber; + | CursorTokenMark + | ThatMark + | SourceMark + // | LastCursorPositionMark Not implemented yet + | DecoratedSymbolMark + | NothingMark + | LineNumberMark; export type SimpleSurroundingPairName = | "angleBrackets" From b7d64f388a50c4c6ad9a4bec85de721749441ff9 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 15 May 2022 10:40:09 +0200 Subject: [PATCH 025/314] Fixed all problems outside of actions --- src/core/commandRunner/CommandRunner.ts | 8 +- .../canonicalizeAndValidateCommand.ts | 17 +- .../canonicalizeTargets.ts | 18 +- src/processTargets/index.ts | 26 +-- .../updateSurroundingPairTest.ts | 31 +-- .../transformations/upgrade.ts | 6 +- src/testUtil/TestCase.ts | 16 +- src/testUtil/cleanUpTestCaseCommand.ts | 2 +- src/typings/Types.ts | 10 +- src/util/editDisplayUtils.ts | 26 +-- src/util/getLinks.ts | 4 +- src/util/getTextWithPossibleDelimiter.ts | 29 --- src/util/performInsideOutsideAdjustment.ts | 49 ---- src/util/selectionType.ts | 5 - src/util/selectionUtils.ts | 51 +---- src/util/targetUtils.ts | 34 +-- src/util/unifyRanges.ts | 213 +++++++++--------- 17 files changed, 201 insertions(+), 344 deletions(-) delete mode 100644 src/util/getTextWithPossibleDelimiter.ts delete mode 100644 src/util/performInsideOutsideAdjustment.ts delete mode 100644 src/util/selectionType.ts diff --git a/src/core/commandRunner/CommandRunner.ts b/src/core/commandRunner/CommandRunner.ts index 5f3e7ad526..97683743b3 100644 --- a/src/core/commandRunner/CommandRunner.ts +++ b/src/core/commandRunner/CommandRunner.ts @@ -65,13 +65,14 @@ export default class CommandRunner { this.graph.debug.log(JSON.stringify(command, null, 3)); } + const commandComplete = canonicalizeAndValidateCommand(command); const { spokenForm, action: actionName, targets: partialTargets, extraArgs, usePrePhraseSnapshot, - } = canonicalizeAndValidateCommand(command); + } = commandComplete; const readableHatMap = await this.graph.hatTokenMap.getReadableMap( usePrePhraseSnapshot @@ -110,7 +111,10 @@ export default class CommandRunner { hatTokenMap: readableHatMap, spokenForm, }; - await this.graph.testCaseRecorder.preCommandHook(command, context); + await this.graph.testCaseRecorder.preCommandHook( + commandComplete, + context + ); } const { diff --git a/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts b/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts index a950eca05c..f9773ec8f9 100644 --- a/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts +++ b/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts @@ -1,6 +1,6 @@ import { commands } from "vscode"; import { ActionableError } from "../../errors"; -import { PartialTarget, SelectionType } from "../../typings/target.types"; +import { PartialTarget, ScopeType } from "../../typings/target.types"; import { ActionType } from "../../typings/Types"; import { getPartialPrimitiveTargets } from "../../util/getPrimitiveTargets"; import { @@ -84,7 +84,7 @@ export function validateCommand( partialTargets: PartialTarget[] ) { if ( - usesSelectionType("notebookCell", partialTargets) && + usesScopeType("notebookCell", partialTargets) && !["editNewLineBefore", "editNewLineAfter"].includes(actionName) ) { throw new Error( @@ -93,11 +93,12 @@ export function validateCommand( } } -function usesSelectionType( - selectionType: SelectionType, - partialTargets: PartialTarget[] -) { - return getPartialPrimitiveTargets(partialTargets).some( - (partialTarget) => partialTarget.selectionType === selectionType +function usesScopeType(scopeType: ScopeType, partialTargets: PartialTarget[]) { + return getPartialPrimitiveTargets(partialTargets).some((partialTarget) => + partialTarget.modifiers?.find( + (mod) => + (mod.type === "containingScope" || mod.type === "everyScope") && + mod.scopeType === scopeType + ) ); } diff --git a/src/core/commandVersionUpgrades/canonicalizeTargets.ts b/src/core/commandVersionUpgrades/canonicalizeTargets.ts index 0fa137acea..1d332ccce4 100644 --- a/src/core/commandVersionUpgrades/canonicalizeTargets.ts +++ b/src/core/commandVersionUpgrades/canonicalizeTargets.ts @@ -20,15 +20,15 @@ const COLOR_CANONICALIZATION_MAPPING: Record = { const canonicalizeScopeTypes = ( target: PartialPrimitiveTarget -): PartialPrimitiveTarget => - target.modifier?.type === "containingScope" - ? update(target, { - modifier: { - scopeType: (scopeType: string) => - SCOPE_TYPE_CANONICALIZATION_MAPPING[scopeType] ?? scopeType, - }, - }) - : target; +): PartialPrimitiveTarget => { + target.modifiers?.forEach((mod) => { + if (mod.type === "containingScope" || mod.type === "everyScope") { + mod.scopeType = + SCOPE_TYPE_CANONICALIZATION_MAPPING[mod.scopeType] ?? mod.scopeType; + } + }); + return target; +}; const canonicalizeColors = ( target: PartialPrimitiveTarget diff --git a/src/processTargets/index.ts b/src/processTargets/index.ts index f45b4cf644..f16f736502 100644 --- a/src/processTargets/index.ts +++ b/src/processTargets/index.ts @@ -2,7 +2,6 @@ import { isEqual, zip } from "lodash"; import { Range } from "vscode"; import { PrimitiveTarget, RangeTarget, Target } from "../typings/target.types"; import { ProcessedTargetsContext, TypedSelection } from "../typings/Types"; -import { performInsideOutsideAdjustment } from "../util/performInsideOutsideAdjustment"; import getMarkStage from "./getMarkStage"; import getModifierStage from "./getModifierStage"; @@ -36,32 +35,15 @@ function processTarget( switch (target.type) { case "list": return target.elements.flatMap((element) => - processNonListTarget(context, element) + processTarget(context, element) ); case "range": + return processRangeTarget(context, target); case "primitive": - return processNonListTarget(context, target); + return processPrimitiveTarget(context, target); } } -function processNonListTarget( - context: ProcessedTargetsContext, - target: RangeTarget | PrimitiveTarget -): TypedSelection[] { - let selections; - switch (target.type) { - case "range": - selections = processRangeTarget(context, target); - break; - case "primitive": - selections = processPrimitiveTarget(context, target); - break; - } - return selections.map((selection) => - performInsideOutsideAdjustment(selection) - ); -} - function processRangeTarget( context: ProcessedTargetsContext, target: RangeTarget @@ -216,7 +198,7 @@ function processPrimitiveTarget( target: PrimitiveTarget ): TypedSelection[] { const markStage = getMarkStage(target.mark); - let selections: TypedSelection[] = markStage.run(context); + let selections = markStage.run(context); for (let i = target.modifiers.length - 1; i > -1; --i) { const modifier = target.modifiers[i]; diff --git a/src/scripts/transformRecordedTests/transformations/updateSurroundingPairTest.ts b/src/scripts/transformRecordedTests/transformations/updateSurroundingPairTest.ts index a7f3c94bc2..4b49e26eaa 100644 --- a/src/scripts/transformRecordedTests/transformations/updateSurroundingPairTest.ts +++ b/src/scripts/transformRecordedTests/transformations/updateSurroundingPairTest.ts @@ -10,23 +10,26 @@ export function updateSurroundingPairTest(fixture: TestCaseFixture) { fixture.command.targets = transformPartialPrimitiveTargets( fixture.command.targets, (target: PartialPrimitiveTarget) => { - if (target.modifier?.type === "surroundingPair") { - let delimiterInclusion: DelimiterInclusion; + target.modifiers?.forEach((modifier) => { + if (modifier?.type === "surroundingPair") { + let delimiterInclusion: DelimiterInclusion; - switch (target.modifier.delimiterInclusion as any) { - case "includeDelimiters": - delimiterInclusion = undefined; - break; - case "excludeDelimiters": - delimiterInclusion = "interiorOnly"; - break; - case "delimitersOnly": - delimiterInclusion = "excludeInterior"; - break; + switch (modifier.delimiterInclusion as any) { + case "includeDelimiters": + delimiterInclusion = undefined; + break; + case "excludeDelimiters": + delimiterInclusion = "interiorOnly"; + break; + case "delimitersOnly": + delimiterInclusion = "excludeInterior"; + break; + } + + modifier.delimiterInclusion = delimiterInclusion; } + }); - target.modifier.delimiterInclusion = delimiterInclusion; - } return target; } ); diff --git a/src/scripts/transformRecordedTests/transformations/upgrade.ts b/src/scripts/transformRecordedTests/transformations/upgrade.ts index b9cb93b2a8..e47268c0c9 100644 --- a/src/scripts/transformRecordedTests/transformations/upgrade.ts +++ b/src/scripts/transformRecordedTests/transformations/upgrade.ts @@ -1,9 +1,9 @@ -import { TestCaseFixture } from "../../../testUtil/TestCase"; -import { canonicalizeAndValidateCommand } from "../../../util/canonicalizeAndValidateCommand"; import { flow } from "lodash"; +import { canonicalizeAndValidateCommand } from "../../../core/commandVersionUpgrades/canonicalizeAndValidateCommand"; import { cleanUpTestCaseCommand } from "../../../testUtil/cleanUpTestCaseCommand"; -import { upgradeFromVersion0 } from "./upgradeFromVersion0"; +import { TestCaseFixture } from "../../../testUtil/TestCase"; import { reorderFields } from "./reorderFields"; +import { upgradeFromVersion0 } from "./upgradeFromVersion0"; export const upgrade = flow(upgradeFromVersion0, upgradeCommand, reorderFields); diff --git a/src/testUtil/TestCase.ts b/src/testUtil/TestCase.ts index 9dd1033d9e..39dccb90f6 100644 --- a/src/testUtil/TestCase.ts +++ b/src/testUtil/TestCase.ts @@ -1,24 +1,24 @@ +import { pick } from "lodash"; import * as vscode from "vscode"; +import { CommandLatest } from "../core/commandRunner/command.types"; +import { ReadOnlyHatMap } from "../core/IndividualHatMap"; import { ThatMark } from "../core/ThatMark"; -import { Token } from "../typings/Types"; import { Target } from "../typings/target.types"; +import { Token } from "../typings/Types"; +import { cleanUpTestCaseCommand } from "./cleanUpTestCaseCommand"; import { extractTargetedMarks, extractTargetKeys, } from "./extractTargetedMarks"; -import { marksToPlainObject, SerializedMarks } from "./toPlainObject"; +import serialize from "./serialize"; import { ExtraSnapshotField, takeSnapshot, TestCaseSnapshot, } from "./takeSnapshot"; -import serialize from "./serialize"; -import { pick } from "lodash"; -import { ReadOnlyHatMap } from "../core/IndividualHatMap"; -import { Command } from "../core/commandRunner/command.types"; -import { cleanUpTestCaseCommand } from "./cleanUpTestCaseCommand"; +import { marksToPlainObject, SerializedMarks } from "./toPlainObject"; -export type TestCaseCommand = Command; +export type TestCaseCommand = CommandLatest; export type TestCaseContext = { thatMark: ThatMark; diff --git a/src/testUtil/cleanUpTestCaseCommand.ts b/src/testUtil/cleanUpTestCaseCommand.ts index c1822abba2..f61acd841d 100644 --- a/src/testUtil/cleanUpTestCaseCommand.ts +++ b/src/testUtil/cleanUpTestCaseCommand.ts @@ -3,7 +3,7 @@ import { TestCaseCommand } from "./TestCase"; export function cleanUpTestCaseCommand( command: TestCaseCommand ): TestCaseCommand { - const { extraArgs, usePrePhraseSnapshot, ...rest } = command; + const { extraArgs, ...rest } = command; return { ...rest, diff --git a/src/typings/Types.ts b/src/typings/Types.ts index a500f52a3d..3407b80d5b 100644 --- a/src/typings/Types.ts +++ b/src/typings/Types.ts @@ -11,7 +11,6 @@ import { Snippets } from "../core/Snippets"; import { RangeUpdater } from "../core/updateSelections/RangeUpdater"; import { TestCaseRecorder } from "../testUtil/TestCaseRecorder"; import { CommandServerApi } from "../util/getExtensionApi"; -import { Position } from "./target.types"; import { FullRangeInfo } from "./updateSelections"; /** @@ -159,10 +158,11 @@ export interface TypedSelection { } export interface ActionPreferences { - position?: Position; - insideOutsideType: InsideOutsideType; - selectionType?: SelectionType; - modifier?: Modifier; + // TODO + // position?: Position; + // insideOutsideType: InsideOutsideType; + // selectionType?: SelectionType; + // modifier?: Modifier; } export type SelectionWithEditorWithContext = { diff --git a/src/util/editDisplayUtils.ts b/src/util/editDisplayUtils.ts index 33800ff545..68d3358cfa 100644 --- a/src/util/editDisplayUtils.ts +++ b/src/util/editDisplayUtils.ts @@ -1,10 +1,9 @@ import { TextEditorDecorationType, window, workspace } from "vscode"; -import { TypedSelection, SelectionWithEditor } from "../typings/Types"; -import { isLineSelectionType } from "./selectionType"; -import { runOnTargetsForEachEditor, runForEachEditor } from "./targetUtils"; import { EditStyle } from "../core/editStyles"; import isTesting from "../testUtil/isTesting"; +import { SelectionWithEditor, TypedSelection } from "../typings/Types"; import sleep from "./sleep"; +import { runForEachEditor, runOnTargetsForEachEditor } from "./targetUtils"; const getPendingEditDecorationTime = () => workspace @@ -72,7 +71,7 @@ export async function setDecorations( editStyle.token, selections .filter((selection) => !useLineDecorations(selection)) - .map((selection) => selection.selection.selection) + .map((selection) => selection.contentRange) ); editor.setDecorations( @@ -80,8 +79,8 @@ export async function setDecorations( selections .filter((selection) => useLineDecorations(selection)) .map((selection) => { - const { document } = selection.selection.editor; - const { start, end } = selection.selection.selection; + const { document } = selection.editor; + const { start, end } = selection.contentRange; const startLine = document.lineAt(start); const hasLeadingLine = start.character === startLine.range.end.character; @@ -91,26 +90,27 @@ export async function setDecorations( ) { // NB: We move end up one line because it is at beginning of // next line - return selection.selection.selection.with({ + return selection.contentRange.with({ end: end.translate(-1), }); } if (hasLeadingLine) { // NB: We move start down one line because it is at end of // previous line - return selection.selection.selection.with({ + return selection.contentRange.with({ start: start.translate(1), }); } - return selection.selection.selection; + return selection.contentRange; }) ); }); } function useLineDecorations(selection: TypedSelection) { - return ( - isLineSelectionType(selection.selectionType) && - selection.position === "contents" - ); + return false; // TODO + // return ( + // isLineSelectionType(selection.selectionType) && + // selection.position === "contents" + // ); } diff --git a/src/util/getLinks.ts b/src/util/getLinks.ts index de5dbd8ca8..8400be2514 100644 --- a/src/util/getLinks.ts +++ b/src/util/getLinks.ts @@ -12,8 +12,8 @@ export async function getLinksForSelections( } export async function getLinkForTarget(target: TypedSelection) { - const links = await getLinksForEditor(target.selection.editor); - return links.find((link) => link.range.contains(target.selection.selection)); + const links = await getLinksForEditor(target.editor); + return links.find((link) => link.range.contains(target.contentRange)); } function getLinksForEditor(editor: vscode.TextEditor) { diff --git a/src/util/getTextWithPossibleDelimiter.ts b/src/util/getTextWithPossibleDelimiter.ts deleted file mode 100644 index 977e4b78d8..0000000000 --- a/src/util/getTextWithPossibleDelimiter.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { TypedSelection } from "../typings/Types"; - -/** Get text from selection. Possibly add delimiter for positions before/after */ -export function getTextWithPossibleDelimiter( - source: TypedSelection, - destination: TypedSelection -) { - const sourceText = source.selection.editor.document.getText( - source.selection.selection - ); - return maybeAddDelimiter(sourceText, destination); -} - -/** Possibly add delimiter for positions before/after */ -export function maybeAddDelimiter( - sourceText: string, - destination: TypedSelection -) { - const { insideOutsideType, position } = destination; - const containingListDelimiter = - destination.selectionContext.containingListDelimiter; - return containingListDelimiter == null || - position === "contents" || - insideOutsideType === "inside" - ? sourceText - : destination.position === "after" - ? containingListDelimiter + sourceText - : sourceText + containingListDelimiter; -} diff --git a/src/util/performInsideOutsideAdjustment.ts b/src/util/performInsideOutsideAdjustment.ts deleted file mode 100644 index 8dce8c4264..0000000000 --- a/src/util/performInsideOutsideAdjustment.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { TypedSelection } from "../typings/Types"; -import { InsideOutsideType } from "../typings/target.types"; -import { updateTypedSelectionRange } from "./selectionUtils"; - -export function performInsideOutsideAdjustment( - selection: TypedSelection, - preferredInsideOutsideType: InsideOutsideType = null -): TypedSelection { - const insideOutsideType = - selection.insideOutsideType ?? preferredInsideOutsideType; - - if (insideOutsideType === "outside") { - if (selection.position !== "contents") { - const delimiterRange = - selection.position === "before" - ? selection.selectionContext.leadingDelimiterRange - : selection.selectionContext.trailingDelimiterRange; - - return delimiterRange == null - ? selection - : updateTypedSelectionRange(selection, delimiterRange); - } - - const usedSelection = - selection.selectionContext.outerSelection ?? - selection.selection.selection; - - const delimiterRange = - selection.selectionContext.trailingDelimiterRange ?? - selection.selectionContext.leadingDelimiterRange; - - const range = - delimiterRange != null - ? usedSelection.union(delimiterRange) - : usedSelection; - - return updateTypedSelectionRange(selection, range); - } - - return selection; -} - -export function performInsideAdjustment(selection: TypedSelection) { - return performInsideOutsideAdjustment(selection, "inside"); -} - -export function performOutsideAdjustment(selection: TypedSelection) { - return performInsideOutsideAdjustment(selection, "outside"); -} diff --git a/src/util/selectionType.ts b/src/util/selectionType.ts deleted file mode 100644 index 41734dfc6a..0000000000 --- a/src/util/selectionType.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { SelectionType } from "../typings/target.types"; - -export function isLineSelectionType(selectionType: SelectionType) { - return selectionType === "line" || selectionType === "paragraph"; -} diff --git a/src/util/selectionUtils.ts b/src/util/selectionUtils.ts index a03a5ae5c3..254775ceee 100644 --- a/src/util/selectionUtils.ts +++ b/src/util/selectionUtils.ts @@ -1,24 +1,5 @@ -import { Range, Selection, Position } from "vscode"; -import update from "immutability-helper"; -import { TypedSelection, SelectionWithEditor } from "../typings/Types"; - -export function selectionFromRange( - selection: Selection, - range: Range -): Selection { - return selectionFromPositions(selection, range.start, range.end); -} - -export function selectionFromPositions( - selection: Selection, - start: Position, - end: Position -): Selection { - // The built in isReversed is bugged on empty selection. don't use - return isForward(selection) - ? new Selection(start, end) - : new Selection(end, start); -} +import { Position, Range, Selection } from "vscode"; +import { SelectionWithEditor } from "../typings/Types"; export function isForward(selection: Selection) { return selection.active.isAfterOrEqual(selection.anchor); @@ -35,7 +16,7 @@ export function selectionWithEditorFromRange( return selectionWithEditorFromPositions(selection, range.start, range.end); } -export function selectionWithEditorFromPositions( +function selectionWithEditorFromPositions( selection: SelectionWithEditor, start: Position, end: Position @@ -46,21 +27,13 @@ export function selectionWithEditorFromPositions( }; } -/** - * Returns a copy of the given typed selection so that the new selection has the new given range - * preserving the direction of the original selection - * - * @param selection The original typed selection to Update - * @param range The new range for the given selection - * @returns The updated typed selection - */ -export function updateTypedSelectionRange( - selection: TypedSelection, - range: Range -): TypedSelection { - return update(selection, { - selection: { - selection: () => selectionFromRange(selection.selection.selection, range), - }, - }); +function selectionFromPositions( + selection: Selection, + start: Position, + end: Position +): Selection { + // The built in isReversed is bugged on empty selection. don't use + return isForward(selection) + ? new Selection(start, end) + : new Selection(end, start); } diff --git a/src/util/targetUtils.ts b/src/util/targetUtils.ts index 86b3b97ac1..395412a2bb 100644 --- a/src/util/targetUtils.ts +++ b/src/util/targetUtils.ts @@ -1,13 +1,13 @@ -import { TextEditor, Selection, Position } from "vscode"; -import { groupBy } from "./itertools"; +import { Position, Range, TextEditor } from "vscode"; import { TypedSelection } from "../typings/Types"; +import { groupBy } from "./itertools"; export function ensureSingleEditor(targets: TypedSelection[]) { if (targets.length === 0) { throw new Error("Require at least one target with this action"); } - const editors = targets.map((target) => target.selection.editor); + const editors = targets.map((target) => target.editor); if (new Set(editors).size > 1) { throw new Error("Can only have one editor with this action"); @@ -40,11 +40,11 @@ export async function runOnTargetsForEachEditor( targets: TypedSelection[], func: (editor: TextEditor, selections: TypedSelection[]) => Promise ): Promise { - return runForEachEditor(targets, (target) => target.selection.editor, func); + return runForEachEditor(targets, (target) => target.editor, func); } export function groupTargetsForEachEditor(targets: TypedSelection[]) { - return groupForEachEditor(targets, (target) => target.selection.editor); + return groupForEachEditor(targets, (target) => target.editor); } export function groupForEachEditor( @@ -66,23 +66,17 @@ export function getOutsideOverflow( insideTarget: TypedSelection, outsideTarget: TypedSelection ): TypedSelection[] { - const { start: insideStart, end: insideEnd } = - insideTarget.selection.selection; - const { start: outsideStart, end: outsideEnd } = - outsideTarget.selection.selection; + const { start: insideStart, end: insideEnd } = insideTarget.contentRange; + const { start: outsideStart, end: outsideEnd } = outsideTarget.contentRange; const result = []; if (outsideStart.isBefore(insideStart)) { result.push( - createTypeSelection( - insideTarget.selection.editor, - outsideStart, - insideStart - ) + createTypeSelection(insideTarget.editor, outsideStart, insideStart) ); } if (outsideEnd.isAfter(insideEnd)) { result.push( - createTypeSelection(insideTarget.selection.editor, insideEnd, outsideEnd) + createTypeSelection(insideTarget.editor, insideEnd, outsideEnd) ); } return result; @@ -94,13 +88,7 @@ function createTypeSelection( end: Position ): TypedSelection { return { - selection: { - editor, - selection: new Selection(start, end), - }, - selectionType: "token", - selectionContext: {}, - insideOutsideType: "inside", - position: "contents", + editor, + contentRange: new Range(start, end), }; } diff --git a/src/util/unifyRanges.ts b/src/util/unifyRanges.ts index dc12103b0c..c66798f398 100644 --- a/src/util/unifyRanges.ts +++ b/src/util/unifyRanges.ts @@ -1,118 +1,107 @@ -import { Range, Selection } from "vscode"; -import { TypedSelection } from "../typings/Types"; -import { performInsideOutsideAdjustment } from "./performInsideOutsideAdjustment"; -import { groupTargetsForEachEditor } from "./targetUtils"; +// TODO +// import { Range } from "vscode"; +// import { TypedSelection } from "../typings/Types"; +// import { performInsideOutsideAdjustment } from "./performInsideOutsideAdjustment"; +// import { groupTargetsForEachEditor } from "./targetUtils"; -/** Unifies overlapping/intersecting ranges */ -export default function unifyRanges(ranges: Range[]): Range[] { - if (ranges.length < 2) { - return ranges; - } - let run = true; - while (run) { - [ranges, run] = unifyRangesOnePass(ranges); - } - return ranges; -} +// /** Unifies overlapping/intersecting ranges */ +// export default function unifyRanges(ranges: Range[]): Range[] { +// if (ranges.length < 2) { +// return ranges; +// } +// let run = true; +// while (run) { +// [ranges, run] = unifyRangesOnePass(ranges); +// } +// return ranges; +// } -function unifyRangesOnePass(ranges: Range[]): [Range[], boolean] { - if (ranges.length < 2) { - return [ranges, false]; - } - const result: Range[] = []; - let madeChanges = false; - ranges.forEach((range) => { - const index = result.findIndex((r) => r.intersection(range) != null); - // Update existing intersecting range - if (index > -1) { - result[index] = result[index].union(range); - madeChanges = true; - } - // Add new range - else { - result.push(range); - } - }); - return [result, madeChanges]; -} +// function unifyRangesOnePass(ranges: Range[]): [Range[], boolean] { +// if (ranges.length < 2) { +// return [ranges, false]; +// } +// const result: Range[] = []; +// let madeChanges = false; +// ranges.forEach((range) => { +// const index = result.findIndex((r) => r.intersection(range) != null); +// // Update existing intersecting range +// if (index > -1) { +// result[index] = result[index].union(range); +// madeChanges = true; +// } +// // Add new range +// else { +// result.push(range); +// } +// }); +// return [result, madeChanges]; +// } -/** - * Unifies overlapping/intersecting targets - * FIXME This code probably needs to update once we have objected oriented targets - * https://github.com/cursorless-dev/cursorless/issues/210 - */ -export function unifyTargets(targets: TypedSelection[]): TypedSelection[] { - if (targets.length < 2) { - return targets; - } - return groupTargetsForEachEditor(targets).flatMap(([_editor, targets]) => { - if (targets.length < 2) { - return targets; - } - let results = [...targets]; - results.sort((a, b) => - a.selection.selection.start.compareTo(b.selection.selection.start) - ); - let run = true; - // Merge targets untill there are no overlaps/intersections - while (run) { - [results, run] = unifyTargetsOnePass(results); - } - return results; - }); -} +// /** +// * Unifies overlapping/intersecting targets +// * FIXME This code probably needs to update once we have objected oriented targets +// * https://github.com/cursorless-dev/cursorless/issues/210 +// */ +// export function unifyTargets(targets: TypedSelection[]): TypedSelection[] { +// if (targets.length < 2) { +// return targets; +// } +// return groupTargetsForEachEditor(targets).flatMap(([_editor, targets]) => { +// if (targets.length < 2) { +// return targets; +// } +// let results = [...targets]; +// results.sort((a, b) => +// a.contentRange.start.compareTo(b.contentRange.start) +// ); +// let run = true; +// // Merge targets untill there are no overlaps/intersections +// while (run) { +// [results, run] = unifyTargetsOnePass(results); +// } +// return results; +// }); +// } -function unifyTargetsOnePass( - targets: TypedSelection[] -): [TypedSelection[], boolean] { - if (targets.length < 2) { - return [targets, false]; - } - const results: TypedSelection[] = []; - let currentGroup: TypedSelection[] = []; - targets.forEach((target) => { - // No intersection. Mark start of new group - if ( - currentGroup.length && - !intersects(currentGroup[currentGroup.length - 1], target) - ) { - results.push(mergeTargets(currentGroup)); - currentGroup = [target]; - } else { - currentGroup.push(target); - } - }); - results.push(mergeTargets(currentGroup)); - return [results, results.length !== targets.length]; -} +// function unifyTargetsOnePass( +// targets: TypedSelection[] +// ): [TypedSelection[], boolean] { +// if (targets.length < 2) { +// return [targets, false]; +// } +// const results: TypedSelection[] = []; +// let currentGroup: TypedSelection[] = []; +// targets.forEach((target) => { +// // No intersection. Mark start of new group +// if ( +// currentGroup.length && +// !intersects(currentGroup[currentGroup.length - 1], target) +// ) { +// results.push(mergeTargets(currentGroup)); +// currentGroup = [target]; +// } else { +// currentGroup.push(target); +// } +// }); +// results.push(mergeTargets(currentGroup)); +// return [results, results.length !== targets.length]; +// } -function mergeTargets(targets: TypedSelection[]): TypedSelection { - if (targets.length === 1) { - return targets[0]; - } - const first = targets[0]; - const last = targets[targets.length - 1]; - const typeSelection: TypedSelection = { - selection: { - editor: first.selection.editor, - selection: new Selection( - first.selection.selection.start, - last.selection.selection.end - ), - }, - position: "contents", - selectionType: first.selectionType, - insideOutsideType: first.insideOutsideType, - selectionContext: { - leadingDelimiterRange: first.selectionContext.leadingDelimiterRange, - trailingDelimiterRange: last.selectionContext.trailingDelimiterRange, - }, - }; - return performInsideOutsideAdjustment(typeSelection); -} +// function mergeTargets(targets: TypedSelection[]): TypedSelection { +// if (targets.length === 1) { +// return targets[0]; +// } +// const first = targets[0]; +// const last = targets[targets.length - 1]; +// const typeSelection: TypedSelection = { +// editor: first.editor, +// contentRange: new Range(first.contentRange.start, last.contentRange.end), +// leadingDelimiterRange: first.leadingDelimiterRange, +// trailingDelimiterRange: last.trailingDelimiterRange, +// }; +// return performInsideOutsideAdjustment(typeSelection); +// } -function intersects(targetA: TypedSelection, targetB: TypedSelection) { - return !!targetA.selection.selection.intersection( - targetB.selection.selection - ); -} +// function intersects(targetA: TypedSelection, targetB: TypedSelection) { +// return !!targetA.contentRange.intersection(targetB.contentRange); +// } From 4f90d82131fe6dcc49df66f43c3e31390e35a47e Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 15 May 2022 11:05:37 +0200 Subject: [PATCH 026/314] Disabled all actions except set selection --- src/actions/Actions.ts | 56 ++ src/actions/BringMoveSwap.ts | 624 +++++++++--------- src/actions/Call.ts | 68 +- src/actions/Clear.ts | 56 +- src/actions/CommandAction.ts | 266 ++++---- src/actions/Comment.ts | 14 +- src/actions/CopyLines.ts | 248 +++---- src/actions/CutCopyPaste.ts | 128 ++-- src/actions/Delete.ts | 114 ++-- src/actions/Deselect.ts | 74 +-- src/actions/EditNewLine.ts | 160 ++--- src/actions/ExecuteCommand.ts | 50 +- src/actions/ExtractVariable.ts | 52 +- src/actions/Find.ts | 56 +- src/actions/Fold.ts | 128 ++-- src/actions/FollowLink.ts | 104 +-- src/actions/GetText.ts | 82 +-- src/actions/Highlight.ts | 56 +- src/actions/Indent.ts | 24 +- src/actions/InsertEmptyLines.ts | 204 +++--- src/actions/Replace.ts | 150 ++--- src/actions/Rewrap.ts | 186 +++--- src/actions/Scroll.ts | 188 +++--- src/actions/SetBreakpoint.ts | 130 ++-- src/actions/SetSelection.ts | 22 +- src/actions/Sort.ts | 94 +-- src/actions/Wrap.ts | 228 +++---- src/actions/WrapWithSnippet.ts | 382 +++++------ src/actions/index.ts | 84 +-- .../canonicalizeActionName.ts | 53 +- src/typings/Types.ts | 78 +-- 31 files changed, 2067 insertions(+), 2092 deletions(-) create mode 100644 src/actions/Actions.ts diff --git a/src/actions/Actions.ts b/src/actions/Actions.ts new file mode 100644 index 0000000000..377d9dae10 --- /dev/null +++ b/src/actions/Actions.ts @@ -0,0 +1,56 @@ +import { ActionRecord, Graph } from "../typings/Types"; +import { + SetSelection, + SetSelectionAfter, + SetSelectionBefore, +} from "./SetSelection"; + +class Actions implements ActionRecord { + constructor(private graph: Graph) {} + + // callAsFunction = new Call(this.graph); + // clearAndSetSelection = new Clear(this.graph); + // copyToClipboard = new Copy(this.graph); + // cutToClipboard = new Cut(this.graph); + // editNewLineAfter = new EditNewLineBelow(this.graph); + // editNewLineBefore = new EditNewLineAbove(this.graph); + // executeCommand = new ExecuteCommand(this.graph); + // extractVariable = new ExtractVariable(this.graph); + // findInWorkspace = new FindInFiles(this.graph); + // foldRegion = new Fold(this.graph); + // followLink = new FollowLink(this.graph); + // getText = new GetText(this.graph); + // highlight = new Highlight(this.graph); + // indentLine = new IndentLines(this.graph); + // insertCopyAfter = new CopyLinesDown(this.graph); + // insertCopyBefore = new CopyLinesUp(this.graph); + // insertEmptyLineAfter = new InsertEmptyLineBelow(this.graph); + // insertEmptyLineBefore = new InsertEmptyLineAbove(this.graph); + // insertEmptyLinesAround = new InsertEmptyLinesAround(this.graph); + // moveToTarget = new Move(this.graph); + // outdentLine = new OutdentLines(this.graph); + // pasteFromClipboard = new Paste(this.graph); + // remove = new Delete(this.graph); + // deselect = new Deselect(this.graph); + // replace = new Replace(this.graph); + // replaceWithTarget = new Bring(this.graph); + // randomizeTargets = new Random(this.graph); + // reverseTargets = new Reverse(this.graph); + // rewrapWithPairedDelimiter = new Rewrap(this.graph); + // scrollToBottom = new ScrollToBottom(this.graph); + // scrollToCenter = new ScrollToCenter(this.graph); + // scrollToTop = new ScrollToTop(this.graph); + setSelection = new SetSelection(this.graph); + setSelectionAfter = new SetSelectionAfter(this.graph); + setSelectionBefore = new SetSelectionBefore(this.graph); + // sortTargets = new Sort(this.graph); + // swapTargets = new Swap(this.graph); + // toggleLineBreakpoint = new SetBreakpoint(this.graph); + // toggleLineComment = new CommentLines(this.graph); + // unfoldRegion = new Unfold(this.graph); + // wrapWithPairedDelimiter = new Wrap(this.graph); + // wrapWithSnippet = new WrapWithSnippet(this.graph); + // +} + +export default Actions; diff --git a/src/actions/BringMoveSwap.ts b/src/actions/BringMoveSwap.ts index 72f853287a..b56becf41e 100644 --- a/src/actions/BringMoveSwap.ts +++ b/src/actions/BringMoveSwap.ts @@ -1,312 +1,312 @@ -import { - Action, - ActionPreferences, - ActionReturnValue, - Graph, - TypedSelection, - Edit, -} from "../typings/Types"; -import { runForEachEditor } from "../util/targetUtils"; -import update from "immutability-helper"; -import displayPendingEditDecorations from "../util/editDisplayUtils"; -import { performOutsideAdjustment } from "../util/performInsideOutsideAdjustment"; -import { flatten } from "lodash"; -import { Selection, TextEditor, DecorationRangeBehavior } from "vscode"; - -import { - getTextWithPossibleDelimiter, - maybeAddDelimiter, -} from "../util/getTextWithPossibleDelimiter"; -import { - getSelectionInfo, - performEditsAndUpdateFullSelectionInfos, -} from "../core/updateSelections/updateSelections"; -import { unifyTargets } from "../util/unifyRanges"; - -type ActionType = "bring" | "move" | "swap"; - -interface ExtendedEdit extends Edit { - editor: TextEditor; - isSource: boolean; - originalSelection: TypedSelection; -} - -interface MarkEntry { - editor: TextEditor; - selection: Selection; - isSource: boolean; - typedSelection: TypedSelection; -} - -class BringMoveSwap implements Action { - getTargetPreferences: () => ActionPreferences[] = () => [ - { insideOutsideType: null }, - { insideOutsideType: null }, - ]; - - constructor(private graph: Graph, private type: ActionType) { - this.run = this.run.bind(this); - } - - private broadcastSource( - sources: TypedSelection[], - destinations: TypedSelection[] - ) { - if (sources.length === 1 && this.type !== "swap") { - // If there is only one source target, expand it to same length as - // destination target - return Array(destinations.length).fill(sources[0]); - } - return sources; - } - - private getDecorationStyles() { - let sourceStyle; - if (this.type === "bring") { - sourceStyle = this.graph.editStyles.referenced; - } else if (this.type === "move") { - sourceStyle = this.graph.editStyles.pendingDelete; - } - // NB this.type === "swap" - else { - sourceStyle = this.graph.editStyles.pendingModification1; - } - return { - sourceStyle, - destinationStyle: this.graph.editStyles.pendingModification0, - }; - } - - private async decorateTargets( - sources: TypedSelection[], - destinations: TypedSelection[] - ) { - const decorationTypes = this.getDecorationStyles(); - await Promise.all([ - displayPendingEditDecorations(sources, decorationTypes.sourceStyle), - displayPendingEditDecorations( - destinations, - decorationTypes.destinationStyle - ), - ]); - } - - private getEdits( - sources: TypedSelection[], - destinations: TypedSelection[] - ): ExtendedEdit[] { - const usedSources: TypedSelection[] = []; - const results: ExtendedEdit[] = []; - const zipSources = - sources.length !== destinations.length && - destinations.length === 1 && - this.type !== "swap"; - - sources.forEach((source, i) => { - let destination = destinations[i]; - if ((source == null || destination == null) && !zipSources) { - throw new Error("Targets must have same number of args"); - } - - if (destination != null) { - let text: string; - if (zipSources) { - text = sources - .map((source, i) => { - let text = source.selection.editor.document.getText( - source.selection.selection - ); - const selectionContext = destination.selectionContext - .isRawSelection - ? source.selectionContext - : destination.selectionContext; - return i > 0 && selectionContext.containingListDelimiter - ? selectionContext.containingListDelimiter + text - : text; - }) - .join(""); - text = maybeAddDelimiter(text, destination); - } else { - // Get text adjusting for destination position - text = getTextWithPossibleDelimiter(source, destination); - } - // Add destination edit - results.push({ - range: destination.selection.selection, - text, - editor: destination.selection.editor, - originalSelection: destination, - isSource: false, - isReplace: destination.position === "after", - }); - } else { - destination = destinations[0]; - } - - // Add source edit - // Prevent multiple instances of the same expanded source. - if (!usedSources.includes(source)) { - usedSources.push(source); - if (this.type !== "move") { - results.push({ - range: source.selection.selection, - text: destination.selection.editor.document.getText( - destination.selection.selection - ), - editor: source.selection.editor, - originalSelection: source, - isSource: true, - isReplace: false, - }); - } - } - }); - - if (this.type === "move") { - let outsideSources = usedSources.map(performOutsideAdjustment); - // Unify overlapping targets. - outsideSources = unifyTargets(outsideSources); - outsideSources.forEach((source) => { - results.push({ - range: source.selection.selection, - text: "", - editor: source.selection.editor, - originalSelection: source, - isSource: true, - isReplace: false, - }); - }); - } - - return results; - } - - private async performEditsAndComputeThatMark( - edits: ExtendedEdit[] - ): Promise { - return flatten( - await runForEachEditor( - edits, - (edit) => edit.editor, - async (editor, edits) => { - // For bring we don't want to update the sources - const filteredEdits = - this.type !== "bring" - ? edits - : edits.filter(({ isSource }) => !isSource); - - const editSelectionInfos = edits.map(({ originalSelection }) => - getSelectionInfo( - editor.document, - originalSelection.selection.selection, - DecorationRangeBehavior.OpenOpen - ) - ); - - const cursorSelectionInfos = editor.selections.map((selection) => - getSelectionInfo( - editor.document, - selection, - DecorationRangeBehavior.ClosedClosed - ) - ); - - const [updatedEditSelections, cursorSelections]: Selection[][] = - await performEditsAndUpdateFullSelectionInfos( - this.graph.rangeUpdater, - editor, - filteredEdits, - [editSelectionInfos, cursorSelectionInfos] - ); - - editor.selections = cursorSelections; - - return edits.map((edit, index) => { - const selection = updatedEditSelections[index]; - return { - editor, - selection, - isSource: edit!.isSource, - typedSelection: update(edit!.originalSelection, { - selection: { - selection: { $set: selection! }, - }, - }), - }; - }); - } - ) - ); - } - - private async decorateThatMark(thatMark: MarkEntry[]) { - const decorationTypes = this.getDecorationStyles(); - return Promise.all([ - displayPendingEditDecorations( - thatMark - .filter(({ isSource }) => isSource) - .map(({ typedSelection }) => typedSelection), - decorationTypes.sourceStyle - ), - displayPendingEditDecorations( - thatMark - .filter(({ isSource }) => !isSource) - .map(({ typedSelection }) => typedSelection), - decorationTypes.destinationStyle - ), - ]); - } - - private calculateMarks(markEntries: MarkEntry[]) { - // Only swap has sources as a "that" mark - const thatMark = - this.type === "swap" - ? markEntries - : markEntries.filter(({ isSource }) => !isSource); - - // Only swap doesn't have a source mark - const sourceMark = - this.type === "swap" - ? [] - : markEntries.filter(({ isSource }) => isSource); - - return { thatMark, sourceMark }; - } - - async run([sources, destinations]: [ - TypedSelection[], - TypedSelection[] - ]): Promise { - sources = this.broadcastSource(sources, destinations); - - await this.decorateTargets(sources, destinations); - - const edits = this.getEdits(sources, destinations); - - const markEntries = await this.performEditsAndComputeThatMark(edits); - - const { thatMark, sourceMark } = this.calculateMarks(markEntries); - - await this.decorateThatMark(thatMark); - - return { thatMark, sourceMark }; - } -} - -export class Bring extends BringMoveSwap { - constructor(graph: Graph) { - super(graph, "bring"); - } -} - -export class Move extends BringMoveSwap { - constructor(graph: Graph) { - super(graph, "move"); - } -} - -export class Swap extends BringMoveSwap { - constructor(graph: Graph) { - super(graph, "swap"); - } -} +// import { +// Action, +// ActionPreferences, +// ActionReturnValue, +// Graph, +// TypedSelection, +// Edit, +// } from "../typings/Types"; +// import { runForEachEditor } from "../util/targetUtils"; +// import update from "immutability-helper"; +// import displayPendingEditDecorations from "../util/editDisplayUtils"; +// import { performOutsideAdjustment } from "../util/performInsideOutsideAdjustment"; +// import { flatten } from "lodash"; +// import { Selection, TextEditor, DecorationRangeBehavior } from "vscode"; + +// import { +// getTextWithPossibleDelimiter, +// maybeAddDelimiter, +// } from "../util/getTextWithPossibleDelimiter"; +// import { +// getSelectionInfo, +// performEditsAndUpdateFullSelectionInfos, +// } from "../core/updateSelections/updateSelections"; +// import { unifyTargets } from "../util/unifyRanges"; + +// type ActionType = "bring" | "move" | "swap"; + +// interface ExtendedEdit extends Edit { +// editor: TextEditor; +// isSource: boolean; +// originalSelection: TypedSelection; +// } + +// interface MarkEntry { +// editor: TextEditor; +// selection: Selection; +// isSource: boolean; +// typedSelection: TypedSelection; +// } + +// class BringMoveSwap implements Action { +// getTargetPreferences: () => ActionPreferences[] = () => [ +// { insideOutsideType: null }, +// { insideOutsideType: null }, +// ]; + +// constructor(private graph: Graph, private type: ActionType) { +// this.run = this.run.bind(this); +// } + +// private broadcastSource( +// sources: TypedSelection[], +// destinations: TypedSelection[] +// ) { +// if (sources.length === 1 && this.type !== "swap") { +// // If there is only one source target, expand it to same length as +// // destination target +// return Array(destinations.length).fill(sources[0]); +// } +// return sources; +// } + +// private getDecorationStyles() { +// let sourceStyle; +// if (this.type === "bring") { +// sourceStyle = this.graph.editStyles.referenced; +// } else if (this.type === "move") { +// sourceStyle = this.graph.editStyles.pendingDelete; +// } +// // NB this.type === "swap" +// else { +// sourceStyle = this.graph.editStyles.pendingModification1; +// } +// return { +// sourceStyle, +// destinationStyle: this.graph.editStyles.pendingModification0, +// }; +// } + +// private async decorateTargets( +// sources: TypedSelection[], +// destinations: TypedSelection[] +// ) { +// const decorationTypes = this.getDecorationStyles(); +// await Promise.all([ +// displayPendingEditDecorations(sources, decorationTypes.sourceStyle), +// displayPendingEditDecorations( +// destinations, +// decorationTypes.destinationStyle +// ), +// ]); +// } + +// private getEdits( +// sources: TypedSelection[], +// destinations: TypedSelection[] +// ): ExtendedEdit[] { +// const usedSources: TypedSelection[] = []; +// const results: ExtendedEdit[] = []; +// const zipSources = +// sources.length !== destinations.length && +// destinations.length === 1 && +// this.type !== "swap"; + +// sources.forEach((source, i) => { +// let destination = destinations[i]; +// if ((source == null || destination == null) && !zipSources) { +// throw new Error("Targets must have same number of args"); +// } + +// if (destination != null) { +// let text: string; +// if (zipSources) { +// text = sources +// .map((source, i) => { +// let text = source.selection.editor.document.getText( +// source.selection.selection +// ); +// const selectionContext = destination.selectionContext +// .isRawSelection +// ? source.selectionContext +// : destination.selectionContext; +// return i > 0 && selectionContext.containingListDelimiter +// ? selectionContext.containingListDelimiter + text +// : text; +// }) +// .join(""); +// text = maybeAddDelimiter(text, destination); +// } else { +// // Get text adjusting for destination position +// text = getTextWithPossibleDelimiter(source, destination); +// } +// // Add destination edit +// results.push({ +// range: destination.selection.selection, +// text, +// editor: destination.selection.editor, +// originalSelection: destination, +// isSource: false, +// isReplace: destination.position === "after", +// }); +// } else { +// destination = destinations[0]; +// } + +// // Add source edit +// // Prevent multiple instances of the same expanded source. +// if (!usedSources.includes(source)) { +// usedSources.push(source); +// if (this.type !== "move") { +// results.push({ +// range: source.selection.selection, +// text: destination.selection.editor.document.getText( +// destination.selection.selection +// ), +// editor: source.selection.editor, +// originalSelection: source, +// isSource: true, +// isReplace: false, +// }); +// } +// } +// }); + +// if (this.type === "move") { +// let outsideSources = usedSources.map(performOutsideAdjustment); +// // Unify overlapping targets. +// outsideSources = unifyTargets(outsideSources); +// outsideSources.forEach((source) => { +// results.push({ +// range: source.selection.selection, +// text: "", +// editor: source.selection.editor, +// originalSelection: source, +// isSource: true, +// isReplace: false, +// }); +// }); +// } + +// return results; +// } + +// private async performEditsAndComputeThatMark( +// edits: ExtendedEdit[] +// ): Promise { +// return flatten( +// await runForEachEditor( +// edits, +// (edit) => edit.editor, +// async (editor, edits) => { +// // For bring we don't want to update the sources +// const filteredEdits = +// this.type !== "bring" +// ? edits +// : edits.filter(({ isSource }) => !isSource); + +// const editSelectionInfos = edits.map(({ originalSelection }) => +// getSelectionInfo( +// editor.document, +// originalSelection.selection.selection, +// DecorationRangeBehavior.OpenOpen +// ) +// ); + +// const cursorSelectionInfos = editor.selections.map((selection) => +// getSelectionInfo( +// editor.document, +// selection, +// DecorationRangeBehavior.ClosedClosed +// ) +// ); + +// const [updatedEditSelections, cursorSelections]: Selection[][] = +// await performEditsAndUpdateFullSelectionInfos( +// this.graph.rangeUpdater, +// editor, +// filteredEdits, +// [editSelectionInfos, cursorSelectionInfos] +// ); + +// editor.selections = cursorSelections; + +// return edits.map((edit, index) => { +// const selection = updatedEditSelections[index]; +// return { +// editor, +// selection, +// isSource: edit!.isSource, +// typedSelection: update(edit!.originalSelection, { +// selection: { +// selection: { $set: selection! }, +// }, +// }), +// }; +// }); +// } +// ) +// ); +// } + +// private async decorateThatMark(thatMark: MarkEntry[]) { +// const decorationTypes = this.getDecorationStyles(); +// return Promise.all([ +// displayPendingEditDecorations( +// thatMark +// .filter(({ isSource }) => isSource) +// .map(({ typedSelection }) => typedSelection), +// decorationTypes.sourceStyle +// ), +// displayPendingEditDecorations( +// thatMark +// .filter(({ isSource }) => !isSource) +// .map(({ typedSelection }) => typedSelection), +// decorationTypes.destinationStyle +// ), +// ]); +// } + +// private calculateMarks(markEntries: MarkEntry[]) { +// // Only swap has sources as a "that" mark +// const thatMark = +// this.type === "swap" +// ? markEntries +// : markEntries.filter(({ isSource }) => !isSource); + +// // Only swap doesn't have a source mark +// const sourceMark = +// this.type === "swap" +// ? [] +// : markEntries.filter(({ isSource }) => isSource); + +// return { thatMark, sourceMark }; +// } + +// async run([sources, destinations]: [ +// TypedSelection[], +// TypedSelection[] +// ]): Promise { +// sources = this.broadcastSource(sources, destinations); + +// await this.decorateTargets(sources, destinations); + +// const edits = this.getEdits(sources, destinations); + +// const markEntries = await this.performEditsAndComputeThatMark(edits); + +// const { thatMark, sourceMark } = this.calculateMarks(markEntries); + +// await this.decorateThatMark(thatMark); + +// return { thatMark, sourceMark }; +// } +// } + +// export class Bring extends BringMoveSwap { +// constructor(graph: Graph) { +// super(graph, "bring"); +// } +// } + +// export class Move extends BringMoveSwap { +// constructor(graph: Graph) { +// super(graph, "move"); +// } +// } + +// export class Swap extends BringMoveSwap { +// constructor(graph: Graph) { +// super(graph, "swap"); +// } +// } diff --git a/src/actions/Call.ts b/src/actions/Call.ts index fc5a72554c..8bffb2e6bb 100644 --- a/src/actions/Call.ts +++ b/src/actions/Call.ts @@ -1,39 +1,39 @@ -import { - Action, - ActionReturnValue, - ActionPreferences, - Graph, - TypedSelection, -} from "../typings/Types"; -import { ensureSingleTarget } from "../util/targetUtils"; +// import { +// Action, +// ActionReturnValue, +// ActionPreferences, +// Graph, +// TypedSelection, +// } from "../typings/Types"; +// import { ensureSingleTarget } from "../util/targetUtils"; -export default class Call implements Action { - getTargetPreferences: () => ActionPreferences[] = () => [ - { insideOutsideType: "inside" }, - { insideOutsideType: "inside" }, - ]; +// export default class Call implements Action { +// getTargetPreferences: () => ActionPreferences[] = () => [ +// { insideOutsideType: "inside" }, +// { insideOutsideType: "inside" }, +// ]; - constructor(private graph: Graph) { - this.run = this.run.bind(this); - } +// constructor(private graph: Graph) { +// this.run = this.run.bind(this); +// } - async run([sources, destinations]: [ - TypedSelection[], - TypedSelection[] - ]): Promise { - ensureSingleTarget(sources); +// async run([sources, destinations]: [ +// TypedSelection[], +// TypedSelection[] +// ]): Promise { +// ensureSingleTarget(sources); - const { returnValue: texts } = await this.graph.actions.getText.run( - [sources], - { - showDecorations: false, - } - ); +// const { returnValue: texts } = await this.graph.actions.getText.run( +// [sources], +// { +// showDecorations: false, +// } +// ); - return this.graph.actions.wrapWithPairedDelimiter.run( - [destinations], - texts[0] + "(", - ")" - ); - } -} +// return this.graph.actions.wrapWithPairedDelimiter.run( +// [destinations], +// texts[0] + "(", +// ")" +// ); +// } +// } diff --git a/src/actions/Clear.ts b/src/actions/Clear.ts index 805a365966..4681d80a6e 100644 --- a/src/actions/Clear.ts +++ b/src/actions/Clear.ts @@ -1,34 +1,34 @@ -import { - Action, - ActionPreferences, - ActionReturnValue, - Graph, - TypedSelection, -} from "../typings/Types"; -import { ensureSingleEditor } from "../util/targetUtils"; -import { setSelectionsAndFocusEditor } from "../util/setSelectionsAndFocusEditor"; +// import { +// Action, +// ActionPreferences, +// ActionReturnValue, +// Graph, +// TypedSelection, +// } from "../typings/Types"; +// import { ensureSingleEditor } from "../util/targetUtils"; +// import { setSelectionsAndFocusEditor } from "../util/setSelectionsAndFocusEditor"; -export default class Clear implements Action { - getTargetPreferences: () => ActionPreferences[] = () => [ - { insideOutsideType: "inside" }, - ]; +// export default class Clear implements Action { +// getTargetPreferences: () => ActionPreferences[] = () => [ +// { insideOutsideType: "inside" }, +// ]; - constructor(private graph: Graph) { - this.run = this.run.bind(this); - } +// constructor(private graph: Graph) { +// this.run = this.run.bind(this); +// } - async run([targets]: [TypedSelection[]]): Promise { - const editor = ensureSingleEditor(targets); +// async run([targets]: [TypedSelection[]]): Promise { +// const editor = ensureSingleEditor(targets); - const { thatMark } = await this.graph.actions.remove.run([targets]); +// const { thatMark } = await this.graph.actions.remove.run([targets]); - if (thatMark != null) { - await setSelectionsAndFocusEditor( - editor, - thatMark.map(({ selection }) => selection) - ); - } +// if (thatMark != null) { +// await setSelectionsAndFocusEditor( +// editor, +// thatMark.map(({ selection }) => selection) +// ); +// } - return { thatMark }; - } -} +// return { thatMark }; +// } +// } diff --git a/src/actions/CommandAction.ts b/src/actions/CommandAction.ts index 815dbfaf15..3ef1ddfe04 100644 --- a/src/actions/CommandAction.ts +++ b/src/actions/CommandAction.ts @@ -1,133 +1,133 @@ -import { commands, window } from "vscode"; -import { - Action, - ActionPreferences, - ActionReturnValue, - Graph, - TypedSelection, - SelectionWithEditor, -} from "../typings/Types"; -import displayPendingEditDecorations from "../util/editDisplayUtils"; -import { runOnTargetsForEachEditor } from "../util/targetUtils"; -import { - focusEditor, - setSelectionsAndFocusEditor, -} from "../util/setSelectionsAndFocusEditor"; -import { flatten } from "lodash"; -import { ensureSingleEditor } from "../util/targetUtils"; -import { callFunctionAndUpdateSelections } from "../core/updateSelections/updateSelections"; - -export interface CommandOptions { - command?: string; - commandArgs?: any[]; - restoreSelection?: boolean; - ensureSingleEditor?: boolean; - showDecorations?: boolean; -} - -const defaultOptions: CommandOptions = { - commandArgs: [], - restoreSelection: true, - ensureSingleEditor: false, - showDecorations: false, -}; - -export default class CommandAction implements Action { - getTargetPreferences: () => ActionPreferences[] = () => [ - { insideOutsideType: "inside" }, - ]; - - constructor(private graph: Graph, private options: CommandOptions = {}) { - this.run = this.run.bind(this); - } - - private async runCommandAndUpdateSelections( - targets: TypedSelection[], - options: Required - ) { - return flatten( - await runOnTargetsForEachEditor( - targets, - async (editor, targets) => { - const originalSelections = editor.selections; - - const targetSelections = targets.map( - (target) => target.selection.selection - ); - - // For command to the work we have to have the correct editor focused - await setSelectionsAndFocusEditor(editor, targetSelections, false); - - const [updatedOriginalSelections, updatedTargetSelections] = - await callFunctionAndUpdateSelections( - this.graph.rangeUpdater, - () => - commands.executeCommand( - options.command, - ...options.commandArgs - ), - editor.document, - [originalSelections, targetSelections] - ); - - // Reset original selections - if (options.restoreSelection) { - editor.selections = updatedOriginalSelections; - } - - return updatedTargetSelections.map((selection) => ({ - editor, - selection, - })); - } - ) - ); - } - - async run( - [targets]: [TypedSelection[]], - options: CommandOptions = {} - ): Promise { - const partialOptions = Object.assign( - {}, - defaultOptions, - this.options, - options - ); - - if (partialOptions.command == null) { - throw Error("Command id must be specified"); - } - - const actualOptions = partialOptions as Required; - - if (actualOptions.showDecorations) { - await displayPendingEditDecorations( - targets, - this.graph.editStyles.referenced - ); - } - - if (actualOptions.ensureSingleEditor) { - ensureSingleEditor(targets); - } - - const originalEditor = window.activeTextEditor; - - const thatMark = await this.runCommandAndUpdateSelections( - targets, - actualOptions - ); - - // If necessary focus back original editor - if ( - actualOptions.restoreSelection && - originalEditor != null && - originalEditor !== window.activeTextEditor - ) { - await focusEditor(originalEditor); - } - - return { thatMark }; - } -} +// import { commands, window } from "vscode"; +// import { +// Action, +// ActionPreferences, +// ActionReturnValue, +// Graph, +// TypedSelection, +// SelectionWithEditor, +// } from "../typings/Types"; +// import displayPendingEditDecorations from "../util/editDisplayUtils"; +// import { runOnTargetsForEachEditor } from "../util/targetUtils"; +// import { +// focusEditor, +// setSelectionsAndFocusEditor, +// } from "../util/setSelectionsAndFocusEditor"; +// import { flatten } from "lodash"; +// import { ensureSingleEditor } from "../util/targetUtils"; +// import { callFunctionAndUpdateSelections } from "../core/updateSelections/updateSelections"; + +// export interface CommandOptions { +// command?: string; +// commandArgs?: any[]; +// restoreSelection?: boolean; +// ensureSingleEditor?: boolean; +// showDecorations?: boolean; +// } + +// const defaultOptions: CommandOptions = { +// commandArgs: [], +// restoreSelection: true, +// ensureSingleEditor: false, +// showDecorations: false, +// }; + +// export default class CommandAction implements Action { +// getTargetPreferences: () => ActionPreferences[] = () => [ +// { insideOutsideType: "inside" }, +// ]; + +// constructor(private graph: Graph, private options: CommandOptions = {}) { +// this.run = this.run.bind(this); +// } + +// private async runCommandAndUpdateSelections( +// targets: TypedSelection[], +// options: Required +// ) { +// return flatten( +// await runOnTargetsForEachEditor( +// targets, +// async (editor, targets) => { +// const originalSelections = editor.selections; + +// const targetSelections = targets.map( +// (target) => target.selection.selection +// ); + +// // For command to the work we have to have the correct editor focused +// await setSelectionsAndFocusEditor(editor, targetSelections, false); + +// const [updatedOriginalSelections, updatedTargetSelections] = +// await callFunctionAndUpdateSelections( +// this.graph.rangeUpdater, +// () => +// commands.executeCommand( +// options.command, +// ...options.commandArgs +// ), +// editor.document, +// [originalSelections, targetSelections] +// ); + +// // Reset original selections +// if (options.restoreSelection) { +// editor.selections = updatedOriginalSelections; +// } + +// return updatedTargetSelections.map((selection) => ({ +// editor, +// selection, +// })); +// } +// ) +// ); +// } + +// async run( +// [targets]: [TypedSelection[]], +// options: CommandOptions = {} +// ): Promise { +// const partialOptions = Object.assign( +// {}, +// defaultOptions, +// this.options, +// options +// ); + +// if (partialOptions.command == null) { +// throw Error("Command id must be specified"); +// } + +// const actualOptions = partialOptions as Required; + +// if (actualOptions.showDecorations) { +// await displayPendingEditDecorations( +// targets, +// this.graph.editStyles.referenced +// ); +// } + +// if (actualOptions.ensureSingleEditor) { +// ensureSingleEditor(targets); +// } + +// const originalEditor = window.activeTextEditor; + +// const thatMark = await this.runCommandAndUpdateSelections( +// targets, +// actualOptions +// ); + +// // If necessary focus back original editor +// if ( +// actualOptions.restoreSelection && +// originalEditor != null && +// originalEditor !== window.activeTextEditor +// ) { +// await focusEditor(originalEditor); +// } + +// return { thatMark }; +// } +// } diff --git a/src/actions/Comment.ts b/src/actions/Comment.ts index bfb93a6c19..cb0f951c01 100644 --- a/src/actions/Comment.ts +++ b/src/actions/Comment.ts @@ -1,8 +1,8 @@ -import { Graph } from "../typings/Types"; -import CommandAction from "./CommandAction"; +// import { Graph } from "../typings/Types"; +// import CommandAction from "./CommandAction"; -export class CommentLines extends CommandAction { - constructor(graph: Graph) { - super(graph, { command: "editor.action.commentLine" }); - } -} +// export class CommentLines extends CommandAction { +// constructor(graph: Graph) { +// super(graph, { command: "editor.action.commentLine" }); +// } +// } diff --git a/src/actions/CopyLines.ts b/src/actions/CopyLines.ts index 0f9cd9144d..4cb36441d0 100644 --- a/src/actions/CopyLines.ts +++ b/src/actions/CopyLines.ts @@ -1,138 +1,138 @@ -import { - Action, - ActionPreferences, - ActionReturnValue, - Graph, - TypedSelection, -} from "../typings/Types"; -import { Range, Selection, TextEditor } from "vscode"; -import { displayPendingEditDecorationsForSelection } from "../util/editDisplayUtils"; -import { runOnTargetsForEachEditor } from "../util/targetUtils"; -import { flatten } from "lodash"; -import unifyRanges from "../util/unifyRanges"; -import expandToContainingLine from "../util/expandToContainingLine"; -import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; +// import { +// Action, +// ActionPreferences, +// ActionReturnValue, +// Graph, +// TypedSelection, +// } from "../typings/Types"; +// import { Range, Selection, TextEditor } from "vscode"; +// import { displayPendingEditDecorationsForSelection } from "../util/editDisplayUtils"; +// import { runOnTargetsForEachEditor } from "../util/targetUtils"; +// import { flatten } from "lodash"; +// import unifyRanges from "../util/unifyRanges"; +// import expandToContainingLine from "../util/expandToContainingLine"; +// import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; -class CopyLines implements Action { - getTargetPreferences: () => ActionPreferences[] = () => [ - { insideOutsideType: "inside" }, - ]; +// class CopyLines implements Action { +// getTargetPreferences: () => ActionPreferences[] = () => [ +// { insideOutsideType: "inside" }, +// ]; - constructor(private graph: Graph, private isUp: boolean) { - this.run = this.run.bind(this); - } +// constructor(private graph: Graph, private isUp: boolean) { +// this.run = this.run.bind(this); +// } - private getRanges(editor: TextEditor, targets: TypedSelection[]) { - const paragraphTargets = targets.filter( - (target) => target.selectionType === "paragraph" - ); - const ranges = targets.map((target) => - expandToContainingLine(editor, target.selection.selection) - ); - const unifiedRanges = unifyRanges(ranges); - return unifiedRanges.map((range) => ({ - range, - isParagraph: - paragraphTargets.find((target) => - target.selection.selection.isEqual(range) - ) != null, - })); - } +// private getRanges(editor: TextEditor, targets: TypedSelection[]) { +// const paragraphTargets = targets.filter( +// (target) => target.selectionType === "paragraph" +// ); +// const ranges = targets.map((target) => +// expandToContainingLine(editor, target.selection.selection) +// ); +// const unifiedRanges = unifyRanges(ranges); +// return unifiedRanges.map((range) => ({ +// range, +// isParagraph: +// paragraphTargets.find((target) => +// target.selection.selection.isEqual(range) +// ) != null, +// })); +// } - private getEdits( - editor: TextEditor, - ranges: { range: Range; isParagraph: boolean }[] - ) { - return ranges.map(({ range, isParagraph }) => { - const delimiter = isParagraph ? "\n\n" : "\n"; - let text = editor.document.getText(range); - const length = text.length; - text = this.isUp ? `${delimiter}${text}` : `${text}${delimiter}`; - const newRange = this.isUp - ? new Range(range.end, range.end) - : new Range(range.start, range.start); - return { - edit: { - editor, - range: newRange, - text, - isReplace: this.isUp, - }, - offset: delimiter.length, - length, - }; - }); - } +// private getEdits( +// editor: TextEditor, +// ranges: { range: Range; isParagraph: boolean }[] +// ) { +// return ranges.map(({ range, isParagraph }) => { +// const delimiter = isParagraph ? "\n\n" : "\n"; +// let text = editor.document.getText(range); +// const length = text.length; +// text = this.isUp ? `${delimiter}${text}` : `${text}${delimiter}`; +// const newRange = this.isUp +// ? new Range(range.end, range.end) +// : new Range(range.start, range.start); +// return { +// edit: { +// editor, +// range: newRange, +// text, +// isReplace: this.isUp, +// }, +// offset: delimiter.length, +// length, +// }; +// }); +// } - async run([targets]: [TypedSelection[]]): Promise { - const results = flatten( - await runOnTargetsForEachEditor(targets, async (editor, targets) => { - const ranges = this.getRanges(editor, targets); - const editWrappers = this.getEdits(editor, ranges); - const rangeSelections = ranges.map( - ({ range }) => new Selection(range.start, range.end) - ); +// async run([targets]: [TypedSelection[]]): Promise { +// const results = flatten( +// await runOnTargetsForEachEditor(targets, async (editor, targets) => { +// const ranges = this.getRanges(editor, targets); +// const editWrappers = this.getEdits(editor, ranges); +// const rangeSelections = ranges.map( +// ({ range }) => new Selection(range.start, range.end) +// ); - const [editorSelections, copySelections] = - await performEditsAndUpdateSelections( - this.graph.rangeUpdater, - editor, - editWrappers.map((wrapper) => wrapper.edit), - [editor.selections, rangeSelections] - ); +// const [editorSelections, copySelections] = +// await performEditsAndUpdateSelections( +// this.graph.rangeUpdater, +// editor, +// editWrappers.map((wrapper) => wrapper.edit), +// [editor.selections, rangeSelections] +// ); - editor.selections = editorSelections; - editor.revealRange(copySelections[0]); +// editor.selections = editorSelections; +// editor.revealRange(copySelections[0]); - let sourceSelections; - if (this.isUp) { - sourceSelections = editWrappers.map((wrapper) => { - const startIndex = - editor.document.offsetAt(wrapper.edit.range.start) + - wrapper.offset; - const endIndex = startIndex + wrapper.length; - return new Selection( - editor.document.positionAt(startIndex), - editor.document.positionAt(endIndex) - ); - }); - } else { - sourceSelections = rangeSelections; - } +// let sourceSelections; +// if (this.isUp) { +// sourceSelections = editWrappers.map((wrapper) => { +// const startIndex = +// editor.document.offsetAt(wrapper.edit.range.start) + +// wrapper.offset; +// const endIndex = startIndex + wrapper.length; +// return new Selection( +// editor.document.positionAt(startIndex), +// editor.document.positionAt(endIndex) +// ); +// }); +// } else { +// sourceSelections = rangeSelections; +// } - return { - sourceMark: sourceSelections.map((selection) => ({ - editor, - selection, - })), - thatMark: copySelections.map((selection) => ({ - editor, - selection, - })), - }; - }) - ); +// return { +// sourceMark: sourceSelections.map((selection) => ({ +// editor, +// selection, +// })), +// thatMark: copySelections.map((selection) => ({ +// editor, +// selection, +// })), +// }; +// }) +// ); - await displayPendingEditDecorationsForSelection( - results.flatMap((result) => result.thatMark), - this.graph.editStyles.justAdded.token - ); +// await displayPendingEditDecorationsForSelection( +// results.flatMap((result) => result.thatMark), +// this.graph.editStyles.justAdded.token +// ); - const sourceMark = results.flatMap((result) => result.sourceMark); - const thatMark = results.flatMap((result) => result.thatMark); +// const sourceMark = results.flatMap((result) => result.sourceMark); +// const thatMark = results.flatMap((result) => result.thatMark); - return { sourceMark, thatMark }; - } -} +// return { sourceMark, thatMark }; +// } +// } -export class CopyLinesUp extends CopyLines { - constructor(graph: Graph) { - super(graph, true); - } -} +// export class CopyLinesUp extends CopyLines { +// constructor(graph: Graph) { +// super(graph, true); +// } +// } -export class CopyLinesDown extends CopyLines { - constructor(graph: Graph) { - super(graph, false); - } -} +// export class CopyLinesDown extends CopyLines { +// constructor(graph: Graph) { +// super(graph, false); +// } +// } diff --git a/src/actions/CutCopyPaste.ts b/src/actions/CutCopyPaste.ts index deb1544570..c1ae42d0fe 100644 --- a/src/actions/CutCopyPaste.ts +++ b/src/actions/CutCopyPaste.ts @@ -1,73 +1,73 @@ -import { - Action, - ActionPreferences, - ActionReturnValue, - Graph, - TypedSelection, -} from "../typings/Types"; -import { performInsideOutsideAdjustment } from "../util/performInsideOutsideAdjustment"; -import CommandAction from "./CommandAction"; -import displayPendingEditDecorations from "../util/editDisplayUtils"; -import { getOutsideOverflow } from "../util/targetUtils"; -import { zip } from "lodash"; +// import { +// Action, +// ActionPreferences, +// ActionReturnValue, +// Graph, +// TypedSelection, +// } from "../typings/Types"; +// import { performInsideOutsideAdjustment } from "../util/performInsideOutsideAdjustment"; +// import CommandAction from "./CommandAction"; +// import displayPendingEditDecorations from "../util/editDisplayUtils"; +// import { getOutsideOverflow } from "../util/targetUtils"; +// import { zip } from "lodash"; -export class Cut implements Action { - getTargetPreferences: () => ActionPreferences[] = () => [ - { insideOutsideType: null }, - ]; +// export class Cut implements Action { +// getTargetPreferences: () => ActionPreferences[] = () => [ +// { insideOutsideType: null }, +// ]; - constructor(private graph: Graph) { - this.run = this.run.bind(this); - } +// constructor(private graph: Graph) { +// this.run = this.run.bind(this); +// } - async run([targets]: [TypedSelection[]]): Promise { - const insideTargets = targets.map((target) => - performInsideOutsideAdjustment(target, "inside") - ); - const outsideTargets = targets.map((target) => - performInsideOutsideAdjustment(target, "outside") - ); - const outsideTargetDecorations = zip(insideTargets, outsideTargets).flatMap( - ([inside, outside]) => getOutsideOverflow(inside!, outside!) - ); - const options = { showDecorations: false }; +// async run([targets]: [TypedSelection[]]): Promise { +// const insideTargets = targets.map((target) => +// performInsideOutsideAdjustment(target, "inside") +// ); +// const outsideTargets = targets.map((target) => +// performInsideOutsideAdjustment(target, "outside") +// ); +// const outsideTargetDecorations = zip(insideTargets, outsideTargets).flatMap( +// ([inside, outside]) => getOutsideOverflow(inside!, outside!) +// ); +// const options = { showDecorations: false }; - await Promise.all([ - displayPendingEditDecorations( - insideTargets, - this.graph.editStyles.referenced - ), - displayPendingEditDecorations( - outsideTargetDecorations, - this.graph.editStyles.pendingDelete - ), - ]); +// await Promise.all([ +// displayPendingEditDecorations( +// insideTargets, +// this.graph.editStyles.referenced +// ), +// displayPendingEditDecorations( +// outsideTargetDecorations, +// this.graph.editStyles.pendingDelete +// ), +// ]); - await this.graph.actions.copyToClipboard.run([insideTargets], options); +// await this.graph.actions.copyToClipboard.run([insideTargets], options); - const { thatMark } = await this.graph.actions.remove.run( - [outsideTargets], - options - ); +// const { thatMark } = await this.graph.actions.remove.run( +// [outsideTargets], +// options +// ); - return { thatMark }; - } -} +// return { thatMark }; +// } +// } -export class Copy extends CommandAction { - constructor(graph: Graph) { - super(graph, { - command: "editor.action.clipboardCopyAction", - ensureSingleEditor: true, - }); - } -} +// export class Copy extends CommandAction { +// constructor(graph: Graph) { +// super(graph, { +// command: "editor.action.clipboardCopyAction", +// ensureSingleEditor: true, +// }); +// } +// } -export class Paste extends CommandAction { - constructor(graph: Graph) { - super(graph, { - command: "editor.action.clipboardPasteAction", - ensureSingleEditor: true, - }); - } -} +// export class Paste extends CommandAction { +// constructor(graph: Graph) { +// super(graph, { +// command: "editor.action.clipboardPasteAction", +// ensureSingleEditor: true, +// }); +// } +// } diff --git a/src/actions/Delete.ts b/src/actions/Delete.ts index 423d1b1339..78fa9eed1b 100644 --- a/src/actions/Delete.ts +++ b/src/actions/Delete.ts @@ -1,57 +1,57 @@ -import { - Action, - ActionPreferences, - ActionReturnValue, - Graph, - TypedSelection, -} from "../typings/Types"; -import { runOnTargetsForEachEditor } from "../util/targetUtils"; -import displayPendingEditDecorations from "../util/editDisplayUtils"; -import { flatten } from "lodash"; -import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; -import { unifyTargets } from "../util/unifyRanges"; - -export default class Delete implements Action { - getTargetPreferences: () => ActionPreferences[] = () => [ - { insideOutsideType: "outside" }, - ]; - - constructor(private graph: Graph) { - this.run = this.run.bind(this); - } - - async run( - [targets]: [TypedSelection[]], - { showDecorations = true } = {} - ): Promise { - // Unify overlapping targets. - targets = unifyTargets(targets); - - if (showDecorations) { - await displayPendingEditDecorations( - targets, - this.graph.editStyles.pendingDelete - ); - } - - const thatMark = flatten( - await runOnTargetsForEachEditor(targets, async (editor, targets) => { - const edits = targets.map((target) => ({ - range: target.selection.selection, - text: "", - })); - - const [updatedSelections] = await performEditsAndUpdateSelections( - this.graph.rangeUpdater, - editor, - edits, - [targets.map((target) => target.selection.selection)] - ); - - return updatedSelections.map((selection) => ({ editor, selection })); - }) - ); - - return { thatMark }; - } -} +// import { +// Action, +// ActionPreferences, +// ActionReturnValue, +// Graph, +// TypedSelection, +// } from "../typings/Types"; +// import { runOnTargetsForEachEditor } from "../util/targetUtils"; +// import displayPendingEditDecorations from "../util/editDisplayUtils"; +// import { flatten } from "lodash"; +// import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; +// import { unifyTargets } from "../util/unifyRanges"; + +// export default class Delete implements Action { +// getTargetPreferences: () => ActionPreferences[] = () => [ +// { insideOutsideType: "outside" }, +// ]; + +// constructor(private graph: Graph) { +// this.run = this.run.bind(this); +// } + +// async run( +// [targets]: [TypedSelection[]], +// { showDecorations = true } = {} +// ): Promise { +// // Unify overlapping targets. +// targets = unifyTargets(targets); + +// if (showDecorations) { +// await displayPendingEditDecorations( +// targets, +// this.graph.editStyles.pendingDelete +// ); +// } + +// const thatMark = flatten( +// await runOnTargetsForEachEditor(targets, async (editor, targets) => { +// const edits = targets.map((target) => ({ +// range: target.selection.selection, +// text: "", +// })); + +// const [updatedSelections] = await performEditsAndUpdateSelections( +// this.graph.rangeUpdater, +// editor, +// edits, +// [targets.map((target) => target.selection.selection)] +// ); + +// return updatedSelections.map((selection) => ({ editor, selection })); +// }) +// ); + +// return { thatMark }; +// } +// } diff --git a/src/actions/Deselect.ts b/src/actions/Deselect.ts index 656c59a40f..ca9922601b 100644 --- a/src/actions/Deselect.ts +++ b/src/actions/Deselect.ts @@ -1,41 +1,41 @@ -import { Selection } from "vscode"; -import { - Action, - ActionPreferences, - ActionReturnValue, - TypedSelection, - Graph, -} from "../typings/Types"; -import { runOnTargetsForEachEditor } from "../util/targetUtils"; +// import { Selection } from "vscode"; +// import { +// Action, +// ActionPreferences, +// ActionReturnValue, +// TypedSelection, +// Graph, +// } from "../typings/Types"; +// import { runOnTargetsForEachEditor } from "../util/targetUtils"; -export default class Deselect implements Action { - getTargetPreferences: () => ActionPreferences[] = () => [ - { insideOutsideType: "inside" }, - ]; +// export default class Deselect implements Action { +// getTargetPreferences: () => ActionPreferences[] = () => [ +// { insideOutsideType: "inside" }, +// ]; - constructor(private graph: Graph) { - this.run = this.run.bind(this); - } +// constructor(private graph: Graph) { +// this.run = this.run.bind(this); +// } - async run([targets]: [TypedSelection[]]): Promise { - await runOnTargetsForEachEditor(targets, async (editor, targets) => { - // Remove selections with a non-empty intersection - const newSelections = editor.selections.filter( - (selection) => - !targets.some((target) => { - const intersection = - target.selection.selection.intersection(selection); - return intersection && (!intersection.isEmpty || selection.isEmpty); - }) - ); - // The editor requires at least one selection. Keep "primary" selection active - editor.selections = newSelections.length - ? newSelections - : [new Selection(editor.selection.active, editor.selection.active)]; - }); +// async run([targets]: [TypedSelection[]]): Promise { +// await runOnTargetsForEachEditor(targets, async (editor, targets) => { +// // Remove selections with a non-empty intersection +// const newSelections = editor.selections.filter( +// (selection) => +// !targets.some((target) => { +// const intersection = +// target.selection.selection.intersection(selection); +// return intersection && (!intersection.isEmpty || selection.isEmpty); +// }) +// ); +// // The editor requires at least one selection. Keep "primary" selection active +// editor.selections = newSelections.length +// ? newSelections +// : [new Selection(editor.selection.active, editor.selection.active)]; +// }); - return { - thatMark: targets.map((target) => target.selection), - }; - } -} +// return { +// thatMark: targets.map((target) => target.selection), +// }; +// } +// } diff --git a/src/actions/EditNewLine.ts b/src/actions/EditNewLine.ts index 111b0fe917..62843b7b02 100644 --- a/src/actions/EditNewLine.ts +++ b/src/actions/EditNewLine.ts @@ -1,91 +1,91 @@ -import { - Action, - ActionPreferences, - ActionReturnValue, - Graph, - TypedSelection, -} from "../typings/Types"; -import { commands, Selection, TextEditor } from "vscode"; -import { getNotebookFromCellDocument } from "../util/notebook"; +// import { +// Action, +// ActionPreferences, +// ActionReturnValue, +// Graph, +// TypedSelection, +// } from "../typings/Types"; +// import { commands, Selection, TextEditor } from "vscode"; +// import { getNotebookFromCellDocument } from "../util/notebook"; -class EditNewLine implements Action { - getTargetPreferences: () => ActionPreferences[] = () => [ - { insideOutsideType: "inside" }, - ]; +// class EditNewLine implements Action { +// getTargetPreferences: () => ActionPreferences[] = () => [ +// { insideOutsideType: "inside" }, +// ]; - constructor(private graph: Graph, private isAbove: boolean) { - this.run = this.run.bind(this); - } +// constructor(private graph: Graph, private isAbove: boolean) { +// this.run = this.run.bind(this); +// } - private correctForParagraph(targets: TypedSelection[]) { - targets.forEach((target) => { - let { start, end } = target.selection.selection; - if (target.selectionType === "paragraph") { - if ( - this.isAbove && - target.selectionContext.leadingDelimiterRange != null - ) { - start = start.translate({ lineDelta: -1 }); - } else if ( - !this.isAbove && - target.selectionContext.trailingDelimiterRange != null - ) { - end = end.translate({ lineDelta: 1 }); - } - target.selection.selection = new Selection(start, end); - } - }); - } +// private correctForParagraph(targets: TypedSelection[]) { +// targets.forEach((target) => { +// let { start, end } = target.selection.selection; +// if (target.selectionType === "paragraph") { +// if ( +// this.isAbove && +// target.selectionContext.leadingDelimiterRange != null +// ) { +// start = start.translate({ lineDelta: -1 }); +// } else if ( +// !this.isAbove && +// target.selectionContext.trailingDelimiterRange != null +// ) { +// end = end.translate({ lineDelta: 1 }); +// } +// target.selection.selection = new Selection(start, end); +// } +// }); +// } - private isNotebookEditor(editor: TextEditor) { - return getNotebookFromCellDocument(editor.document) != null; - } +// private isNotebookEditor(editor: TextEditor) { +// return getNotebookFromCellDocument(editor.document) != null; +// } - private getCommand(target: TypedSelection) { - if (target.selectionContext.isNotebookCell) { - if (this.isNotebookEditor(target.selection.editor)) { - return this.isAbove - ? "notebook.cell.insertCodeCellAbove" - : "notebook.cell.insertCodeCellBelow"; - } - return this.isAbove - ? "jupyter.insertCellAbove" - : "jupyter.insertCellBelow"; - } - return this.isAbove - ? "editor.action.insertLineBefore" - : "editor.action.insertLineAfter"; - } +// private getCommand(target: TypedSelection) { +// if (target.selectionContext.isNotebookCell) { +// if (this.isNotebookEditor(target.selection.editor)) { +// return this.isAbove +// ? "notebook.cell.insertCodeCellAbove" +// : "notebook.cell.insertCodeCellBelow"; +// } +// return this.isAbove +// ? "jupyter.insertCellAbove" +// : "jupyter.insertCellBelow"; +// } +// return this.isAbove +// ? "editor.action.insertLineBefore" +// : "editor.action.insertLineAfter"; +// } - async run([targets]: [TypedSelection[]]): Promise { - this.correctForParagraph(targets); +// async run([targets]: [TypedSelection[]]): Promise { +// this.correctForParagraph(targets); - if (this.isAbove) { - await this.graph.actions.setSelectionBefore.run([targets]); - } else { - await this.graph.actions.setSelectionAfter.run([targets]); - } +// if (this.isAbove) { +// await this.graph.actions.setSelectionBefore.run([targets]); +// } else { +// await this.graph.actions.setSelectionAfter.run([targets]); +// } - const command = this.getCommand(targets[0]); - await commands.executeCommand(command); +// const command = this.getCommand(targets[0]); +// await commands.executeCommand(command); - return { - thatMark: targets.map((target) => ({ - selection: target.selection.editor.selection, - editor: target.selection.editor, - })), - }; - } -} +// return { +// thatMark: targets.map((target) => ({ +// selection: target.selection.editor.selection, +// editor: target.selection.editor, +// })), +// }; +// } +// } -export class EditNewLineAbove extends EditNewLine { - constructor(graph: Graph) { - super(graph, true); - } -} +// export class EditNewLineAbove extends EditNewLine { +// constructor(graph: Graph) { +// super(graph, true); +// } +// } -export class EditNewLineBelow extends EditNewLine { - constructor(graph: Graph) { - super(graph, false); - } -} +// export class EditNewLineBelow extends EditNewLine { +// constructor(graph: Graph) { +// super(graph, false); +// } +// } diff --git a/src/actions/ExecuteCommand.ts b/src/actions/ExecuteCommand.ts index 6a27036034..4f01c2c199 100644 --- a/src/actions/ExecuteCommand.ts +++ b/src/actions/ExecuteCommand.ts @@ -1,28 +1,28 @@ -import { - Action, - ActionPreferences, - ActionReturnValue, - Graph, - TypedSelection, -} from "../typings/Types"; -import CommandAction, { CommandOptions } from "./CommandAction"; +// import { +// Action, +// ActionPreferences, +// ActionReturnValue, +// Graph, +// TypedSelection, +// } from "../typings/Types"; +// import CommandAction, { CommandOptions } from "./CommandAction"; -export default class ExecuteCommand implements Action { - getTargetPreferences: () => ActionPreferences[] = () => [ - { insideOutsideType: "inside" }, - ]; - private commandAction: CommandAction; +// export default class ExecuteCommand implements Action { +// getTargetPreferences: () => ActionPreferences[] = () => [ +// { insideOutsideType: "inside" }, +// ]; +// private commandAction: CommandAction; - constructor(graph: Graph) { - this.run = this.run.bind(this); - this.commandAction = new CommandAction(graph); - } +// constructor(graph: Graph) { +// this.run = this.run.bind(this); +// this.commandAction = new CommandAction(graph); +// } - async run( - targets: [TypedSelection[]], - command: string, - args: CommandOptions = {} - ): Promise { - return this.commandAction.run(targets, { ...args, command }); - } -} +// async run( +// targets: [TypedSelection[]], +// command: string, +// args: CommandOptions = {} +// ): Promise { +// return this.commandAction.run(targets, { ...args, command }); +// } +// } diff --git a/src/actions/ExtractVariable.ts b/src/actions/ExtractVariable.ts index ecf3daf2e2..de0f5ea62f 100644 --- a/src/actions/ExtractVariable.ts +++ b/src/actions/ExtractVariable.ts @@ -1,32 +1,32 @@ -import { - Action, - ActionPreferences, - ActionReturnValue, - Graph, - TypedSelection, -} from "../typings/Types"; -import { ensureSingleTarget } from "../util/targetUtils"; -import { commands } from "vscode"; +// import { +// Action, +// ActionPreferences, +// ActionReturnValue, +// Graph, +// TypedSelection, +// } from "../typings/Types"; +// import { ensureSingleTarget } from "../util/targetUtils"; +// import { commands } from "vscode"; -export default class ExtractVariable implements Action { - getTargetPreferences: () => ActionPreferences[] = () => [ - { insideOutsideType: "inside" }, - ]; +// export default class ExtractVariable implements Action { +// getTargetPreferences: () => ActionPreferences[] = () => [ +// { insideOutsideType: "inside" }, +// ]; - constructor(private graph: Graph) { - this.run = this.run.bind(this); - } +// constructor(private graph: Graph) { +// this.run = this.run.bind(this); +// } - async run([targets]: [TypedSelection[]]): Promise { - ensureSingleTarget(targets); +// async run([targets]: [TypedSelection[]]): Promise { +// ensureSingleTarget(targets); - await this.graph.actions.setSelection.run([targets]); +// await this.graph.actions.setSelection.run([targets]); - await commands.executeCommand("editor.action.codeAction", { - kind: "refactor.extract.constant", - preferred: true, - }); +// await commands.executeCommand("editor.action.codeAction", { +// kind: "refactor.extract.constant", +// preferred: true, +// }); - return {}; - } -} +// return {}; +// } +// } diff --git a/src/actions/Find.ts b/src/actions/Find.ts index f69e0d58f3..0e46ed9ae3 100644 --- a/src/actions/Find.ts +++ b/src/actions/Find.ts @@ -1,34 +1,34 @@ -import { - Action, - ActionReturnValue, - ActionPreferences, - Graph, - TypedSelection, -} from "../typings/Types"; -import { commands } from "vscode"; -import { ensureSingleTarget } from "../util/targetUtils"; +// import { +// Action, +// ActionReturnValue, +// ActionPreferences, +// Graph, +// TypedSelection, +// } from "../typings/Types"; +// import { commands } from "vscode"; +// import { ensureSingleTarget } from "../util/targetUtils"; -export class FindInFiles implements Action { - getTargetPreferences: () => ActionPreferences[] = () => [ - { insideOutsideType: "inside" }, - ]; +// export class FindInFiles implements Action { +// getTargetPreferences: () => ActionPreferences[] = () => [ +// { insideOutsideType: "inside" }, +// ]; - constructor(private graph: Graph) { - this.run = this.run.bind(this); - } +// constructor(private graph: Graph) { +// this.run = this.run.bind(this); +// } - async run([targets]: [TypedSelection[]]): Promise { - ensureSingleTarget(targets); +// async run([targets]: [TypedSelection[]]): Promise { +// ensureSingleTarget(targets); - const { - returnValue: [query], - thatMark, - } = await this.graph.actions.getText.run([targets]); +// const { +// returnValue: [query], +// thatMark, +// } = await this.graph.actions.getText.run([targets]); - await commands.executeCommand("workbench.action.findInFiles", { - query, - }); +// await commands.executeCommand("workbench.action.findInFiles", { +// query, +// }); - return { thatMark }; - } -} +// return { thatMark }; +// } +// } diff --git a/src/actions/Fold.ts b/src/actions/Fold.ts index 62bcf074ec..b8b200b63a 100644 --- a/src/actions/Fold.ts +++ b/src/actions/Fold.ts @@ -1,74 +1,74 @@ -import { commands, window } from "vscode"; -import { - Action, - ActionPreferences, - ActionReturnValue, - Graph, - TypedSelection, -} from "../typings/Types"; -import { focusEditor } from "../util/setSelectionsAndFocusEditor"; -import { ensureSingleEditor } from "../util/targetUtils"; +// import { commands, window } from "vscode"; +// import { +// Action, +// ActionPreferences, +// ActionReturnValue, +// Graph, +// TypedSelection, +// } from "../typings/Types"; +// import { focusEditor } from "../util/setSelectionsAndFocusEditor"; +// import { ensureSingleEditor } from "../util/targetUtils"; -class FoldAction implements Action { - getTargetPreferences: () => ActionPreferences[] = () => [ - { insideOutsideType: "inside" }, - ]; +// class FoldAction implements Action { +// getTargetPreferences: () => ActionPreferences[] = () => [ +// { insideOutsideType: "inside" }, +// ]; - constructor(private command: string) { - this.run = this.run.bind(this); - } +// constructor(private command: string) { +// this.run = this.run.bind(this); +// } - async run([targets]: [ - TypedSelection[], - TypedSelection[] - ]): Promise { - const originalEditor = window.activeTextEditor; - const editor = ensureSingleEditor(targets); +// async run([targets]: [ +// TypedSelection[], +// TypedSelection[] +// ]): Promise { +// const originalEditor = window.activeTextEditor; +// const editor = ensureSingleEditor(targets); - if (originalEditor !== editor) { - await focusEditor(editor); - } +// if (originalEditor !== editor) { +// await focusEditor(editor); +// } - const singleLineTargets = targets.filter( - (target) => target.selection.selection.isSingleLine - ); - const multiLineTargets = targets.filter( - (target) => !target.selection.selection.isSingleLine - ); - // Don't mix multi and single line targets. - // This is probably the result of an "every" command - // and folding the single line targets will fold the parent as well - const selectedTargets = multiLineTargets.length - ? multiLineTargets - : singleLineTargets; +// const singleLineTargets = targets.filter( +// (target) => target.selection.selection.isSingleLine +// ); +// const multiLineTargets = targets.filter( +// (target) => !target.selection.selection.isSingleLine +// ); +// // Don't mix multi and single line targets. +// // This is probably the result of an "every" command +// // and folding the single line targets will fold the parent as well +// const selectedTargets = multiLineTargets.length +// ? multiLineTargets +// : singleLineTargets; - await commands.executeCommand(this.command, { - levels: 1, - direction: "down", - selectionLines: selectedTargets.map( - (target) => target.selection.selection.start.line - ), - }); +// await commands.executeCommand(this.command, { +// levels: 1, +// direction: "down", +// selectionLines: selectedTargets.map( +// (target) => target.selection.selection.start.line +// ), +// }); - // If necessary focus back original editor - if (originalEditor != null && originalEditor !== editor) { - await focusEditor(originalEditor); - } +// // If necessary focus back original editor +// if (originalEditor != null && originalEditor !== editor) { +// await focusEditor(originalEditor); +// } - return { - thatMark: targets.map((target) => target.selection), - }; - } -} +// return { +// thatMark: targets.map((target) => target.selection), +// }; +// } +// } -export class Fold extends FoldAction { - constructor(_graph: Graph) { - super("editor.fold"); - } -} +// export class Fold extends FoldAction { +// constructor(_graph: Graph) { +// super("editor.fold"); +// } +// } -export class Unfold extends FoldAction { - constructor(_graph: Graph) { - super("editor.unfold"); - } -} +// export class Unfold extends FoldAction { +// constructor(_graph: Graph) { +// super("editor.unfold"); +// } +// } diff --git a/src/actions/FollowLink.ts b/src/actions/FollowLink.ts index ee5e6af384..ee6e6f3aec 100644 --- a/src/actions/FollowLink.ts +++ b/src/actions/FollowLink.ts @@ -1,59 +1,59 @@ -import { env, Uri, window } from "vscode"; -import { - Action, - ActionPreferences, - ActionReturnValue, - Graph, - TypedSelection, -} from "../typings/Types"; -import displayPendingEditDecorations from "../util/editDisplayUtils"; -import { getLinkForTarget } from "../util/getLinks"; -import { ensureSingleTarget } from "../util/targetUtils"; +// 1import { env, Uri, window } from "vscode"; +// import { +// Action, +// ActionPreferences, +// ActionReturnValue, +// Graph, +// TypedSelection, +// } from "../typings/Types"; +// import displayPendingEditDecorations from "../util/editDisplayUtils"; +// import { getLinkForTarget } from "../util/getLinks"; +// import { ensureSingleTarget } from "../util/targetUtils"; -export default class FollowLink implements Action { - getTargetPreferences: () => ActionPreferences[] = () => [ - { insideOutsideType: "inside" }, - ]; +// export default class FollowLink implements Action { +// getTargetPreferences: () => ActionPreferences[] = () => [ +// { insideOutsideType: "inside" }, +// ]; - constructor(private graph: Graph) { - this.run = this.run.bind(this); - } +// constructor(private graph: Graph) { +// this.run = this.run.bind(this); +// } - async run([targets]: [TypedSelection[]]): Promise { - const target = ensureSingleTarget(targets); +// async run([targets]: [TypedSelection[]]): Promise { +// const target = ensureSingleTarget(targets); - await displayPendingEditDecorations( - targets, - this.graph.editStyles.referenced - ); +// await displayPendingEditDecorations( +// targets, +// this.graph.editStyles.referenced +// ); - const link = await getLinkForTarget(target); - if (link) { - await this.openUri(link.target!); - } else { - await this.graph.actions.executeCommand.run( - [targets], - "editor.action.revealDefinition", - { restoreSelection: false } - ); - } +// const link = await getLinkForTarget(target); +// if (link) { +// await this.openUri(link.target!); +// } else { +// await this.graph.actions.executeCommand.run( +// [targets], +// "editor.action.revealDefinition", +// { restoreSelection: false } +// ); +// } - return { - thatMark: targets.map((target) => target.selection), - }; - } +// return { +// thatMark: targets.map((target) => target.selection), +// }; +// } - private async openUri(uri: Uri) { - switch (uri.scheme) { - case "http": - case "https": - await env.openExternal(uri); - break; - case "file": - await window.showTextDocument(uri); - break; - default: - throw Error(`Unknown uri scheme '${uri.scheme}'`); - } - } -} +// private async openUri(uri: Uri) { +// switch (uri.scheme) { +// case "http": +// case "https": +// await env.openExternal(uri); +// break; +// case "file": +// await window.showTextDocument(uri); +// break; +// default: +// throw Error(`Unknown uri scheme '${uri.scheme}'`); +// } +// } +// } diff --git a/src/actions/GetText.ts b/src/actions/GetText.ts index 9fbb4db403..04230786eb 100644 --- a/src/actions/GetText.ts +++ b/src/actions/GetText.ts @@ -1,46 +1,46 @@ -import { - Action, - ActionPreferences, - ActionReturnValue, - Graph, - TypedSelection, -} from "../typings/Types"; -import displayPendingEditDecorations from "../util/editDisplayUtils"; -import { ensureSingleTarget } from "../util/targetUtils"; +// import { +// Action, +// ActionPreferences, +// ActionReturnValue, +// Graph, +// TypedSelection, +// } from "../typings/Types"; +// import displayPendingEditDecorations from "../util/editDisplayUtils"; +// import { ensureSingleTarget } from "../util/targetUtils"; -export default class GetText implements Action { - getTargetPreferences: () => ActionPreferences[] = () => [ - { insideOutsideType: "inside" }, - ]; +// export default class GetText implements Action { +// getTargetPreferences: () => ActionPreferences[] = () => [ +// { insideOutsideType: "inside" }, +// ]; - constructor(private graph: Graph) { - this.run = this.run.bind(this); - } +// constructor(private graph: Graph) { +// this.run = this.run.bind(this); +// } - async run( - [targets]: [TypedSelection[]], - { - showDecorations = true, - ensureSingleTarget: doEnsureSingleTarget = false, - } = {} - ): Promise { - if (showDecorations) { - await displayPendingEditDecorations( - targets, - this.graph.editStyles.referenced - ); - } - if (doEnsureSingleTarget) { - ensureSingleTarget(targets); - } +// async run( +// [targets]: [TypedSelection[]], +// { +// showDecorations = true, +// ensureSingleTarget: doEnsureSingleTarget = false, +// } = {} +// ): Promise { +// if (showDecorations) { +// await displayPendingEditDecorations( +// targets, +// this.graph.editStyles.referenced +// ); +// } +// if (doEnsureSingleTarget) { +// ensureSingleTarget(targets); +// } - const returnValue = targets.map((target) => - target.selection.editor.document.getText(target.selection.selection) - ); +// const returnValue = targets.map((target) => +// target.selection.editor.document.getText(target.selection.selection) +// ); - return { - returnValue, - thatMark: targets.map((target) => target.selection), - }; - } -} +// return { +// returnValue, +// thatMark: targets.map((target) => target.selection), +// }; +// } +// } diff --git a/src/actions/Highlight.ts b/src/actions/Highlight.ts index 67753bf076..0a5e058758 100644 --- a/src/actions/Highlight.ts +++ b/src/actions/Highlight.ts @@ -1,33 +1,33 @@ -import { EditStyleName } from "../core/editStyles"; -import { - Action, - ActionPreferences, - ActionReturnValue, - TypedSelection, - Graph, -} from "../typings/Types"; -import { clearDecorations, setDecorations } from "../util/editDisplayUtils"; +// import { EditStyleName } from "../core/editStyles"; +// import { +// Action, +// ActionPreferences, +// ActionReturnValue, +// TypedSelection, +// Graph, +// } from "../typings/Types"; +// import { clearDecorations, setDecorations } from "../util/editDisplayUtils"; -export default class Highlight implements Action { - getTargetPreferences: () => ActionPreferences[] = () => [ - { insideOutsideType: "inside" }, - ]; +// export default class Highlight implements Action { +// getTargetPreferences: () => ActionPreferences[] = () => [ +// { insideOutsideType: "inside" }, +// ]; - constructor(private graph: Graph) { - this.run = this.run.bind(this); - } +// constructor(private graph: Graph) { +// this.run = this.run.bind(this); +// } - async run( - [targets]: [TypedSelection[]], - styleName: EditStyleName = "highlight0" - ): Promise { - const style = this.graph.editStyles[styleName]; +// async run( +// [targets]: [TypedSelection[]], +// styleName: EditStyleName = "highlight0" +// ): Promise { +// const style = this.graph.editStyles[styleName]; - clearDecorations(style); - await setDecorations(targets, style); +// clearDecorations(style); +// await setDecorations(targets, style); - return { - thatMark: targets.map((target) => target.selection), - }; - } -} +// return { +// thatMark: targets.map((target) => target.selection), +// }; +// } +// } diff --git a/src/actions/Indent.ts b/src/actions/Indent.ts index e91a676528..aee2b02061 100644 --- a/src/actions/Indent.ts +++ b/src/actions/Indent.ts @@ -1,14 +1,14 @@ -import { Graph } from "../typings/Types"; -import CommandAction from "./CommandAction"; +// import { Graph } from "../typings/Types"; +// import CommandAction from "./CommandAction"; -export class IndentLines extends CommandAction { - constructor(graph: Graph) { - super(graph, { command: "editor.action.indentLines" }); - } -} +// export class IndentLines extends CommandAction { +// constructor(graph: Graph) { +// super(graph, { command: "editor.action.indentLines" }); +// } +// } -export class OutdentLines extends CommandAction { - constructor(graph: Graph) { - super(graph, { command: "editor.action.outdentLines" }); - } -} +// export class OutdentLines extends CommandAction { +// constructor(graph: Graph) { +// super(graph, { command: "editor.action.outdentLines" }); +// } +// } diff --git a/src/actions/InsertEmptyLines.ts b/src/actions/InsertEmptyLines.ts index 415432f2fd..351c57540a 100644 --- a/src/actions/InsertEmptyLines.ts +++ b/src/actions/InsertEmptyLines.ts @@ -1,117 +1,117 @@ -import { - Action, - ActionPreferences, - ActionReturnValue, - Graph, - TypedSelection, -} from "../typings/Types"; -import { Selection, Range } from "vscode"; -import { displayPendingEditDecorationsForSelection } from "../util/editDisplayUtils"; -import { runOnTargetsForEachEditor } from "../util/targetUtils"; -import { flatten } from "lodash"; -import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; +// import { +// Action, +// ActionPreferences, +// ActionReturnValue, +// Graph, +// TypedSelection, +// } from "../typings/Types"; +// import { Selection, Range } from "vscode"; +// import { displayPendingEditDecorationsForSelection } from "../util/editDisplayUtils"; +// import { runOnTargetsForEachEditor } from "../util/targetUtils"; +// import { flatten } from "lodash"; +// import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; -class InsertEmptyLines implements Action { - getTargetPreferences: () => ActionPreferences[] = () => [ - { insideOutsideType: "inside" }, - ]; +// class InsertEmptyLines implements Action { +// getTargetPreferences: () => ActionPreferences[] = () => [ +// { insideOutsideType: "inside" }, +// ]; - constructor( - private graph: Graph, - private insertAbove: boolean, - private insertBelow: boolean - ) { - this.run = this.run.bind(this); - } +// constructor( +// private graph: Graph, +// private insertAbove: boolean, +// private insertBelow: boolean +// ) { +// this.run = this.run.bind(this); +// } - private getRanges(targets: TypedSelection[]) { - let lines = targets.flatMap((target) => { - const lines = []; - if (this.insertAbove) { - lines.push(target.selection.selection.start.line); - } - if (this.insertBelow) { - lines.push(target.selection.selection.end.line + 1); - } - return lines; - }); - // Remove duplicates - lines = [...new Set(lines)]; +// private getRanges(targets: TypedSelection[]) { +// let lines = targets.flatMap((target) => { +// const lines = []; +// if (this.insertAbove) { +// lines.push(target.selection.selection.start.line); +// } +// if (this.insertBelow) { +// lines.push(target.selection.selection.end.line + 1); +// } +// return lines; +// }); +// // Remove duplicates +// lines = [...new Set(lines)]; - return lines.map((line) => new Range(line, 0, line, 0)); - } +// return lines.map((line) => new Range(line, 0, line, 0)); +// } - private getEdits(ranges: Range[]) { - return ranges.map((range) => ({ - range, - text: "\n", - })); - } +// private getEdits(ranges: Range[]) { +// return ranges.map((range) => ({ +// range, +// text: "\n", +// })); +// } - async run([targets]: [TypedSelection[]]): Promise { - const results = flatten( - await runOnTargetsForEachEditor(targets, async (editor, targets) => { - const ranges = this.getRanges(targets); - const edits = this.getEdits(ranges); +// async run([targets]: [TypedSelection[]]): Promise { +// const results = flatten( +// await runOnTargetsForEachEditor(targets, async (editor, targets) => { +// const ranges = this.getRanges(targets); +// const edits = this.getEdits(ranges); - const [updatedSelections, lineSelections, updatedOriginalSelections] = - await performEditsAndUpdateSelections( - this.graph.rangeUpdater, - editor, - edits, - [ - targets.map((target) => target.selection.selection), - ranges.map((range) => new Selection(range.start, range.end)), - editor.selections, - ] - ); +// const [updatedSelections, lineSelections, updatedOriginalSelections] = +// await performEditsAndUpdateSelections( +// this.graph.rangeUpdater, +// editor, +// edits, +// [ +// targets.map((target) => target.selection.selection), +// ranges.map((range) => new Selection(range.start, range.end)), +// editor.selections, +// ] +// ); - editor.selections = updatedOriginalSelections; +// editor.selections = updatedOriginalSelections; - return { - thatMark: updatedSelections.map((selection) => ({ - editor, - selection, - })), - lineSelections: lineSelections.map((selection, index) => ({ - editor, - selection: - ranges[index].start.line < editor.document.lineCount - 1 - ? new Selection( - selection.start.translate({ lineDelta: -1 }), - selection.end.translate({ lineDelta: -1 }) - ) - : selection, - })), - }; - }) - ); +// return { +// thatMark: updatedSelections.map((selection) => ({ +// editor, +// selection, +// })), +// lineSelections: lineSelections.map((selection, index) => ({ +// editor, +// selection: +// ranges[index].start.line < editor.document.lineCount - 1 +// ? new Selection( +// selection.start.translate({ lineDelta: -1 }), +// selection.end.translate({ lineDelta: -1 }) +// ) +// : selection, +// })), +// }; +// }) +// ); - await displayPendingEditDecorationsForSelection( - results.flatMap((result) => result.lineSelections), - this.graph.editStyles.justAdded.line - ); +// await displayPendingEditDecorationsForSelection( +// results.flatMap((result) => result.lineSelections), +// this.graph.editStyles.justAdded.line +// ); - const thatMark = results.flatMap((result) => result.thatMark); +// const thatMark = results.flatMap((result) => result.thatMark); - return { thatMark }; - } -} +// return { thatMark }; +// } +// } -export class InsertEmptyLinesAround extends InsertEmptyLines { - constructor(graph: Graph) { - super(graph, true, true); - } -} +// export class InsertEmptyLinesAround extends InsertEmptyLines { +// constructor(graph: Graph) { +// super(graph, true, true); +// } +// } -export class InsertEmptyLineAbove extends InsertEmptyLines { - constructor(graph: Graph) { - super(graph, true, false); - } -} +// export class InsertEmptyLineAbove extends InsertEmptyLines { +// constructor(graph: Graph) { +// super(graph, true, false); +// } +// } -export class InsertEmptyLineBelow extends InsertEmptyLines { - constructor(graph: Graph) { - super(graph, false, true); - } -} +// export class InsertEmptyLineBelow extends InsertEmptyLines { +// constructor(graph: Graph) { +// super(graph, false, true); +// } +// } diff --git a/src/actions/Replace.ts b/src/actions/Replace.ts index 953ba4cd09..94768340a4 100644 --- a/src/actions/Replace.ts +++ b/src/actions/Replace.ts @@ -1,86 +1,86 @@ -import { - Action, - ActionPreferences, - ActionReturnValue, - Graph, - TypedSelection, -} from "../typings/Types"; -import displayPendingEditDecorations from "../util/editDisplayUtils"; -import { runForEachEditor } from "../util/targetUtils"; -import { flatten, zip } from "lodash"; -import { maybeAddDelimiter } from "../util/getTextWithPossibleDelimiter"; -import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; +// import { +// Action, +// ActionPreferences, +// ActionReturnValue, +// Graph, +// TypedSelection, +// } from "../typings/Types"; +// import displayPendingEditDecorations from "../util/editDisplayUtils"; +// import { runForEachEditor } from "../util/targetUtils"; +// import { flatten, zip } from "lodash"; +// import { maybeAddDelimiter } from "../util/getTextWithPossibleDelimiter"; +// import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; -type RangeGenerator = { start: number }; +// type RangeGenerator = { start: number }; -export default class implements Action { - getTargetPreferences: () => ActionPreferences[] = () => [ - { insideOutsideType: null }, - ]; +// export default class implements Action { +// getTargetPreferences: () => ActionPreferences[] = () => [ +// { insideOutsideType: null }, +// ]; - constructor(private graph: Graph) { - this.run = this.run.bind(this); - } +// constructor(private graph: Graph) { +// this.run = this.run.bind(this); +// } - private getTexts( - targets: TypedSelection[], - replaceWith: string[] | RangeGenerator - ): string[] { - if (Array.isArray(replaceWith)) { - // Broadcast single text to each target - if (replaceWith.length === 1) { - return Array(targets.length).fill(replaceWith[0]); - } - return replaceWith; - } - const numbers = []; - for (let i = 0; i < targets.length; ++i) { - numbers[i] = (replaceWith.start + i).toString(); - } - return numbers; - } +// private getTexts( +// targets: TypedSelection[], +// replaceWith: string[] | RangeGenerator +// ): string[] { +// if (Array.isArray(replaceWith)) { +// // Broadcast single text to each target +// if (replaceWith.length === 1) { +// return Array(targets.length).fill(replaceWith[0]); +// } +// return replaceWith; +// } +// const numbers = []; +// for (let i = 0; i < targets.length; ++i) { +// numbers[i] = (replaceWith.start + i).toString(); +// } +// return numbers; +// } - async run( - [targets]: [TypedSelection[]], - replaceWith: string[] | RangeGenerator - ): Promise { - await displayPendingEditDecorations( - targets, - this.graph.editStyles.pendingModification0 - ); +// async run( +// [targets]: [TypedSelection[]], +// replaceWith: string[] | RangeGenerator +// ): Promise { +// await displayPendingEditDecorations( +// targets, +// this.graph.editStyles.pendingModification0 +// ); - const texts = this.getTexts(targets, replaceWith); +// const texts = this.getTexts(targets, replaceWith); - if (targets.length !== texts.length) { - throw new Error("Targets and texts must have same length"); - } +// if (targets.length !== texts.length) { +// throw new Error("Targets and texts must have same length"); +// } - const edits = zip(targets, texts).map(([target, text]) => ({ - editor: target!.selection.editor, - range: target!.selection.selection, - text: maybeAddDelimiter(text!, target!), - })); +// const edits = zip(targets, texts).map(([target, text]) => ({ +// editor: target!.selection.editor, +// range: target!.selection.selection, +// text: maybeAddDelimiter(text!, target!), +// })); - const thatMark = flatten( - await runForEachEditor( - edits, - (edit) => edit.editor, - async (editor, edits) => { - const [updatedSelections] = await performEditsAndUpdateSelections( - this.graph.rangeUpdater, - editor, - edits, - [targets.map((target) => target.selection.selection)] - ); +// const thatMark = flatten( +// await runForEachEditor( +// edits, +// (edit) => edit.editor, +// async (editor, edits) => { +// const [updatedSelections] = await performEditsAndUpdateSelections( +// this.graph.rangeUpdater, +// editor, +// edits, +// [targets.map((target) => target.selection.selection)] +// ); - return updatedSelections.map((selection) => ({ - editor, - selection, - })); - } - ) - ); +// return updatedSelections.map((selection) => ({ +// editor, +// selection, +// })); +// } +// ) +// ); - return { thatMark }; - } -} +// return { thatMark }; +// } +// } diff --git a/src/actions/Rewrap.ts b/src/actions/Rewrap.ts index cf738163c0..f2397d6db3 100644 --- a/src/actions/Rewrap.ts +++ b/src/actions/Rewrap.ts @@ -1,104 +1,104 @@ -import { flatten, zip } from "lodash"; -import { TextEditor } from "vscode"; -import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; -import { - Action, - ActionPreferences, - ActionReturnValue, - Graph, - SelectionWithContext, - TypedSelection, -} from "../typings/Types"; -import displayPendingEditDecorations from "../util/editDisplayUtils"; -import { runForEachEditor } from "../util/targetUtils"; +// import { flatten, zip } from "lodash"; +// import { TextEditor } from "vscode"; +// import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; +// import { +// Action, +// ActionPreferences, +// ActionReturnValue, +// Graph, +// SelectionWithContext, +// TypedSelection, +// } from "../typings/Types"; +// import displayPendingEditDecorations from "../util/editDisplayUtils"; +// import { runForEachEditor } from "../util/targetUtils"; -export default class Rewrap implements Action { - getTargetPreferences: () => ActionPreferences[] = () => [ - { - insideOutsideType: "inside", - modifier: { - type: "surroundingPair", - delimiter: "any", - delimiterInclusion: undefined, - }, - }, - ]; +// export default class Rewrap implements Action { +// getTargetPreferences: () => ActionPreferences[] = () => [ +// { +// insideOutsideType: "inside", +// modifier: { +// type: "surroundingPair", +// delimiter: "any", +// delimiterInclusion: undefined, +// }, +// }, +// ]; - constructor(private graph: Graph) { - this.run = this.run.bind(this); - } +// constructor(private graph: Graph) { +// this.run = this.run.bind(this); +// } - async run( - [targets]: [TypedSelection[]], - left: string, - right: string - ): Promise { - const targetInfos = targets.flatMap((target) => { - const boundary = target.selectionContext.boundary; +// async run( +// [targets]: [TypedSelection[]], +// left: string, +// right: string +// ): Promise { +// const targetInfos = targets.flatMap((target) => { +// const boundary = target.selectionContext.boundary; - if (boundary == null || boundary.length !== 2) { - throw Error("Target must have an opening and closing delimiter"); - } +// if (boundary == null || boundary.length !== 2) { +// throw Error("Target must have an opening and closing delimiter"); +// } - return { - editor: target.selection.editor, - boundary: boundary.map((edge) => - constructSimpleTypedSelection(target.selection.editor, edge) - ), - targetSelection: target.selection.selection, - }; - }); +// return { +// editor: target.selection.editor, +// boundary: boundary.map((edge) => +// constructSimpleTypedSelection(target.selection.editor, edge) +// ), +// targetSelection: target.selection.selection, +// }; +// }); - await displayPendingEditDecorations( - targetInfos.flatMap(({ boundary }) => boundary), - this.graph.editStyles.pendingModification0 - ); +// await displayPendingEditDecorations( +// targetInfos.flatMap(({ boundary }) => boundary), +// this.graph.editStyles.pendingModification0 +// ); - const thatMark = flatten( - await runForEachEditor( - targetInfos, - (targetInfo) => targetInfo.editor, - async (editor, targetInfos) => { - const edits = targetInfos.flatMap((targetInfo) => - zip(targetInfo.boundary, [left, right]).map(([target, text]) => ({ - editor, - range: target!.selection.selection, - text: text!, - })) - ); +// const thatMark = flatten( +// await runForEachEditor( +// targetInfos, +// (targetInfo) => targetInfo.editor, +// async (editor, targetInfos) => { +// const edits = targetInfos.flatMap((targetInfo) => +// zip(targetInfo.boundary, [left, right]).map(([target, text]) => ({ +// editor, +// range: target!.selection.selection, +// text: text!, +// })) +// ); - const [updatedTargetSelections] = - await performEditsAndUpdateSelections( - this.graph.rangeUpdater, - editor, - edits, - [targetInfos.map((targetInfo) => targetInfo.targetSelection)] - ); +// const [updatedTargetSelections] = +// await performEditsAndUpdateSelections( +// this.graph.rangeUpdater, +// editor, +// edits, +// [targetInfos.map((targetInfo) => targetInfo.targetSelection)] +// ); - return updatedTargetSelections.map((selection) => ({ - editor, - selection, - })); - } - ) - ); +// return updatedTargetSelections.map((selection) => ({ +// editor, +// selection, +// })); +// } +// ) +// ); - return { thatMark }; - } -} +// return { thatMark }; +// } +// } -function constructSimpleTypedSelection( - editor: TextEditor, - selection: SelectionWithContext -): TypedSelection { - return { - selection: { - selection: selection.selection, - editor, - }, - selectionType: "token", - selectionContext: selection.context, - insideOutsideType: null, - position: "contents", - }; -} +// function constructSimpleTypedSelection( +// editor: TextEditor, +// selection: SelectionWithContext +// ): TypedSelection { +// return { +// selection: { +// selection: selection.selection, +// editor, +// }, +// selectionType: "token", +// selectionContext: selection.context, +// insideOutsideType: null, +// position: "contents", +// }; +// } diff --git a/src/actions/Scroll.ts b/src/actions/Scroll.ts index 19ea4590bd..dac4c777ac 100644 --- a/src/actions/Scroll.ts +++ b/src/actions/Scroll.ts @@ -1,109 +1,109 @@ -import { - Action, - ActionPreferences, - ActionReturnValue, - Graph, - TypedSelection, -} from "../typings/Types"; -import { groupBy } from "../util/itertools"; -import { commands, window } from "vscode"; -import { focusEditor } from "../util/setSelectionsAndFocusEditor"; -import { displayPendingEditDecorationsForSelection } from "../util/editDisplayUtils"; +// import { +// Action, +// ActionPreferences, +// ActionReturnValue, +// Graph, +// TypedSelection, +// } from "../typings/Types"; +// import { groupBy } from "../util/itertools"; +// import { commands, window } from "vscode"; +// import { focusEditor } from "../util/setSelectionsAndFocusEditor"; +// import { displayPendingEditDecorationsForSelection } from "../util/editDisplayUtils"; -class Scroll implements Action { - getTargetPreferences: () => ActionPreferences[] = () => [ - { insideOutsideType: "inside" }, - ]; +// class Scroll implements Action { +// getTargetPreferences: () => ActionPreferences[] = () => [ +// { insideOutsideType: "inside" }, +// ]; - constructor(private graph: Graph, private at: string) { - this.run = this.run.bind(this); - } +// constructor(private graph: Graph, private at: string) { +// this.run = this.run.bind(this); +// } - async run([targets]: [TypedSelection[]]): Promise { - const selectionGroups = groupBy( - targets, - (t: TypedSelection) => t.selection.editor - ); +// async run([targets]: [TypedSelection[]]): Promise { +// const selectionGroups = groupBy( +// targets, +// (t: TypedSelection) => t.selection.editor +// ); - const lines = Array.from(selectionGroups, ([editor, targets]) => { - return { lineNumber: getLineNumber(targets, this.at), editor }; - }); +// const lines = Array.from(selectionGroups, ([editor, targets]) => { +// return { lineNumber: getLineNumber(targets, this.at), editor }; +// }); - const originalEditor = window.activeTextEditor; +// const originalEditor = window.activeTextEditor; - for (const lineWithEditor of lines) { - // For reveal line to the work we have to have the correct editor focused - if (lineWithEditor.editor !== window.activeTextEditor) { - await focusEditor(lineWithEditor.editor); - } - await commands.executeCommand("revealLine", { - lineNumber: lineWithEditor.lineNumber, - at: this.at, - }); - } +// for (const lineWithEditor of lines) { +// // For reveal line to the work we have to have the correct editor focused +// if (lineWithEditor.editor !== window.activeTextEditor) { +// await focusEditor(lineWithEditor.editor); +// } +// await commands.executeCommand("revealLine", { +// lineNumber: lineWithEditor.lineNumber, +// at: this.at, +// }); +// } - // If necessary focus back original editor - if (originalEditor != null && originalEditor !== window.activeTextEditor) { - await focusEditor(originalEditor); - } +// // If necessary focus back original editor +// if (originalEditor != null && originalEditor !== window.activeTextEditor) { +// await focusEditor(originalEditor); +// } - const decorationSelections = targets - .map((target) => target.selection) - .filter((selection) => { - const visibleRanges = selection.editor.visibleRanges; - const startLine = visibleRanges[0].start.line; - const endLine = visibleRanges[visibleRanges.length - 1].end.line; - // Don't show decorations for selections that are larger than the visible range - return ( - selection.selection.start.line > startLine || - selection.selection.end.line < endLine || - (selection.selection.start.line === startLine && - selection.selection.end.line === endLine) - ); - }); +// const decorationSelections = targets +// .map((target) => target.selection) +// .filter((selection) => { +// const visibleRanges = selection.editor.visibleRanges; +// const startLine = visibleRanges[0].start.line; +// const endLine = visibleRanges[visibleRanges.length - 1].end.line; +// // Don't show decorations for selections that are larger than the visible range +// return ( +// selection.selection.start.line > startLine || +// selection.selection.end.line < endLine || +// (selection.selection.start.line === startLine && +// selection.selection.end.line === endLine) +// ); +// }); - await displayPendingEditDecorationsForSelection( - decorationSelections, - this.graph.editStyles.referenced.line - ); +// await displayPendingEditDecorationsForSelection( +// decorationSelections, +// this.graph.editStyles.referenced.line +// ); - return { - thatMark: targets.map((target) => target.selection), - }; - } -} +// return { +// thatMark: targets.map((target) => target.selection), +// }; +// } +// } -export class ScrollToTop extends Scroll { - constructor(graph: Graph) { - super(graph, "top"); - } -} +// export class ScrollToTop extends Scroll { +// constructor(graph: Graph) { +// super(graph, "top"); +// } +// } -export class ScrollToCenter extends Scroll { - constructor(graph: Graph) { - super(graph, "center"); - } -} +// export class ScrollToCenter extends Scroll { +// constructor(graph: Graph) { +// super(graph, "center"); +// } +// } -export class ScrollToBottom extends Scroll { - constructor(graph: Graph) { - super(graph, "bottom"); - } -} +// export class ScrollToBottom extends Scroll { +// constructor(graph: Graph) { +// super(graph, "bottom"); +// } +// } -function getLineNumber(targets: TypedSelection[], at: string) { - let startLine = Number.MAX_SAFE_INTEGER; - let endLine = 0; - targets.forEach((t: TypedSelection) => { - startLine = Math.min(startLine, t.selection.selection.start.line); - endLine = Math.max(endLine, t.selection.selection.end.line); - }); +// function getLineNumber(targets: TypedSelection[], at: string) { +// let startLine = Number.MAX_SAFE_INTEGER; +// let endLine = 0; +// targets.forEach((t: TypedSelection) => { +// startLine = Math.min(startLine, t.selection.selection.start.line); +// endLine = Math.max(endLine, t.selection.selection.end.line); +// }); - if (at === "top") { - return startLine; - } - if (at === "bottom") { - return endLine; - } - return Math.floor((startLine + endLine) / 2); -} +// if (at === "top") { +// return startLine; +// } +// if (at === "bottom") { +// return endLine; +// } +// return Math.floor((startLine + endLine) / 2); +// } diff --git a/src/actions/SetBreakpoint.ts b/src/actions/SetBreakpoint.ts index 0a224d1363..7ced26c342 100644 --- a/src/actions/SetBreakpoint.ts +++ b/src/actions/SetBreakpoint.ts @@ -1,74 +1,74 @@ -import { - Action, - ActionPreferences, - ActionReturnValue, - Graph, - TypedSelection, -} from "../typings/Types"; -import { - SourceBreakpoint, - Location, - debug, - Uri, - Range, - Breakpoint, -} from "vscode"; -import displayPendingEditDecorations from "../util/editDisplayUtils"; -import { isLineSelectionType } from "../util/selectionType"; +// import { +// Action, +// ActionPreferences, +// ActionReturnValue, +// Graph, +// TypedSelection, +// } from "../typings/Types"; +// import { +// SourceBreakpoint, +// Location, +// debug, +// Uri, +// Range, +// Breakpoint, +// } from "vscode"; +// import displayPendingEditDecorations from "../util/editDisplayUtils"; +// import { isLineSelectionType } from "../util/selectionType"; -function getBreakpoints(uri: Uri, range: Range) { - return debug.breakpoints.filter( - (breakpoint) => - breakpoint instanceof SourceBreakpoint && - breakpoint.location.uri.toString() === uri.toString() && - breakpoint.location.range.intersection(range) != null - ); -} +// function getBreakpoints(uri: Uri, range: Range) { +// return debug.breakpoints.filter( +// (breakpoint) => +// breakpoint instanceof SourceBreakpoint && +// breakpoint.location.uri.toString() === uri.toString() && +// breakpoint.location.range.intersection(range) != null +// ); +// } -export default class SetBreakpoint implements Action { - getTargetPreferences: () => ActionPreferences[] = () => [ - { insideOutsideType: "inside", selectionType: "line" }, - ]; +// export default class SetBreakpoint implements Action { +// getTargetPreferences: () => ActionPreferences[] = () => [ +// { insideOutsideType: "inside", selectionType: "line" }, +// ]; - constructor(private graph: Graph) { - this.run = this.run.bind(this); - } +// constructor(private graph: Graph) { +// this.run = this.run.bind(this); +// } - async run([targets]: [ - TypedSelection[], - TypedSelection[] - ]): Promise { - await displayPendingEditDecorations( - targets, - this.graph.editStyles.referenced - ); +// async run([targets]: [ +// TypedSelection[], +// TypedSelection[] +// ]): Promise { +// await displayPendingEditDecorations( +// targets, +// this.graph.editStyles.referenced +// ); - const toAdd: Breakpoint[] = []; - const toRemove: Breakpoint[] = []; +// const toAdd: Breakpoint[] = []; +// const toRemove: Breakpoint[] = []; - targets.forEach((target) => { - let range: Range = target.selection.selection; - // The action preference give us line content but line breakpoints are registered on character 0 - if (isLineSelectionType(target.selectionType)) { - range = range.with(range.start.with(undefined, 0), undefined); - } - const uri = target.selection.editor.document.uri; - const existing = getBreakpoints(uri, range); - if (existing.length > 0) { - toRemove.push(...existing); - } else { - if (isLineSelectionType(target.selectionType)) { - range = range.with(undefined, range.end.with(undefined, 0)); - } - toAdd.push(new SourceBreakpoint(new Location(uri, range))); - } - }); +// targets.forEach((target) => { +// let range: Range = target.selection.selection; +// // The action preference give us line content but line breakpoints are registered on character 0 +// if (isLineSelectionType(target.selectionType)) { +// range = range.with(range.start.with(undefined, 0), undefined); +// } +// const uri = target.selection.editor.document.uri; +// const existing = getBreakpoints(uri, range); +// if (existing.length > 0) { +// toRemove.push(...existing); +// } else { +// if (isLineSelectionType(target.selectionType)) { +// range = range.with(undefined, range.end.with(undefined, 0)); +// } +// toAdd.push(new SourceBreakpoint(new Location(uri, range))); +// } +// }); - debug.addBreakpoints(toAdd); - debug.removeBreakpoints(toRemove); +// debug.addBreakpoints(toAdd); +// debug.removeBreakpoints(toRemove); - const thatMark = targets.map((target) => target.selection); +// const thatMark = targets.map((target) => target.selection); - return { thatMark }; - } -} +// return { thatMark }; +// } +// } diff --git a/src/actions/SetSelection.ts b/src/actions/SetSelection.ts index 77db7cab02..14f57565c3 100644 --- a/src/actions/SetSelection.ts +++ b/src/actions/SetSelection.ts @@ -19,34 +19,34 @@ export class SetSelection implements Action { } protected getSelection(target: TypedSelection) { - return target.selection.selection; + return target.isReversed + ? new Selection(target.contentRange.end, target.contentRange.start) + : new Selection(target.contentRange.start, target.contentRange.end); } async run([targets]: [TypedSelection[]]): Promise { const editor = ensureSingleEditor(targets); - await setSelectionsAndFocusEditor(editor, targets.map(this.getSelection)); + const selections = targets.map(this.getSelection); + await setSelectionsAndFocusEditor(editor, selections); return { - thatMark: targets.map((target) => target.selection), + thatMark: selections.map((selection) => ({ + editor, + selection, + })), }; } } export class SetSelectionBefore extends SetSelection { protected getSelection(target: TypedSelection) { - return new Selection( - target.selection.selection.start, - target.selection.selection.start - ); + return new Selection(target.contentRange.start, target.contentRange.start); } } export class SetSelectionAfter extends SetSelection { protected getSelection(target: TypedSelection) { - return new Selection( - target.selection.selection.end, - target.selection.selection.end - ); + return new Selection(target.contentRange.end, target.contentRange.end); } } diff --git a/src/actions/Sort.ts b/src/actions/Sort.ts index 1efd5a0cb0..d090eb4cf4 100644 --- a/src/actions/Sort.ts +++ b/src/actions/Sort.ts @@ -1,47 +1,47 @@ -import { shuffle } from "lodash"; -import { - Action, - ActionReturnValue, - ActionPreferences, - Graph, - TypedSelection, -} from "../typings/Types"; - -export class Sort implements Action { - getTargetPreferences: () => ActionPreferences[] = () => [ - { insideOutsideType: "inside" }, - ]; - - constructor(private graph: Graph) { - this.run = this.run.bind(this); - } - - protected sortTexts(texts: string[]) { - return texts.sort(); - } - - async run(targets: TypedSelection[][]): Promise { - const { returnValue: unsortedTexts } = await this.graph.actions.getText.run( - targets, - { - showDecorations: false, - } - ); - - const sortedTexts = this.sortTexts(unsortedTexts); - - return this.graph.actions.replace.run(targets, sortedTexts); - } -} - -export class Reverse extends Sort { - protected sortTexts(texts: string[]) { - return texts.reverse(); - } -} - -export class Random extends Sort { - protected sortTexts(texts: string[]) { - return shuffle(texts); - } -} +// import { shuffle } from "lodash"; +// import { +// Action, +// ActionReturnValue, +// ActionPreferences, +// Graph, +// TypedSelection, +// } from "../typings/Types"; + +// export class Sort implements Action { +// getTargetPreferences: () => ActionPreferences[] = () => [ +// { insideOutsideType: "inside" }, +// ]; + +// constructor(private graph: Graph) { +// this.run = this.run.bind(this); +// } + +// protected sortTexts(texts: string[]) { +// return texts.sort(); +// } + +// async run(targets: TypedSelection[][]): Promise { +// const { returnValue: unsortedTexts } = await this.graph.actions.getText.run( +// targets, +// { +// showDecorations: false, +// } +// ); + +// const sortedTexts = this.sortTexts(unsortedTexts); + +// return this.graph.actions.replace.run(targets, sortedTexts); +// } +// } + +// export class Reverse extends Sort { +// protected sortTexts(texts: string[]) { +// return texts.reverse(); +// } +// } + +// export class Random extends Sort { +// protected sortTexts(texts: string[]) { +// return shuffle(texts); +// } +// } diff --git a/src/actions/Wrap.ts b/src/actions/Wrap.ts index 0cd11b086b..cc0e081e90 100644 --- a/src/actions/Wrap.ts +++ b/src/actions/Wrap.ts @@ -1,126 +1,126 @@ -import { DecorationRangeBehavior, Selection } from "vscode"; -import { flatten } from "lodash"; -import { - Action, - ActionPreferences, - ActionReturnValue, - Edit, - Graph, - SelectionWithEditor, - TypedSelection, -} from "../typings/Types"; -import { runOnTargetsForEachEditor } from "../util/targetUtils"; -import { decorationSleep } from "../util/editDisplayUtils"; -import { FullSelectionInfo } from "../typings/updateSelections"; -import { - getSelectionInfo, - performEditsAndUpdateFullSelectionInfos, -} from "../core/updateSelections/updateSelections"; +// import { DecorationRangeBehavior, Selection } from "vscode"; +// import { flatten } from "lodash"; +// import { +// Action, +// ActionPreferences, +// ActionReturnValue, +// Edit, +// Graph, +// SelectionWithEditor, +// TypedSelection, +// } from "../typings/Types"; +// import { runOnTargetsForEachEditor } from "../util/targetUtils"; +// import { decorationSleep } from "../util/editDisplayUtils"; +// import { FullSelectionInfo } from "../typings/updateSelections"; +// import { +// getSelectionInfo, +// performEditsAndUpdateFullSelectionInfos, +// } from "../core/updateSelections/updateSelections"; -export default class Wrap implements Action { - getTargetPreferences: () => ActionPreferences[] = () => [ - { insideOutsideType: "inside" }, - ]; +// export default class Wrap implements Action { +// getTargetPreferences: () => ActionPreferences[] = () => [ +// { insideOutsideType: "inside" }, +// ]; - constructor(private graph: Graph) { - this.run = this.run.bind(this); - } +// constructor(private graph: Graph) { +// this.run = this.run.bind(this); +// } - async run( - [targets]: [TypedSelection[]], - left: string, - right: string - ): Promise { - const thatMark = flatten( - await runOnTargetsForEachEditor( - targets, - async (editor, targets) => { - const { document } = editor; - const boundaries = targets.map((target) => ({ - start: new Selection( - target.selection.selection.start, - target.selection.selection.start - ), - end: new Selection( - target.selection.selection.end, - target.selection.selection.end - ), - })); +// async run( +// [targets]: [TypedSelection[]], +// left: string, +// right: string +// ): Promise { +// const thatMark = flatten( +// await runOnTargetsForEachEditor( +// targets, +// async (editor, targets) => { +// const { document } = editor; +// const boundaries = targets.map((target) => ({ +// start: new Selection( +// target.selection.selection.start, +// target.selection.selection.start +// ), +// end: new Selection( +// target.selection.selection.end, +// target.selection.selection.end +// ), +// })); - const edits: Edit[] = boundaries.flatMap(({ start, end }) => [ - { - text: left, - range: start, - }, - { - text: right, - range: end, - isReplace: true, - }, - ]); +// const edits: Edit[] = boundaries.flatMap(({ start, end }) => [ +// { +// text: left, +// range: start, +// }, +// { +// text: right, +// range: end, +// isReplace: true, +// }, +// ]); - const delimiterSelectionInfos: FullSelectionInfo[] = - boundaries.flatMap(({ start, end }) => { - return [ - getSelectionInfo( - document, - start, - DecorationRangeBehavior.OpenClosed - ), - getSelectionInfo( - document, - end, - DecorationRangeBehavior.ClosedOpen - ), - ]; - }); +// const delimiterSelectionInfos: FullSelectionInfo[] = +// boundaries.flatMap(({ start, end }) => { +// return [ +// getSelectionInfo( +// document, +// start, +// DecorationRangeBehavior.OpenClosed +// ), +// getSelectionInfo( +// document, +// end, +// DecorationRangeBehavior.ClosedOpen +// ), +// ]; +// }); - const cursorSelectionInfos = editor.selections.map((selection) => - getSelectionInfo( - document, - selection, - DecorationRangeBehavior.ClosedClosed - ) - ); +// const cursorSelectionInfos = editor.selections.map((selection) => +// getSelectionInfo( +// document, +// selection, +// DecorationRangeBehavior.ClosedClosed +// ) +// ); - const thatMarkSelectionInfos = targets.map( - ({ selection: { selection } }) => - getSelectionInfo( - document, - selection, - DecorationRangeBehavior.OpenOpen - ) - ); +// const thatMarkSelectionInfos = targets.map( +// ({ selection: { selection } }) => +// getSelectionInfo( +// document, +// selection, +// DecorationRangeBehavior.OpenOpen +// ) +// ); - const [delimiterSelections, cursorSelections, thatMarkSelections] = - await performEditsAndUpdateFullSelectionInfos( - this.graph.rangeUpdater, - editor, - edits, - [ - delimiterSelectionInfos, - cursorSelectionInfos, - thatMarkSelectionInfos, - ] - ); +// const [delimiterSelections, cursorSelections, thatMarkSelections] = +// await performEditsAndUpdateFullSelectionInfos( +// this.graph.rangeUpdater, +// editor, +// edits, +// [ +// delimiterSelectionInfos, +// cursorSelectionInfos, +// thatMarkSelectionInfos, +// ] +// ); - editor.selections = cursorSelections; +// editor.selections = cursorSelections; - editor.setDecorations( - this.graph.editStyles.justAdded.token, - delimiterSelections - ); - await decorationSleep(); - editor.setDecorations(this.graph.editStyles.justAdded.token, []); +// editor.setDecorations( +// this.graph.editStyles.justAdded.token, +// delimiterSelections +// ); +// await decorationSleep(); +// editor.setDecorations(this.graph.editStyles.justAdded.token, []); - return thatMarkSelections.map((selection) => ({ - editor, - selection, - })); - } - ) - ); +// return thatMarkSelections.map((selection) => ({ +// editor, +// selection, +// })); +// } +// ) +// ); - return { thatMark }; - } -} +// return { thatMark }; +// } +// } diff --git a/src/actions/WrapWithSnippet.ts b/src/actions/WrapWithSnippet.ts index 0fc160c4c6..3dceb3260d 100644 --- a/src/actions/WrapWithSnippet.ts +++ b/src/actions/WrapWithSnippet.ts @@ -1,191 +1,191 @@ -import { commands } from "vscode"; -import { callFunctionAndUpdateSelections } from "../core/updateSelections/updateSelections"; -import { SnippetDefinition } from "../typings/snippet"; -import { - Action, - ActionPreferences, - ActionReturnValue, - Graph, - TypedSelection, -} from "../typings/Types"; -import displayPendingEditDecorations from "../util/editDisplayUtils"; -import { ensureSingleEditor } from "../util/targetUtils"; -import { - Placeholder, - SnippetParser, - TextmateSnippet, - Variable, -} from "../vendor/snippet/snippetParser"; -import { KnownSnippetVariableNames } from "../vendor/snippet/snippetVariables"; - -export default class WrapWithSnippet implements Action { - private snippetParser = new SnippetParser(); - - getTargetPreferences(snippetLocation: string): ActionPreferences[] { - const [snippetName, placeholderName] = - parseSnippetLocation(snippetLocation); - - const snippet = this.graph.snippets.getSnippet(snippetName); - - if (snippet == null) { - throw new Error(`Couldn't find snippet ${snippetName}`); - } - - const variables = snippet.variables ?? {}; - const defaultScopeType = variables[placeholderName]?.wrapperScopeType; - - return [ - { - insideOutsideType: "inside", - modifier: - defaultScopeType == null - ? undefined - : { - type: "containingScope", - scopeType: defaultScopeType, - includeSiblings: false, - }, - }, - ]; - } - - constructor(private graph: Graph) { - this.run = this.run.bind(this); - } - - async run( - [targets]: [TypedSelection[]], - snippetLocation: string - ): Promise { - const [snippetName, placeholderName] = - parseSnippetLocation(snippetLocation); - - const snippet = this.graph.snippets.getSnippet(snippetName)!; - - const editor = ensureSingleEditor(targets); - - // Find snippet definition matching context. - // NB: We only look at the first target to create our context. This means - // that if there are two snippets that match two different contexts, and - // the two targets match those two different contexts, we will just use the - // snippet that matches the first context for both targets - const definition = findMatchingSnippetDefinition( - targets[0], - snippet.definitions - ); - - if (definition == null) { - throw new Error("Couldn't find matching snippet definition"); - } - - const parsedSnippet = this.snippetParser.parse(definition.body.join("\n")); - - transformSnippetVariables(parsedSnippet, placeholderName); - - const snippetString = parsedSnippet.toTextmateString(); - - await displayPendingEditDecorations( - targets, - this.graph.editStyles.pendingModification0 - ); - - const targetSelections = targets.map( - (target) => target.selection.selection - ); - - await this.graph.actions.setSelection.run([targets]); - - // NB: We used the command "editor.action.insertSnippet" instead of calling editor.insertSnippet - // because the latter doesn't support special variables like CLIPBOARD - const [updatedTargetSelections] = await callFunctionAndUpdateSelections( - this.graph.rangeUpdater, - () => - commands.executeCommand("editor.action.insertSnippet", { - snippet: snippetString, - }), - editor.document, - [targetSelections] - ); - - return { - thatMark: updatedTargetSelections.map((selection) => ({ - editor, - selection, - })), - }; - } -} - -/** - * Replaces the snippet variable with name `placeholderName` with TM_SELECTED_TEXT - * - * Also replaces any unknown variables with placeholders. We do this so it's - * easier to leave one of the placeholders blank. We may make it so that you - * can disable this with a setting in the future - * @param parsedSnippet The parsed textmate snippet to operate on - * @param placeholderName The variable name to replace with TM_SELECTED_TEXT - */ -function transformSnippetVariables( - parsedSnippet: TextmateSnippet, - placeholderName: string -) { - var placeholderIndex = getMaxPlaceholderIndex(parsedSnippet) + 1; - - parsedSnippet.walk((candidate) => { - if (candidate instanceof Variable) { - if (candidate.name === placeholderName) { - candidate.name = "TM_SELECTED_TEXT"; - } else if (!KnownSnippetVariableNames[candidate.name]) { - const placeholder = new Placeholder(placeholderIndex++); - candidate.children.forEach((child) => placeholder.appendChild(child)); - candidate.parent.replace(candidate, [placeholder]); - } - } - return true; - }); -} - -function getMaxPlaceholderIndex(parsedSnippet: TextmateSnippet) { - var placeholderIndex = 0; - parsedSnippet.walk((candidate) => { - if (candidate instanceof Placeholder) { - placeholderIndex = Math.max(placeholderIndex, candidate.index); - } - return true; - }); - return placeholderIndex; -} - -function parseSnippetLocation(snippetLocation: string): [string, string] { - const [snippetName, placeholderName] = snippetLocation.split("."); - if (snippetName == null || placeholderName == null) { - throw new Error("Snippet location missing '.'"); - } - return [snippetName, placeholderName]; -} - -function findMatchingSnippetDefinition( - typedSelection: TypedSelection, - definitions: SnippetDefinition[] -) { - const languageId = typedSelection.selection.editor.document.languageId; - - return definitions.find(({ scope }) => { - if (scope == null) { - return true; - } - - const { langIds, scopeType } = scope; - - if (langIds != null && !langIds.includes(languageId)) { - return false; - } - - if (scopeType != null) { - // TODO: Implement scope types by refactoring code out of processScopeType - throw new Error("Scope types not yet implemented"); - } - - return true; - }); -} +// import { commands } from "vscode"; +// import { callFunctionAndUpdateSelections } from "../core/updateSelections/updateSelections"; +// import { SnippetDefinition } from "../typings/snippet"; +// import { +// Action, +// ActionPreferences, +// ActionReturnValue, +// Graph, +// TypedSelection, +// } from "../typings/Types"; +// import displayPendingEditDecorations from "../util/editDisplayUtils"; +// import { ensureSingleEditor } from "../util/targetUtils"; +// import { +// Placeholder, +// SnippetParser, +// TextmateSnippet, +// Variable, +// } from "../vendor/snippet/snippetParser"; +// import { KnownSnippetVariableNames } from "../vendor/snippet/snippetVariables"; + +// export default class WrapWithSnippet implements Action { +// private snippetParser = new SnippetParser(); + +// getTargetPreferences(snippetLocation: string): ActionPreferences[] { +// const [snippetName, placeholderName] = +// parseSnippetLocation(snippetLocation); + +// const snippet = this.graph.snippets.getSnippet(snippetName); + +// if (snippet == null) { +// throw new Error(`Couldn't find snippet ${snippetName}`); +// } + +// const variables = snippet.variables ?? {}; +// const defaultScopeType = variables[placeholderName]?.wrapperScopeType; + +// return [ +// { +// insideOutsideType: "inside", +// modifier: +// defaultScopeType == null +// ? undefined +// : { +// type: "containingScope", +// scopeType: defaultScopeType, +// includeSiblings: false, +// }, +// }, +// ]; +// } + +// constructor(private graph: Graph) { +// this.run = this.run.bind(this); +// } + +// async run( +// [targets]: [TypedSelection[]], +// snippetLocation: string +// ): Promise { +// const [snippetName, placeholderName] = +// parseSnippetLocation(snippetLocation); + +// const snippet = this.graph.snippets.getSnippet(snippetName)!; + +// const editor = ensureSingleEditor(targets); + +// // Find snippet definition matching context. +// // NB: We only look at the first target to create our context. This means +// // that if there are two snippets that match two different contexts, and +// // the two targets match those two different contexts, we will just use the +// // snippet that matches the first context for both targets +// const definition = findMatchingSnippetDefinition( +// targets[0], +// snippet.definitions +// ); + +// if (definition == null) { +// throw new Error("Couldn't find matching snippet definition"); +// } + +// const parsedSnippet = this.snippetParser.parse(definition.body.join("\n")); + +// transformSnippetVariables(parsedSnippet, placeholderName); + +// const snippetString = parsedSnippet.toTextmateString(); + +// await displayPendingEditDecorations( +// targets, +// this.graph.editStyles.pendingModification0 +// ); + +// const targetSelections = targets.map( +// (target) => target.selection.selection +// ); + +// await this.graph.actions.setSelection.run([targets]); + +// // NB: We used the command "editor.action.insertSnippet" instead of calling editor.insertSnippet +// // because the latter doesn't support special variables like CLIPBOARD +// const [updatedTargetSelections] = await callFunctionAndUpdateSelections( +// this.graph.rangeUpdater, +// () => +// commands.executeCommand("editor.action.insertSnippet", { +// snippet: snippetString, +// }), +// editor.document, +// [targetSelections] +// ); + +// return { +// thatMark: updatedTargetSelections.map((selection) => ({ +// editor, +// selection, +// })), +// }; +// } +// } + +// /** +// * Replaces the snippet variable with name `placeholderName` with TM_SELECTED_TEXT +// * +// * Also replaces any unknown variables with placeholders. We do this so it's +// * easier to leave one of the placeholders blank. We may make it so that you +// * can disable this with a setting in the future +// * @param parsedSnippet The parsed textmate snippet to operate on +// * @param placeholderName The variable name to replace with TM_SELECTED_TEXT +// */ +// function transformSnippetVariables( +// parsedSnippet: TextmateSnippet, +// placeholderName: string +// ) { +// var placeholderIndex = getMaxPlaceholderIndex(parsedSnippet) + 1; + +// parsedSnippet.walk((candidate) => { +// if (candidate instanceof Variable) { +// if (candidate.name === placeholderName) { +// candidate.name = "TM_SELECTED_TEXT"; +// } else if (!KnownSnippetVariableNames[candidate.name]) { +// const placeholder = new Placeholder(placeholderIndex++); +// candidate.children.forEach((child) => placeholder.appendChild(child)); +// candidate.parent.replace(candidate, [placeholder]); +// } +// } +// return true; +// }); +// } + +// function getMaxPlaceholderIndex(parsedSnippet: TextmateSnippet) { +// var placeholderIndex = 0; +// parsedSnippet.walk((candidate) => { +// if (candidate instanceof Placeholder) { +// placeholderIndex = Math.max(placeholderIndex, candidate.index); +// } +// return true; +// }); +// return placeholderIndex; +// } + +// function parseSnippetLocation(snippetLocation: string): [string, string] { +// const [snippetName, placeholderName] = snippetLocation.split("."); +// if (snippetName == null || placeholderName == null) { +// throw new Error("Snippet location missing '.'"); +// } +// return [snippetName, placeholderName]; +// } + +// function findMatchingSnippetDefinition( +// typedSelection: TypedSelection, +// definitions: SnippetDefinition[] +// ) { +// const languageId = typedSelection.selection.editor.document.languageId; + +// return definitions.find(({ scope }) => { +// if (scope == null) { +// return true; +// } + +// const { langIds, scopeType } = scope; + +// if (langIds != null && !langIds.includes(languageId)) { +// return false; +// } + +// if (scopeType != null) { +// // TODO: Implement scope types by refactoring code out of processScopeType +// throw new Error("Scope types not yet implemented"); +// } + +// return true; +// }); +// } diff --git a/src/actions/index.ts b/src/actions/index.ts index 143d2b4112..d3e3dc2ea6 100644 --- a/src/actions/index.ts +++ b/src/actions/index.ts @@ -1,84 +1,2 @@ -import { ActionRecord, Graph } from "../typings/Types"; -import Clear from "./Clear"; -import { Cut, Copy, Paste } from "./CutCopyPaste"; -import Delete from "./Delete"; -import ExtractVariable from "./ExtractVariable"; -import { Fold, Unfold } from "./Fold"; -import { EditNewLineAbove, EditNewLineBelow } from "./EditNewLine"; -import { - SetSelection, - SetSelectionBefore, - SetSelectionAfter, -} from "./SetSelection"; -import Wrap from "./Wrap"; -import { ScrollToTop, ScrollToCenter, ScrollToBottom } from "./Scroll"; -import { IndentLines, OutdentLines } from "./Indent"; -import { CommentLines } from "./Comment"; -import { Bring, Move, Swap } from "./BringMoveSwap"; -import { - InsertEmptyLineAbove, - InsertEmptyLineBelow, - InsertEmptyLinesAround, -} from "./InsertEmptyLines"; -import GetText from "./GetText"; -import { FindInFiles } from "./Find"; -import Replace from "./Replace"; -import { CopyLinesUp, CopyLinesDown } from "./CopyLines"; -import SetBreakpoint from "./SetBreakpoint"; -import { Sort, Reverse, Random } from "./Sort"; -import Call from "./Call"; -import WrapWithSnippet from "./WrapWithSnippet"; -import Deselect from "./Deselect"; -import Rewrap from "./Rewrap"; -import ExecuteCommand from "./ExecuteCommand"; -import FollowLink from "./FollowLink"; -import Highlight from "./Highlight"; - -class Actions implements ActionRecord { - constructor(private graph: Graph) {} - - callAsFunction = new Call(this.graph); - clearAndSetSelection = new Clear(this.graph); - copyToClipboard = new Copy(this.graph); - cutToClipboard = new Cut(this.graph); - editNewLineAfter = new EditNewLineBelow(this.graph); - editNewLineBefore = new EditNewLineAbove(this.graph); - executeCommand = new ExecuteCommand(this.graph); - extractVariable = new ExtractVariable(this.graph); - findInWorkspace = new FindInFiles(this.graph); - foldRegion = new Fold(this.graph); - followLink = new FollowLink(this.graph); - getText = new GetText(this.graph); - highlight = new Highlight(this.graph); - indentLine = new IndentLines(this.graph); - insertCopyAfter = new CopyLinesDown(this.graph); - insertCopyBefore = new CopyLinesUp(this.graph); - insertEmptyLineAfter = new InsertEmptyLineBelow(this.graph); - insertEmptyLineBefore = new InsertEmptyLineAbove(this.graph); - insertEmptyLinesAround = new InsertEmptyLinesAround(this.graph); - moveToTarget = new Move(this.graph); - outdentLine = new OutdentLines(this.graph); - pasteFromClipboard = new Paste(this.graph); - remove = new Delete(this.graph); - deselect = new Deselect(this.graph); - replace = new Replace(this.graph); - replaceWithTarget = new Bring(this.graph); - randomizeTargets = new Random(this.graph); - reverseTargets = new Reverse(this.graph); - rewrapWithPairedDelimiter = new Rewrap(this.graph); - scrollToBottom = new ScrollToBottom(this.graph); - scrollToCenter = new ScrollToCenter(this.graph); - scrollToTop = new ScrollToTop(this.graph); - setSelection = new SetSelection(this.graph); - setSelectionAfter = new SetSelectionAfter(this.graph); - setSelectionBefore = new SetSelectionBefore(this.graph); - sortTargets = new Sort(this.graph); - swapTargets = new Swap(this.graph); - toggleLineBreakpoint = new SetBreakpoint(this.graph); - toggleLineComment = new CommentLines(this.graph); - unfoldRegion = new Unfold(this.graph); - wrapWithPairedDelimiter = new Wrap(this.graph); - wrapWithSnippet = new WrapWithSnippet(this.graph); -} - +import Actions from "./Actions"; export default Actions; diff --git a/src/core/commandVersionUpgrades/canonicalizeActionName.ts b/src/core/commandVersionUpgrades/canonicalizeActionName.ts index b7111cd521..b90868f5fb 100644 --- a/src/core/commandVersionUpgrades/canonicalizeActionName.ts +++ b/src/core/commandVersionUpgrades/canonicalizeActionName.ts @@ -1,32 +1,33 @@ import { ActionType } from "../../typings/Types"; const actionAliasToCanonicalName: Record = { - bring: "replaceWithTarget", - call: "callAsFunction", - clear: "clearAndSetSelection", - commentLines: "toggleLineComment", - copy: "copyToClipboard", - cut: "cutToClipboard", - delete: "remove", - editNewLineAbove: "editNewLineBefore", - editNewLineBelow: "editNewLineAfter", - findInFiles: "findInWorkspace", - fold: "foldRegion", - indentLines: "indentLine", - insertEmptyLineAbove: "insertEmptyLineBefore", - insertEmptyLineBelow: "insertEmptyLineAfter", - insertLineAfter: "editNewLineAfter", - insertLineBefore: "editNewLineBefore", - move: "moveToTarget", - outdentLines: "outdentLine", - paste: "pasteFromClipboard", - reverse: "reverseTargets", - setBreakpoint: "toggleLineBreakpoint", - sort: "sortTargets", - swap: "swapTargets", - unfold: "unfoldRegion", - use: "replaceWithTarget", - wrap: "wrapWithPairedDelimiter", + // TODO + // bring: "replaceWithTarget", + // call: "callAsFunction", + // clear: "clearAndSetSelection", + // commentLines: "toggleLineComment", + // copy: "copyToClipboard", + // cut: "cutToClipboard", + // delete: "remove", + // editNewLineAbove: "editNewLineBefore", + // editNewLineBelow: "editNewLineAfter", + // findInFiles: "findInWorkspace", + // fold: "foldRegion", + // indentLines: "indentLine", + // insertEmptyLineAbove: "insertEmptyLineBefore", + // insertEmptyLineBelow: "insertEmptyLineAfter", + // insertLineAfter: "editNewLineAfter", + // insertLineBefore: "editNewLineBefore", + // move: "moveToTarget", + // outdentLines: "outdentLine", + // paste: "pasteFromClipboard", + // reverse: "reverseTargets", + // setBreakpoint: "toggleLineBreakpoint", + // sort: "sortTargets", + // swap: "swapTargets", + // unfold: "unfoldRegion", + // use: "replaceWithTarget", + // wrap: "wrapWithPairedDelimiter", }; export default function canonicalizeActionName(actionName: string) { diff --git a/src/typings/Types.ts b/src/typings/Types.ts index 3407b80d5b..f4ff578485 100644 --- a/src/typings/Types.ts +++ b/src/typings/Types.ts @@ -192,47 +192,47 @@ export interface Action { } export type ActionType = - | "callAsFunction" - | "clearAndSetSelection" - | "copyToClipboard" - | "cutToClipboard" - | "deselect" - | "editNewLineAfter" - | "editNewLineBefore" - | "executeCommand" - | "extractVariable" - | "findInWorkspace" - | "foldRegion" - | "followLink" - | "getText" - | "highlight" - | "indentLine" - | "insertCopyAfter" - | "insertCopyBefore" - | "insertEmptyLineAfter" - | "insertEmptyLineBefore" - | "insertEmptyLinesAround" - | "moveToTarget" - | "outdentLine" - | "pasteFromClipboard" - | "remove" - | "replace" - | "replaceWithTarget" - | "reverseTargets" - | "rewrapWithPairedDelimiter" - | "scrollToBottom" - | "scrollToCenter" - | "scrollToTop" - | "setSelection" + // | "callAsFunction" + // | "clearAndSetSelection" + // | "copyToClipboard" + // | "cutToClipboard" + // | "deselect" + // | "editNewLineAfter" + // | "editNewLineBefore" + // | "executeCommand" + // | "extractVariable" + // | "findInWorkspace" + // | "foldRegion" + // | "followLink" + // | "getText" + // | "highlight" + // | "indentLine" + // | "insertCopyAfter" + // | "insertCopyBefore" + // | "insertEmptyLineAfter" + // | "insertEmptyLineBefore" + // | "insertEmptyLinesAround" + // | "moveToTarget" + // | "outdentLine" + // | "pasteFromClipboard" + // | "remove" + // | "replace" + // | "replaceWithTarget" + // | "reverseTargets" + // | "rewrapWithPairedDelimiter" + // | "scrollToBottom" + // | "scrollToCenter" + // | "scrollToTop" + "setSelection" | "setSelectionAfter" | "setSelectionBefore" - | "sortTargets" - | "swapTargets" - | "toggleLineBreakpoint" - | "toggleLineComment" - | "unfoldRegion" - | "wrapWithPairedDelimiter" - | "wrapWithSnippet"; + // | "sortTargets" + // | "swapTargets" + // | "toggleLineBreakpoint" + // | "toggleLineComment" + // | "unfoldRegion" + // | "wrapWithPairedDelimiter" + // | "wrapWithSnippet" export type ActionRecord = Record; From aef0395944fe7202e68edb4e91e4609f75ea316b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 15 May 2022 09:06:02 +0000 Subject: [PATCH 027/314] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/typings/Types.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/typings/Types.ts b/src/typings/Types.ts index f4ff578485..63a49bc475 100644 --- a/src/typings/Types.ts +++ b/src/typings/Types.ts @@ -223,16 +223,14 @@ export type ActionType = // | "scrollToBottom" // | "scrollToCenter" // | "scrollToTop" - "setSelection" - | "setSelectionAfter" - | "setSelectionBefore" - // | "sortTargets" - // | "swapTargets" - // | "toggleLineBreakpoint" - // | "toggleLineComment" - // | "unfoldRegion" - // | "wrapWithPairedDelimiter" - // | "wrapWithSnippet" + "setSelection" | "setSelectionAfter" | "setSelectionBefore"; +// | "sortTargets" +// | "swapTargets" +// | "toggleLineBreakpoint" +// | "toggleLineComment" +// | "unfoldRegion" +// | "wrapWithPairedDelimiter" +// | "wrapWithSnippet" export type ActionRecord = Record; From 14451eeb003488aa1b16994b782faa4a287d1f28 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 15 May 2022 13:07:47 +0200 Subject: [PATCH 028/314] Added v1 => v2 migration --- .../upgradeV1ToV2/commandV1.types.ts | 46 ++++++-- .../upgradeV1ToV2/upgradeStrictHere.ts | 1 - .../upgradeV1ToV2/upgradeV1ToV2.ts | 100 ++++++++++++++++-- src/core/inferFullTargets.ts | 1 - src/typings/target.types.ts | 2 - 5 files changed, 127 insertions(+), 23 deletions(-) diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/commandV1.types.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/commandV1.types.ts index c073359429..30c167bc93 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/commandV1.types.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/commandV1.types.ts @@ -43,10 +43,10 @@ interface CommandV0V1 { extraArgs?: unknown[]; } -interface PartialPrimitiveTarget { +export interface PartialPrimitiveTargetV0V1 { type: "primitive"; mark?: Mark; - modifier?: Modifier; + modifier?: ModifierV0V1; selectionType?: SelectionType; position?: Position; insideOutsideType?: InsideOutsideType; @@ -55,8 +55,8 @@ interface PartialPrimitiveTarget { interface PartialRangeTarget { type: "range"; - start: PartialPrimitiveTarget; - end: PartialPrimitiveTarget; + start: PartialPrimitiveTargetV0V1; + end: PartialPrimitiveTargetV0V1; excludeStart?: boolean; excludeEnd?: boolean; rangeType?: RangeType; @@ -66,11 +66,11 @@ type RangeType = "continuous" | "vertical"; interface PartialListTarget { type: "list"; - elements: (PartialPrimitiveTarget | PartialRangeTarget)[]; + elements: (PartialPrimitiveTargetV0V1 | PartialRangeTarget)[]; } export type PartialTargetV0V1 = - | PartialPrimitiveTarget + | PartialPrimitiveTargetV0V1 | PartialRangeTarget | PartialListTarget; @@ -105,12 +105,38 @@ interface Nothing { interface DecoratedSymbol { type: "decoratedSymbol"; - // NB: We use the type string instead of the more specific hat style type - // because this will go through a canonicalization mapping anyway - symbolColor: string; + symbolColor: HatStyleName; character: string; } +const HAT_COLORS = [ + "default", + "blue", + "green", + "red", + "pink", + "yellow", + "userColor1", + "userColor2", +] as const; + +const HAT_NON_DEFAULT_SHAPES = [ + "ex", + "fox", + "wing", + "hole", + "frame", + "curve", + "eye", + "play", + "bolt", + "crosshairs", +] as const; + +type HatColor = typeof HAT_COLORS[number]; +type HatNonDefaultShape = typeof HAT_NON_DEFAULT_SHAPES[number]; +type HatStyleName = HatColor | `${HatColor}-${HatNonDefaultShape}`; + type LineNumberType = "absolute" | "relative" | "modulo100"; interface LineNumberPosition { @@ -218,7 +244,7 @@ interface TailModifier { type: "tail"; } -type Modifier = +export type ModifierV0V1 = | IdentityModifier | SurroundingPairModifier | ContainingScopeModifier diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeStrictHere.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeStrictHere.ts index 829e718bb0..424fda3134 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeStrictHere.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeStrictHere.ts @@ -11,7 +11,6 @@ const STRICT_HERE = { }; const IMPLICIT_TARGET: PartialPrimitiveTarget = { type: "primitive", - isImplicit: true, }; export const upgradeStrictHere = ( target: PartialPrimitiveTarget diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts index 6ea9e58a31..da04a6e5ed 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts @@ -1,9 +1,20 @@ import { flow } from "lodash"; -import { PartialTarget } from "../../../typings/target.types"; +import { + Modifier, + PartialPrimitiveTarget, + PartialRangeTarget, + PartialTarget, + ScopeType, +} from "../../../typings/target.types"; import { ActionType } from "../../../typings/Types"; import { transformPartialPrimitiveTargets } from "../../../util/getPrimitiveTargets"; import { CommandV2 } from "../../commandRunner/command.types"; -import { CommandV1, PartialTargetV0V1 } from "./commandV1.types"; +import { + CommandV1, + ModifierV0V1, + PartialPrimitiveTargetV0V1, + PartialTargetV0V1, +} from "./commandV1.types"; import { upgradeStrictHere } from "./upgradeStrictHere"; export function upgradeV1ToV2(command: CommandV1): CommandV2 { @@ -17,14 +28,85 @@ export function upgradeV1ToV2(command: CommandV1): CommandV2 { }; } -function upgradeTargets(partialTargets: PartialTargetV0V1[]) { - // const partialTargetsV2: PartialTarget[] = partialTargets.map( - // (target) => ({ +function upgradeModifier(modifier: ModifierV0V1): Modifier | null { + switch (modifier.type) { + case "identity": + return null; + case "containingScope": + const mod = { + ...modifier, + scopeType: modifier.scopeType as ScopeType, + }; + if (modifier.includeSiblings) { + return { + ...mod, + type: "everyScope", + }; + } + return mod; + default: + return modifier; + } +} - // }) - // ); - // TODO do target migration - const partialTargetsV2: PartialTarget[] = []; +function upgradePrimitiveTarget( + target: PartialPrimitiveTargetV0V1 +): PartialPrimitiveTarget { + const { + insideOutsideType, + modifier, + isImplicit, + selectionType, + position, + ...rest + } = target; + const modifiers: Modifier[] = []; + if (modifier) { + const mod = upgradeModifier(modifier); + if (mod) { + modifiers.push(mod); + } + } + if (isImplicit) { + modifiers.push({ type: "toRawSelection" }); + } + if (selectionType) { + modifiers.push({ type: "containingScope", scopeType: selectionType }); + } + if (position && position !== "contents") { + modifiers.push({ type: "position", position: position }); + } + // Modifiers are processed backwards + modifiers.reverse(); + return { + ...rest, + modifiers, + }; +} + +function upgradeTarget(target: PartialTargetV0V1): PartialTarget { + switch (target.type) { + case "list": + return { + ...target, + elements: target.elements.map( + (target) => + upgradeTarget(target) as PartialPrimitiveTarget | PartialRangeTarget + ), + }; + case "range": + return { + ...target, + anchor: upgradePrimitiveTarget(target.start), + active: upgradePrimitiveTarget(target.end), + }; + case "primitive": + return upgradePrimitiveTarget(target); + } +} + +function upgradeTargets(partialTargets: PartialTargetV0V1[]) { + const partialTargetsV2: PartialTarget[] = partialTargets.map(upgradeTarget); return transformPartialPrimitiveTargets( partialTargetsV2, flow(upgradeStrictHere) diff --git a/src/core/inferFullTargets.ts b/src/core/inferFullTargets.ts index f62c2631aa..21c9ca4b45 100644 --- a/src/core/inferFullTargets.ts +++ b/src/core/inferFullTargets.ts @@ -117,7 +117,6 @@ function inferPrimitiveTarget( type: target.type, mark, modifiers, - isImplicit: target.isImplicit ?? false, }; } diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 3a39c14518..bd03326c6b 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -181,7 +181,6 @@ export interface PartialPrimitiveTarget { type: "primitive"; mark?: Mark; modifiers?: Modifier[]; - isImplicit?: boolean; } export type Modifier = @@ -214,7 +213,6 @@ export type PartialTarget = | PartialListTarget; export interface PrimitiveTarget extends PartialPrimitiveTarget { - isImplicit: boolean; mark: Mark; modifiers: Modifier[]; } From ecae08ae28cade2e522b7d482ae63671db68eec6 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 15 May 2022 14:00:21 +0200 Subject: [PATCH 029/314] Renamed target types --- src/actions/BringMoveSwap.ts | 24 +- src/actions/Call.ts | 6 +- src/actions/Clear.ts | 4 +- src/actions/CommandAction.ts | 6 +- src/actions/CopyLines.ts | 6 +- src/actions/CutCopyPaste.ts | 4 +- src/actions/Delete.ts | 4 +- src/actions/Deselect.ts | 4 +- src/actions/EditNewLine.ts | 8 +- src/actions/ExecuteCommand.ts | 4 +- src/actions/ExtractVariable.ts | 4 +- src/actions/Find.ts | 4 +- src/actions/Fold.ts | 6 +- src/actions/FollowLink.ts | 4 +- src/actions/GetText.ts | 4 +- src/actions/Highlight.ts | 4 +- src/actions/InsertEmptyLines.ts | 6 +- src/actions/Replace.ts | 6 +- src/actions/Rewrap.ts | 6 +- src/actions/Scroll.ts | 10 +- src/actions/SetBreakpoint.ts | 6 +- src/actions/SetSelection.ts | 10 +- src/actions/Sort.ts | 4 +- src/actions/Wrap.ts | 4 +- src/actions/WrapWithSnippet.ts | 6 +- src/core/commandRunner/CommandRunner.ts | 2 +- src/core/commandRunner/command.types.ts | 4 +- .../canonicalizeAndValidateCommand.ts | 9 +- .../canonicalizeTargets.ts | 16 +- .../upgradeV1ToV2/upgradeStrictHere.ts | 8 +- .../upgradeV1ToV2/upgradeV1ToV2.ts | 17 +- src/core/inferFullTargets.ts | 60 ++--- src/processTargets/PipelineStages.types.ts | 10 +- src/processTargets/index.ts | 228 +---------------- src/processTargets/marks/CursorStage.ts | 5 +- src/processTargets/marks/CursorTokenStage.ts | 6 +- .../marks/DecoratedSymbolStage.ts | 6 +- src/processTargets/marks/LineNumberStage.ts | 5 +- src/processTargets/marks/NothingStage.ts | 5 +- src/processTargets/marks/SourceStage.ts | 6 +- src/processTargets/marks/ThatStage.ts | 6 +- .../modifiers/ContainingScopeStage.ts | 7 +- src/processTargets/modifiers/DocumentStage.ts | 8 +- src/processTargets/modifiers/HeadTailStage.ts | 9 +- src/processTargets/modifiers/LineStage.ts | 10 +- .../modifiers/NotebookCellStage.ts | 8 +- .../modifiers/ParagraphStage.ts | 8 +- src/processTargets/modifiers/PositionStage.ts | 11 +- .../modifiers/RawSelectionStage.ts | 9 +- src/processTargets/modifiers/RegexStage.ts | 8 +- src/processTargets/modifiers/SubPieceStage.ts | 9 +- .../modifiers/SurroundingPairStage.ts | 10 +- src/processTargets/modifiers/TokenStage.ts | 10 +- src/processTargets/processTargets.ts | 231 ++++++++++++++++++ .../updateSurroundingPairTest.ts | 4 +- .../transformations/upgradeFromVersion0.ts | 4 +- .../fixtures/inferFullTargets.fixture.ts | 6 +- src/testUtil/TestCase.ts | 10 +- src/testUtil/extractTargetedMarks.ts | 6 +- src/typings/Types.ts | 84 +------ src/typings/target.types.ts | 98 ++++++-- src/util/editDisplayUtils.ts | 12 +- src/util/getLinks.ts | 4 +- src/util/getPrimitiveTargets.ts | 34 +-- src/util/targetUtils.ts | 20 +- src/util/unifyRanges.ts | 18 +- 66 files changed, 574 insertions(+), 611 deletions(-) create mode 100644 src/processTargets/processTargets.ts diff --git a/src/actions/BringMoveSwap.ts b/src/actions/BringMoveSwap.ts index b56becf41e..4115484aed 100644 --- a/src/actions/BringMoveSwap.ts +++ b/src/actions/BringMoveSwap.ts @@ -3,7 +3,7 @@ // ActionPreferences, // ActionReturnValue, // Graph, -// TypedSelection, +// Target, // Edit, // } from "../typings/Types"; // import { runForEachEditor } from "../util/targetUtils"; @@ -28,14 +28,14 @@ // interface ExtendedEdit extends Edit { // editor: TextEditor; // isSource: boolean; -// originalSelection: TypedSelection; +// originalSelection: Target; // } // interface MarkEntry { // editor: TextEditor; // selection: Selection; // isSource: boolean; -// typedSelection: TypedSelection; +// typedSelection: Target; // } // class BringMoveSwap implements Action { @@ -49,8 +49,8 @@ // } // private broadcastSource( -// sources: TypedSelection[], -// destinations: TypedSelection[] +// sources: Target[], +// destinations: Target[] // ) { // if (sources.length === 1 && this.type !== "swap") { // // If there is only one source target, expand it to same length as @@ -78,8 +78,8 @@ // } // private async decorateTargets( -// sources: TypedSelection[], -// destinations: TypedSelection[] +// sources: Target[], +// destinations: Target[] // ) { // const decorationTypes = this.getDecorationStyles(); // await Promise.all([ @@ -92,10 +92,10 @@ // } // private getEdits( -// sources: TypedSelection[], -// destinations: TypedSelection[] +// sources: Target[], +// destinations: Target[] // ): ExtendedEdit[] { -// const usedSources: TypedSelection[] = []; +// const usedSources: Target[] = []; // const results: ExtendedEdit[] = []; // const zipSources = // sources.length !== destinations.length && @@ -274,8 +274,8 @@ // } // async run([sources, destinations]: [ -// TypedSelection[], -// TypedSelection[] +// Target[], +// Target[] // ]): Promise { // sources = this.broadcastSource(sources, destinations); diff --git a/src/actions/Call.ts b/src/actions/Call.ts index 8bffb2e6bb..2b39f0a5f3 100644 --- a/src/actions/Call.ts +++ b/src/actions/Call.ts @@ -3,7 +3,7 @@ // ActionReturnValue, // ActionPreferences, // Graph, -// TypedSelection, +// Target, // } from "../typings/Types"; // import { ensureSingleTarget } from "../util/targetUtils"; @@ -18,8 +18,8 @@ // } // async run([sources, destinations]: [ -// TypedSelection[], -// TypedSelection[] +// Target[], +// Target[] // ]): Promise { // ensureSingleTarget(sources); diff --git a/src/actions/Clear.ts b/src/actions/Clear.ts index 4681d80a6e..43c762d637 100644 --- a/src/actions/Clear.ts +++ b/src/actions/Clear.ts @@ -3,7 +3,7 @@ // ActionPreferences, // ActionReturnValue, // Graph, -// TypedSelection, +// Target, // } from "../typings/Types"; // import { ensureSingleEditor } from "../util/targetUtils"; // import { setSelectionsAndFocusEditor } from "../util/setSelectionsAndFocusEditor"; @@ -17,7 +17,7 @@ // this.run = this.run.bind(this); // } -// async run([targets]: [TypedSelection[]]): Promise { +// async run([targets]: [Target[]]): Promise { // const editor = ensureSingleEditor(targets); // const { thatMark } = await this.graph.actions.remove.run([targets]); diff --git a/src/actions/CommandAction.ts b/src/actions/CommandAction.ts index 3ef1ddfe04..6d75da6c34 100644 --- a/src/actions/CommandAction.ts +++ b/src/actions/CommandAction.ts @@ -4,7 +4,7 @@ // ActionPreferences, // ActionReturnValue, // Graph, -// TypedSelection, +// Target, // SelectionWithEditor, // } from "../typings/Types"; // import displayPendingEditDecorations from "../util/editDisplayUtils"; @@ -42,7 +42,7 @@ // } // private async runCommandAndUpdateSelections( -// targets: TypedSelection[], +// targets: Target[], // options: Required // ) { // return flatten( @@ -85,7 +85,7 @@ // } // async run( -// [targets]: [TypedSelection[]], +// [targets]: [Target[]], // options: CommandOptions = {} // ): Promise { // const partialOptions = Object.assign( diff --git a/src/actions/CopyLines.ts b/src/actions/CopyLines.ts index 4cb36441d0..b372a5f18b 100644 --- a/src/actions/CopyLines.ts +++ b/src/actions/CopyLines.ts @@ -3,7 +3,7 @@ // ActionPreferences, // ActionReturnValue, // Graph, -// TypedSelection, +// Target, // } from "../typings/Types"; // import { Range, Selection, TextEditor } from "vscode"; // import { displayPendingEditDecorationsForSelection } from "../util/editDisplayUtils"; @@ -22,7 +22,7 @@ // this.run = this.run.bind(this); // } -// private getRanges(editor: TextEditor, targets: TypedSelection[]) { +// private getRanges(editor: TextEditor, targets: Target[]) { // const paragraphTargets = targets.filter( // (target) => target.selectionType === "paragraph" // ); @@ -64,7 +64,7 @@ // }); // } -// async run([targets]: [TypedSelection[]]): Promise { +// async run([targets]: [Target[]]): Promise { // const results = flatten( // await runOnTargetsForEachEditor(targets, async (editor, targets) => { // const ranges = this.getRanges(editor, targets); diff --git a/src/actions/CutCopyPaste.ts b/src/actions/CutCopyPaste.ts index c1ae42d0fe..c5b448258f 100644 --- a/src/actions/CutCopyPaste.ts +++ b/src/actions/CutCopyPaste.ts @@ -3,7 +3,7 @@ // ActionPreferences, // ActionReturnValue, // Graph, -// TypedSelection, +// Target, // } from "../typings/Types"; // import { performInsideOutsideAdjustment } from "../util/performInsideOutsideAdjustment"; // import CommandAction from "./CommandAction"; @@ -20,7 +20,7 @@ // this.run = this.run.bind(this); // } -// async run([targets]: [TypedSelection[]]): Promise { +// async run([targets]: [Target[]]): Promise { // const insideTargets = targets.map((target) => // performInsideOutsideAdjustment(target, "inside") // ); diff --git a/src/actions/Delete.ts b/src/actions/Delete.ts index 78fa9eed1b..d48fea5885 100644 --- a/src/actions/Delete.ts +++ b/src/actions/Delete.ts @@ -3,7 +3,7 @@ // ActionPreferences, // ActionReturnValue, // Graph, -// TypedSelection, +// Target, // } from "../typings/Types"; // import { runOnTargetsForEachEditor } from "../util/targetUtils"; // import displayPendingEditDecorations from "../util/editDisplayUtils"; @@ -21,7 +21,7 @@ // } // async run( -// [targets]: [TypedSelection[]], +// [targets]: [Target[]], // { showDecorations = true } = {} // ): Promise { // // Unify overlapping targets. diff --git a/src/actions/Deselect.ts b/src/actions/Deselect.ts index ca9922601b..1d109fda81 100644 --- a/src/actions/Deselect.ts +++ b/src/actions/Deselect.ts @@ -3,7 +3,7 @@ // Action, // ActionPreferences, // ActionReturnValue, -// TypedSelection, +// Target, // Graph, // } from "../typings/Types"; // import { runOnTargetsForEachEditor } from "../util/targetUtils"; @@ -17,7 +17,7 @@ // this.run = this.run.bind(this); // } -// async run([targets]: [TypedSelection[]]): Promise { +// async run([targets]: [Target[]]): Promise { // await runOnTargetsForEachEditor(targets, async (editor, targets) => { // // Remove selections with a non-empty intersection // const newSelections = editor.selections.filter( diff --git a/src/actions/EditNewLine.ts b/src/actions/EditNewLine.ts index 62843b7b02..0179f75426 100644 --- a/src/actions/EditNewLine.ts +++ b/src/actions/EditNewLine.ts @@ -3,7 +3,7 @@ // ActionPreferences, // ActionReturnValue, // Graph, -// TypedSelection, +// Target, // } from "../typings/Types"; // import { commands, Selection, TextEditor } from "vscode"; // import { getNotebookFromCellDocument } from "../util/notebook"; @@ -17,7 +17,7 @@ // this.run = this.run.bind(this); // } -// private correctForParagraph(targets: TypedSelection[]) { +// private correctForParagraph(targets: Target[]) { // targets.forEach((target) => { // let { start, end } = target.selection.selection; // if (target.selectionType === "paragraph") { @@ -41,7 +41,7 @@ // return getNotebookFromCellDocument(editor.document) != null; // } -// private getCommand(target: TypedSelection) { +// private getCommand(target: Target) { // if (target.selectionContext.isNotebookCell) { // if (this.isNotebookEditor(target.selection.editor)) { // return this.isAbove @@ -57,7 +57,7 @@ // : "editor.action.insertLineAfter"; // } -// async run([targets]: [TypedSelection[]]): Promise { +// async run([targets]: [Target[]]): Promise { // this.correctForParagraph(targets); // if (this.isAbove) { diff --git a/src/actions/ExecuteCommand.ts b/src/actions/ExecuteCommand.ts index 4f01c2c199..c9d04beed1 100644 --- a/src/actions/ExecuteCommand.ts +++ b/src/actions/ExecuteCommand.ts @@ -3,7 +3,7 @@ // ActionPreferences, // ActionReturnValue, // Graph, -// TypedSelection, +// Target, // } from "../typings/Types"; // import CommandAction, { CommandOptions } from "./CommandAction"; @@ -19,7 +19,7 @@ // } // async run( -// targets: [TypedSelection[]], +// targets: [Target[]], // command: string, // args: CommandOptions = {} // ): Promise { diff --git a/src/actions/ExtractVariable.ts b/src/actions/ExtractVariable.ts index de0f5ea62f..d57fdd9b76 100644 --- a/src/actions/ExtractVariable.ts +++ b/src/actions/ExtractVariable.ts @@ -3,7 +3,7 @@ // ActionPreferences, // ActionReturnValue, // Graph, -// TypedSelection, +// Target, // } from "../typings/Types"; // import { ensureSingleTarget } from "../util/targetUtils"; // import { commands } from "vscode"; @@ -17,7 +17,7 @@ // this.run = this.run.bind(this); // } -// async run([targets]: [TypedSelection[]]): Promise { +// async run([targets]: [Target[]]): Promise { // ensureSingleTarget(targets); // await this.graph.actions.setSelection.run([targets]); diff --git a/src/actions/Find.ts b/src/actions/Find.ts index 0e46ed9ae3..8a942fc609 100644 --- a/src/actions/Find.ts +++ b/src/actions/Find.ts @@ -3,7 +3,7 @@ // ActionReturnValue, // ActionPreferences, // Graph, -// TypedSelection, +// Target, // } from "../typings/Types"; // import { commands } from "vscode"; // import { ensureSingleTarget } from "../util/targetUtils"; @@ -17,7 +17,7 @@ // this.run = this.run.bind(this); // } -// async run([targets]: [TypedSelection[]]): Promise { +// async run([targets]: [Target[]]): Promise { // ensureSingleTarget(targets); // const { diff --git a/src/actions/Fold.ts b/src/actions/Fold.ts index b8b200b63a..328c8a0a4c 100644 --- a/src/actions/Fold.ts +++ b/src/actions/Fold.ts @@ -4,7 +4,7 @@ // ActionPreferences, // ActionReturnValue, // Graph, -// TypedSelection, +// Target, // } from "../typings/Types"; // import { focusEditor } from "../util/setSelectionsAndFocusEditor"; // import { ensureSingleEditor } from "../util/targetUtils"; @@ -19,8 +19,8 @@ // } // async run([targets]: [ -// TypedSelection[], -// TypedSelection[] +// Target[], +// Target[] // ]): Promise { // const originalEditor = window.activeTextEditor; // const editor = ensureSingleEditor(targets); diff --git a/src/actions/FollowLink.ts b/src/actions/FollowLink.ts index ee6e6f3aec..a6ee0ef294 100644 --- a/src/actions/FollowLink.ts +++ b/src/actions/FollowLink.ts @@ -4,7 +4,7 @@ // ActionPreferences, // ActionReturnValue, // Graph, -// TypedSelection, +// Target, // } from "../typings/Types"; // import displayPendingEditDecorations from "../util/editDisplayUtils"; // import { getLinkForTarget } from "../util/getLinks"; @@ -19,7 +19,7 @@ // this.run = this.run.bind(this); // } -// async run([targets]: [TypedSelection[]]): Promise { +// async run([targets]: [Target[]]): Promise { // const target = ensureSingleTarget(targets); // await displayPendingEditDecorations( diff --git a/src/actions/GetText.ts b/src/actions/GetText.ts index 04230786eb..696c821b17 100644 --- a/src/actions/GetText.ts +++ b/src/actions/GetText.ts @@ -3,7 +3,7 @@ // ActionPreferences, // ActionReturnValue, // Graph, -// TypedSelection, +// Target, // } from "../typings/Types"; // import displayPendingEditDecorations from "../util/editDisplayUtils"; // import { ensureSingleTarget } from "../util/targetUtils"; @@ -18,7 +18,7 @@ // } // async run( -// [targets]: [TypedSelection[]], +// [targets]: [Target[]], // { // showDecorations = true, // ensureSingleTarget: doEnsureSingleTarget = false, diff --git a/src/actions/Highlight.ts b/src/actions/Highlight.ts index 0a5e058758..5ebc98e36b 100644 --- a/src/actions/Highlight.ts +++ b/src/actions/Highlight.ts @@ -3,7 +3,7 @@ // Action, // ActionPreferences, // ActionReturnValue, -// TypedSelection, +// Target, // Graph, // } from "../typings/Types"; // import { clearDecorations, setDecorations } from "../util/editDisplayUtils"; @@ -18,7 +18,7 @@ // } // async run( -// [targets]: [TypedSelection[]], +// [targets]: [Target[]], // styleName: EditStyleName = "highlight0" // ): Promise { // const style = this.graph.editStyles[styleName]; diff --git a/src/actions/InsertEmptyLines.ts b/src/actions/InsertEmptyLines.ts index 351c57540a..08f1fbb71e 100644 --- a/src/actions/InsertEmptyLines.ts +++ b/src/actions/InsertEmptyLines.ts @@ -3,7 +3,7 @@ // ActionPreferences, // ActionReturnValue, // Graph, -// TypedSelection, +// Target, // } from "../typings/Types"; // import { Selection, Range } from "vscode"; // import { displayPendingEditDecorationsForSelection } from "../util/editDisplayUtils"; @@ -24,7 +24,7 @@ // this.run = this.run.bind(this); // } -// private getRanges(targets: TypedSelection[]) { +// private getRanges(targets: Target[]) { // let lines = targets.flatMap((target) => { // const lines = []; // if (this.insertAbove) { @@ -48,7 +48,7 @@ // })); // } -// async run([targets]: [TypedSelection[]]): Promise { +// async run([targets]: [Target[]]): Promise { // const results = flatten( // await runOnTargetsForEachEditor(targets, async (editor, targets) => { // const ranges = this.getRanges(targets); diff --git a/src/actions/Replace.ts b/src/actions/Replace.ts index 94768340a4..3fabfda529 100644 --- a/src/actions/Replace.ts +++ b/src/actions/Replace.ts @@ -3,7 +3,7 @@ // ActionPreferences, // ActionReturnValue, // Graph, -// TypedSelection, +// Target, // } from "../typings/Types"; // import displayPendingEditDecorations from "../util/editDisplayUtils"; // import { runForEachEditor } from "../util/targetUtils"; @@ -23,7 +23,7 @@ // } // private getTexts( -// targets: TypedSelection[], +// targets: Target[], // replaceWith: string[] | RangeGenerator // ): string[] { // if (Array.isArray(replaceWith)) { @@ -41,7 +41,7 @@ // } // async run( -// [targets]: [TypedSelection[]], +// [targets]: [Target[]], // replaceWith: string[] | RangeGenerator // ): Promise { // await displayPendingEditDecorations( diff --git a/src/actions/Rewrap.ts b/src/actions/Rewrap.ts index f2397d6db3..282951c1b0 100644 --- a/src/actions/Rewrap.ts +++ b/src/actions/Rewrap.ts @@ -7,7 +7,7 @@ // ActionReturnValue, // Graph, // SelectionWithContext, -// TypedSelection, +// Target, // } from "../typings/Types"; // import displayPendingEditDecorations from "../util/editDisplayUtils"; // import { runForEachEditor } from "../util/targetUtils"; @@ -29,7 +29,7 @@ // } // async run( -// [targets]: [TypedSelection[]], +// [targets]: [Target[]], // left: string, // right: string // ): Promise { @@ -90,7 +90,7 @@ // function constructSimpleTypedSelection( // editor: TextEditor, // selection: SelectionWithContext -// ): TypedSelection { +// ): Target { // return { // selection: { // selection: selection.selection, diff --git a/src/actions/Scroll.ts b/src/actions/Scroll.ts index dac4c777ac..026f64f9ed 100644 --- a/src/actions/Scroll.ts +++ b/src/actions/Scroll.ts @@ -3,7 +3,7 @@ // ActionPreferences, // ActionReturnValue, // Graph, -// TypedSelection, +// Target, // } from "../typings/Types"; // import { groupBy } from "../util/itertools"; // import { commands, window } from "vscode"; @@ -19,10 +19,10 @@ // this.run = this.run.bind(this); // } -// async run([targets]: [TypedSelection[]]): Promise { +// async run([targets]: [Target[]]): Promise { // const selectionGroups = groupBy( // targets, -// (t: TypedSelection) => t.selection.editor +// (t: Target) => t.selection.editor // ); // const lines = Array.from(selectionGroups, ([editor, targets]) => { @@ -91,10 +91,10 @@ // } // } -// function getLineNumber(targets: TypedSelection[], at: string) { +// function getLineNumber(targets: Target[], at: string) { // let startLine = Number.MAX_SAFE_INTEGER; // let endLine = 0; -// targets.forEach((t: TypedSelection) => { +// targets.forEach((t: Target) => { // startLine = Math.min(startLine, t.selection.selection.start.line); // endLine = Math.max(endLine, t.selection.selection.end.line); // }); diff --git a/src/actions/SetBreakpoint.ts b/src/actions/SetBreakpoint.ts index 7ced26c342..d29d70f91b 100644 --- a/src/actions/SetBreakpoint.ts +++ b/src/actions/SetBreakpoint.ts @@ -3,7 +3,7 @@ // ActionPreferences, // ActionReturnValue, // Graph, -// TypedSelection, +// Target, // } from "../typings/Types"; // import { // SourceBreakpoint, @@ -35,8 +35,8 @@ // } // async run([targets]: [ -// TypedSelection[], -// TypedSelection[] +// Target[], +// Target[] // ]): Promise { // await displayPendingEditDecorations( // targets, diff --git a/src/actions/SetSelection.ts b/src/actions/SetSelection.ts index 14f57565c3..beb357b37a 100644 --- a/src/actions/SetSelection.ts +++ b/src/actions/SetSelection.ts @@ -2,12 +2,12 @@ import { Action, ActionPreferences, ActionReturnValue, - TypedSelection, Graph, } from "../typings/Types"; import { ensureSingleEditor } from "../util/targetUtils"; import { Selection } from "vscode"; import { setSelectionsAndFocusEditor } from "../util/setSelectionsAndFocusEditor"; +import { Target } from "../typings/target.types"; export class SetSelection implements Action { getTargetPreferences: () => ActionPreferences[] = () => [ @@ -18,13 +18,13 @@ export class SetSelection implements Action { this.run = this.run.bind(this); } - protected getSelection(target: TypedSelection) { + protected getSelection(target: Target) { return target.isReversed ? new Selection(target.contentRange.end, target.contentRange.start) : new Selection(target.contentRange.start, target.contentRange.end); } - async run([targets]: [TypedSelection[]]): Promise { + async run([targets]: [Target[]]): Promise { const editor = ensureSingleEditor(targets); const selections = targets.map(this.getSelection); @@ -40,13 +40,13 @@ export class SetSelection implements Action { } export class SetSelectionBefore extends SetSelection { - protected getSelection(target: TypedSelection) { + protected getSelection(target: Target) { return new Selection(target.contentRange.start, target.contentRange.start); } } export class SetSelectionAfter extends SetSelection { - protected getSelection(target: TypedSelection) { + protected getSelection(target: Target) { return new Selection(target.contentRange.end, target.contentRange.end); } } diff --git a/src/actions/Sort.ts b/src/actions/Sort.ts index d090eb4cf4..b937076147 100644 --- a/src/actions/Sort.ts +++ b/src/actions/Sort.ts @@ -4,7 +4,7 @@ // ActionReturnValue, // ActionPreferences, // Graph, -// TypedSelection, +// Target, // } from "../typings/Types"; // export class Sort implements Action { @@ -20,7 +20,7 @@ // return texts.sort(); // } -// async run(targets: TypedSelection[][]): Promise { +// async run(targets: Target[][]): Promise { // const { returnValue: unsortedTexts } = await this.graph.actions.getText.run( // targets, // { diff --git a/src/actions/Wrap.ts b/src/actions/Wrap.ts index cc0e081e90..e2f41cec43 100644 --- a/src/actions/Wrap.ts +++ b/src/actions/Wrap.ts @@ -7,7 +7,7 @@ // Edit, // Graph, // SelectionWithEditor, -// TypedSelection, +// Target, // } from "../typings/Types"; // import { runOnTargetsForEachEditor } from "../util/targetUtils"; // import { decorationSleep } from "../util/editDisplayUtils"; @@ -27,7 +27,7 @@ // } // async run( -// [targets]: [TypedSelection[]], +// [targets]: [Target[]], // left: string, // right: string // ): Promise { diff --git a/src/actions/WrapWithSnippet.ts b/src/actions/WrapWithSnippet.ts index 3dceb3260d..652e986198 100644 --- a/src/actions/WrapWithSnippet.ts +++ b/src/actions/WrapWithSnippet.ts @@ -6,7 +6,7 @@ // ActionPreferences, // ActionReturnValue, // Graph, -// TypedSelection, +// Target, // } from "../typings/Types"; // import displayPendingEditDecorations from "../util/editDisplayUtils"; // import { ensureSingleEditor } from "../util/targetUtils"; @@ -54,7 +54,7 @@ // } // async run( -// [targets]: [TypedSelection[]], +// [targets]: [Target[]], // snippetLocation: string // ): Promise { // const [snippetName, placeholderName] = @@ -165,7 +165,7 @@ // } // function findMatchingSnippetDefinition( -// typedSelection: TypedSelection, +// typedSelection: Target, // definitions: SnippetDefinition[] // ) { // const languageId = typedSelection.selection.editor.document.languageId; diff --git a/src/core/commandRunner/CommandRunner.ts b/src/core/commandRunner/CommandRunner.ts index 97683743b3..b6731c41a1 100644 --- a/src/core/commandRunner/CommandRunner.ts +++ b/src/core/commandRunner/CommandRunner.ts @@ -49,7 +49,7 @@ export default class CommandRunner { * 3. Construct a {@link ProcessedTargetsContext} object to capture the * environment needed by {@link processTargets}. * 4. Call {@link processTargets} to map each abstract {@link Target} object - * to a concrete list of {@link TypedSelection} objects. + * to a concrete list of {@link Target} objects. * 5. Run the requested action on the given selections. The mapping from * action id (eg `remove`) to implementation is defined in * {@link Actions}. To understand how actions work, see some examples, diff --git a/src/core/commandRunner/command.types.ts b/src/core/commandRunner/command.types.ts index 5f6e6df241..4e9a5f008c 100644 --- a/src/core/commandRunner/command.types.ts +++ b/src/core/commandRunner/command.types.ts @@ -1,4 +1,4 @@ -import { PartialTarget } from "../../typings/target.types"; +import { PartialTargetDesc } from "../../typings/target.types"; import { ActionType } from "../../typings/Types"; import { CommandV0, @@ -44,7 +44,7 @@ export interface CommandV2 { * A list of targets expected by the action. Inference will be run on the * targets */ - targets: PartialTarget[]; + targets: PartialTargetDesc[]; /** * A list of extra arguments expected by the given action. diff --git a/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts b/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts index f9773ec8f9..b726161599 100644 --- a/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts +++ b/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts @@ -1,6 +1,6 @@ import { commands } from "vscode"; import { ActionableError } from "../../errors"; -import { PartialTarget, ScopeType } from "../../typings/target.types"; +import { PartialTargetDesc, ScopeType } from "../../typings/target.types"; import { ActionType } from "../../typings/Types"; import { getPartialPrimitiveTargets } from "../../util/getPrimitiveTargets"; import { @@ -81,7 +81,7 @@ function upgradeCommand(command: Command): CommandLatest { export function validateCommand( actionName: ActionType, - partialTargets: PartialTarget[] + partialTargets: PartialTargetDesc[] ) { if ( usesScopeType("notebookCell", partialTargets) && @@ -93,7 +93,10 @@ export function validateCommand( } } -function usesScopeType(scopeType: ScopeType, partialTargets: PartialTarget[]) { +function usesScopeType( + scopeType: ScopeType, + partialTargets: PartialTargetDesc[] +) { return getPartialPrimitiveTargets(partialTargets).some((partialTarget) => partialTarget.modifiers?.find( (mod) => diff --git a/src/core/commandVersionUpgrades/canonicalizeTargets.ts b/src/core/commandVersionUpgrades/canonicalizeTargets.ts index 1d332ccce4..5dca959849 100644 --- a/src/core/commandVersionUpgrades/canonicalizeTargets.ts +++ b/src/core/commandVersionUpgrades/canonicalizeTargets.ts @@ -1,8 +1,8 @@ import update from "immutability-helper"; import { flow } from "lodash"; import { - PartialPrimitiveTarget, - PartialTarget, + PartialPrimitiveTargetDesc, + PartialTargetDesc, ScopeType, } from "../../typings/target.types"; import { transformPartialPrimitiveTargets } from "../../util/getPrimitiveTargets"; @@ -19,8 +19,8 @@ const COLOR_CANONICALIZATION_MAPPING: Record = { }; const canonicalizeScopeTypes = ( - target: PartialPrimitiveTarget -): PartialPrimitiveTarget => { + target: PartialPrimitiveTargetDesc +): PartialPrimitiveTargetDesc => { target.modifiers?.forEach((mod) => { if (mod.type === "containingScope" || mod.type === "everyScope") { mod.scopeType = @@ -31,8 +31,8 @@ const canonicalizeScopeTypes = ( }; const canonicalizeColors = ( - target: PartialPrimitiveTarget -): PartialPrimitiveTarget => + target: PartialPrimitiveTargetDesc +): PartialPrimitiveTargetDesc => target.mark?.type === "decoratedSymbol" ? update(target, { mark: { @@ -42,7 +42,9 @@ const canonicalizeColors = ( }) : target; -export default function canonicalizeTargets(partialTargets: PartialTarget[]) { +export default function canonicalizeTargets( + partialTargets: PartialTargetDesc[] +) { return transformPartialPrimitiveTargets( partialTargets, flow(canonicalizeScopeTypes, canonicalizeColors) diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeStrictHere.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeStrictHere.ts index 424fda3134..9c2aa3512a 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeStrictHere.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeStrictHere.ts @@ -1,5 +1,5 @@ import { isDeepStrictEqual } from "util"; -import { PartialPrimitiveTarget } from "../../../typings/target.types"; +import { PartialPrimitiveTargetDesc } from "../../../typings/target.types"; const STRICT_HERE = { type: "primitive", @@ -9,10 +9,10 @@ const STRICT_HERE = { modifier: { type: "identity" }, insideOutsideType: "inside", }; -const IMPLICIT_TARGET: PartialPrimitiveTarget = { +const IMPLICIT_TARGET: PartialPrimitiveTargetDesc = { type: "primitive", }; export const upgradeStrictHere = ( - target: PartialPrimitiveTarget -): PartialPrimitiveTarget => + target: PartialPrimitiveTargetDesc +): PartialPrimitiveTargetDesc => isDeepStrictEqual(target, STRICT_HERE) ? IMPLICIT_TARGET : target; diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts index da04a6e5ed..9f410f31cb 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts @@ -1,9 +1,9 @@ import { flow } from "lodash"; import { Modifier, - PartialPrimitiveTarget, - PartialRangeTarget, - PartialTarget, + PartialPrimitiveTargetDesc, + PartialRangeTargetDesc, + PartialTargetDesc, ScopeType, } from "../../../typings/target.types"; import { ActionType } from "../../../typings/Types"; @@ -51,7 +51,7 @@ function upgradeModifier(modifier: ModifierV0V1): Modifier | null { function upgradePrimitiveTarget( target: PartialPrimitiveTargetV0V1 -): PartialPrimitiveTarget { +): PartialPrimitiveTargetDesc { const { insideOutsideType, modifier, @@ -84,14 +84,16 @@ function upgradePrimitiveTarget( }; } -function upgradeTarget(target: PartialTargetV0V1): PartialTarget { +function upgradeTarget(target: PartialTargetV0V1): PartialTargetDesc { switch (target.type) { case "list": return { ...target, elements: target.elements.map( (target) => - upgradeTarget(target) as PartialPrimitiveTarget | PartialRangeTarget + upgradeTarget(target) as + | PartialPrimitiveTargetDesc + | PartialRangeTargetDesc ), }; case "range": @@ -106,7 +108,8 @@ function upgradeTarget(target: PartialTargetV0V1): PartialTarget { } function upgradeTargets(partialTargets: PartialTargetV0V1[]) { - const partialTargetsV2: PartialTarget[] = partialTargets.map(upgradeTarget); + const partialTargetsV2: PartialTargetDesc[] = + partialTargets.map(upgradeTarget); return transformPartialPrimitiveTargets( partialTargetsV2, flow(upgradeStrictHere) diff --git a/src/core/inferFullTargets.ts b/src/core/inferFullTargets.ts index 21c9ca4b45..1a1ca66b35 100644 --- a/src/core/inferFullTargets.ts +++ b/src/core/inferFullTargets.ts @@ -1,11 +1,11 @@ import { - PartialListTarget, - PartialPrimitiveTarget, - PartialRangeTarget, - PartialTarget, - PrimitiveTarget, - RangeTarget, - Target, + PartialListTargetDesc, + PartialPrimitiveTargetDesc, + PartialRangeTargetDesc, + PartialTargetDesc, + PrimitiveTargetDesc, + RangeTargetDesc, + TargetDesc, } from "../typings/target.types"; import { ActionPreferences } from "../typings/Types"; @@ -20,9 +20,9 @@ import { ActionPreferences } from "../typings/Types"; * @returns Target objects fully filled out and ready to be processed by {@link processTargets}. */ export default function inferFullTargets( - targets: PartialTarget[], + targets: PartialTargetDesc[], actionPreferences: ActionPreferences[] -): Target[] { +): TargetDesc[] { if (targets.length !== actionPreferences.length) { throw new Error("Target length is not equal to action preference length"); } @@ -33,10 +33,10 @@ export default function inferFullTargets( } function inferTarget( - target: PartialTarget, - previousTargets: PartialTarget[], + target: PartialTargetDesc, + previousTargets: PartialTargetDesc[], actionPreferences: ActionPreferences -): Target { +): TargetDesc { switch (target.type) { case "list": return inferListTarget(target, previousTargets, actionPreferences); @@ -47,10 +47,10 @@ function inferTarget( } function inferListTarget( - target: PartialListTarget, - previousTargets: PartialTarget[], + target: PartialListTargetDesc, + previousTargets: PartialTargetDesc[], actionPreferences: ActionPreferences -): Target { +): TargetDesc { return { ...target, elements: target.elements.map((element, index) => @@ -64,10 +64,10 @@ function inferListTarget( } function inferNonListTarget( - target: PartialPrimitiveTarget | PartialRangeTarget, - previousTargets: PartialTarget[], + target: PartialPrimitiveTargetDesc | PartialRangeTargetDesc, + previousTargets: PartialTargetDesc[], actionPreferences: ActionPreferences -): PrimitiveTarget | RangeTarget { +): PrimitiveTargetDesc | RangeTargetDesc { switch (target.type) { case "primitive": return inferPrimitiveTarget(target, previousTargets, actionPreferences); @@ -77,10 +77,10 @@ function inferNonListTarget( } function inferRangeTarget( - target: PartialRangeTarget, - previousTargets: PartialTarget[], + target: PartialRangeTargetDesc, + previousTargets: PartialTargetDesc[], actionPreferences: ActionPreferences -): RangeTarget { +): RangeTargetDesc { return { type: "range", excludeAnchor: target.excludeStart ?? false, @@ -100,10 +100,10 @@ function inferRangeTarget( } function inferPrimitiveTarget( - target: PartialPrimitiveTarget, - previousTargets: PartialTarget[], + target: PartialPrimitiveTargetDesc, + previousTargets: PartialTargetDesc[], actionPreferences: ActionPreferences -): PrimitiveTarget { +): PrimitiveTargetDesc { const mark = target.mark ?? getPreviousAttribute(previousTargets, "mark") ?? { type: "cursor" }; const modifiers = @@ -120,21 +120,21 @@ function inferPrimitiveTarget( }; } -function getPreviousAttribute( - previousTargets: PartialTarget[], +function getPreviousAttribute( + previousTargets: PartialTargetDesc[], attributeName: T ) { const target = getPreviousTarget( previousTargets, - (target: PartialPrimitiveTarget) => !!target[attributeName] + (target: PartialPrimitiveTargetDesc) => !!target[attributeName] ); return target != null ? target[attributeName] : null; } function getPreviousTarget( - previousTargets: PartialTarget[], - useTarget: (target: PartialPrimitiveTarget) => boolean -): PartialPrimitiveTarget | null { + previousTargets: PartialTargetDesc[], + useTarget: (target: PartialPrimitiveTargetDesc) => boolean +): PartialPrimitiveTargetDesc | null { // Search from back(last) to front(first) for (let i = previousTargets.length - 1; i > -1; --i) { const target = previousTargets[i]; diff --git a/src/processTargets/PipelineStages.types.ts b/src/processTargets/PipelineStages.types.ts index 6fd33ccb87..7f1553428d 100644 --- a/src/processTargets/PipelineStages.types.ts +++ b/src/processTargets/PipelineStages.types.ts @@ -1,12 +1,10 @@ -import { ProcessedTargetsContext, TypedSelection } from "../typings/Types"; +import { Target } from "../typings/target.types"; +import { ProcessedTargetsContext } from "../typings/Types"; export interface MarkStage { - run(context: ProcessedTargetsContext): TypedSelection[]; + run(context: ProcessedTargetsContext): Target[]; } export interface ModifierStage { - run( - context: ProcessedTargetsContext, - target?: TypedSelection - ): TypedSelection | TypedSelection[]; + run(context: ProcessedTargetsContext, target?: Target): Target | Target[]; } diff --git a/src/processTargets/index.ts b/src/processTargets/index.ts index f16f736502..c3ac65a39c 100644 --- a/src/processTargets/index.ts +++ b/src/processTargets/index.ts @@ -1,226 +1,2 @@ -import { isEqual, zip } from "lodash"; -import { Range } from "vscode"; -import { PrimitiveTarget, RangeTarget, Target } from "../typings/target.types"; -import { ProcessedTargetsContext, TypedSelection } from "../typings/Types"; -import getMarkStage from "./getMarkStage"; -import getModifierStage from "./getModifierStage"; - -/** - * Converts the abstract target descriptions provided by the user to a concrete - * representation usable by actions. Conceptually, the input will be something - * like "the function call argument containing the cursor" and the output will be something - * like "line 3, characters 5 through 10". - * @param context Captures the environment needed to convert the abstract target - * description given by the user to a concrete representation usable by - * actions - * @param targets The abstract target representations provided by the user - * @returns A list of lists of typed selections, one list per input target. Each - * typed selection includes the selection, as well the uri of the document - * containing it, and potentially rich context information such as how to remove - * the target - */ -export default function ( - context: ProcessedTargetsContext, - targets: Target[] -): TypedSelection[][] { - return targets.map((target) => - filterDuplicateSelections(processTarget(context, target)) - ); -} - -function processTarget( - context: ProcessedTargetsContext, - target: Target -): TypedSelection[] { - switch (target.type) { - case "list": - return target.elements.flatMap((element) => - processTarget(context, element) - ); - case "range": - return processRangeTarget(context, target); - case "primitive": - return processPrimitiveTarget(context, target); - } -} - -function processRangeTarget( - context: ProcessedTargetsContext, - target: RangeTarget -): TypedSelection[] { - const anchorTargets = processPrimitiveTarget(context, target.anchor); - const activeTargets = processPrimitiveTarget(context, target.active); - - return zip(anchorTargets, activeTargets).flatMap( - ([anchorTarget, activeTarget]) => { - if (anchorTarget == null || activeTarget == null) { - throw new Error("anchorTargets and activeTargets lengths don't match"); - } - - if (anchorTarget.editor !== activeTarget.editor) { - throw new Error( - "anchorTarget and activeTarget must be in same document" - ); - } - - const anchorRange = anchorTarget.contentRange; - const activeRange = activeTarget.contentRange; - const isForward = anchorRange.start.isBeforeOrEqual(activeRange.start); - - switch (target.rangeType) { - case "continuous": - return processContinuousRangeTarget( - target, - anchorTarget, - activeTarget, - isForward - ); - case "vertical": - return processVerticalRangeTarget( - target, - anchorTarget, - activeTarget, - isForward - ); - } - } - ); -} - -function processContinuousRangeTarget( - target: RangeTarget, - anchorTarget: TypedSelection, - activeTarget: TypedSelection, - isForward: boolean -): TypedSelection[] { - const { excludeAnchor, excludeActive } = target; - - const contentRange = unionRanges( - isForward, - excludeAnchor, - excludeActive, - anchorTarget.contentRange, - activeTarget.contentRange - )!; - - const interiorRange = unionRanges( - isForward, - excludeAnchor, - excludeActive, - anchorTarget.interiorRange, - activeTarget.interiorRange - ); - - const anchorContext = excludeAnchor ? undefined : anchorTarget; - const activeContext = excludeActive ? undefined : activeTarget; - const leadingDelimiterRange = isForward - ? anchorContext?.leadingDelimiterRange - : activeContext?.leadingDelimiterRange; - const trailingDelimiterRange = isForward - ? activeContext?.trailingDelimiterRange - : anchorContext?.trailingDelimiterRange; - - return [ - { - editor: activeTarget.editor, - isReversed: !isForward, - delimiter: anchorTarget.delimiter, - contentRange, - interiorRange, - leadingDelimiterRange, - trailingDelimiterRange, - }, - ]; -} - -function unionRanges( - isForward: boolean, - excludeAnchor: boolean, - excludeActive: boolean, - anchor?: Range, - active?: Range -) { - if (anchor == null || active == null) { - return anchor == null ? active : anchor; - } - return new Range( - getPosition(anchor, isForward, excludeAnchor), - getPosition(active, !isForward, excludeActive) - ); -} - -function getPosition(range: Range, isStartOfRange: boolean, exclude: boolean) { - if (exclude) { - return isStartOfRange ? range.end : range.start; - } - return isStartOfRange ? range.start : range.end; -} - -function processVerticalRangeTarget( - target: RangeTarget, - anchorTarget: TypedSelection, - activeTarget: TypedSelection, - isForward: boolean -): TypedSelection[] { - const { excludeAnchor, excludeActive } = target; - const delta = isForward ? 1 : -1; - - const anchorPosition = isForward - ? anchorTarget.contentRange.end - : anchorTarget.contentRange.start; - const anchorLine = anchorPosition.line + (excludeAnchor ? delta : 0); - const activePosition = isForward - ? activeTarget.contentRange.end - : activeTarget.contentRange.start; - const activeLine = activePosition.line - (excludeActive ? delta : 0); - - const results: TypedSelection[] = []; - for (let i = anchorLine; true; i += delta) { - results.push({ - editor: anchorTarget.editor, - isReversed: !isForward, - delimiter: anchorTarget.delimiter, - contentRange: new Range( - i, - anchorTarget.contentRange.start.character, - i, - anchorTarget.contentRange.end.character - ), - }); - if (i === activeLine) { - return results; - } - } -} - -function processPrimitiveTarget( - context: ProcessedTargetsContext, - target: PrimitiveTarget -): TypedSelection[] { - const markStage = getMarkStage(target.mark); - let selections = markStage.run(context); - - for (let i = target.modifiers.length - 1; i > -1; --i) { - const modifier = target.modifiers[i]; - const stage = getModifierStage(modifier); - const stageSelections: TypedSelection[] = []; - for (const selection of selections) { - const stageResult = stage.run(context, selection); - if (Array.isArray(stageResult)) { - stageSelections.push(...stageResult); - } else { - stageSelections.push(stageResult); - } - } - selections = stageSelections; - } - - return selections; -} - -function filterDuplicateSelections(selections: TypedSelection[]) { - return selections.filter( - (selection, index, selections) => - selections.findIndex((s) => isEqual(s, selection)) === index - ); -} +import processTargets from "./processTargets"; +export default processTargets; diff --git a/src/processTargets/marks/CursorStage.ts b/src/processTargets/marks/CursorStage.ts index 0833aefc17..e136fa1912 100644 --- a/src/processTargets/marks/CursorStage.ts +++ b/src/processTargets/marks/CursorStage.ts @@ -1,6 +1,5 @@ import { window } from "vscode"; -import { CursorMark } from "../../typings/target.types"; -import { TypedSelection } from "../../typings/Types"; +import { CursorMark, Target } from "../../typings/target.types"; import { isReversed } from "../../util/selectionUtils"; import { getTokenContext } from "../modifiers/TokenStage"; import { MarkStage } from "../PipelineStages.types"; @@ -8,7 +7,7 @@ import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { constructor(private modifier: CursorMark) {} - run(): TypedSelection[] { + run(): Target[] { if (window.activeTextEditor == null) { return []; } diff --git a/src/processTargets/marks/CursorTokenStage.ts b/src/processTargets/marks/CursorTokenStage.ts index 11dc298e13..587030db6c 100644 --- a/src/processTargets/marks/CursorTokenStage.ts +++ b/src/processTargets/marks/CursorTokenStage.ts @@ -1,6 +1,6 @@ import { Range, window } from "vscode"; -import { CursorTokenMark } from "../../typings/target.types"; -import { SelectionWithEditor, TypedSelection } from "../../typings/Types"; +import { CursorTokenMark, Target } from "../../typings/target.types"; +import { SelectionWithEditor } from "../../typings/Types"; import { getTokensInRange, PartialToken } from "../../util/getTokensInRange"; import { isReversed } from "../../util/selectionUtils"; import { getTokenContext } from "../modifiers/TokenStage"; @@ -9,7 +9,7 @@ import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { constructor(private modifier: CursorTokenMark) {} - run(): TypedSelection[] { + run(): Target[] { const editor = window.activeTextEditor; if (editor == null) { return []; diff --git a/src/processTargets/marks/DecoratedSymbolStage.ts b/src/processTargets/marks/DecoratedSymbolStage.ts index 10324ba2ea..a7004aa0ea 100644 --- a/src/processTargets/marks/DecoratedSymbolStage.ts +++ b/src/processTargets/marks/DecoratedSymbolStage.ts @@ -1,12 +1,12 @@ -import { DecoratedSymbolMark } from "../../typings/target.types"; -import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import { DecoratedSymbolMark, Target } from "../../typings/target.types"; +import { ProcessedTargetsContext } from "../../typings/Types"; import { getTokenContext } from "../modifiers/TokenStage"; import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { constructor(private modifier: DecoratedSymbolMark) {} - run(context: ProcessedTargetsContext): TypedSelection[] { + run(context: ProcessedTargetsContext): Target[] { const token = context.hatTokenMap.getToken( this.modifier.symbolColor, this.modifier.character diff --git a/src/processTargets/marks/LineNumberStage.ts b/src/processTargets/marks/LineNumberStage.ts index efd500b2e0..4785550b0b 100644 --- a/src/processTargets/marks/LineNumberStage.ts +++ b/src/processTargets/marks/LineNumberStage.ts @@ -1,13 +1,12 @@ import { Range, TextEditor, window } from "vscode"; -import { LineNumberMark, LineNumberPosition } from "../../typings/target.types"; -import { TypedSelection } from "../../typings/Types"; +import { LineNumberMark, LineNumberPosition, Target } from "../../typings/target.types"; import { getLineContext } from "../modifiers/LineStage"; import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { constructor(private modifier: LineNumberMark) {} - run(): TypedSelection[] { + run(): Target[] { if (window.activeTextEditor == null) { return []; } diff --git a/src/processTargets/marks/NothingStage.ts b/src/processTargets/marks/NothingStage.ts index 28689d2edf..e64feb0596 100644 --- a/src/processTargets/marks/NothingStage.ts +++ b/src/processTargets/marks/NothingStage.ts @@ -1,11 +1,10 @@ -import { NothingMark } from "../../typings/target.types"; -import { TypedSelection } from "../../typings/Types"; +import { NothingMark, Target } from "../../typings/target.types"; import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { constructor(private modifier: NothingMark) {} - run(): TypedSelection[] { + run(): Target[] { return []; } } diff --git a/src/processTargets/marks/SourceStage.ts b/src/processTargets/marks/SourceStage.ts index b54b39b25c..2ca22f5a5d 100644 --- a/src/processTargets/marks/SourceStage.ts +++ b/src/processTargets/marks/SourceStage.ts @@ -1,5 +1,5 @@ -import { SourceMark } from "../../typings/target.types"; -import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import { SourceMark, Target } from "../../typings/target.types"; +import { ProcessedTargetsContext } from "../../typings/Types"; import { isReversed } from "../../util/selectionUtils"; import { getTokenContext } from "../modifiers/TokenStage"; import { MarkStage } from "../PipelineStages.types"; @@ -7,7 +7,7 @@ import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { constructor(private modifier: SourceMark) {} - run(context: ProcessedTargetsContext): TypedSelection[] { + run(context: ProcessedTargetsContext): Target[] { return context.sourceMark.map((selection) => ({ editor: selection.editor, isReversed: isReversed(selection.selection), diff --git a/src/processTargets/marks/ThatStage.ts b/src/processTargets/marks/ThatStage.ts index 3528d6bd3e..cea3cf698f 100644 --- a/src/processTargets/marks/ThatStage.ts +++ b/src/processTargets/marks/ThatStage.ts @@ -1,5 +1,5 @@ -import { ThatMark } from "../../typings/target.types"; -import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import { ThatMark, Target } from "../../typings/target.types"; +import { ProcessedTargetsContext } from "../../typings/Types"; import { isReversed } from "../../util/selectionUtils"; import { getTokenContext } from "../modifiers/TokenStage"; import { MarkStage } from "../PipelineStages.types"; @@ -7,7 +7,7 @@ import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { constructor(private modifier: ThatMark) {} - run(context: ProcessedTargetsContext): TypedSelection[] { + run(context: ProcessedTargetsContext): Target[] { return context.thatMark.map((selection) => ({ editor: selection.editor, isReversed: isReversed(selection.selection), diff --git a/src/processTargets/modifiers/ContainingScopeStage.ts b/src/processTargets/modifiers/ContainingScopeStage.ts index 096b537994..d38b31eb2e 100644 --- a/src/processTargets/modifiers/ContainingScopeStage.ts +++ b/src/processTargets/modifiers/ContainingScopeStage.ts @@ -4,12 +4,12 @@ import { getNodeMatcher } from "../../languages/getNodeMatcher"; import { ContainingScopeModifier, EveryScopeModifier, + Target, } from "../../typings/target.types"; import { NodeMatcher, ProcessedTargetsContext, SelectionWithEditor, - TypedSelection, } from "../../typings/Types"; import { selectionWithEditorFromRange } from "../../util/selectionUtils"; import { ModifierStage } from "../PipelineStages.types"; @@ -17,10 +17,7 @@ import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} - run( - context: ProcessedTargetsContext, - selection: TypedSelection - ): TypedSelection[] { + run(context: ProcessedTargetsContext, selection: Target): Target[] { const nodeMatcher = getNodeMatcher( selection.editor.document.languageId, this.modifier.scopeType, diff --git a/src/processTargets/modifiers/DocumentStage.ts b/src/processTargets/modifiers/DocumentStage.ts index 26b4e2773d..2f041a1fee 100644 --- a/src/processTargets/modifiers/DocumentStage.ts +++ b/src/processTargets/modifiers/DocumentStage.ts @@ -2,18 +2,16 @@ import { Range, TextDocument } from "vscode"; import { ContainingScopeModifier, EveryScopeModifier, + Target, } from "../../typings/target.types"; -import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import { ProcessedTargetsContext } from "../../typings/Types"; import { getDocumentRange } from "../../util/range"; import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} - run( - context: ProcessedTargetsContext, - selection: TypedSelection - ): TypedSelection { + run(context: ProcessedTargetsContext, selection: Target): Target { return { ...selection, editor: selection.editor, diff --git a/src/processTargets/modifiers/HeadTailStage.ts b/src/processTargets/modifiers/HeadTailStage.ts index e04486a1e7..6884d855c7 100644 --- a/src/processTargets/modifiers/HeadTailStage.ts +++ b/src/processTargets/modifiers/HeadTailStage.ts @@ -1,6 +1,6 @@ import { Position, Range, TextEditor } from "vscode"; -import { HeadModifier, TailModifier } from "../../typings/target.types"; -import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import { HeadModifier, TailModifier, Target } from "../../typings/target.types"; +import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; abstract class HeadTailStage implements ModifierStage { @@ -8,10 +8,7 @@ abstract class HeadTailStage implements ModifierStage { constructor(private isReversed: boolean) {} - run( - context: ProcessedTargetsContext, - selection: TypedSelection - ): TypedSelection { + run(context: ProcessedTargetsContext, selection: Target): Target { return { ...selection, isReversed: this.isReversed, diff --git a/src/processTargets/modifiers/LineStage.ts b/src/processTargets/modifiers/LineStage.ts index 96c51bc23f..ddc5de5a19 100644 --- a/src/processTargets/modifiers/LineStage.ts +++ b/src/processTargets/modifiers/LineStage.ts @@ -2,17 +2,15 @@ import { Position, Range, TextEditor } from "vscode"; import { ContainingScopeModifier, EveryScopeModifier, + Target, } from "../../typings/target.types"; -import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} - run( - context: ProcessedTargetsContext, - selection: TypedSelection - ): TypedSelection { + run(context: ProcessedTargetsContext, selection: Target): Target { const { document } = selection.editor; const startLine = document.lineAt(selection.contentRange.start); const endLine = document.lineAt(selection.contentRange.end); @@ -33,7 +31,7 @@ export default class implements ModifierStage { export function getLineContext( editor: TextEditor, range: Range -): Partial { +): Partial { const { document } = editor; const { start, end } = range; diff --git a/src/processTargets/modifiers/NotebookCellStage.ts b/src/processTargets/modifiers/NotebookCellStage.ts index 70a7db3bf4..5d2f423b8f 100644 --- a/src/processTargets/modifiers/NotebookCellStage.ts +++ b/src/processTargets/modifiers/NotebookCellStage.ts @@ -1,17 +1,15 @@ import { ContainingScopeModifier, EveryScopeModifier, + Target, } from "../../typings/target.types"; -import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} - run( - context: ProcessedTargetsContext, - selection: TypedSelection - ): TypedSelection { + run(context: ProcessedTargetsContext, selection: Target): Target { return { ...selection, isNotebookCell: true, diff --git a/src/processTargets/modifiers/ParagraphStage.ts b/src/processTargets/modifiers/ParagraphStage.ts index 672d1bea7f..fbe546e001 100644 --- a/src/processTargets/modifiers/ParagraphStage.ts +++ b/src/processTargets/modifiers/ParagraphStage.ts @@ -2,17 +2,15 @@ import { Position, Range, TextDocument } from "vscode"; import { ContainingScopeModifier, EveryScopeModifier, + Target, } from "../../typings/target.types"; -import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} - run( - context: ProcessedTargetsContext, - selection: TypedSelection - ): TypedSelection { + run(context: ProcessedTargetsContext, selection: Target): Target { const { document } = selection.editor; let startLine = document.lineAt(selection.contentRange.start); diff --git a/src/processTargets/modifiers/PositionStage.ts b/src/processTargets/modifiers/PositionStage.ts index 4b052879c8..4327e84ca9 100644 --- a/src/processTargets/modifiers/PositionStage.ts +++ b/src/processTargets/modifiers/PositionStage.ts @@ -1,16 +1,13 @@ import * as vscode from "vscode"; -import { PositionModifier } from "../../typings/target.types"; -import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import { PositionModifier, Target } from "../../typings/target.types"; +import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { constructor(private modifier: PositionModifier) {} - run( - context: ProcessedTargetsContext, - selection: TypedSelection - ): TypedSelection { - const res: TypedSelection = { + run(context: ProcessedTargetsContext, selection: Target): Target { + const res: Target = { ...selection, leadingDelimiterRange: undefined, trailingDelimiterRange: undefined, diff --git a/src/processTargets/modifiers/RawSelectionStage.ts b/src/processTargets/modifiers/RawSelectionStage.ts index c9a73f53ba..9a01231eb8 100644 --- a/src/processTargets/modifiers/RawSelectionStage.ts +++ b/src/processTargets/modifiers/RawSelectionStage.ts @@ -1,14 +1,11 @@ -import { RawSelectionModifier } from "../../typings/target.types"; -import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import { RawSelectionModifier, Target } from "../../typings/target.types"; +import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { constructor(private modifier: RawSelectionModifier) {} - run( - context: ProcessedTargetsContext, - selection: TypedSelection - ): TypedSelection { + run(context: ProcessedTargetsContext, selection: Target): Target { return { ...selection, isRawSelection: true }; } } diff --git a/src/processTargets/modifiers/RegexStage.ts b/src/processTargets/modifiers/RegexStage.ts index f24617c4fb..48e66e1d46 100644 --- a/src/processTargets/modifiers/RegexStage.ts +++ b/src/processTargets/modifiers/RegexStage.ts @@ -2,18 +2,16 @@ import { Position, Range } from "vscode"; import { ContainingScopeModifier, EveryScopeModifier, + Target, } from "../../typings/target.types"; -import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; import { getTokenContext } from "./TokenStage"; class RegexStage implements ModifierStage { constructor(private regex: RegExp, private name?: string) {} - run( - context: ProcessedTargetsContext, - selection: TypedSelection - ): TypedSelection { + run(context: ProcessedTargetsContext, selection: Target): Target { const getMatch = (position: Position) => { const line = selection.editor.document.lineAt(position); const result = [...line.text.matchAll(this.regex)] diff --git a/src/processTargets/modifiers/SubPieceStage.ts b/src/processTargets/modifiers/SubPieceStage.ts index 5c8f99a6c0..3cda3ee3e0 100644 --- a/src/processTargets/modifiers/SubPieceStage.ts +++ b/src/processTargets/modifiers/SubPieceStage.ts @@ -1,17 +1,14 @@ import { range } from "lodash"; import { Range } from "vscode"; import { SUBWORD_MATCHER } from "../../core/constants"; -import { SubTokenModifier } from "../../typings/target.types"; -import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import { SubTokenModifier, Target } from "../../typings/target.types"; +import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { constructor(private modifier: SubTokenModifier) {} - run( - context: ProcessedTargetsContext, - selection: TypedSelection - ): TypedSelection { + run(context: ProcessedTargetsContext, selection: Target): Target { const token = selection.editor.document.getText(selection.contentRange); let pieces: { start: number; end: number }[] = []; diff --git a/src/processTargets/modifiers/SurroundingPairStage.ts b/src/processTargets/modifiers/SurroundingPairStage.ts index be9263341f..d41c107356 100644 --- a/src/processTargets/modifiers/SurroundingPairStage.ts +++ b/src/processTargets/modifiers/SurroundingPairStage.ts @@ -7,8 +7,9 @@ import getTextFragmentExtractor, { import { ComplexSurroundingPairName, SurroundingPairModifier, + Target, } from "../../typings/target.types"; -import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; import { complexDelimiterMap } from "./surroundingPair/delimiterMaps"; import { findSurroundingPairParseTreeBased } from "./surroundingPair/findSurroundingPairParseTreeBased"; @@ -30,10 +31,7 @@ import { findSurroundingPairTextBased } from "./surroundingPair/findSurroundingP export default class implements ModifierStage { constructor(private modifier: SurroundingPairModifier) {} - run( - context: ProcessedTargetsContext, - selection: TypedSelection - ): TypedSelection | TypedSelection[] { + run(context: ProcessedTargetsContext, selection: Target): Target | Target[] { const pairs = processSurroundingPair(context, this.modifier, selection); if (pairs == null) { throw new Error("Couldn't find containing pair"); @@ -57,7 +55,7 @@ export default class implements ModifierStage { function processSurroundingPair( context: ProcessedTargetsContext, modifier: SurroundingPairModifier, - selection: TypedSelection + selection: Target ) { const document = selection.editor.document; const delimiters = complexDelimiterMap[ diff --git a/src/processTargets/modifiers/TokenStage.ts b/src/processTargets/modifiers/TokenStage.ts index 63f3dc9458..8741632069 100644 --- a/src/processTargets/modifiers/TokenStage.ts +++ b/src/processTargets/modifiers/TokenStage.ts @@ -2,17 +2,15 @@ import { Range, TextEditor } from "vscode"; import { ContainingScopeModifier, EveryScopeModifier, + Target, } from "../../typings/target.types"; -import { ProcessedTargetsContext, TypedSelection } from "../../typings/Types"; +import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} - run( - context: ProcessedTargetsContext, - selection: TypedSelection - ): TypedSelection { + run(context: ProcessedTargetsContext, selection: Target): Target { return { ...selection, ...getTokenContext(selection.editor, selection.contentRange), @@ -23,7 +21,7 @@ export default class implements ModifierStage { export function getTokenContext( editor: TextEditor, range: Range -): Partial { +): Partial { const document = editor.document; const { start, end } = range; const endLine = document.lineAt(end); diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts new file mode 100644 index 0000000000..1aec347615 --- /dev/null +++ b/src/processTargets/processTargets.ts @@ -0,0 +1,231 @@ +import { isEqual, zip } from "lodash"; +import { Range } from "vscode"; +import { + PrimitiveTargetDesc, + RangeTargetDesc, + TargetDesc, + Target, +} from "../typings/target.types"; +import { ProcessedTargetsContext } from "../typings/Types"; +import getMarkStage from "./getMarkStage"; +import getModifierStage from "./getModifierStage"; + +/** + * Converts the abstract target descriptions provided by the user to a concrete + * representation usable by actions. Conceptually, the input will be something + * like "the function call argument containing the cursor" and the output will be something + * like "line 3, characters 5 through 10". + * @param context Captures the environment needed to convert the abstract target + * description given by the user to a concrete representation usable by + * actions + * @param targets The abstract target representations provided by the user + * @returns A list of lists of typed selections, one list per input target. Each + * typed selection includes the selection, as well the uri of the document + * containing it, and potentially rich context information such as how to remove + * the target + */ +export default function ( + context: ProcessedTargetsContext, + targets: TargetDesc[] +): Target[][] { + return targets.map((target) => + filterDuplicateSelections(processTarget(context, target)) + ); +} + +function processTarget( + context: ProcessedTargetsContext, + target: TargetDesc +): Target[] { + switch (target.type) { + case "list": + return target.elements.flatMap((element) => + processTarget(context, element) + ); + case "range": + return processRangeTarget(context, target); + case "primitive": + return processPrimitiveTarget(context, target); + } +} + +function processRangeTarget( + context: ProcessedTargetsContext, + target: RangeTargetDesc +): Target[] { + const anchorTargets = processPrimitiveTarget(context, target.anchor); + const activeTargets = processPrimitiveTarget(context, target.active); + + return zip(anchorTargets, activeTargets).flatMap( + ([anchorTarget, activeTarget]) => { + if (anchorTarget == null || activeTarget == null) { + throw new Error("anchorTargets and activeTargets lengths don't match"); + } + + if (anchorTarget.editor !== activeTarget.editor) { + throw new Error( + "anchorTarget and activeTarget must be in same document" + ); + } + + const anchorRange = anchorTarget.contentRange; + const activeRange = activeTarget.contentRange; + const isForward = anchorRange.start.isBeforeOrEqual(activeRange.start); + + switch (target.rangeType) { + case "continuous": + return processContinuousRangeTarget( + target, + anchorTarget, + activeTarget, + isForward + ); + case "vertical": + return processVerticalRangeTarget( + target, + anchorTarget, + activeTarget, + isForward + ); + } + } + ); +} + +function processContinuousRangeTarget( + target: RangeTargetDesc, + anchorTarget: Target, + activeTarget: Target, + isForward: boolean +): Target[] { + const { excludeAnchor, excludeActive } = target; + + const contentRange = unionRanges( + isForward, + excludeAnchor, + excludeActive, + anchorTarget.contentRange, + activeTarget.contentRange + )!; + + const interiorRange = unionRanges( + isForward, + excludeAnchor, + excludeActive, + anchorTarget.interiorRange, + activeTarget.interiorRange + ); + + const anchorContext = excludeAnchor ? undefined : anchorTarget; + const activeContext = excludeActive ? undefined : activeTarget; + const leadingDelimiterRange = isForward + ? anchorContext?.leadingDelimiterRange + : activeContext?.leadingDelimiterRange; + const trailingDelimiterRange = isForward + ? activeContext?.trailingDelimiterRange + : anchorContext?.trailingDelimiterRange; + + return [ + { + editor: activeTarget.editor, + isReversed: !isForward, + delimiter: anchorTarget.delimiter, + contentRange, + interiorRange, + leadingDelimiterRange, + trailingDelimiterRange, + }, + ]; +} + +function unionRanges( + isForward: boolean, + excludeAnchor: boolean, + excludeActive: boolean, + anchor?: Range, + active?: Range +) { + if (anchor == null || active == null) { + return anchor == null ? active : anchor; + } + return new Range( + getPosition(anchor, isForward, excludeAnchor), + getPosition(active, !isForward, excludeActive) + ); +} + +function getPosition(range: Range, isStartOfRange: boolean, exclude: boolean) { + if (exclude) { + return isStartOfRange ? range.end : range.start; + } + return isStartOfRange ? range.start : range.end; +} + +function processVerticalRangeTarget( + target: RangeTargetDesc, + anchorTarget: Target, + activeTarget: Target, + isForward: boolean +): Target[] { + const { excludeAnchor, excludeActive } = target; + const delta = isForward ? 1 : -1; + + const anchorPosition = isForward + ? anchorTarget.contentRange.end + : anchorTarget.contentRange.start; + const anchorLine = anchorPosition.line + (excludeAnchor ? delta : 0); + const activePosition = isForward + ? activeTarget.contentRange.end + : activeTarget.contentRange.start; + const activeLine = activePosition.line - (excludeActive ? delta : 0); + + const results: Target[] = []; + for (let i = anchorLine; true; i += delta) { + results.push({ + editor: anchorTarget.editor, + isReversed: !isForward, + delimiter: anchorTarget.delimiter, + contentRange: new Range( + i, + anchorTarget.contentRange.start.character, + i, + anchorTarget.contentRange.end.character + ), + }); + if (i === activeLine) { + return results; + } + } +} + +function processPrimitiveTarget( + context: ProcessedTargetsContext, + target: PrimitiveTargetDesc +): Target[] { + const markStage = getMarkStage(target.mark); + let selections = markStage.run(context); + + for (let i = target.modifiers.length - 1; i > -1; --i) { + const modifier = target.modifiers[i]; + const stage = getModifierStage(modifier); + const stageSelections: Target[] = []; + for (const selection of selections) { + const stageResult = stage.run(context, selection); + if (Array.isArray(stageResult)) { + stageSelections.push(...stageResult); + } else { + stageSelections.push(stageResult); + } + } + selections = stageSelections; + } + + return selections; +} + +function filterDuplicateSelections(selections: Target[]) { + return selections.filter( + (selection, index, selections) => + selections.findIndex((s) => isEqual(s, selection)) === index + ); +} diff --git a/src/scripts/transformRecordedTests/transformations/updateSurroundingPairTest.ts b/src/scripts/transformRecordedTests/transformations/updateSurroundingPairTest.ts index 4b49e26eaa..20c17f4b4b 100644 --- a/src/scripts/transformRecordedTests/transformations/updateSurroundingPairTest.ts +++ b/src/scripts/transformRecordedTests/transformations/updateSurroundingPairTest.ts @@ -2,14 +2,14 @@ import { TestCaseFixture } from "../../../testUtil/TestCase"; import { transformPartialPrimitiveTargets } from "../../../util/getPrimitiveTargets"; import { DelimiterInclusion, - PartialPrimitiveTarget, + PartialPrimitiveTargetDesc, } from "../../../typings/target.types"; // Leaving an example here in case it's helpful export function updateSurroundingPairTest(fixture: TestCaseFixture) { fixture.command.targets = transformPartialPrimitiveTargets( fixture.command.targets, - (target: PartialPrimitiveTarget) => { + (target: PartialPrimitiveTargetDesc) => { target.modifiers?.forEach((modifier) => { if (modifier?.type === "surroundingPair") { let delimiterInclusion: DelimiterInclusion; diff --git a/src/scripts/transformRecordedTests/transformations/upgradeFromVersion0.ts b/src/scripts/transformRecordedTests/transformations/upgradeFromVersion0.ts index ed55cab58a..edea866e53 100644 --- a/src/scripts/transformRecordedTests/transformations/upgradeFromVersion0.ts +++ b/src/scripts/transformRecordedTests/transformations/upgradeFromVersion0.ts @@ -1,6 +1,6 @@ import { TestCaseFixture } from "../../../testUtil/TestCase"; import { transformPartialPrimitiveTargets } from "../../../util/getPrimitiveTargets"; -import { PartialPrimitiveTarget } from "../../../typings/target.types"; +import { PartialPrimitiveTargetDesc } from "../../../typings/target.types"; export function upgradeFromVersion0(fixture: TestCaseFixture) { const { command, spokenForm: oldSpokenForm, ...rest } = fixture as any; @@ -16,7 +16,7 @@ export function upgradeFromVersion0(fixture: TestCaseFixture) { const targets = transformPartialPrimitiveTargets( newTargets ?? oldTargets, - (target: PartialPrimitiveTarget) => { + (target: PartialPrimitiveTargetDesc) => { if (target.mark?.type === "decoratedSymbol") { (target.mark as any).usePrePhraseSnapshot = undefined; } diff --git a/src/test/suite/fixtures/inferFullTargets.fixture.ts b/src/test/suite/fixtures/inferFullTargets.fixture.ts index d3bdf2cf9e..ce969fb87a 100644 --- a/src/test/suite/fixtures/inferFullTargets.fixture.ts +++ b/src/test/suite/fixtures/inferFullTargets.fixture.ts @@ -1,16 +1,16 @@ // @ts-nocheck import { ActionPreferences, InferenceContext } from "../../../typings/Types"; -import { PartialTarget, Target } from "../../../typings/target.types"; +import { PartialTargetDesc, TargetDesc } from "../../../typings/target.types"; interface FixtureInput { context: InferenceContext; - partialTargets: PartialTarget[]; + partialTargets: PartialTargetDesc[]; actionPreferences: ActionPreferences[]; } interface Fixture { input: FixtureInput; - expectedOutput: Target[]; + expectedOutput: TargetDesc[]; } const fixture: Fixture[] = [ diff --git a/src/testUtil/TestCase.ts b/src/testUtil/TestCase.ts index 39dccb90f6..82a6f178d6 100644 --- a/src/testUtil/TestCase.ts +++ b/src/testUtil/TestCase.ts @@ -3,7 +3,7 @@ import * as vscode from "vscode"; import { CommandLatest } from "../core/commandRunner/command.types"; import { ReadOnlyHatMap } from "../core/IndividualHatMap"; import { ThatMark } from "../core/ThatMark"; -import { Target } from "../typings/target.types"; +import { TargetDesc } from "../typings/target.types"; import { Token } from "../typings/Types"; import { cleanUpTestCaseCommand } from "./cleanUpTestCaseCommand"; import { @@ -23,7 +23,7 @@ export type TestCaseCommand = CommandLatest; export type TestCaseContext = { thatMark: ThatMark; sourceMark: ThatMark; - targets: Target[]; + targets: TargetDesc[]; hatTokenMap: ReadOnlyHatMap; }; @@ -40,12 +40,12 @@ export type TestCaseFixture = { finalState: TestCaseSnapshot; returnValue: unknown; /** Inferred full targets added for context; not currently used in testing */ - fullTargets: Target[]; + fullTargets: TargetDesc[]; }; export class TestCase { languageId: string; - fullTargets: Target[]; + fullTargets: TargetDesc[]; initialState: TestCaseSnapshot | null = null; finalState: TestCaseSnapshot | null = null; returnValue: unknown = null; @@ -90,7 +90,7 @@ export class TestCase { return marksToPlainObject(marks); } - private includesThatMark(target: Target, type: string): boolean { + private includesThatMark(target: TargetDesc, type: string): boolean { if (target.type === "primitive" && target.mark.type === type) { return true; } else if (target.type === "list") { diff --git a/src/testUtil/extractTargetedMarks.ts b/src/testUtil/extractTargetedMarks.ts index 2f579fe274..9c95d5ee66 100644 --- a/src/testUtil/extractTargetedMarks.ts +++ b/src/testUtil/extractTargetedMarks.ts @@ -1,9 +1,9 @@ import { ReadOnlyHatMap } from "../core/IndividualHatMap"; import HatTokenMap from "../core/HatTokenMap"; import { Token } from "../typings/Types"; -import { PrimitiveTarget, Target } from "../typings/target.types"; +import { PrimitiveTargetDesc, TargetDesc } from "../typings/target.types"; -function extractPrimitiveTargetKeys(...targets: PrimitiveTarget[]) { +function extractPrimitiveTargetKeys(...targets: PrimitiveTargetDesc[]) { const keys: string[] = []; targets.forEach((target) => { if (target.mark.type === "decoratedSymbol") { @@ -14,7 +14,7 @@ function extractPrimitiveTargetKeys(...targets: PrimitiveTarget[]) { return keys; } -export function extractTargetKeys(target: Target): string[] { +export function extractTargetKeys(target: TargetDesc): string[] { switch (target.type) { case "primitive": return extractPrimitiveTargetKeys(target); diff --git a/src/typings/Types.ts b/src/typings/Types.ts index 63a49bc475..e801d57fb8 100644 --- a/src/typings/Types.ts +++ b/src/typings/Types.ts @@ -11,6 +11,7 @@ import { Snippets } from "../core/Snippets"; import { RangeUpdater } from "../core/updateSelections/RangeUpdater"; import { TestCaseRecorder } from "../testUtil/TestCaseRecorder"; import { CommandServerApi } from "../util/getExtensionApi"; +import { Target } from "./target.types"; import { FullRangeInfo } from "./updateSelections"; /** @@ -76,87 +77,6 @@ export interface SelectionContext { isRawSelection?: boolean; } -/** - * Represents a selection in a particular document along with potential rich - * context information such as how to remove the given selection - */ -// export interface TypedSelection { -// /** -// * The selection. If insideOutsideType is non-null, it will be adjusted to -// * include delimiter if outside -// */ -// selection: SelectionWithEditor; -// selectionContext: SelectionContext; - -// /** -// * Mirrored from the target from which this selection was constructed -// */ -// position: Position; -// } - -export interface TypedSelection { - /** - * The text editor used for all ranges - */ - editor: vscode.TextEditor; - - /** - * If true active is before anchor - */ - isReversed?: boolean; - - /** - * Indicates that this is a raw selection with no type information so for - * example if it is the destination of a bring or move it should inherit the - * type information such as delimiters from its source - */ - isRawSelection?: boolean; - - /** - * If true this selection is part of a notebook cell - */ - isNotebookCell?: boolean; - - /** - * If this selection has a delimiter. For example, new line for a line or paragraph and comma for a list or argument - */ - delimiter?: string; - - /** - * The range of the content - */ - contentRange: vscode.Range; - - /** - * Represents the interior range of this selection. For example, for a - * surrounding pair this would exclude the opening and closing delimiter. For an if - * statement this would be the statements in the body. - */ - interiorRange?: vscode.Range; - - /** - * The range that needs to be removed - */ - removalRange?: vscode.Range; - - /** - * The range of the delimiter before the content selection - */ - leadingDelimiterRange?: vscode.Range; - - /** - * The range of the delimiter after the content selection - */ - trailingDelimiterRange?: vscode.Range; - - /** - * Represents the boundary ranges of this selection. For example, for a - * surrounding pair this would be the opening and closing delimiter. For an if - * statement this would be the line of the guard as well as the closing brace. - */ - boundary?: vscode.Range[]; -} - export interface ActionPreferences { // TODO // position?: Position; @@ -182,7 +102,7 @@ export interface ActionReturnValue { } export interface Action { - run(targets: TypedSelection[][], ...args: any[]): Promise; + run(targets: Target[][], ...args: any[]): Promise; /** * Used to define default values for parts of target during inference. diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index bd03326c6b..d989923823 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -1,3 +1,4 @@ +import { Range, TextEditor } from "vscode"; import { HatStyleName } from "../core/constants"; export interface CursorMark { @@ -177,7 +178,7 @@ export interface PositionModifier { position: Position; } -export interface PartialPrimitiveTarget { +export interface PartialPrimitiveTargetDesc { type: "primitive"; mark?: Mark; modifiers?: Modifier[]; @@ -193,34 +194,34 @@ export type Modifier = | TailModifier | RawSelectionModifier; -export interface PartialRangeTarget { +export interface PartialRangeTargetDesc { type: "range"; - anchor: PartialPrimitiveTarget; - active: PartialPrimitiveTarget; + anchor: PartialPrimitiveTargetDesc; + active: PartialPrimitiveTargetDesc; excludeStart?: boolean; excludeEnd?: boolean; rangeType?: RangeType; } -export interface PartialListTarget { +export interface PartialListTargetDesc { type: "list"; - elements: (PartialPrimitiveTarget | PartialRangeTarget)[]; + elements: (PartialPrimitiveTargetDesc | PartialRangeTargetDesc)[]; } -export type PartialTarget = - | PartialPrimitiveTarget - | PartialRangeTarget - | PartialListTarget; +export type PartialTargetDesc = + | PartialPrimitiveTargetDesc + | PartialRangeTargetDesc + | PartialListTargetDesc; -export interface PrimitiveTarget extends PartialPrimitiveTarget { +export interface PrimitiveTargetDesc extends PartialPrimitiveTargetDesc { mark: Mark; modifiers: Modifier[]; } -export interface RangeTarget { +export interface RangeTargetDesc { type: "range"; - anchor: PrimitiveTarget; - active: PrimitiveTarget; + anchor: PrimitiveTargetDesc; + active: PrimitiveTargetDesc; excludeAnchor: boolean; excludeActive: boolean; rangeType: RangeType; @@ -230,9 +231,72 @@ export interface RangeTarget { // vertical puts a selection on each line vertically between the two targets export type RangeType = "continuous" | "vertical"; -export interface ListTarget { +export interface ListTargetDesc { type: "list"; - elements: (PrimitiveTarget | RangeTarget)[]; + elements: (PrimitiveTargetDesc | RangeTargetDesc)[]; } -export type Target = PrimitiveTarget | RangeTarget | ListTarget; +export type TargetDesc = PrimitiveTargetDesc | RangeTargetDesc | ListTargetDesc; + +export interface Target { + /** + * The text editor used for all ranges + */ + editor: TextEditor; + + /** + * If true active is before anchor + */ + isReversed?: boolean; + + /** + * Indicates that this is a raw selection with no type information so for + * example if it is the destination of a bring or move it should inherit the + * type information such as delimiters from its source + */ + isRawSelection?: boolean; + + /** + * If true this selection is part of a notebook cell + */ + isNotebookCell?: boolean; + + /** + * If this selection has a delimiter. For example, new line for a line or paragraph and comma for a list or argument + */ + delimiter?: string; + + /** + * The range of the content + */ + contentRange: Range; + + /** + * Represents the interior range of this selection. For example, for a + * surrounding pair this would exclude the opening and closing delimiter. For an if + * statement this would be the statements in the body. + */ + interiorRange?: Range; + + /** + * The range that needs to be removed + */ + removalRange?: Range; + + /** + * The range of the delimiter before the content selection + */ + leadingDelimiterRange?: Range; + + /** + * The range of the delimiter after the content selection + */ + trailingDelimiterRange?: Range; + + /** + * Represents the boundary ranges of this selection. For example, for a + * surrounding pair this would be the opening and closing delimiter. For an if + * statement this would be the line of the guard as well as the closing brace. + */ + boundary?: Range[]; +} diff --git a/src/util/editDisplayUtils.ts b/src/util/editDisplayUtils.ts index 68d3358cfa..6022d99973 100644 --- a/src/util/editDisplayUtils.ts +++ b/src/util/editDisplayUtils.ts @@ -1,7 +1,8 @@ import { TextEditorDecorationType, window, workspace } from "vscode"; import { EditStyle } from "../core/editStyles"; import isTesting from "../testUtil/isTesting"; -import { SelectionWithEditor, TypedSelection } from "../typings/Types"; +import { Target } from "../typings/target.types"; +import { SelectionWithEditor } from "../typings/Types"; import sleep from "./sleep"; import { runForEachEditor, runOnTargetsForEachEditor } from "./targetUtils"; @@ -45,7 +46,7 @@ export async function displayPendingEditDecorationsForSelection( } export default async function displayPendingEditDecorations( - targets: TypedSelection[], + targets: Target[], editStyle: EditStyle ) { await setDecorations(targets, editStyle); @@ -62,10 +63,7 @@ export function clearDecorations(editStyle: EditStyle) { }); } -export async function setDecorations( - targets: TypedSelection[], - editStyle: EditStyle -) { +export async function setDecorations(targets: Target[], editStyle: EditStyle) { await runOnTargetsForEachEditor(targets, async (editor, selections) => { editor.setDecorations( editStyle.token, @@ -107,7 +105,7 @@ export async function setDecorations( }); } -function useLineDecorations(selection: TypedSelection) { +function useLineDecorations(selection: Target) { return false; // TODO // return ( // isLineSelectionType(selection.selectionType) && diff --git a/src/util/getLinks.ts b/src/util/getLinks.ts index 8400be2514..a36fa6d761 100644 --- a/src/util/getLinks.ts +++ b/src/util/getLinks.ts @@ -1,5 +1,5 @@ import * as vscode from "vscode"; -import { TypedSelection } from "../typings/Types"; +import { Target } from "../typings/target.types"; export async function getLinksForSelections( editor: vscode.TextEditor, @@ -11,7 +11,7 @@ export async function getLinksForSelections( ); } -export async function getLinkForTarget(target: TypedSelection) { +export async function getLinkForTarget(target: Target) { const links = await getLinksForEditor(target.editor); return links.find((link) => link.range.contains(target.contentRange)); } diff --git a/src/util/getPrimitiveTargets.ts b/src/util/getPrimitiveTargets.ts index aaecaa73dc..3980b34373 100644 --- a/src/util/getPrimitiveTargets.ts +++ b/src/util/getPrimitiveTargets.ts @@ -1,9 +1,9 @@ import { - PartialPrimitiveTarget, - PartialRangeTarget, - PartialTarget, - PrimitiveTarget, - Target, + PartialPrimitiveTargetDesc, + PartialRangeTargetDesc, + PartialTargetDesc, + PrimitiveTargetDesc, + TargetDesc, } from "../typings/target.types"; /** @@ -13,13 +13,13 @@ import { * @param targets The targets to extract from * @returns A list of primitive targets */ -export function getPartialPrimitiveTargets(targets: PartialTarget[]) { +export function getPartialPrimitiveTargets(targets: PartialTargetDesc[]) { return targets.flatMap(getPartialPrimitiveTargetsHelper); } function getPartialPrimitiveTargetsHelper( - target: PartialTarget -): PartialPrimitiveTarget[] { + target: PartialTargetDesc +): PartialPrimitiveTargetDesc[] { switch (target.type) { case "primitive": return [target]; @@ -36,11 +36,11 @@ function getPartialPrimitiveTargetsHelper( * @param targets The targets to extract from * @returns A list of primitive targets */ -export function getPrimitiveTargets(targets: Target[]) { +export function getPrimitiveTargets(targets: TargetDesc[]) { return targets.flatMap(getPrimitiveTargetsHelper); } -function getPrimitiveTargetsHelper(target: Target): PrimitiveTarget[] { +function getPrimitiveTargetsHelper(target: TargetDesc): PrimitiveTargetDesc[] { switch (target.type) { case "primitive": return [target]; @@ -59,8 +59,8 @@ function getPrimitiveTargetsHelper(target: Target): PrimitiveTarget[] { * @returns A list of primitive targets */ export function transformPartialPrimitiveTargets( - targets: PartialTarget[], - func: (target: PartialPrimitiveTarget) => PartialPrimitiveTarget + targets: PartialTargetDesc[], + func: (target: PartialPrimitiveTargetDesc) => PartialPrimitiveTargetDesc ) { return targets.map((target) => transformPartialPrimitiveTargetsHelper(target, func) @@ -68,9 +68,9 @@ export function transformPartialPrimitiveTargets( } function transformPartialPrimitiveTargetsHelper( - target: PartialTarget, - func: (target: PartialPrimitiveTarget) => PartialPrimitiveTarget -): PartialTarget { + target: PartialTargetDesc, + func: (target: PartialPrimitiveTargetDesc) => PartialPrimitiveTargetDesc +): PartialTargetDesc { switch (target.type) { case "primitive": return func(target); @@ -80,8 +80,8 @@ function transformPartialPrimitiveTargetsHelper( elements: target.elements.map( (element) => transformPartialPrimitiveTargetsHelper(element, func) as - | PartialPrimitiveTarget - | PartialRangeTarget + | PartialPrimitiveTargetDesc + | PartialRangeTargetDesc ), }; case "range": diff --git a/src/util/targetUtils.ts b/src/util/targetUtils.ts index 395412a2bb..d089f66bc9 100644 --- a/src/util/targetUtils.ts +++ b/src/util/targetUtils.ts @@ -1,8 +1,8 @@ import { Position, Range, TextEditor } from "vscode"; -import { TypedSelection } from "../typings/Types"; +import { Target } from "../typings/target.types"; import { groupBy } from "./itertools"; -export function ensureSingleEditor(targets: TypedSelection[]) { +export function ensureSingleEditor(targets: Target[]) { if (targets.length === 0) { throw new Error("Require at least one target with this action"); } @@ -16,7 +16,7 @@ export function ensureSingleEditor(targets: TypedSelection[]) { return editors[0]; } -export function ensureSingleTarget(targets: TypedSelection[]) { +export function ensureSingleTarget(targets: Target[]) { if (targets.length !== 1) { throw new Error("Can only have one target with this action"); } @@ -37,13 +37,13 @@ export async function runForEachEditor( } export async function runOnTargetsForEachEditor( - targets: TypedSelection[], - func: (editor: TextEditor, selections: TypedSelection[]) => Promise + targets: Target[], + func: (editor: TextEditor, selections: Target[]) => Promise ): Promise { return runForEachEditor(targets, (target) => target.editor, func); } -export function groupTargetsForEachEditor(targets: TypedSelection[]) { +export function groupTargetsForEachEditor(targets: Target[]) { return groupForEachEditor(targets, (target) => target.editor); } @@ -63,9 +63,9 @@ export function groupForEachEditor( /** Get the possible leading and trailing overflow ranges of the outside target compared to the inside target */ export function getOutsideOverflow( - insideTarget: TypedSelection, - outsideTarget: TypedSelection -): TypedSelection[] { + insideTarget: Target, + outsideTarget: Target +): Target[] { const { start: insideStart, end: insideEnd } = insideTarget.contentRange; const { start: outsideStart, end: outsideEnd } = outsideTarget.contentRange; const result = []; @@ -86,7 +86,7 @@ function createTypeSelection( editor: TextEditor, start: Position, end: Position -): TypedSelection { +): Target { return { editor, contentRange: new Range(start, end), diff --git a/src/util/unifyRanges.ts b/src/util/unifyRanges.ts index c66798f398..0285ff06a7 100644 --- a/src/util/unifyRanges.ts +++ b/src/util/unifyRanges.ts @@ -1,6 +1,6 @@ // TODO // import { Range } from "vscode"; -// import { TypedSelection } from "../typings/Types"; +// import { Target } from "../typings/Types"; // import { performInsideOutsideAdjustment } from "./performInsideOutsideAdjustment"; // import { groupTargetsForEachEditor } from "./targetUtils"; @@ -42,7 +42,7 @@ // * FIXME This code probably needs to update once we have objected oriented targets // * https://github.com/cursorless-dev/cursorless/issues/210 // */ -// export function unifyTargets(targets: TypedSelection[]): TypedSelection[] { +// export function unifyTargets(targets: Target[]): Target[] { // if (targets.length < 2) { // return targets; // } @@ -64,13 +64,13 @@ // } // function unifyTargetsOnePass( -// targets: TypedSelection[] -// ): [TypedSelection[], boolean] { +// targets: Target[] +// ): [Target[], boolean] { // if (targets.length < 2) { // return [targets, false]; // } -// const results: TypedSelection[] = []; -// let currentGroup: TypedSelection[] = []; +// const results: Target[] = []; +// let currentGroup: Target[] = []; // targets.forEach((target) => { // // No intersection. Mark start of new group // if ( @@ -87,13 +87,13 @@ // return [results, results.length !== targets.length]; // } -// function mergeTargets(targets: TypedSelection[]): TypedSelection { +// function mergeTargets(targets: Target[]): Target { // if (targets.length === 1) { // return targets[0]; // } // const first = targets[0]; // const last = targets[targets.length - 1]; -// const typeSelection: TypedSelection = { +// const typeSelection: Target = { // editor: first.editor, // contentRange: new Range(first.contentRange.start, last.contentRange.end), // leadingDelimiterRange: first.leadingDelimiterRange, @@ -102,6 +102,6 @@ // return performInsideOutsideAdjustment(typeSelection); // } -// function intersects(targetA: TypedSelection, targetB: TypedSelection) { +// function intersects(targetA: Target, targetB: Target) { // return !!targetA.contentRange.intersection(targetB.contentRange); // } From 2e4e5c56d99f30fd2ea0355c4d46283ea5656652 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 15 May 2022 12:00:44 +0000 Subject: [PATCH 030/314] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/processTargets/marks/LineNumberStage.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/processTargets/marks/LineNumberStage.ts b/src/processTargets/marks/LineNumberStage.ts index 4785550b0b..d3048adce9 100644 --- a/src/processTargets/marks/LineNumberStage.ts +++ b/src/processTargets/marks/LineNumberStage.ts @@ -1,5 +1,9 @@ import { Range, TextEditor, window } from "vscode"; -import { LineNumberMark, LineNumberPosition, Target } from "../../typings/target.types"; +import { + LineNumberMark, + LineNumberPosition, + Target, +} from "../../typings/target.types"; import { getLineContext } from "../modifiers/LineStage"; import { MarkStage } from "../PipelineStages.types"; From 2e461edeaea5e7f8c4224b8344f3411e0b8c79e9 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 15 May 2022 15:04:13 +0200 Subject: [PATCH 031/314] Stages and modifiers tested manually --- .../marks/DecoratedSymbolStage.ts | 1 + src/processTargets/marks/LineNumberStage.ts | 7 ++- .../modifiers/ContainingScopeStage.ts | 15 +++-- src/processTargets/modifiers/DocumentStage.ts | 19 +++--- src/processTargets/modifiers/HeadTailStage.ts | 9 +-- src/processTargets/modifiers/LineStage.ts | 37 ++++++----- .../modifiers/NotebookCellStage.ts | 6 +- .../modifiers/ParagraphStage.ts | 19 +++--- src/processTargets/modifiers/PositionStage.ts | 38 +++++------ .../modifiers/RawSelectionStage.ts | 8 ++- src/processTargets/modifiers/RegexStage.ts | 63 +++++++++---------- src/processTargets/modifiers/SubPieceStage.ts | 24 ++++--- .../modifiers/SurroundingPairStage.ts | 6 +- src/processTargets/modifiers/TokenStage.ts | 9 +-- src/typings/target.types.ts | 9 +-- src/util/targetUtils.ts | 1 + 16 files changed, 137 insertions(+), 134 deletions(-) diff --git a/src/processTargets/marks/DecoratedSymbolStage.ts b/src/processTargets/marks/DecoratedSymbolStage.ts index a7004aa0ea..2a6c655afd 100644 --- a/src/processTargets/marks/DecoratedSymbolStage.ts +++ b/src/processTargets/marks/DecoratedSymbolStage.ts @@ -20,6 +20,7 @@ export default class implements MarkStage { { editor: token.editor, contentRange: token.range, + isReversed: false, ...getTokenContext(token.editor, token.range), }, ]; diff --git a/src/processTargets/marks/LineNumberStage.ts b/src/processTargets/marks/LineNumberStage.ts index 4785550b0b..b4c05b6801 100644 --- a/src/processTargets/marks/LineNumberStage.ts +++ b/src/processTargets/marks/LineNumberStage.ts @@ -1,5 +1,9 @@ import { Range, TextEditor, window } from "vscode"; -import { LineNumberMark, LineNumberPosition, Target } from "../../typings/target.types"; +import { + LineNumberMark, + LineNumberPosition, + Target, +} from "../../typings/target.types"; import { getLineContext } from "../modifiers/LineStage"; import { MarkStage } from "../PipelineStages.types"; @@ -21,6 +25,7 @@ export default class implements MarkStage { { editor, contentRange, + isReversed: false, ...getLineContext(editor, contentRange), }, ]; diff --git a/src/processTargets/modifiers/ContainingScopeStage.ts b/src/processTargets/modifiers/ContainingScopeStage.ts index d38b31eb2e..b4df75845c 100644 --- a/src/processTargets/modifiers/ContainingScopeStage.ts +++ b/src/processTargets/modifiers/ContainingScopeStage.ts @@ -17,21 +17,21 @@ import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} - run(context: ProcessedTargetsContext, selection: Target): Target[] { + run(context: ProcessedTargetsContext, target: Target): Target[] { const nodeMatcher = getNodeMatcher( - selection.editor.document.languageId, + target.editor.document.languageId, this.modifier.scopeType, this.modifier.type === "everyScope" ); const node: SyntaxNode | null = context.getNodeAtLocation( - new Location(selection.editor.document.uri, selection.contentRange.start) + new Location(target.editor.document.uri, target.contentRange.start) ); const scopeNodes = findNearestContainingAncestorNode(node, nodeMatcher, { - editor: selection.editor, + editor: target.editor, selection: new Selection( - selection.contentRange.start, - selection.contentRange.end + target.contentRange.start, + target.contentRange.end ), }); @@ -40,12 +40,11 @@ export default class implements ModifierStage { } return scopeNodes.map((scope) => ({ - ...selection, + isReversed: target.isReversed, editor: scope.selection.editor, contentRange: scope.selection.selection, interiorRange: scope.context.interior?.at(0)?.selection, removalRange: scope.context.outerSelection ?? undefined, - isRawSelection: scope.context.isRawSelection, isNotebookCell: scope.context.isNotebookCell, delimiter: scope.context.containingListDelimiter ?? undefined, boundary: scope.context.boundary?.map((bound) => bound.selection), diff --git a/src/processTargets/modifiers/DocumentStage.ts b/src/processTargets/modifiers/DocumentStage.ts index 2f041a1fee..355586ebbe 100644 --- a/src/processTargets/modifiers/DocumentStage.ts +++ b/src/processTargets/modifiers/DocumentStage.ts @@ -11,18 +11,13 @@ import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} - run(context: ProcessedTargetsContext, selection: Target): Target { + run(context: ProcessedTargetsContext, target: Target): Target { return { - ...selection, - editor: selection.editor, - isReversed: selection.isReversed, - contentRange: getDocumentContentRange(selection.editor.document), - removalRange: getDocumentRange(selection.editor.document), + editor: target.editor, + isReversed: target.isReversed, delimiter: "\n", - interiorRange: undefined, - boundary: undefined, - leadingDelimiterRange: undefined, - trailingDelimiterRange: undefined, + contentRange: getDocumentContentRange(target.editor.document), + removalRange: getDocumentRange(target.editor.document), }; } } @@ -33,16 +28,16 @@ function getDocumentContentRange(document: TextDocument) { for (let i = firstLineNum; i < document.lineCount; ++i) { if (!document.lineAt(i).isEmptyOrWhitespace) { + firstLineNum = i; break; } - firstLineNum = i; } for (let i = lastLineNum; i > -1; --i) { if (!document.lineAt(i).isEmptyOrWhitespace) { + lastLineNum = i; break; } - lastLineNum = i; } const firstLine = document.lineAt(firstLineNum); diff --git a/src/processTargets/modifiers/HeadTailStage.ts b/src/processTargets/modifiers/HeadTailStage.ts index 6884d855c7..39a4acb9af 100644 --- a/src/processTargets/modifiers/HeadTailStage.ts +++ b/src/processTargets/modifiers/HeadTailStage.ts @@ -8,14 +8,11 @@ abstract class HeadTailStage implements ModifierStage { constructor(private isReversed: boolean) {} - run(context: ProcessedTargetsContext, selection: Target): Target { + run(context: ProcessedTargetsContext, target: Target): Target { return { - ...selection, + editor: target.editor, isReversed: this.isReversed, - contentRange: this.update(selection.editor, selection.contentRange), - interiorRange: selection.interiorRange - ? this.update(selection.editor, selection.interiorRange) - : undefined, + contentRange: this.update(target.editor, target.contentRange), }; } } diff --git a/src/processTargets/modifiers/LineStage.ts b/src/processTargets/modifiers/LineStage.ts index ddc5de5a19..a910ca684f 100644 --- a/src/processTargets/modifiers/LineStage.ts +++ b/src/processTargets/modifiers/LineStage.ts @@ -10,20 +10,16 @@ import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} - run(context: ProcessedTargetsContext, selection: Target): Target { - const { document } = selection.editor; - const startLine = document.lineAt(selection.contentRange.start); - const endLine = document.lineAt(selection.contentRange.end); - const start = new Position( - startLine.lineNumber, - startLine.firstNonWhitespaceCharacterIndex + run(context: ProcessedTargetsContext, target: Target): Target { + const contentRange = fitRangeToLineContent( + target.editor, + target.contentRange ); - const end = endLine.range.end; - const contentRange = new Range(start, end); - return { - ...selection, - ...getLineContext(selection.editor, contentRange), + editor: target.editor, + isReversed: target.isReversed, + contentRange, + ...getLineContext(target.editor, contentRange), }; } } @@ -51,11 +47,22 @@ export function getLineContext( return { delimiter: "\n", - interiorRange: undefined, - boundary: undefined, - isRawSelection: undefined, removalRange, leadingDelimiterRange, trailingDelimiterRange, }; } + +function fitRangeToLineContent(editor: TextEditor, range: Range) { + const startLine = editor.document.lineAt(range.start); + const endLine = editor.document.lineAt(range.end); + const endCharacterIndex = + endLine.range.end.character - + (endLine.text.length - endLine.text.trimEnd().length); + return new Range( + startLine.lineNumber, + startLine.firstNonWhitespaceCharacterIndex, + endLine.lineNumber, + endCharacterIndex + ); +} diff --git a/src/processTargets/modifiers/NotebookCellStage.ts b/src/processTargets/modifiers/NotebookCellStage.ts index 5d2f423b8f..528d361f0b 100644 --- a/src/processTargets/modifiers/NotebookCellStage.ts +++ b/src/processTargets/modifiers/NotebookCellStage.ts @@ -9,9 +9,11 @@ import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} - run(context: ProcessedTargetsContext, selection: Target): Target { + run(context: ProcessedTargetsContext, target: Target): Target { return { - ...selection, + editor: target.editor, + isReversed: target.isReversed, + contentRange: target.contentRange, isNotebookCell: true, }; } diff --git a/src/processTargets/modifiers/ParagraphStage.ts b/src/processTargets/modifiers/ParagraphStage.ts index fbe546e001..2319d74a2d 100644 --- a/src/processTargets/modifiers/ParagraphStage.ts +++ b/src/processTargets/modifiers/ParagraphStage.ts @@ -10,10 +10,10 @@ import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} - run(context: ProcessedTargetsContext, selection: Target): Target { - const { document } = selection.editor; + run(context: ProcessedTargetsContext, target: Target): Target { + const { document } = target.editor; - let startLine = document.lineAt(selection.contentRange.start); + let startLine = document.lineAt(target.contentRange.start); if (!startLine.isEmptyOrWhitespace) { while (startLine.lineNumber > 0) { const line = document.lineAt(startLine.lineNumber - 1); @@ -24,7 +24,7 @@ export default class implements ModifierStage { } } const lineCount = document.lineCount; - let endLine = document.lineAt(selection.contentRange.end); + let endLine = document.lineAt(target.contentRange.end); if (!endLine.isEmptyOrWhitespace) { while (endLine.lineNumber + 1 < lineCount) { const line = document.lineAt(endLine.lineNumber + 1); @@ -41,9 +41,11 @@ export default class implements ModifierStage { ); const end = endLine.range.end; + const contentRange = new Range(start, end); + const removalRange = new Range( new Position(start.line, 0), - selection.editor.document.lineAt(end).range.end + target.editor.document.lineAt(end).range.end ); const leadingLine = getPreviousNonEmptyLine(document, start.line); @@ -71,14 +73,13 @@ export default class implements ModifierStage { : undefined; return { - ...selection, + editor: target.editor, + isReversed: target.isReversed, delimiter: "\n\n", - contentRange: new Range(start, end), + contentRange, removalRange, leadingDelimiterRange, trailingDelimiterRange, - interiorRange: undefined, - boundary: undefined, }; } } diff --git a/src/processTargets/modifiers/PositionStage.ts b/src/processTargets/modifiers/PositionStage.ts index 4327e84ca9..3b4dadab2d 100644 --- a/src/processTargets/modifiers/PositionStage.ts +++ b/src/processTargets/modifiers/PositionStage.ts @@ -1,4 +1,4 @@ -import * as vscode from "vscode"; +import { Range } from "vscode"; import { PositionModifier, Target } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; @@ -6,30 +6,30 @@ import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { constructor(private modifier: PositionModifier) {} - run(context: ProcessedTargetsContext, selection: Target): Target { - const res: Target = { - ...selection, - leadingDelimiterRange: undefined, - trailingDelimiterRange: undefined, + run(context: ProcessedTargetsContext, target: Target): Target { + const res = { + editor: target.editor, + isReversed: false, }; switch (this.modifier.position) { case "before": case "start": - res.contentRange = range(res.contentRange.start)!; - res.interiorRange = range(res.interiorRange?.start); - res.removalRange = range(res.removalRange?.start); - break; + return { + ...res, + contentRange: new Range( + target.contentRange.start, + target.contentRange.start + ), + }; case "after": case "end": - res.contentRange = range(res.contentRange.end)!; - res.interiorRange = range(res.interiorRange?.end); - res.removalRange = range(res.removalRange?.end); - break; + return { + ...res, + contentRange: new Range( + target.contentRange.end, + target.contentRange.end + ), + }; } - return res; } } - -function range(position?: vscode.Position) { - return position ? new vscode.Range(position, position) : undefined; -} diff --git a/src/processTargets/modifiers/RawSelectionStage.ts b/src/processTargets/modifiers/RawSelectionStage.ts index 9a01231eb8..1f7a79007b 100644 --- a/src/processTargets/modifiers/RawSelectionStage.ts +++ b/src/processTargets/modifiers/RawSelectionStage.ts @@ -5,7 +5,11 @@ import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { constructor(private modifier: RawSelectionModifier) {} - run(context: ProcessedTargetsContext, selection: Target): Target { - return { ...selection, isRawSelection: true }; + run(context: ProcessedTargetsContext, target: Target): Target { + return { + editor: target.editor, + contentRange: target.contentRange, + isReversed: target.isReversed, + }; } } diff --git a/src/processTargets/modifiers/RegexStage.ts b/src/processTargets/modifiers/RegexStage.ts index 48e66e1d46..649b86d7ed 100644 --- a/src/processTargets/modifiers/RegexStage.ts +++ b/src/processTargets/modifiers/RegexStage.ts @@ -1,4 +1,4 @@ -import { Position, Range } from "vscode"; +import { Position, Range, TextEditor } from "vscode"; import { ContainingScopeModifier, EveryScopeModifier, @@ -11,42 +11,41 @@ import { getTokenContext } from "./TokenStage"; class RegexStage implements ModifierStage { constructor(private regex: RegExp, private name?: string) {} - run(context: ProcessedTargetsContext, selection: Target): Target { - const getMatch = (position: Position) => { - const line = selection.editor.document.lineAt(position); - const result = [...line.text.matchAll(this.regex)] - .map( - (match) => - new Range( - position.line, - match.index!, - position.line, - match.index! + match[0].length - ) - ) - .find((range) => range.contains(position)); - if (result == null) { - if (this.name) { - throw new Error(`Couldn't find containing ${this.name}`); - } else { - throw new Error( - `Cannot find sequence defined by regex: ${this.regex}` - ); - } - } - return result; - }; - - const start = getMatch(selection.contentRange.start).start; - const end = getMatch(selection.contentRange.end).end; + run(context: ProcessedTargetsContext, target: Target): Target { + const { editor } = target; + const start = this.getMatch(editor, target.contentRange.start).start; + const end = this.getMatch(editor, target.contentRange.end).end; const contentRange = new Range(start, end); - return { - ...selection, + editor, + isReversed: target.isReversed, contentRange, - ...getTokenContext(selection.editor, contentRange), + ...getTokenContext(target.editor, contentRange), }; } + + getMatch(editor: TextEditor, position: Position) { + const line = editor.document.lineAt(position); + const result = [...line.text.matchAll(this.regex)] + .map( + (match) => + new Range( + position.line, + match.index!, + position.line, + match.index! + match[0].length + ) + ) + .find((range) => range.contains(position)); + if (result == null) { + if (this.name) { + throw new Error(`Couldn't find containing ${this.name}`); + } else { + throw new Error(`Cannot find sequence defined by regex: ${this.regex}`); + } + } + return result; + } } export class NonWhitespaceSequenceStage extends RegexStage { diff --git a/src/processTargets/modifiers/SubPieceStage.ts b/src/processTargets/modifiers/SubPieceStage.ts index 3cda3ee3e0..8c5ea8ad94 100644 --- a/src/processTargets/modifiers/SubPieceStage.ts +++ b/src/processTargets/modifiers/SubPieceStage.ts @@ -8,8 +8,8 @@ import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { constructor(private modifier: SubTokenModifier) {} - run(context: ProcessedTargetsContext, selection: Target): Target { - const token = selection.editor.document.getText(selection.contentRange); + run(context: ProcessedTargetsContext, target: Target): Target { + const token = target.editor.document.getText(target.contentRange); let pieces: { start: number; end: number }[] = []; if (this.modifier.excludeActive || this.modifier.excludeAnchor) { @@ -48,11 +48,11 @@ export default class implements ModifierStage { const isReversed = activeIndex < anchorIndex; - const anchor = selection.contentRange.start.translate( + const anchor = target.contentRange.start.translate( undefined, isReversed ? pieces[anchorIndex].end : pieces[anchorIndex].start ); - const active = selection.contentRange.start.translate( + const active = target.contentRange.start.translate( undefined, isReversed ? pieces[activeIndex].start : pieces[activeIndex].end ); @@ -62,10 +62,10 @@ export default class implements ModifierStage { const leadingDelimiterRange = startIndex > 0 && pieces[startIndex - 1].end < pieces[startIndex].start ? new Range( - selection.contentRange.start.translate({ + target.contentRange.start.translate({ characterDelta: pieces[startIndex - 1].end, }), - selection.contentRange.start.translate({ + target.contentRange.start.translate({ characterDelta: pieces[startIndex].start, }) ) @@ -74,10 +74,10 @@ export default class implements ModifierStage { endIndex + 1 < pieces.length && pieces[endIndex].end < pieces[endIndex + 1].start ? new Range( - selection.contentRange.start.translate({ + target.contentRange.start.translate({ characterDelta: pieces[endIndex].end, }), - selection.contentRange.start.translate({ + target.contentRange.start.translate({ characterDelta: pieces[endIndex + 1].start, }) ) @@ -85,18 +85,16 @@ export default class implements ModifierStage { const isInDelimitedList = leadingDelimiterRange != null || trailingDelimiterRange != null; const containingListDelimiter = isInDelimitedList - ? selection.editor.document.getText( + ? target.editor.document.getText( (leadingDelimiterRange ?? trailingDelimiterRange)! ) : undefined; return { - ...selection, + editor: target.editor, isReversed, contentRange: new Range(anchor, active), - interiorRange: undefined, - removalRange: undefined, - delimiter: containingListDelimiter ?? undefined, + delimiter: containingListDelimiter, leadingDelimiterRange, trailingDelimiterRange, }; diff --git a/src/processTargets/modifiers/SurroundingPairStage.ts b/src/processTargets/modifiers/SurroundingPairStage.ts index d41c107356..477167972e 100644 --- a/src/processTargets/modifiers/SurroundingPairStage.ts +++ b/src/processTargets/modifiers/SurroundingPairStage.ts @@ -31,13 +31,13 @@ import { findSurroundingPairTextBased } from "./surroundingPair/findSurroundingP export default class implements ModifierStage { constructor(private modifier: SurroundingPairModifier) {} - run(context: ProcessedTargetsContext, selection: Target): Target | Target[] { - const pairs = processSurroundingPair(context, this.modifier, selection); + run(context: ProcessedTargetsContext, target: Target): Target[] { + const pairs = processSurroundingPair(context, this.modifier, target); if (pairs == null) { throw new Error("Couldn't find containing pair"); } return pairs.map((pair) => ({ - ...selection, + isReversed: target.isReversed, editor: pair.selection.editor, contentRange: pair.selection.selection, interiorRange: pair.context.interior?.at(0)?.selection, diff --git a/src/processTargets/modifiers/TokenStage.ts b/src/processTargets/modifiers/TokenStage.ts index 8741632069..dcc871dd86 100644 --- a/src/processTargets/modifiers/TokenStage.ts +++ b/src/processTargets/modifiers/TokenStage.ts @@ -10,10 +10,12 @@ import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} - run(context: ProcessedTargetsContext, selection: Target): Target { + run(context: ProcessedTargetsContext, target: Target): Target { return { - ...selection, - ...getTokenContext(selection.editor, selection.contentRange), + editor: target.editor, + isReversed: target.isReversed, + contentRange: target.contentRange, + ...getTokenContext(target.editor, target.contentRange), }; } } @@ -62,7 +64,6 @@ export function getTokenContext( removalRange: undefined, interiorRange: undefined, boundary: undefined, - isRawSelection: undefined, leadingDelimiterRange: isInDelimitedList ? leadingDelimiterRange : undefined, diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index d989923823..18a19c940d 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -247,14 +247,7 @@ export interface Target { /** * If true active is before anchor */ - isReversed?: boolean; - - /** - * Indicates that this is a raw selection with no type information so for - * example if it is the destination of a bring or move it should inherit the - * type information such as delimiters from its source - */ - isRawSelection?: boolean; + isReversed: boolean; /** * If true this selection is part of a notebook cell diff --git a/src/util/targetUtils.ts b/src/util/targetUtils.ts index d089f66bc9..dcc5ef3649 100644 --- a/src/util/targetUtils.ts +++ b/src/util/targetUtils.ts @@ -90,5 +90,6 @@ function createTypeSelection( return { editor, contentRange: new Range(start, end), + isReversed: false, }; } From 960acecd18fd9f93ac83d91979aac75833930c07 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 15 May 2022 15:58:01 +0200 Subject: [PATCH 032/314] Added interior and boundary modifiers --- .../src/modifiers/surrounding_pair.py | 1 + .../upgradeV1ToV2/upgradeV1ToV2.ts | 20 +++- src/processTargets/getModifierStage.ts | 6 + src/processTargets/modifiers/BoundaryStage.ts | 18 +++ src/processTargets/modifiers/InteriorStage.ts | 18 +++ .../modifiers/SurroundingPairStage.ts | 105 +++--------------- ...ractSelectionFromSurroundingPairOffsets.ts | 43 +++---- .../findSurroundingPairParseTreeBased.ts | 6 +- .../findSurroundingPairTextBased.ts | 6 +- .../modifiers/surroundingPair/index.ts | 3 - .../updateSurroundingPairTest.ts | 29 ++--- src/typings/target.types.ts | 21 ++-- 12 files changed, 117 insertions(+), 159 deletions(-) create mode 100644 src/processTargets/modifiers/BoundaryStage.ts create mode 100644 src/processTargets/modifiers/InteriorStage.ts diff --git a/cursorless-talon/src/modifiers/surrounding_pair.py b/cursorless-talon/src/modifiers/surrounding_pair.py index bf170718dc..f9f3302afc 100644 --- a/cursorless-talon/src/modifiers/surrounding_pair.py +++ b/cursorless-talon/src/modifiers/surrounding_pair.py @@ -64,6 +64,7 @@ def cursorless_surrounding_pair(m) -> dict[str, Any]: "delimiter": surrounding_pair_scope_type, } + # TODO make as own modifier stage try: modifier["delimiterInclusion"] = m.cursorless_delimiter_inclusion except AttributeError: diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts index 9f410f31cb..d337af285d 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts @@ -28,10 +28,11 @@ export function upgradeV1ToV2(command: CommandV1): CommandV2 { }; } -function upgradeModifier(modifier: ModifierV0V1): Modifier | null { +function upgradeModifier(modifier: ModifierV0V1): Modifier | Modifier[] | null { switch (modifier.type) { case "identity": return null; + case "containingScope": const mod = { ...modifier, @@ -44,6 +45,17 @@ function upgradeModifier(modifier: ModifierV0V1): Modifier | null { }; } return mod; + + case "surroundingPair": + const { delimiterInclusion, ...rest } = modifier; + if (delimiterInclusion === "interiorOnly") { + return [rest, { type: "interior" }]; + } + if (delimiterInclusion === "excludeInterior") { + return [rest, { type: "boundary" }]; + } + return rest; + default: return modifier; } @@ -64,7 +76,11 @@ function upgradePrimitiveTarget( if (modifier) { const mod = upgradeModifier(modifier); if (mod) { - modifiers.push(mod); + if (Array.isArray(mod)) { + modifiers.push(...mod); + } else { + modifiers.push(mod); + } } } if (isImplicit) { diff --git a/src/processTargets/getModifierStage.ts b/src/processTargets/getModifierStage.ts index 5fc5f09d59..4929be6c90 100644 --- a/src/processTargets/getModifierStage.ts +++ b/src/processTargets/getModifierStage.ts @@ -3,9 +3,11 @@ import { EveryScopeModifier, Modifier, } from "../typings/target.types"; +import BoundaryStage from "./modifiers/BoundaryStage"; import ContainingScopeStage from "./modifiers/ContainingScopeStage"; import DocumentStage from "./modifiers/DocumentStage"; import { HeadStage, TailStage } from "./modifiers/HeadTailStage"; +import InteriorStage from "./modifiers/InteriorStage"; import LineStage from "./modifiers/LineStage"; import NotebookCellStage from "./modifiers/NotebookCellStage"; import ParagraphStage from "./modifiers/ParagraphStage"; @@ -31,6 +33,10 @@ export default (modifier: Modifier): ModifierStage => { return new SubPieceStage(modifier); case "surroundingPair": return new SurroundingPairStage(modifier); + case "interior": + return new InteriorStage(modifier); + case "boundary": + return new BoundaryStage(modifier); case "containingScope": case "everyScope": return getContainingScopeStage(modifier); diff --git a/src/processTargets/modifiers/BoundaryStage.ts b/src/processTargets/modifiers/BoundaryStage.ts new file mode 100644 index 0000000000..263df4c8ad --- /dev/null +++ b/src/processTargets/modifiers/BoundaryStage.ts @@ -0,0 +1,18 @@ +import { BoundaryModifier, Target } from "../../typings/target.types"; +import { ProcessedTargetsContext } from "../../typings/Types"; +import { ModifierStage } from "../PipelineStages.types"; + +export default class implements ModifierStage { + constructor(private modifier: BoundaryModifier) {} + + run(context: ProcessedTargetsContext, target: Target): Target[] { + if (target.boundary == null) { + throw Error("No available boundary"); + } + return target.boundary.map((contentRange) => ({ + editor: target.editor, + isReversed: target.isReversed, + contentRange, + })); + } +} diff --git a/src/processTargets/modifiers/InteriorStage.ts b/src/processTargets/modifiers/InteriorStage.ts new file mode 100644 index 0000000000..02ef006f33 --- /dev/null +++ b/src/processTargets/modifiers/InteriorStage.ts @@ -0,0 +1,18 @@ +import { InteriorModifier, Target } from "../../typings/target.types"; +import { ProcessedTargetsContext } from "../../typings/Types"; +import { ModifierStage } from "../PipelineStages.types"; + +export default class implements ModifierStage { + constructor(private modifier: InteriorModifier) {} + + run(context: ProcessedTargetsContext, target: Target): Target { + if (target.interiorRange == null) { + throw Error("No available interior"); + } + return { + editor: target.editor, + isReversed: target.isReversed, + contentRange: target.interiorRange, + }; + } +} diff --git a/src/processTargets/modifiers/SurroundingPairStage.ts b/src/processTargets/modifiers/SurroundingPairStage.ts index 477167972e..fdecb4fe52 100644 --- a/src/processTargets/modifiers/SurroundingPairStage.ts +++ b/src/processTargets/modifiers/SurroundingPairStage.ts @@ -1,19 +1,8 @@ -import * as vscode from "vscode"; import { Selection } from "vscode"; -import { SyntaxNode } from "web-tree-sitter"; -import getTextFragmentExtractor, { - TextFragmentExtractor, -} from "../../languages/getTextFragmentExtractor"; -import { - ComplexSurroundingPairName, - SurroundingPairModifier, - Target, -} from "../../typings/target.types"; +import { SurroundingPairModifier, Target } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; -import { complexDelimiterMap } from "./surroundingPair/delimiterMaps"; -import { findSurroundingPairParseTreeBased } from "./surroundingPair/findSurroundingPairParseTreeBased"; -import { findSurroundingPairTextBased } from "./surroundingPair/findSurroundingPairTextBased"; +import { processSurroundingPair } from "./surroundingPair"; /** * Applies the surrounding pair modifier to the given selection. First looks to @@ -32,7 +21,18 @@ export default class implements ModifierStage { constructor(private modifier: SurroundingPairModifier) {} run(context: ProcessedTargetsContext, target: Target): Target[] { - const pairs = processSurroundingPair(context, this.modifier, target); + const selectionWithEditor = { + editor: target.editor, + selection: new Selection( + target.contentRange.start, + target.contentRange.end + ), + }; + const pairs = processSurroundingPair( + context, + selectionWithEditor, + this.modifier + ); if (pairs == null) { throw new Error("Couldn't find containing pair"); } @@ -42,8 +42,6 @@ export default class implements ModifierStage { contentRange: pair.selection.selection, interiorRange: pair.context.interior?.at(0)?.selection, removalRange: pair.context.outerSelection ?? undefined, - isRawSelection: pair.context.isRawSelection, - isNotebookCell: pair.context.isNotebookCell, delimiter: pair.context.containingListDelimiter ?? undefined, boundary: pair.context.boundary?.map((bound) => bound.selection), leadingDelimiterRange: pair.context.leadingDelimiterRange ?? undefined, @@ -51,78 +49,3 @@ export default class implements ModifierStage { })); } } - -function processSurroundingPair( - context: ProcessedTargetsContext, - modifier: SurroundingPairModifier, - selection: Target -) { - const document = selection.editor.document; - const delimiters = complexDelimiterMap[ - modifier.delimiter as ComplexSurroundingPairName - ] ?? [modifier.delimiter]; - - let node: SyntaxNode | null; - let textFragmentExtractor: TextFragmentExtractor; - - try { - node = context.getNodeAtLocation( - new vscode.Location(document.uri, selection.contentRange) - ); - - textFragmentExtractor = getTextFragmentExtractor(document.languageId); - } catch (err) { - if ((err as Error).name === "UnsupportedLanguageError") { - // If we're in a language where we don't have a parse tree we use the text - // based algorithm - return findSurroundingPairTextBased( - selection.editor, - selection.contentRange, - null, - delimiters, - modifier.delimiterInclusion, - modifier.forceDirection - ); - } else { - throw err; - } - } - - const selectionWithEditor = { - editor: selection.editor, - selection: new Selection( - selection.contentRange.start, - selection.contentRange.end - ), - }; - - // If we have a parse tree but we are in a string node or in a comment node, - // then we use the text-based algorithm - const textFragmentRange = textFragmentExtractor(node, selectionWithEditor); - if (textFragmentRange != null) { - const surroundingRange = findSurroundingPairTextBased( - selection.editor, - selection.contentRange, - textFragmentRange, - delimiters, - modifier.delimiterInclusion, - modifier.forceDirection - ); - - if (surroundingRange != null) { - return surroundingRange; - } - } - - // If we have a parse tree and either we are not in a string or comment or we - // couldn't find a surrounding pair within a string or comment, we use the - // parse tree-based algorithm - return findSurroundingPairParseTreeBased( - selection.editor, - selection.contentRange, - node, - delimiters, - modifier.delimiterInclusion, - modifier.forceDirection - ); -} diff --git a/src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts b/src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts index b949d66a15..e24fc05f60 100644 --- a/src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts +++ b/src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts @@ -1,6 +1,5 @@ import { Selection, TextDocument } from "vscode"; import { SelectionWithContext } from "../../../typings/Types"; -import { DelimiterInclusion } from "../../../typings/target.types"; import { SurroundingPairOffsets } from "./types"; /** @@ -15,8 +14,7 @@ import { SurroundingPairOffsets } from "./types"; export function extractSelectionFromSurroundingPairOffsets( document: TextDocument, baseOffset: number, - surroundingPairOffsets: SurroundingPairOffsets, - delimiterInclusion: DelimiterInclusion + surroundingPairOffsets: SurroundingPairOffsets ): SelectionWithContext[] { const interior = [ { @@ -57,31 +55,20 @@ export function extractSelectionFromSurroundingPairOffsets( }, ]; - // If delimiter inclusion is null, do default behavior and include the - // delimiters - if (delimiterInclusion == null) { - return [ - { - selection: new Selection( - document.positionAt( - baseOffset + surroundingPairOffsets.leftDelimiter.start - ), - document.positionAt( - baseOffset + surroundingPairOffsets.rightDelimiter.end - ) + return [ + { + selection: new Selection( + document.positionAt( + baseOffset + surroundingPairOffsets.leftDelimiter.start ), - context: { - boundary, - interior, - }, + document.positionAt( + baseOffset + surroundingPairOffsets.rightDelimiter.end + ) + ), + context: { + boundary, + interior, }, - ]; - } - - switch (delimiterInclusion) { - case "interiorOnly": - return interior; - case "excludeInterior": - return boundary; - } + }, + ]; } diff --git a/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts b/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts index c118d0e0f1..a96c3a7bf4 100644 --- a/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts +++ b/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts @@ -1,7 +1,6 @@ import { Range, TextDocument, TextEditor } from "vscode"; import { SyntaxNode } from "web-tree-sitter"; import { - DelimiterInclusion, SimpleSurroundingPairName, SurroundingPairDirection, } from "../../../typings/target.types"; @@ -56,7 +55,6 @@ import { * @param selection The selection to find surrounding pair around * @param node A parse tree node overlapping with the selection * @param delimiters The acceptable surrounding pair names - * @param delimiterInclusion Whether to include / exclude the delimiters themselves * @returns The newly expanded selection, including editor info */ export function findSurroundingPairParseTreeBased( @@ -64,7 +62,6 @@ export function findSurroundingPairParseTreeBased( selection: Range, node: SyntaxNode, delimiters: SimpleSurroundingPairName[], - delimiterInclusion: DelimiterInclusion, forceDirection: "left" | "right" | undefined ) { const document: TextDocument = editor.document; @@ -118,8 +115,7 @@ export function findSurroundingPairParseTreeBased( return extractSelectionFromSurroundingPairOffsets( document, 0, - pairOffsets, - delimiterInclusion + pairOffsets ).map(({ selection, context }) => ({ selection: { selection, editor }, context, diff --git a/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts b/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts index a83e5f48b0..a4cdf7772b 100644 --- a/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts +++ b/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts @@ -1,7 +1,6 @@ import { escapeRegExp, findLast, uniq } from "lodash"; import { Range, TextDocument, TextEditor } from "vscode"; import { - DelimiterInclusion, SimpleSurroundingPairName, SurroundingPairDirection, SurroundingPairName, @@ -64,7 +63,6 @@ const SCAN_EXPANSION_FACTOR = 3; * @param allowableRange The range in which to look for delimiters, or the * entire document if `null` * @param delimiters The acceptable surrounding pair names - * @param delimiterInclusion Whether to include / exclude the delimiters themselves * @returns The newly expanded selection, including editor info */ export function findSurroundingPairTextBased( @@ -72,7 +70,6 @@ export function findSurroundingPairTextBased( selection: Range, allowableRange: Range | null, delimiters: SimpleSurroundingPairName[], - delimiterInclusion: DelimiterInclusion, forceDirection: "left" | "right" | undefined ) { const document: TextDocument = editor.document; @@ -168,8 +165,7 @@ export function findSurroundingPairTextBased( return extractSelectionFromSurroundingPairOffsets( document, currentRangeOffsets.start, - pairOffsets, - delimiterInclusion + pairOffsets ).map(({ selection, context }) => ({ selection: { selection, editor }, context, diff --git a/src/processTargets/modifiers/surroundingPair/index.ts b/src/processTargets/modifiers/surroundingPair/index.ts index 1305f02b28..bba26bfbd0 100644 --- a/src/processTargets/modifiers/surroundingPair/index.ts +++ b/src/processTargets/modifiers/surroundingPair/index.ts @@ -57,7 +57,6 @@ export function processSurroundingPair( selection.selection, null, delimiters, - modifier.delimiterInclusion, modifier.forceDirection ); } else { @@ -74,7 +73,6 @@ export function processSurroundingPair( selection.selection, textFragmentRange, delimiters, - modifier.delimiterInclusion, modifier.forceDirection ); @@ -91,7 +89,6 @@ export function processSurroundingPair( selection.selection, node, delimiters, - modifier.delimiterInclusion, modifier.forceDirection ); } diff --git a/src/scripts/transformRecordedTests/transformations/updateSurroundingPairTest.ts b/src/scripts/transformRecordedTests/transformations/updateSurroundingPairTest.ts index 20c17f4b4b..1a1032ab06 100644 --- a/src/scripts/transformRecordedTests/transformations/updateSurroundingPairTest.ts +++ b/src/scripts/transformRecordedTests/transformations/updateSurroundingPairTest.ts @@ -1,7 +1,6 @@ import { TestCaseFixture } from "../../../testUtil/TestCase"; import { transformPartialPrimitiveTargets } from "../../../util/getPrimitiveTargets"; import { - DelimiterInclusion, PartialPrimitiveTargetDesc, } from "../../../typings/target.types"; @@ -12,21 +11,23 @@ export function updateSurroundingPairTest(fixture: TestCaseFixture) { (target: PartialPrimitiveTargetDesc) => { target.modifiers?.forEach((modifier) => { if (modifier?.type === "surroundingPair") { - let delimiterInclusion: DelimiterInclusion; + + // TODO + // let delimiterInclusion: DelimiterInclusion; - switch (modifier.delimiterInclusion as any) { - case "includeDelimiters": - delimiterInclusion = undefined; - break; - case "excludeDelimiters": - delimiterInclusion = "interiorOnly"; - break; - case "delimitersOnly": - delimiterInclusion = "excludeInterior"; - break; - } + // switch (modifier.delimiterInclusion as any) { + // case "includeDelimiters": + // delimiterInclusion = undefined; + // break; + // case "excludeDelimiters": + // delimiterInclusion = "interiorOnly"; + // break; + // case "delimitersOnly": + // delimiterInclusion = "excludeInterior"; + // break; + // } - modifier.delimiterInclusion = delimiterInclusion; + // modifier.delimiterInclusion = delimiterInclusion; } }); diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 18a19c940d..9f4a0dfc74 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -117,24 +117,21 @@ export type ScopeType = export type SubTokenType = "word" | "character"; -/** - * Indicates whether to include or exclude delimiters in a surrounding pair - * modifier. In the future, these will become proper modifiers that can be - * applied in many places, such as to restrict to the body of an if statement. - * By default, a surrounding pair modifier refers to the entire surrounding - * range, so if delimiter inclusion is undefined, it's equivalent to not having - * one of these modifiers; ie include the delimiters. - */ -export type DelimiterInclusion = "excludeInterior" | "interiorOnly" | undefined; - export type SurroundingPairDirection = "left" | "right"; export interface SurroundingPairModifier { type: "surroundingPair"; delimiter: SurroundingPairName; - delimiterInclusion: DelimiterInclusion; forceDirection?: SurroundingPairDirection; } +export interface InteriorModifier { + type: "interior"; +} + +export interface BoundaryModifier { + type: "boundary"; +} + export interface ContainingScopeModifier { type: "containingScope"; scopeType: ScopeType; @@ -187,6 +184,8 @@ export interface PartialPrimitiveTargetDesc { export type Modifier = | PositionModifier | SurroundingPairModifier + | InteriorModifier + | BoundaryModifier | ContainingScopeModifier | EveryScopeModifier | SubTokenModifier From 79d62756a3257bdd39c8dd1b4d4e4a00f474c9fa Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 15 May 2022 13:58:23 +0000 Subject: [PATCH 033/314] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../transformations/updateSurroundingPairTest.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/scripts/transformRecordedTests/transformations/updateSurroundingPairTest.ts b/src/scripts/transformRecordedTests/transformations/updateSurroundingPairTest.ts index 1a1032ab06..840d793f79 100644 --- a/src/scripts/transformRecordedTests/transformations/updateSurroundingPairTest.ts +++ b/src/scripts/transformRecordedTests/transformations/updateSurroundingPairTest.ts @@ -1,8 +1,6 @@ import { TestCaseFixture } from "../../../testUtil/TestCase"; import { transformPartialPrimitiveTargets } from "../../../util/getPrimitiveTargets"; -import { - PartialPrimitiveTargetDesc, -} from "../../../typings/target.types"; +import { PartialPrimitiveTargetDesc } from "../../../typings/target.types"; // Leaving an example here in case it's helpful export function updateSurroundingPairTest(fixture: TestCaseFixture) { @@ -11,10 +9,8 @@ export function updateSurroundingPairTest(fixture: TestCaseFixture) { (target: PartialPrimitiveTargetDesc) => { target.modifiers?.forEach((modifier) => { if (modifier?.type === "surroundingPair") { - // TODO // let delimiterInclusion: DelimiterInclusion; - // switch (modifier.delimiterInclusion as any) { // case "includeDelimiters": // delimiterInclusion = undefined; @@ -26,7 +22,6 @@ export function updateSurroundingPairTest(fixture: TestCaseFixture) { // delimiterInclusion = "excludeInterior"; // break; // } - // modifier.delimiterInclusion = delimiterInclusion; } }); From 32d13f83e19ead82b8d4c4fcbd4bd9085b0c61e0 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 15 May 2022 16:02:00 +0200 Subject: [PATCH 034/314] Updated upgrade --- .../upgradeV1ToV2/upgradeV1ToV2.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts index d337af285d..2233905705 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts @@ -73,6 +73,11 @@ function upgradePrimitiveTarget( ...rest } = target; const modifiers: Modifier[] = []; + + if (isImplicit) { + modifiers.push({ type: "toRawSelection" }); + } + if (modifier) { const mod = upgradeModifier(modifier); if (mod) { @@ -83,17 +88,18 @@ function upgradePrimitiveTarget( } } } - if (isImplicit) { - modifiers.push({ type: "toRawSelection" }); - } + if (selectionType) { modifiers.push({ type: "containingScope", scopeType: selectionType }); } + if (position && position !== "contents") { modifiers.push({ type: "position", position: position }); } + // Modifiers are processed backwards modifiers.reverse(); + return { ...rest, modifiers, From f16a8c644fcbf23579865c00b8efe29604e37d3b Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 15 May 2022 16:08:38 +0200 Subject: [PATCH 035/314] Updated migration --- .../upgradeV1ToV2/upgradeV1ToV2.ts | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts index 2233905705..594d2a461c 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts @@ -74,10 +74,6 @@ function upgradePrimitiveTarget( } = target; const modifiers: Modifier[] = []; - if (isImplicit) { - modifiers.push({ type: "toRawSelection" }); - } - if (modifier) { const mod = upgradeModifier(modifier); if (mod) { @@ -93,16 +89,18 @@ function upgradePrimitiveTarget( modifiers.push({ type: "containingScope", scopeType: selectionType }); } + if (isImplicit) { + modifiers.push({ type: "toRawSelection" }); + } + if (position && position !== "contents") { modifiers.push({ type: "position", position: position }); } - // Modifiers are processed backwards - modifiers.reverse(); - return { ...rest, - modifiers, + // Modifiers are processed backwards + modifiers: modifiers.reverse(), }; } From e11d0d2a8a2cb1bfea1d2a5c543b2934fde53640 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 15 May 2022 17:48:02 +0200 Subject: [PATCH 036/314] Added delete action --- src/actions/Actions.ts | 3 +- src/actions/Delete.ts | 115 ++++++++--------- src/actions/SetSelection.ts | 11 +- src/core/commandRunner/CommandRunner.ts | 4 +- src/core/inferFullTargets.ts | 7 +- src/core/updateSelections/updateSelections.ts | 116 ++++++++---------- src/typings/Types.ts | 2 +- src/util/selectionUtils.ts | 14 +++ 8 files changed, 133 insertions(+), 139 deletions(-) diff --git a/src/actions/Actions.ts b/src/actions/Actions.ts index 377d9dae10..aba8b8f440 100644 --- a/src/actions/Actions.ts +++ b/src/actions/Actions.ts @@ -1,4 +1,5 @@ import { ActionRecord, Graph } from "../typings/Types"; +import Delete from "./Delete"; import { SetSelection, SetSelectionAfter, @@ -30,7 +31,7 @@ class Actions implements ActionRecord { // moveToTarget = new Move(this.graph); // outdentLine = new OutdentLines(this.graph); // pasteFromClipboard = new Paste(this.graph); - // remove = new Delete(this.graph); + remove = new Delete(this.graph); // deselect = new Deselect(this.graph); // replace = new Replace(this.graph); // replaceWithTarget = new Bring(this.graph); diff --git a/src/actions/Delete.ts b/src/actions/Delete.ts index d48fea5885..7f5404ab84 100644 --- a/src/actions/Delete.ts +++ b/src/actions/Delete.ts @@ -1,57 +1,60 @@ -// import { -// Action, -// ActionPreferences, -// ActionReturnValue, -// Graph, -// Target, -// } from "../typings/Types"; -// import { runOnTargetsForEachEditor } from "../util/targetUtils"; -// import displayPendingEditDecorations from "../util/editDisplayUtils"; -// import { flatten } from "lodash"; -// import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; +import { flatten } from "lodash"; +import { performEditsAndUpdateRanges } from "../core/updateSelections/updateSelections"; // import { unifyTargets } from "../util/unifyRanges"; - -// export default class Delete implements Action { -// getTargetPreferences: () => ActionPreferences[] = () => [ -// { insideOutsideType: "outside" }, -// ]; - -// constructor(private graph: Graph) { -// this.run = this.run.bind(this); -// } - -// async run( -// [targets]: [Target[]], -// { showDecorations = true } = {} -// ): Promise { -// // Unify overlapping targets. -// targets = unifyTargets(targets); - -// if (showDecorations) { -// await displayPendingEditDecorations( -// targets, -// this.graph.editStyles.pendingDelete -// ); -// } - -// const thatMark = flatten( -// await runOnTargetsForEachEditor(targets, async (editor, targets) => { -// const edits = targets.map((target) => ({ -// range: target.selection.selection, -// text: "", -// })); - -// const [updatedSelections] = await performEditsAndUpdateSelections( -// this.graph.rangeUpdater, -// editor, -// edits, -// [targets.map((target) => target.selection.selection)] -// ); - -// return updatedSelections.map((selection) => ({ editor, selection })); -// }) -// ); - -// return { thatMark }; -// } -// } +import { Target } from "../typings/target.types"; +import { Action, ActionReturnValue, Graph } from "../typings/Types"; +import displayPendingEditDecorations from "../util/editDisplayUtils"; +import { createThatMark } from "../util/selectionUtils"; +import { runOnTargetsForEachEditor } from "../util/targetUtils"; + +export default class Delete implements Action { + constructor(private graph: Graph) { + this.run = this.run.bind(this); + } + + async run( + [targets]: [Target[]], + { showDecorations = true } = {} + ): Promise { + // Unify overlapping targets. + // TODO + // targets = unifyTargets(targets); + + if (showDecorations) { + await displayPendingEditDecorations( + targets, + this.graph.editStyles.pendingDelete + ); + } + + const thatMark = flatten( + await runOnTargetsForEachEditor(targets, async (editor, targets) => { + const ranges = targets.map(getRemovalRange); + const edits = ranges.map((range) => ({ + range, + text: "", + })); + + const [updatedRanges] = await performEditsAndUpdateRanges( + this.graph.rangeUpdater, + editor, + edits, + [ranges] + ); + + return createThatMark(targets, updatedRanges); + }) + ); + + return { thatMark }; + } +} + +function getRemovalRange(target: Target) { + const removalRange = target.removalRange ?? target.contentRange; + const delimiterRange = + target.trailingDelimiterRange ?? target.leadingDelimiterRange; + return delimiterRange != null + ? removalRange.union(delimiterRange) + : removalRange; +} diff --git a/src/actions/SetSelection.ts b/src/actions/SetSelection.ts index beb357b37a..707b02f88a 100644 --- a/src/actions/SetSelection.ts +++ b/src/actions/SetSelection.ts @@ -1,19 +1,10 @@ -import { - Action, - ActionPreferences, - ActionReturnValue, - Graph, -} from "../typings/Types"; +import { Action, ActionReturnValue, Graph } from "../typings/Types"; import { ensureSingleEditor } from "../util/targetUtils"; import { Selection } from "vscode"; import { setSelectionsAndFocusEditor } from "../util/setSelectionsAndFocusEditor"; import { Target } from "../typings/target.types"; export class SetSelection implements Action { - getTargetPreferences: () => ActionPreferences[] = () => [ - { insideOutsideType: "inside" }, - ]; - constructor(private graph: Graph) { this.run = this.run.bind(this); } diff --git a/src/core/commandRunner/CommandRunner.ts b/src/core/commandRunner/CommandRunner.ts index b6731c41a1..f054a8df26 100644 --- a/src/core/commandRunner/CommandRunner.ts +++ b/src/core/commandRunner/CommandRunner.ts @@ -86,7 +86,9 @@ export default class CommandRunner { const targets = inferFullTargets( partialTargets, - action.getTargetPreferences(...extraArgs) + // TODO + [] + // action.getTargetPreferences(...extraArgs) ); if (this.graph.debug.active) { diff --git a/src/core/inferFullTargets.ts b/src/core/inferFullTargets.ts index 1a1ca66b35..8c3792708b 100644 --- a/src/core/inferFullTargets.ts +++ b/src/core/inferFullTargets.ts @@ -23,9 +23,10 @@ export default function inferFullTargets( targets: PartialTargetDesc[], actionPreferences: ActionPreferences[] ): TargetDesc[] { - if (targets.length !== actionPreferences.length) { - throw new Error("Target length is not equal to action preference length"); - } + // TODO + // if (targets.length !== actionPreferences.length) { + // throw new Error("Target length is not equal to action preference length"); + // } return targets.map((target, index) => inferTarget(target, targets.slice(0, index), actionPreferences[index]) diff --git a/src/core/updateSelections/updateSelections.ts b/src/core/updateSelections/updateSelections.ts index db18afeac2..d4a17b15d4 100644 --- a/src/core/updateSelections/updateSelections.ts +++ b/src/core/updateSelections/updateSelections.ts @@ -1,18 +1,13 @@ +import { flatten } from "lodash"; import { - Selection, - TextEditor, - TextDocument, DecorationRangeBehavior, Range, + TextDocument, + TextEditor, } from "vscode"; -import { flatten } from "lodash"; -import { - FullSelectionInfo, - SelectionInfo, -} from "../../typings/updateSelections"; -import { performDocumentEdits } from "../../util/performDocumentEdits"; -import { isForward } from "../../util/selectionUtils"; import { Edit } from "../../typings/Types"; +import { FullRangeInfo, RangeInfo } from "../../typings/updateSelections"; +import { performDocumentEdits } from "../../util/performDocumentEdits"; import { RangeUpdater } from "./RangeUpdater"; /** @@ -20,18 +15,17 @@ import { RangeUpdater } from "./RangeUpdater"; * be passed in to any of the commands that update selections. * * @param document The document containing the selection - * @param selection The selection + * @param range The range * @param rangeBehavior How selection should behave with respect to insertions on either end * @returns An object that can be used for selection tracking */ -export function getSelectionInfo( +export function getRangeInfo( document: TextDocument, - selection: Selection, + range: Range, rangeBehavior: DecorationRangeBehavior -): FullSelectionInfo { +): FullRangeInfo { return { - range: new Range(selection.start, selection.end), - isForward: isForward(selection), + range: new Range(range.start, range.end), expansionBehavior: { start: { type: @@ -49,10 +43,10 @@ export function getSelectionInfo( }, }, offsets: { - start: document.offsetAt(selection.start), - end: document.offsetAt(selection.end), + start: document.offsetAt(range.start), + end: document.offsetAt(range.end), }, - text: document.getText(selection), + text: document.getText(range), }; } @@ -60,30 +54,28 @@ export function getSelectionInfo( * Creates SelectionInfo objects for all selections in a list of lists. * * @param document The document containing the selections - * @param selectionMatrix A list of lists of selections + * @param rangeMatrix A list of lists of selections * @param rangeBehavior How selections should behave with respect to insertions on either end * @returns A list of lists of selection info objects */ -export function selectionsToSelectionInfos( +export function rangesToRangeInfos( document: TextDocument, - selectionMatrix: (readonly Selection[])[], + rangeMatrix: (readonly Range[])[], rangeBehavior: DecorationRangeBehavior = DecorationRangeBehavior.ClosedClosed -): FullSelectionInfo[][] { - return selectionMatrix.map((selections) => - selections.map((selection) => - getSelectionInfo(document, selection, rangeBehavior) - ) +): FullRangeInfo[][] { + return rangeMatrix.map((ranges) => + ranges.map((range) => getRangeInfo(document, range, rangeBehavior)) ); } -function fillOutSelectionInfos( +function fillOutRangeInfos( document: TextDocument, - selectionInfoMatrix: SelectionInfo[][] -): selectionInfoMatrix is FullSelectionInfo[][] { - selectionInfoMatrix.forEach((selectionInfos) => - selectionInfos.map((selectionInfo) => { - const { range } = selectionInfo; - Object.assign(selectionInfo, { + rangeInfoMatrix: RangeInfo[][] +): rangeInfoMatrix is FullRangeInfo[][] { + rangeInfoMatrix.forEach((rangeInfos) => + rangeInfos.map((rangeInfo) => { + const { range } = rangeInfo; + Object.assign(rangeInfo, { offsets: { start: document.offsetAt(range.start), end: document.offsetAt(range.end), @@ -95,13 +87,9 @@ function fillOutSelectionInfos( return true; } -function selectionInfosToSelections( - selectionInfoMatrix: SelectionInfo[][] -): Selection[][] { - return selectionInfoMatrix.map((selectionInfos) => - selectionInfos.map(({ range: { start, end }, isForward }) => - isForward ? new Selection(start, end) : new Selection(end, start) - ) +function rangeInfosToRanges(rangeInfoMatrix: RangeInfo[][]): Range[][] { + return rangeInfoMatrix.map((rangeInfos) => + rangeInfos.map(({ range }) => range) ); } @@ -111,25 +99,22 @@ function selectionInfosToSelections( * @param rangeUpdater A RangeUpdate instance that will perform actual range updating * @param func The function to call * @param document The document containing the selections - * @param selectionMatrix A matrix of selections to update + * @param rangeMatrix A matrix of selections to update * @returns The initial selections updated based upon what happened in the function */ export async function callFunctionAndUpdateSelections( rangeUpdater: RangeUpdater, func: () => Thenable, document: TextDocument, - selectionMatrix: (readonly Selection[])[] -): Promise { - const selectionInfoMatrix = selectionsToSelectionInfos( - document, - selectionMatrix - ); + rangeMatrix: (readonly Range[])[] +): Promise { + const rangeInfoMatrix = rangesToRangeInfos(document, rangeMatrix); return await callFunctionAndUpdateSelectionInfos( rangeUpdater, func, document, - selectionInfoMatrix + rangeInfoMatrix ); } @@ -146,18 +131,18 @@ export async function callFunctionAndUpdateSelectionInfos( rangeUpdater: RangeUpdater, func: () => Thenable, document: TextDocument, - selectionInfoMatrix: FullSelectionInfo[][] + rangeInfoMatrix: FullRangeInfo[][] ) { const unsubscribe = rangeUpdater.registerRangeInfoList( document, - flatten(selectionInfoMatrix) + flatten(rangeInfoMatrix) ); await func(); unsubscribe(); - return selectionInfosToSelections(selectionInfoMatrix); + return rangeInfosToRanges(rangeInfoMatrix); } /** @@ -166,20 +151,17 @@ export async function callFunctionAndUpdateSelectionInfos( * @param rangeUpdater A RangeUpdate instance that will perform actual range updating * @param editor The editor containing the selections * @param edits A list of edits to apply - * @param originalSelections The selections to update + * @param originalRanges The selections to update * @returns The updated selections */ -export async function performEditsAndUpdateSelections( +export async function performEditsAndUpdateRanges( rangeUpdater: RangeUpdater, editor: TextEditor, edits: Edit[], - originalSelections: (readonly Selection[])[] + originalRanges: (readonly Range[])[] ) { const document = editor.document; - const selectionInfoMatrix = selectionsToSelectionInfos( - document, - originalSelections - ); + const selectionInfoMatrix = rangesToRangeInfos(document, originalRanges); await performEditsAndUpdateFullSelectionInfos( rangeUpdater, @@ -188,7 +170,7 @@ export async function performEditsAndUpdateSelections( selectionInfoMatrix ); - return selectionInfosToSelections(selectionInfoMatrix); + return rangeInfosToRanges(selectionInfoMatrix); } // TODO: Remove this function if we don't end up using it for the next couple use cases, eg `that` mark and cursor history @@ -196,15 +178,15 @@ export async function performEditsAndUpdateSelectionInfos( rangeUpdater: RangeUpdater, editor: TextEditor, edits: Edit[], - originalSelectionInfos: SelectionInfo[][] + originalRangeInfos: RangeInfo[][] ) { - fillOutSelectionInfos(editor.document, originalSelectionInfos); + fillOutRangeInfos(editor.document, originalRangeInfos); return await performEditsAndUpdateFullSelectionInfos( rangeUpdater, editor, edits, - originalSelectionInfos as FullSelectionInfo[][] + originalRangeInfos as FullRangeInfo[][] ); } @@ -214,14 +196,14 @@ export async function performEditsAndUpdateSelectionInfos( * @param rangeUpdater A RangeUpdate instance that will perform actual range updating * @param editor The editor containing the selections * @param edits A list of edits to apply - * @param originalSelectionInfos The selection info objects to update + * @param originalRangeInfos The selection info objects to update * @returns The updated selections */ export async function performEditsAndUpdateFullSelectionInfos( rangeUpdater: RangeUpdater, editor: TextEditor, edits: Edit[], - originalSelectionInfos: FullSelectionInfo[][] + originalRangeInfos: FullRangeInfo[][] ) { // NB: We do everything using VSCode listeners. We can associate changes // with our changes just by looking at their offets / text in order to @@ -262,8 +244,8 @@ export async function performEditsAndUpdateFullSelectionInfos( rangeUpdater, func, editor.document, - originalSelectionInfos + originalRangeInfos ); - return selectionInfosToSelections(originalSelectionInfos); + return rangeInfosToRanges(originalRangeInfos); } diff --git a/src/typings/Types.ts b/src/typings/Types.ts index e801d57fb8..bf81098e13 100644 --- a/src/typings/Types.ts +++ b/src/typings/Types.ts @@ -108,7 +108,7 @@ export interface Action { * Used to define default values for parts of target during inference. * @param args Extra args to command */ - getTargetPreferences(...args: any[]): ActionPreferences[]; + // getTargetPreferences(...args: any[]): ActionPreferences[]; } export type ActionType = diff --git a/src/util/selectionUtils.ts b/src/util/selectionUtils.ts index 254775ceee..6dddd34362 100644 --- a/src/util/selectionUtils.ts +++ b/src/util/selectionUtils.ts @@ -1,4 +1,6 @@ +import { zip } from "lodash"; import { Position, Range, Selection } from "vscode"; +import { Target } from "../typings/target.types"; import { SelectionWithEditor } from "../typings/Types"; export function isForward(selection: Selection) { @@ -37,3 +39,15 @@ function selectionFromPositions( ? new Selection(start, end) : new Selection(end, start); } + +export function createThatMark( + targets: Target[], + ranges: Range[] +): SelectionWithEditor[] { + return zip(targets, ranges).map(([target, range]) => ({ + editor: target!.editor, + selection: target?.isReversed + ? new Selection(range!.end, range!.start) + : new Selection(range!.start, range!.end), + })); +} From 0eb862fbcea520b44d908f283af99ddeaf910b8f Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 15 May 2022 21:02:41 +0200 Subject: [PATCH 037/314] Added highlights range to target --- src/actions/Delete.ts | 15 +++- src/processTargets/modifiers/DocumentStage.ts | 1 + src/processTargets/modifiers/LineStage.ts | 12 +++ .../modifiers/ParagraphStage.ts | 74 ++++++++++++++----- src/typings/target.types.ts | 15 ++++ src/util/editDisplayUtils.ts | 63 ++++++---------- src/util/targetUtils.ts | 2 +- 7 files changed, 118 insertions(+), 64 deletions(-) diff --git a/src/actions/Delete.ts b/src/actions/Delete.ts index 7f5404ab84..9b828edb4c 100644 --- a/src/actions/Delete.ts +++ b/src/actions/Delete.ts @@ -23,7 +23,8 @@ export default class Delete implements Action { if (showDecorations) { await displayPendingEditDecorations( targets, - this.graph.editStyles.pendingDelete + this.graph.editStyles.pendingDelete, + getRemovalHighlightRange ); } @@ -58,3 +59,15 @@ function getRemovalRange(target: Target) { ? removalRange.union(delimiterRange) : removalRange; } + +function getRemovalHighlightRange(target: Target) { + const removalRange = target.removalRange ?? target.contentRange; + const delimiterRange = + target.trailingDelimiterHighlightRange ?? + target.trailingDelimiterRange ?? + target.leadingDelimiterHighlightRange ?? + target.leadingDelimiterRange; + return delimiterRange != null + ? removalRange.union(delimiterRange) + : removalRange; +} diff --git a/src/processTargets/modifiers/DocumentStage.ts b/src/processTargets/modifiers/DocumentStage.ts index 355586ebbe..2e3dee2e3a 100644 --- a/src/processTargets/modifiers/DocumentStage.ts +++ b/src/processTargets/modifiers/DocumentStage.ts @@ -15,6 +15,7 @@ export default class implements ModifierStage { return { editor: target.editor, isReversed: target.isReversed, + scopeType: "document", delimiter: "\n", contentRange: getDocumentContentRange(target.editor.document), removalRange: getDocumentRange(target.editor.document), diff --git a/src/processTargets/modifiers/LineStage.ts b/src/processTargets/modifiers/LineStage.ts index a910ca684f..dc950f8345 100644 --- a/src/processTargets/modifiers/LineStage.ts +++ b/src/processTargets/modifiers/LineStage.ts @@ -45,9 +45,21 @@ export function getLineContext( ? new Range(removalRange.end, new Position(end.line + 1, 0)) : undefined; + const leadingDelimiterHighlightRange = new Range( + removalRange.start, + removalRange.start + ); + const trailingDelimiterHighlightRange = new Range( + removalRange.end, + removalRange.end + ); + return { + scopeType: "line", delimiter: "\n", removalRange, + leadingDelimiterHighlightRange, + trailingDelimiterHighlightRange, leadingDelimiterRange, trailingDelimiterRange, }; diff --git a/src/processTargets/modifiers/ParagraphStage.ts b/src/processTargets/modifiers/ParagraphStage.ts index 2319d74a2d..e283e59027 100644 --- a/src/processTargets/modifiers/ParagraphStage.ts +++ b/src/processTargets/modifiers/ParagraphStage.ts @@ -51,39 +51,73 @@ export default class implements ModifierStage { const leadingLine = getPreviousNonEmptyLine(document, start.line); const trailingLine = getNextNonEmptyLine(document, end.line); - const leadingDelimiterStart = - leadingLine != null - ? leadingLine.range.end - : start.line > 0 - ? new Position(0, 0) - : undefined; - const trailingDelimiterEnd = - trailingLine != null - ? trailingLine.range.start - : end.line < document.lineCount - 1 - ? document.lineAt(document.lineCount - 1).range.end - : undefined; - const leadingDelimiterRange = - leadingDelimiterStart != null - ? new Range(leadingDelimiterStart, removalRange.start) - : undefined; - const trailingDelimiterRange = - trailingDelimiterEnd != null - ? new Range(removalRange.end, trailingDelimiterEnd) - : undefined; + const leadingDelimiterRange = getLeadingDelimiterRange( + document, + removalRange, + leadingLine?.range.end + ); + const trailingDelimiterRange = getTrailingDelimiterRange( + document, + removalRange, + trailingLine?.range.start + ); + + const leadingDelimiterHighlightRange = getLeadingDelimiterRange( + document, + removalRange, + leadingLine ? new Position(leadingLine.range.end.line + 1, 0) : undefined + ); + const trailingDelimiterHighlightRange = getTrailingDelimiterRange( + document, + removalRange, + trailingLine + ? document.lineAt(trailingLine.range.start.line - 1).range.end + : undefined + ); return { editor: target.editor, isReversed: target.isReversed, + scopeType: "paragraph", delimiter: "\n\n", contentRange, removalRange, leadingDelimiterRange, trailingDelimiterRange, + leadingDelimiterHighlightRange, + trailingDelimiterHighlightRange, }; } } +function getLeadingDelimiterRange( + document: TextDocument, + removalRange: Range, + position?: Position +) { + const start = + position != null + ? position + : removalRange.start.line > 0 + ? new Position(0, 0) + : undefined; + return start != null ? new Range(start, removalRange.start) : undefined; +} + +function getTrailingDelimiterRange( + document: TextDocument, + removalRange: Range, + position?: Position +) { + const end = + position != null + ? position + : removalRange.end.line < document.lineCount - 1 + ? document.lineAt(document.lineCount - 1).range.end + : undefined; + return end != null ? new Range(removalRange.end, end) : undefined; +} + function getPreviousNonEmptyLine( document: TextDocument, startLineNumber: number diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 9f4a0dfc74..d8af71d72c 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -253,6 +253,11 @@ export interface Target { */ isNotebookCell?: boolean; + /** + * Is this a scope type other raw selection? + */ + scopeType?: ScopeType; + /** * If this selection has a delimiter. For example, new line for a line or paragraph and comma for a list or argument */ @@ -285,6 +290,16 @@ export interface Target { */ trailingDelimiterRange?: Range; + /** + * The range of the highlight for the leading delimiter + */ + leadingDelimiterHighlightRange?: Range; + + /** + * The range of the highlight for the trailing delimiter + */ + trailingDelimiterHighlightRange?: Range; + /** * Represents the boundary ranges of this selection. For example, for a * surrounding pair this would be the opening and closing delimiter. For an if diff --git a/src/util/editDisplayUtils.ts b/src/util/editDisplayUtils.ts index 6022d99973..430aecd389 100644 --- a/src/util/editDisplayUtils.ts +++ b/src/util/editDisplayUtils.ts @@ -1,4 +1,4 @@ -import { TextEditorDecorationType, window, workspace } from "vscode"; +import { Range, TextEditorDecorationType, window, workspace } from "vscode"; import { EditStyle } from "../core/editStyles"; import isTesting from "../testUtil/isTesting"; import { Target } from "../typings/target.types"; @@ -47,9 +47,10 @@ export async function displayPendingEditDecorationsForSelection( export default async function displayPendingEditDecorations( targets: Target[], - editStyle: EditStyle + editStyle: EditStyle, + getRange: (target: Target) => Range ) { - await setDecorations(targets, editStyle); + await setDecorations(targets, editStyle, getRange); await decorationSleep(); @@ -63,52 +64,30 @@ export function clearDecorations(editStyle: EditStyle) { }); } -export async function setDecorations(targets: Target[], editStyle: EditStyle) { - await runOnTargetsForEachEditor(targets, async (editor, selections) => { +export async function setDecorations( + targets: Target[], + editStyle: EditStyle, + getRange: (target: Target) => Range +) { + await runOnTargetsForEachEditor(targets, async (editor, targets) => { editor.setDecorations( editStyle.token, - selections - .filter((selection) => !useLineDecorations(selection)) - .map((selection) => selection.contentRange) + targets.filter((target) => !useLineDecorations(target)).map(getRange) ); - editor.setDecorations( editStyle.line, - selections - .filter((selection) => useLineDecorations(selection)) - .map((selection) => { - const { document } = selection.editor; - const { start, end } = selection.contentRange; - const startLine = document.lineAt(start); - const hasLeadingLine = - start.character === startLine.range.end.character; - if ( - end.character === 0 && - (!hasLeadingLine || start.character === 0) - ) { - // NB: We move end up one line because it is at beginning of - // next line - return selection.contentRange.with({ - end: end.translate(-1), - }); - } - if (hasLeadingLine) { - // NB: We move start down one line because it is at end of - // previous line - return selection.contentRange.with({ - start: start.translate(1), - }); - } - return selection.contentRange; - }) + targets.filter((target) => useLineDecorations(target)).map(getRange) ); }); } -function useLineDecorations(selection: Target) { - return false; // TODO - // return ( - // isLineSelectionType(selection.selectionType) && - // selection.position === "contents" - // ); +function useLineDecorations(target: Target) { + switch (target.scopeType) { + case "line": + case "paragraph": + case "document": + return true; + default: + return false; + } } diff --git a/src/util/targetUtils.ts b/src/util/targetUtils.ts index dcc5ef3649..e919595a73 100644 --- a/src/util/targetUtils.ts +++ b/src/util/targetUtils.ts @@ -38,7 +38,7 @@ export async function runForEachEditor( export async function runOnTargetsForEachEditor( targets: Target[], - func: (editor: TextEditor, selections: Target[]) => Promise + func: (editor: TextEditor, targets: Target[]) => Promise ): Promise { return runForEachEditor(targets, (target) => target.editor, func); } From f5eaf5b4500fc872a0a5107502926128253ab685 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 15 May 2022 21:29:55 +0200 Subject: [PATCH 038/314] Updated paragraph and document to fit content on selection --- src/processTargets/modifiers/DocumentStage.ts | 13 +++++++++---- src/processTargets/modifiers/LineStage.ts | 2 +- src/processTargets/modifiers/ParagraphStage.ts | 6 +++++- src/processTargets/modifiers/TokenStage.ts | 3 --- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/processTargets/modifiers/DocumentStage.ts b/src/processTargets/modifiers/DocumentStage.ts index 2e3dee2e3a..9905b3f2f5 100644 --- a/src/processTargets/modifiers/DocumentStage.ts +++ b/src/processTargets/modifiers/DocumentStage.ts @@ -1,4 +1,4 @@ -import { Range, TextDocument } from "vscode"; +import { Range, TextEditor } from "vscode"; import { ContainingScopeModifier, EveryScopeModifier, @@ -7,6 +7,7 @@ import { import { ProcessedTargetsContext } from "../../typings/Types"; import { getDocumentRange } from "../../util/range"; import { ModifierStage } from "../PipelineStages.types"; +import { fitRangeToLineContent } from "./LineStage"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} @@ -17,13 +18,14 @@ export default class implements ModifierStage { isReversed: target.isReversed, scopeType: "document", delimiter: "\n", - contentRange: getDocumentContentRange(target.editor.document), + contentRange: getDocumentContentRange(target.editor), removalRange: getDocumentRange(target.editor.document), }; } } -function getDocumentContentRange(document: TextDocument) { +function getDocumentContentRange(editor: TextEditor) { + const { document } = editor; let firstLineNum = 0; let lastLineNum = document.lineCount - 1; @@ -44,5 +46,8 @@ function getDocumentContentRange(document: TextDocument) { const firstLine = document.lineAt(firstLineNum); const lastLine = document.lineAt(lastLineNum); - return new Range(firstLine.range.start, lastLine.range.end); + return fitRangeToLineContent( + editor, + new Range(firstLine.range.start, lastLine.range.end) + ); } diff --git a/src/processTargets/modifiers/LineStage.ts b/src/processTargets/modifiers/LineStage.ts index dc950f8345..99611f0208 100644 --- a/src/processTargets/modifiers/LineStage.ts +++ b/src/processTargets/modifiers/LineStage.ts @@ -65,7 +65,7 @@ export function getLineContext( }; } -function fitRangeToLineContent(editor: TextEditor, range: Range) { +export function fitRangeToLineContent(editor: TextEditor, range: Range) { const startLine = editor.document.lineAt(range.start); const endLine = editor.document.lineAt(range.end); const endCharacterIndex = diff --git a/src/processTargets/modifiers/ParagraphStage.ts b/src/processTargets/modifiers/ParagraphStage.ts index e283e59027..f8728249af 100644 --- a/src/processTargets/modifiers/ParagraphStage.ts +++ b/src/processTargets/modifiers/ParagraphStage.ts @@ -6,6 +6,7 @@ import { } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; +import { fitRangeToLineContent } from "./LineStage"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} @@ -41,7 +42,10 @@ export default class implements ModifierStage { ); const end = endLine.range.end; - const contentRange = new Range(start, end); + const contentRange = fitRangeToLineContent( + target.editor, + new Range(start, end) + ); const removalRange = new Range( new Position(start.line, 0), diff --git a/src/processTargets/modifiers/TokenStage.ts b/src/processTargets/modifiers/TokenStage.ts index dcc871dd86..11a70a1221 100644 --- a/src/processTargets/modifiers/TokenStage.ts +++ b/src/processTargets/modifiers/TokenStage.ts @@ -61,9 +61,6 @@ export function getTokenContext( return { delimiter: " ", - removalRange: undefined, - interiorRange: undefined, - boundary: undefined, leadingDelimiterRange: isInDelimitedList ? leadingDelimiterRange : undefined, From 60e9f40aeeec892147860c938303970e74fe825d Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 15 May 2022 21:52:29 +0200 Subject: [PATCH 039/314] Added clear action --- src/actions/Actions.ts | 7 ++-- src/actions/Clear.ts | 52 ++++++++++++---------------- src/actions/{Delete.ts => Remove.ts} | 13 +++++-- src/typings/Types.ts | 8 +++-- src/util/editDisplayUtils.ts | 32 ++++++++++------- 5 files changed, 61 insertions(+), 51 deletions(-) rename src/actions/{Delete.ts => Remove.ts} (86%) diff --git a/src/actions/Actions.ts b/src/actions/Actions.ts index aba8b8f440..d18891335a 100644 --- a/src/actions/Actions.ts +++ b/src/actions/Actions.ts @@ -1,5 +1,6 @@ import { ActionRecord, Graph } from "../typings/Types"; -import Delete from "./Delete"; +import Clear from "./Clear"; +import Remove from "./Remove"; import { SetSelection, SetSelectionAfter, @@ -10,7 +11,7 @@ class Actions implements ActionRecord { constructor(private graph: Graph) {} // callAsFunction = new Call(this.graph); - // clearAndSetSelection = new Clear(this.graph); + clearAndSetSelection = new Clear(this.graph); // copyToClipboard = new Copy(this.graph); // cutToClipboard = new Cut(this.graph); // editNewLineAfter = new EditNewLineBelow(this.graph); @@ -31,7 +32,7 @@ class Actions implements ActionRecord { // moveToTarget = new Move(this.graph); // outdentLine = new OutdentLines(this.graph); // pasteFromClipboard = new Paste(this.graph); - remove = new Delete(this.graph); + remove = new Remove(this.graph); // deselect = new Deselect(this.graph); // replace = new Replace(this.graph); // replaceWithTarget = new Bring(this.graph); diff --git a/src/actions/Clear.ts b/src/actions/Clear.ts index 43c762d637..44608b52c1 100644 --- a/src/actions/Clear.ts +++ b/src/actions/Clear.ts @@ -1,34 +1,28 @@ -// import { -// Action, -// ActionPreferences, -// ActionReturnValue, -// Graph, -// Target, -// } from "../typings/Types"; -// import { ensureSingleEditor } from "../util/targetUtils"; -// import { setSelectionsAndFocusEditor } from "../util/setSelectionsAndFocusEditor"; +import { Target } from "../typings/target.types"; +import { Action, ActionReturnValue, Graph } from "../typings/Types"; +import { setSelectionsAndFocusEditor } from "../util/setSelectionsAndFocusEditor"; +import { ensureSingleEditor } from "../util/targetUtils"; -// export default class Clear implements Action { -// getTargetPreferences: () => ActionPreferences[] = () => [ -// { insideOutsideType: "inside" }, -// ]; +export default class Clear implements Action { + constructor(private graph: Graph) { + this.run = this.run.bind(this); + } -// constructor(private graph: Graph) { -// this.run = this.run.bind(this); -// } + async run([targets]: [Target[]]): Promise { + const editor = ensureSingleEditor(targets); -// async run([targets]: [Target[]]): Promise { -// const editor = ensureSingleEditor(targets); + const { thatMark } = await this.graph.actions.remove.run([targets], { + showDecorations: true, + contentOnly: true, + }); -// const { thatMark } = await this.graph.actions.remove.run([targets]); + if (thatMark != null) { + await setSelectionsAndFocusEditor( + editor, + thatMark.map(({ selection }) => selection) + ); + } -// if (thatMark != null) { -// await setSelectionsAndFocusEditor( -// editor, -// thatMark.map(({ selection }) => selection) -// ); -// } - -// return { thatMark }; -// } -// } + return { thatMark }; + } +} diff --git a/src/actions/Delete.ts b/src/actions/Remove.ts similarity index 86% rename from src/actions/Delete.ts rename to src/actions/Remove.ts index 9b828edb4c..b83d6ac1a3 100644 --- a/src/actions/Delete.ts +++ b/src/actions/Remove.ts @@ -14,7 +14,7 @@ export default class Delete implements Action { async run( [targets]: [Target[]], - { showDecorations = true } = {} + { showDecorations = true, contentOnly = false } = {} ): Promise { // Unify overlapping targets. // TODO @@ -24,13 +24,16 @@ export default class Delete implements Action { await displayPendingEditDecorations( targets, this.graph.editStyles.pendingDelete, - getRemovalHighlightRange + contentOnly ? getContentRange : getRemovalHighlightRange, + contentOnly ); } const thatMark = flatten( await runOnTargetsForEachEditor(targets, async (editor, targets) => { - const ranges = targets.map(getRemovalRange); + const ranges = targets.map( + contentOnly ? getContentRange : getRemovalRange + ); const edits = ranges.map((range) => ({ range, text: "", @@ -51,6 +54,10 @@ export default class Delete implements Action { } } +function getContentRange(target: Target) { + return target.contentRange; +} + function getRemovalRange(target: Target) { const removalRange = target.removalRange ?? target.contentRange; const delimiterRange = diff --git a/src/typings/Types.ts b/src/typings/Types.ts index bf81098e13..14ffe57472 100644 --- a/src/typings/Types.ts +++ b/src/typings/Types.ts @@ -113,7 +113,7 @@ export interface Action { export type ActionType = // | "callAsFunction" - // | "clearAndSetSelection" + | "clearAndSetSelection" // | "copyToClipboard" // | "cutToClipboard" // | "deselect" @@ -135,7 +135,7 @@ export type ActionType = // | "moveToTarget" // | "outdentLine" // | "pasteFromClipboard" - // | "remove" + | "remove" // | "replace" // | "replaceWithTarget" // | "reverseTargets" @@ -143,7 +143,9 @@ export type ActionType = // | "scrollToBottom" // | "scrollToCenter" // | "scrollToTop" - "setSelection" | "setSelectionAfter" | "setSelectionBefore"; + | "setSelection" + | "setSelectionAfter" + | "setSelectionBefore"; // | "sortTargets" // | "swapTargets" // | "toggleLineBreakpoint" diff --git a/src/util/editDisplayUtils.ts b/src/util/editDisplayUtils.ts index 430aecd389..69dcf21f80 100644 --- a/src/util/editDisplayUtils.ts +++ b/src/util/editDisplayUtils.ts @@ -48,36 +48,42 @@ export async function displayPendingEditDecorationsForSelection( export default async function displayPendingEditDecorations( targets: Target[], editStyle: EditStyle, - getRange: (target: Target) => Range + getRange: (target: Target) => Range, + contentOnly?: boolean ) { - await setDecorations(targets, editStyle, getRange); + await setDecorations(targets, editStyle, getRange, contentOnly); await decorationSleep(); clearDecorations(editStyle); } -export function clearDecorations(editStyle: EditStyle) { +function clearDecorations(editStyle: EditStyle) { window.visibleTextEditors.map((editor) => { editor.setDecorations(editStyle.token, []); editor.setDecorations(editStyle.line, []); }); } -export async function setDecorations( +async function setDecorations( targets: Target[], editStyle: EditStyle, - getRange: (target: Target) => Range + getRange: (target: Target) => Range, + contentOnly?: boolean ) { await runOnTargetsForEachEditor(targets, async (editor, targets) => { - editor.setDecorations( - editStyle.token, - targets.filter((target) => !useLineDecorations(target)).map(getRange) - ); - editor.setDecorations( - editStyle.line, - targets.filter((target) => useLineDecorations(target)).map(getRange) - ); + if (contentOnly) { + editor.setDecorations(editStyle.token, targets.map(getRange)); + } else { + editor.setDecorations( + editStyle.token, + targets.filter((target) => !useLineDecorations(target)).map(getRange) + ); + editor.setDecorations( + editStyle.line, + targets.filter((target) => useLineDecorations(target)).map(getRange) + ); + } }); } From d642e884e8c6cb87356486246cb18a5d2fff98d8 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 15 May 2022 22:02:03 +0200 Subject: [PATCH 040/314] Moved action types to separate file --- src/actions/actions.types.ts | 35 +++++++++++++++ src/core/commandRunner/CommandRunner.ts | 7 +-- src/core/commandRunner/command.types.ts | 2 +- .../canonicalizeActionName.ts | 2 +- .../canonicalizeAndValidateCommand.ts | 2 +- .../upgradeV1ToV2/upgradeV1ToV2.ts | 2 +- src/typings/Types.ts | 45 +------------------ 7 files changed, 43 insertions(+), 52 deletions(-) create mode 100644 src/actions/actions.types.ts diff --git a/src/actions/actions.types.ts b/src/actions/actions.types.ts new file mode 100644 index 0000000000..ade01d9831 --- /dev/null +++ b/src/actions/actions.types.ts @@ -0,0 +1,35 @@ +export type ActionType = + // | "callAsFunction" + | "clearAndSetSelection" + // | "copyToClipboard" + // | "cutToClipboard" + // | "deselect" + // | "editNewLineAfter" + // | "editNewLineBefore" + // | "executeCommand" + // | "extractVariable" + // | "findInWorkspace" + // | "foldRegion" + // | "followLink" + // | "getText" + // | "highlight" + // | "indentLine" + // | "insertCopyAfter" + // | "insertCopyBefore" + // | "insertEmptyLineAfter" + // | "insertEmptyLineBefore" + // | "insertEmptyLinesAround" + // | "moveToTarget" + // | "outdentLine" + // | "pasteFromClipboard" + | "remove" + // | "replace" + // | "replaceWithTarget" + // | "reverseTargets" + // | "rewrapWithPairedDelimiter" + // | "scrollToBottom" + // | "scrollToCenter" + // | "scrollToTop" + | "setSelection" + | "setSelectionAfter" + | "setSelectionBefore"; diff --git a/src/core/commandRunner/CommandRunner.ts b/src/core/commandRunner/CommandRunner.ts index f054a8df26..2df4582ef8 100644 --- a/src/core/commandRunner/CommandRunner.ts +++ b/src/core/commandRunner/CommandRunner.ts @@ -1,11 +1,8 @@ import * as vscode from "vscode"; +import { ActionType } from "../../actions/actions.types"; import { ActionableError } from "../../errors"; import processTargets from "../../processTargets"; -import { - ActionType, - Graph, - ProcessedTargetsContext, -} from "../../typings/Types"; +import { Graph, ProcessedTargetsContext } from "../../typings/Types"; import { isString } from "../../util/type"; import { canonicalizeAndValidateCommand } from "../commandVersionUpgrades/canonicalizeAndValidateCommand"; import { PartialTargetV0V1 } from "../commandVersionUpgrades/upgradeV1ToV2/commandV1.types"; diff --git a/src/core/commandRunner/command.types.ts b/src/core/commandRunner/command.types.ts index 4e9a5f008c..fdceaffd6b 100644 --- a/src/core/commandRunner/command.types.ts +++ b/src/core/commandRunner/command.types.ts @@ -1,5 +1,5 @@ import { PartialTargetDesc } from "../../typings/target.types"; -import { ActionType } from "../../typings/Types"; +import { ActionType } from "../../actions/actions.types"; import { CommandV0, CommandV1, diff --git a/src/core/commandVersionUpgrades/canonicalizeActionName.ts b/src/core/commandVersionUpgrades/canonicalizeActionName.ts index b90868f5fb..b30ba22861 100644 --- a/src/core/commandVersionUpgrades/canonicalizeActionName.ts +++ b/src/core/commandVersionUpgrades/canonicalizeActionName.ts @@ -1,4 +1,4 @@ -import { ActionType } from "../../typings/Types"; +import { ActionType } from "../../actions/actions.types"; const actionAliasToCanonicalName: Record = { // TODO diff --git a/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts b/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts index b726161599..0cf7d98a60 100644 --- a/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts +++ b/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts @@ -1,7 +1,7 @@ import { commands } from "vscode"; import { ActionableError } from "../../errors"; import { PartialTargetDesc, ScopeType } from "../../typings/target.types"; -import { ActionType } from "../../typings/Types"; +import { ActionType } from "../../actions/actions.types"; import { getPartialPrimitiveTargets } from "../../util/getPrimitiveTargets"; import { Command, diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts index 594d2a461c..e323dc9005 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts @@ -6,7 +6,7 @@ import { PartialTargetDesc, ScopeType, } from "../../../typings/target.types"; -import { ActionType } from "../../../typings/Types"; +import { ActionType } from "../../../actions/actions.types"; import { transformPartialPrimitiveTargets } from "../../../util/getPrimitiveTargets"; import { CommandV2 } from "../../commandRunner/command.types"; import { diff --git a/src/typings/Types.ts b/src/typings/Types.ts index 14ffe57472..2b3fc331d6 100644 --- a/src/typings/Types.ts +++ b/src/typings/Types.ts @@ -11,6 +11,7 @@ import { Snippets } from "../core/Snippets"; import { RangeUpdater } from "../core/updateSelections/RangeUpdater"; import { TestCaseRecorder } from "../testUtil/TestCaseRecorder"; import { CommandServerApi } from "../util/getExtensionApi"; +import { ActionType } from "../actions/actions.types"; import { Target } from "./target.types"; import { FullRangeInfo } from "./updateSelections"; @@ -108,52 +109,10 @@ export interface Action { * Used to define default values for parts of target during inference. * @param args Extra args to command */ + // TODO // getTargetPreferences(...args: any[]): ActionPreferences[]; } -export type ActionType = - // | "callAsFunction" - | "clearAndSetSelection" - // | "copyToClipboard" - // | "cutToClipboard" - // | "deselect" - // | "editNewLineAfter" - // | "editNewLineBefore" - // | "executeCommand" - // | "extractVariable" - // | "findInWorkspace" - // | "foldRegion" - // | "followLink" - // | "getText" - // | "highlight" - // | "indentLine" - // | "insertCopyAfter" - // | "insertCopyBefore" - // | "insertEmptyLineAfter" - // | "insertEmptyLineBefore" - // | "insertEmptyLinesAround" - // | "moveToTarget" - // | "outdentLine" - // | "pasteFromClipboard" - | "remove" - // | "replace" - // | "replaceWithTarget" - // | "reverseTargets" - // | "rewrapWithPairedDelimiter" - // | "scrollToBottom" - // | "scrollToCenter" - // | "scrollToTop" - | "setSelection" - | "setSelectionAfter" - | "setSelectionBefore"; -// | "sortTargets" -// | "swapTargets" -// | "toggleLineBreakpoint" -// | "toggleLineComment" -// | "unfoldRegion" -// | "wrapWithPairedDelimiter" -// | "wrapWithSnippet" - export type ActionRecord = Record; export interface Graph { From 9aae4ad7aab9f444dfca7723a15c045cbe46f438 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 15 May 2022 22:12:54 +0200 Subject: [PATCH 041/314] Added highlight action --- src/actions/Actions.ts | 3 ++- src/actions/Highlight.ts | 50 +++++++++++++++--------------------- src/actions/Remove.ts | 12 ++++----- src/actions/actions.types.ts | 2 +- src/util/editDisplayUtils.ts | 12 ++++++--- src/util/selectionUtils.ts | 14 ---------- src/util/targetUtils.ts | 28 +++++++++++++++++++- 7 files changed, 65 insertions(+), 56 deletions(-) diff --git a/src/actions/Actions.ts b/src/actions/Actions.ts index d18891335a..84308cbc30 100644 --- a/src/actions/Actions.ts +++ b/src/actions/Actions.ts @@ -1,5 +1,6 @@ import { ActionRecord, Graph } from "../typings/Types"; import Clear from "./Clear"; +import Highlight from "./Highlight"; import Remove from "./Remove"; import { SetSelection, @@ -22,7 +23,7 @@ class Actions implements ActionRecord { // foldRegion = new Fold(this.graph); // followLink = new FollowLink(this.graph); // getText = new GetText(this.graph); - // highlight = new Highlight(this.graph); + highlight = new Highlight(this.graph); // indentLine = new IndentLines(this.graph); // insertCopyAfter = new CopyLinesDown(this.graph); // insertCopyBefore = new CopyLinesUp(this.graph); diff --git a/src/actions/Highlight.ts b/src/actions/Highlight.ts index 5ebc98e36b..f6612a2917 100644 --- a/src/actions/Highlight.ts +++ b/src/actions/Highlight.ts @@ -1,33 +1,25 @@ -// import { EditStyleName } from "../core/editStyles"; -// import { -// Action, -// ActionPreferences, -// ActionReturnValue, -// Target, -// Graph, -// } from "../typings/Types"; -// import { clearDecorations, setDecorations } from "../util/editDisplayUtils"; +import { EditStyleName } from "../core/editStyles"; +import { Target } from "../typings/target.types"; +import { Action, ActionReturnValue, Graph } from "../typings/Types"; +import { clearDecorations, setDecorations } from "../util/editDisplayUtils"; +import { createThatMark } from "../util/targetUtils"; -// export default class Highlight implements Action { -// getTargetPreferences: () => ActionPreferences[] = () => [ -// { insideOutsideType: "inside" }, -// ]; +export default class Highlight implements Action { + constructor(private graph: Graph) { + this.run = this.run.bind(this); + } -// constructor(private graph: Graph) { -// this.run = this.run.bind(this); -// } + async run( + [targets]: [Target[]], + styleName: EditStyleName = "highlight0" + ): Promise { + const style = this.graph.editStyles[styleName]; -// async run( -// [targets]: [Target[]], -// styleName: EditStyleName = "highlight0" -// ): Promise { -// const style = this.graph.editStyles[styleName]; + clearDecorations(style); + await setDecorations(targets, style); -// clearDecorations(style); -// await setDecorations(targets, style); - -// return { -// thatMark: targets.map((target) => target.selection), -// }; -// } -// } + return { + thatMark: createThatMark(targets), + }; + } +} diff --git a/src/actions/Remove.ts b/src/actions/Remove.ts index b83d6ac1a3..d9c44f3353 100644 --- a/src/actions/Remove.ts +++ b/src/actions/Remove.ts @@ -4,8 +4,12 @@ import { performEditsAndUpdateRanges } from "../core/updateSelections/updateSele import { Target } from "../typings/target.types"; import { Action, ActionReturnValue, Graph } from "../typings/Types"; import displayPendingEditDecorations from "../util/editDisplayUtils"; -import { createThatMark } from "../util/selectionUtils"; -import { runOnTargetsForEachEditor } from "../util/targetUtils"; + +import { + createThatMark, + getContentRange, + runOnTargetsForEachEditor, +} from "../util/targetUtils"; export default class Delete implements Action { constructor(private graph: Graph) { @@ -54,10 +58,6 @@ export default class Delete implements Action { } } -function getContentRange(target: Target) { - return target.contentRange; -} - function getRemovalRange(target: Target) { const removalRange = target.removalRange ?? target.contentRange; const delimiterRange = diff --git a/src/actions/actions.types.ts b/src/actions/actions.types.ts index ade01d9831..c18ec26971 100644 --- a/src/actions/actions.types.ts +++ b/src/actions/actions.types.ts @@ -12,7 +12,7 @@ export type ActionType = // | "foldRegion" // | "followLink" // | "getText" - // | "highlight" + | "highlight" // | "indentLine" // | "insertCopyAfter" // | "insertCopyBefore" diff --git a/src/util/editDisplayUtils.ts b/src/util/editDisplayUtils.ts index 69dcf21f80..4a639c5859 100644 --- a/src/util/editDisplayUtils.ts +++ b/src/util/editDisplayUtils.ts @@ -4,7 +4,11 @@ import isTesting from "../testUtil/isTesting"; import { Target } from "../typings/target.types"; import { SelectionWithEditor } from "../typings/Types"; import sleep from "./sleep"; -import { runForEachEditor, runOnTargetsForEachEditor } from "./targetUtils"; +import { + getContentRange, + runForEachEditor, + runOnTargetsForEachEditor, +} from "./targetUtils"; const getPendingEditDecorationTime = () => workspace @@ -58,17 +62,17 @@ export default async function displayPendingEditDecorations( clearDecorations(editStyle); } -function clearDecorations(editStyle: EditStyle) { +export function clearDecorations(editStyle: EditStyle) { window.visibleTextEditors.map((editor) => { editor.setDecorations(editStyle.token, []); editor.setDecorations(editStyle.line, []); }); } -async function setDecorations( +export async function setDecorations( targets: Target[], editStyle: EditStyle, - getRange: (target: Target) => Range, + getRange: (target: Target) => Range = getContentRange, contentOnly?: boolean ) { await runOnTargetsForEachEditor(targets, async (editor, targets) => { diff --git a/src/util/selectionUtils.ts b/src/util/selectionUtils.ts index 6dddd34362..254775ceee 100644 --- a/src/util/selectionUtils.ts +++ b/src/util/selectionUtils.ts @@ -1,6 +1,4 @@ -import { zip } from "lodash"; import { Position, Range, Selection } from "vscode"; -import { Target } from "../typings/target.types"; import { SelectionWithEditor } from "../typings/Types"; export function isForward(selection: Selection) { @@ -39,15 +37,3 @@ function selectionFromPositions( ? new Selection(start, end) : new Selection(end, start); } - -export function createThatMark( - targets: Target[], - ranges: Range[] -): SelectionWithEditor[] { - return zip(targets, ranges).map(([target, range]) => ({ - editor: target!.editor, - selection: target?.isReversed - ? new Selection(range!.end, range!.start) - : new Selection(range!.start, range!.end), - })); -} diff --git a/src/util/targetUtils.ts b/src/util/targetUtils.ts index e919595a73..d425c46cef 100644 --- a/src/util/targetUtils.ts +++ b/src/util/targetUtils.ts @@ -1,5 +1,7 @@ -import { Position, Range, TextEditor } from "vscode"; +import { zip } from "lodash"; +import { Position, Range, Selection, TextEditor } from "vscode"; import { Target } from "../typings/target.types"; +import { SelectionWithEditor } from "../typings/Types"; import { groupBy } from "./itertools"; export function ensureSingleEditor(targets: Target[]) { @@ -93,3 +95,27 @@ function createTypeSelection( isReversed: false, }; } + +export function getContentRange(target: Target) { + return target.contentRange; +} + +export function createThatMark( + targets: Target[], + ranges?: Range[] +): SelectionWithEditor[] { + if (ranges) { + return zip(targets, ranges).map(([target, range]) => ({ + editor: target!.editor, + selection: target?.isReversed + ? new Selection(range!.end, range!.start) + : new Selection(range!.start, range!.end), + })); + } + return targets.map((target) => ({ + editor: target!.editor, + selection: target?.isReversed + ? new Selection(target.contentRange.end, target.contentRange.start) + : new Selection(target.contentRange.start, target.contentRange.end), + })); +} From 340c9c464dfb23d3be7922d937afc22dacc4bf40 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 15 May 2022 22:17:16 +0200 Subject: [PATCH 042/314] Added action get text --- src/actions/Actions.ts | 3 +- src/actions/GetText.ts | 75 ++++++++++++++++-------------------- src/actions/actions.types.ts | 2 +- src/util/editDisplayUtils.ts | 2 +- 4 files changed, 37 insertions(+), 45 deletions(-) diff --git a/src/actions/Actions.ts b/src/actions/Actions.ts index 84308cbc30..c78ff4b109 100644 --- a/src/actions/Actions.ts +++ b/src/actions/Actions.ts @@ -1,5 +1,6 @@ import { ActionRecord, Graph } from "../typings/Types"; import Clear from "./Clear"; +import GetText from "./GetText"; import Highlight from "./Highlight"; import Remove from "./Remove"; import { @@ -22,7 +23,7 @@ class Actions implements ActionRecord { // findInWorkspace = new FindInFiles(this.graph); // foldRegion = new Fold(this.graph); // followLink = new FollowLink(this.graph); - // getText = new GetText(this.graph); + getText = new GetText(this.graph); highlight = new Highlight(this.graph); // indentLine = new IndentLines(this.graph); // insertCopyAfter = new CopyLinesDown(this.graph); diff --git a/src/actions/GetText.ts b/src/actions/GetText.ts index 696c821b17..8deac56ead 100644 --- a/src/actions/GetText.ts +++ b/src/actions/GetText.ts @@ -1,46 +1,37 @@ -// import { -// Action, -// ActionPreferences, -// ActionReturnValue, -// Graph, -// Target, -// } from "../typings/Types"; -// import displayPendingEditDecorations from "../util/editDisplayUtils"; -// import { ensureSingleTarget } from "../util/targetUtils"; +import { Target } from "../typings/target.types"; +import { Action, ActionReturnValue, Graph } from "../typings/Types"; +import displayPendingEditDecorations from "../util/editDisplayUtils"; +import { createThatMark, ensureSingleTarget } from "../util/targetUtils"; -// export default class GetText implements Action { -// getTargetPreferences: () => ActionPreferences[] = () => [ -// { insideOutsideType: "inside" }, -// ]; +export default class GetText implements Action { + constructor(private graph: Graph) { + this.run = this.run.bind(this); + } -// constructor(private graph: Graph) { -// this.run = this.run.bind(this); -// } + async run( + [targets]: [Target[]], + { + showDecorations = true, + ensureSingleTarget: doEnsureSingleTarget = false, + } = {} + ): Promise { + if (showDecorations) { + await displayPendingEditDecorations( + targets, + this.graph.editStyles.referenced + ); + } + if (doEnsureSingleTarget) { + ensureSingleTarget(targets); + } -// async run( -// [targets]: [Target[]], -// { -// showDecorations = true, -// ensureSingleTarget: doEnsureSingleTarget = false, -// } = {} -// ): Promise { -// if (showDecorations) { -// await displayPendingEditDecorations( -// targets, -// this.graph.editStyles.referenced -// ); -// } -// if (doEnsureSingleTarget) { -// ensureSingleTarget(targets); -// } + const returnValue = targets.map((target) => + target.editor.document.getText(target.contentRange) + ); -// const returnValue = targets.map((target) => -// target.selection.editor.document.getText(target.selection.selection) -// ); - -// return { -// returnValue, -// thatMark: targets.map((target) => target.selection), -// }; -// } -// } + return { + returnValue, + thatMark: createThatMark(targets), + }; + } +} diff --git a/src/actions/actions.types.ts b/src/actions/actions.types.ts index c18ec26971..71ddefb836 100644 --- a/src/actions/actions.types.ts +++ b/src/actions/actions.types.ts @@ -11,7 +11,7 @@ export type ActionType = // | "findInWorkspace" // | "foldRegion" // | "followLink" - // | "getText" + | "getText" | "highlight" // | "indentLine" // | "insertCopyAfter" diff --git a/src/util/editDisplayUtils.ts b/src/util/editDisplayUtils.ts index 4a639c5859..7dec84323e 100644 --- a/src/util/editDisplayUtils.ts +++ b/src/util/editDisplayUtils.ts @@ -52,7 +52,7 @@ export async function displayPendingEditDecorationsForSelection( export default async function displayPendingEditDecorations( targets: Target[], editStyle: EditStyle, - getRange: (target: Target) => Range, + getRange: (target: Target) => Range = getContentRange, contentOnly?: boolean ) { await setDecorations(targets, editStyle, getRange, contentOnly); From 2ffed5e9d2ac38cbdcc6ecf463b6b545b34ec123 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 15 May 2022 22:20:06 +0200 Subject: [PATCH 043/314] Added action deselect --- src/actions/Actions.ts | 3 +- src/actions/Deselect.ts | 66 +++++++++++++++--------------------- src/actions/actions.types.ts | 2 +- 3 files changed, 31 insertions(+), 40 deletions(-) diff --git a/src/actions/Actions.ts b/src/actions/Actions.ts index c78ff4b109..592d4fb915 100644 --- a/src/actions/Actions.ts +++ b/src/actions/Actions.ts @@ -1,5 +1,6 @@ import { ActionRecord, Graph } from "../typings/Types"; import Clear from "./Clear"; +import Deselect from "./Deselect"; import GetText from "./GetText"; import Highlight from "./Highlight"; import Remove from "./Remove"; @@ -35,7 +36,7 @@ class Actions implements ActionRecord { // outdentLine = new OutdentLines(this.graph); // pasteFromClipboard = new Paste(this.graph); remove = new Remove(this.graph); - // deselect = new Deselect(this.graph); + deselect = new Deselect(this.graph); // replace = new Replace(this.graph); // replaceWithTarget = new Bring(this.graph); // randomizeTargets = new Random(this.graph); diff --git a/src/actions/Deselect.ts b/src/actions/Deselect.ts index 1d109fda81..6c26789c9e 100644 --- a/src/actions/Deselect.ts +++ b/src/actions/Deselect.ts @@ -1,41 +1,31 @@ -// import { Selection } from "vscode"; -// import { -// Action, -// ActionPreferences, -// ActionReturnValue, -// Target, -// Graph, -// } from "../typings/Types"; -// import { runOnTargetsForEachEditor } from "../util/targetUtils"; +import { Selection } from "vscode"; +import { Target } from "../typings/target.types"; +import { Action, ActionReturnValue, Graph } from "../typings/Types"; +import { createThatMark, runOnTargetsForEachEditor } from "../util/targetUtils"; -// export default class Deselect implements Action { -// getTargetPreferences: () => ActionPreferences[] = () => [ -// { insideOutsideType: "inside" }, -// ]; +export default class Deselect implements Action { + constructor(private graph: Graph) { + this.run = this.run.bind(this); + } -// constructor(private graph: Graph) { -// this.run = this.run.bind(this); -// } + async run([targets]: [Target[]]): Promise { + await runOnTargetsForEachEditor(targets, async (editor, targets) => { + // Remove selections with a non-empty intersection + const newSelections = editor.selections.filter( + (selection) => + !targets.some((target) => { + const intersection = target.contentRange.intersection(selection); + return intersection && (!intersection.isEmpty || selection.isEmpty); + }) + ); + // The editor requires at least one selection. Keep "primary" selection active + editor.selections = newSelections.length + ? newSelections + : [new Selection(editor.selection.active, editor.selection.active)]; + }); -// async run([targets]: [Target[]]): Promise { -// await runOnTargetsForEachEditor(targets, async (editor, targets) => { -// // Remove selections with a non-empty intersection -// const newSelections = editor.selections.filter( -// (selection) => -// !targets.some((target) => { -// const intersection = -// target.selection.selection.intersection(selection); -// return intersection && (!intersection.isEmpty || selection.isEmpty); -// }) -// ); -// // The editor requires at least one selection. Keep "primary" selection active -// editor.selections = newSelections.length -// ? newSelections -// : [new Selection(editor.selection.active, editor.selection.active)]; -// }); - -// return { -// thatMark: targets.map((target) => target.selection), -// }; -// } -// } + return { + thatMark: createThatMark(targets), + }; + } +} diff --git a/src/actions/actions.types.ts b/src/actions/actions.types.ts index 71ddefb836..f32259003e 100644 --- a/src/actions/actions.types.ts +++ b/src/actions/actions.types.ts @@ -3,7 +3,7 @@ export type ActionType = | "clearAndSetSelection" // | "copyToClipboard" // | "cutToClipboard" - // | "deselect" + | "deselect" // | "editNewLineAfter" // | "editNewLineBefore" // | "executeCommand" From cc87b8437d72830b57058f878f9e212ca5c5fd40 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 15 May 2022 22:49:23 +0200 Subject: [PATCH 044/314] Added indent and command actions --- src/actions/Actions.ts | 8 +- src/actions/CommandAction.ts | 251 ++++++++---------- src/actions/ExecuteCommand.ts | 42 ++- src/actions/GetText.ts | 13 +- src/actions/Indent.ts | 24 +- src/actions/Remove.ts | 2 +- src/actions/SetSelection.ts | 6 +- src/actions/actions.types.ts | 6 +- src/core/commandRunner/CommandRunner.ts | 14 +- src/core/updateSelections/updateRanges.ts | 215 +++++++++++++++ src/core/updateSelections/updateSelections.ts | 116 ++++---- src/util/targetUtils.ts | 17 ++ 12 files changed, 471 insertions(+), 243 deletions(-) create mode 100644 src/core/updateSelections/updateRanges.ts diff --git a/src/actions/Actions.ts b/src/actions/Actions.ts index 592d4fb915..2f7e683298 100644 --- a/src/actions/Actions.ts +++ b/src/actions/Actions.ts @@ -1,8 +1,10 @@ import { ActionRecord, Graph } from "../typings/Types"; import Clear from "./Clear"; import Deselect from "./Deselect"; +import ExecuteCommand from "./ExecuteCommand"; import GetText from "./GetText"; import Highlight from "./Highlight"; +import { IndentLines, OutdentLines } from "./Indent"; import Remove from "./Remove"; import { SetSelection, @@ -19,21 +21,21 @@ class Actions implements ActionRecord { // cutToClipboard = new Cut(this.graph); // editNewLineAfter = new EditNewLineBelow(this.graph); // editNewLineBefore = new EditNewLineAbove(this.graph); - // executeCommand = new ExecuteCommand(this.graph); + executeCommand = new ExecuteCommand(this.graph); // extractVariable = new ExtractVariable(this.graph); // findInWorkspace = new FindInFiles(this.graph); // foldRegion = new Fold(this.graph); // followLink = new FollowLink(this.graph); getText = new GetText(this.graph); highlight = new Highlight(this.graph); - // indentLine = new IndentLines(this.graph); + indentLine = new IndentLines(this.graph); // insertCopyAfter = new CopyLinesDown(this.graph); // insertCopyBefore = new CopyLinesUp(this.graph); // insertEmptyLineAfter = new InsertEmptyLineBelow(this.graph); // insertEmptyLineBefore = new InsertEmptyLineAbove(this.graph); // insertEmptyLinesAround = new InsertEmptyLinesAround(this.graph); // moveToTarget = new Move(this.graph); - // outdentLine = new OutdentLines(this.graph); + outdentLine = new OutdentLines(this.graph); // pasteFromClipboard = new Paste(this.graph); remove = new Remove(this.graph); deselect = new Deselect(this.graph); diff --git a/src/actions/CommandAction.ts b/src/actions/CommandAction.ts index 6d75da6c34..93fa7c9f62 100644 --- a/src/actions/CommandAction.ts +++ b/src/actions/CommandAction.ts @@ -1,133 +1,118 @@ -// import { commands, window } from "vscode"; -// import { -// Action, -// ActionPreferences, -// ActionReturnValue, -// Graph, -// Target, -// SelectionWithEditor, -// } from "../typings/Types"; -// import displayPendingEditDecorations from "../util/editDisplayUtils"; -// import { runOnTargetsForEachEditor } from "../util/targetUtils"; -// import { -// focusEditor, -// setSelectionsAndFocusEditor, -// } from "../util/setSelectionsAndFocusEditor"; -// import { flatten } from "lodash"; -// import { ensureSingleEditor } from "../util/targetUtils"; -// import { callFunctionAndUpdateSelections } from "../core/updateSelections/updateSelections"; - -// export interface CommandOptions { -// command?: string; -// commandArgs?: any[]; -// restoreSelection?: boolean; -// ensureSingleEditor?: boolean; -// showDecorations?: boolean; -// } - -// const defaultOptions: CommandOptions = { -// commandArgs: [], -// restoreSelection: true, -// ensureSingleEditor: false, -// showDecorations: false, -// }; - -// export default class CommandAction implements Action { -// getTargetPreferences: () => ActionPreferences[] = () => [ -// { insideOutsideType: "inside" }, -// ]; - -// constructor(private graph: Graph, private options: CommandOptions = {}) { -// this.run = this.run.bind(this); -// } - -// private async runCommandAndUpdateSelections( -// targets: Target[], -// options: Required -// ) { -// return flatten( -// await runOnTargetsForEachEditor( -// targets, -// async (editor, targets) => { -// const originalSelections = editor.selections; - -// const targetSelections = targets.map( -// (target) => target.selection.selection -// ); - -// // For command to the work we have to have the correct editor focused -// await setSelectionsAndFocusEditor(editor, targetSelections, false); - -// const [updatedOriginalSelections, updatedTargetSelections] = -// await callFunctionAndUpdateSelections( -// this.graph.rangeUpdater, -// () => -// commands.executeCommand( -// options.command, -// ...options.commandArgs -// ), -// editor.document, -// [originalSelections, targetSelections] -// ); - -// // Reset original selections -// if (options.restoreSelection) { -// editor.selections = updatedOriginalSelections; -// } - -// return updatedTargetSelections.map((selection) => ({ -// editor, -// selection, -// })); -// } -// ) -// ); -// } - -// async run( -// [targets]: [Target[]], -// options: CommandOptions = {} -// ): Promise { -// const partialOptions = Object.assign( -// {}, -// defaultOptions, -// this.options, -// options -// ); - -// if (partialOptions.command == null) { -// throw Error("Command id must be specified"); -// } - -// const actualOptions = partialOptions as Required; - -// if (actualOptions.showDecorations) { -// await displayPendingEditDecorations( -// targets, -// this.graph.editStyles.referenced -// ); -// } - -// if (actualOptions.ensureSingleEditor) { -// ensureSingleEditor(targets); -// } - -// const originalEditor = window.activeTextEditor; - -// const thatMark = await this.runCommandAndUpdateSelections( -// targets, -// actualOptions -// ); - -// // If necessary focus back original editor -// if ( -// actualOptions.restoreSelection && -// originalEditor != null && -// originalEditor !== window.activeTextEditor -// ) { -// await focusEditor(originalEditor); -// } - -// return { thatMark }; -// } -// } +import { flatten } from "lodash"; +import { commands, window } from "vscode"; +import { callFunctionAndUpdateSelections } from "../core/updateSelections/updateSelections"; +import { Target } from "../typings/target.types"; +import { Action, ActionReturnValue, Graph } from "../typings/Types"; +import displayPendingEditDecorations from "../util/editDisplayUtils"; +import { + focusEditor, + setSelectionsAndFocusEditor, +} from "../util/setSelectionsAndFocusEditor"; +import { + ensureSingleEditor, + getContentSelection, + runOnTargetsForEachEditor, +} from "../util/targetUtils"; + +export interface CommandOptions { + command?: string; + commandArgs?: any[]; + restoreSelection?: boolean; + ensureSingleEditor?: boolean; + showDecorations?: boolean; +} + +const defaultOptions: CommandOptions = { + commandArgs: [], + restoreSelection: true, + ensureSingleEditor: false, + showDecorations: false, +}; + +export default class CommandAction implements Action { + constructor(private graph: Graph, private options: CommandOptions = {}) { + this.run = this.run.bind(this); + } + + private async runCommandAndUpdateSelections( + targets: Target[], + options: Required + ) { + return flatten( + await runOnTargetsForEachEditor(targets, async (editor, targets) => { + const originalSelections = editor.selections; + + const targetSelections = targets.map(getContentSelection); + + // For command to the work we have to have the correct editor focused + await setSelectionsAndFocusEditor(editor, targetSelections, false); + + const [updatedOriginalSelections, updatedTargetSelections] = + await callFunctionAndUpdateSelections( + this.graph.rangeUpdater, + () => + commands.executeCommand(options.command, ...options.commandArgs), + editor.document, + [originalSelections, targetSelections] + ); + + // Reset original selections + if (options.restoreSelection) { + editor.selections = updatedOriginalSelections; + } + + return updatedTargetSelections.map((selection) => ({ + editor, + selection, + })); + }) + ); + } + + async run( + [targets]: [Target[]], + options: CommandOptions = {} + ): Promise { + const partialOptions = Object.assign( + {}, + defaultOptions, + this.options, + options + ); + + if (partialOptions.command == null) { + throw Error("Command id must be specified"); + } + + const actualOptions = partialOptions as Required; + + if (actualOptions.showDecorations) { + await displayPendingEditDecorations( + targets, + this.graph.editStyles.referenced + ); + } + + if (actualOptions.ensureSingleEditor) { + ensureSingleEditor(targets); + } + + const originalEditor = window.activeTextEditor; + + const thatMark = await this.runCommandAndUpdateSelections( + targets, + actualOptions + ); + + // If necessary focus back original editor + if ( + actualOptions.restoreSelection && + originalEditor != null && + originalEditor !== window.activeTextEditor + ) { + await focusEditor(originalEditor); + } + + return { thatMark }; + } +} diff --git a/src/actions/ExecuteCommand.ts b/src/actions/ExecuteCommand.ts index c9d04beed1..5bd31b4ffb 100644 --- a/src/actions/ExecuteCommand.ts +++ b/src/actions/ExecuteCommand.ts @@ -1,28 +1,20 @@ -// import { -// Action, -// ActionPreferences, -// ActionReturnValue, -// Graph, -// Target, -// } from "../typings/Types"; -// import CommandAction, { CommandOptions } from "./CommandAction"; +import { Target } from "../typings/target.types"; +import { Action, ActionReturnValue, Graph } from "../typings/Types"; +import CommandAction, { CommandOptions } from "./CommandAction"; -// export default class ExecuteCommand implements Action { -// getTargetPreferences: () => ActionPreferences[] = () => [ -// { insideOutsideType: "inside" }, -// ]; -// private commandAction: CommandAction; +export default class ExecuteCommand implements Action { + private commandAction: CommandAction; -// constructor(graph: Graph) { -// this.run = this.run.bind(this); -// this.commandAction = new CommandAction(graph); -// } + constructor(graph: Graph) { + this.run = this.run.bind(this); + this.commandAction = new CommandAction(graph); + } -// async run( -// targets: [Target[]], -// command: string, -// args: CommandOptions = {} -// ): Promise { -// return this.commandAction.run(targets, { ...args, command }); -// } -// } + async run( + targets: [Target[]], + command: string, + args: CommandOptions = {} + ): Promise { + return this.commandAction.run(targets, { ...args, command }); + } +} diff --git a/src/actions/GetText.ts b/src/actions/GetText.ts index 8deac56ead..588c746bf0 100644 --- a/src/actions/GetText.ts +++ b/src/actions/GetText.ts @@ -1,7 +1,11 @@ import { Target } from "../typings/target.types"; import { Action, ActionReturnValue, Graph } from "../typings/Types"; import displayPendingEditDecorations from "../util/editDisplayUtils"; -import { createThatMark, ensureSingleTarget } from "../util/targetUtils"; +import { + createThatMark, + ensureSingleTarget, + getContentText, +} from "../util/targetUtils"; export default class GetText implements Action { constructor(private graph: Graph) { @@ -21,16 +25,13 @@ export default class GetText implements Action { this.graph.editStyles.referenced ); } + if (doEnsureSingleTarget) { ensureSingleTarget(targets); } - const returnValue = targets.map((target) => - target.editor.document.getText(target.contentRange) - ); - return { - returnValue, + returnValue: targets.map(getContentText), thatMark: createThatMark(targets), }; } diff --git a/src/actions/Indent.ts b/src/actions/Indent.ts index aee2b02061..e91a676528 100644 --- a/src/actions/Indent.ts +++ b/src/actions/Indent.ts @@ -1,14 +1,14 @@ -// import { Graph } from "../typings/Types"; -// import CommandAction from "./CommandAction"; +import { Graph } from "../typings/Types"; +import CommandAction from "./CommandAction"; -// export class IndentLines extends CommandAction { -// constructor(graph: Graph) { -// super(graph, { command: "editor.action.indentLines" }); -// } -// } +export class IndentLines extends CommandAction { + constructor(graph: Graph) { + super(graph, { command: "editor.action.indentLines" }); + } +} -// export class OutdentLines extends CommandAction { -// constructor(graph: Graph) { -// super(graph, { command: "editor.action.outdentLines" }); -// } -// } +export class OutdentLines extends CommandAction { + constructor(graph: Graph) { + super(graph, { command: "editor.action.outdentLines" }); + } +} diff --git a/src/actions/Remove.ts b/src/actions/Remove.ts index d9c44f3353..e021031043 100644 --- a/src/actions/Remove.ts +++ b/src/actions/Remove.ts @@ -1,5 +1,5 @@ import { flatten } from "lodash"; -import { performEditsAndUpdateRanges } from "../core/updateSelections/updateSelections"; +import { performEditsAndUpdateRanges } from "../core/updateSelections/updateRanges"; // import { unifyTargets } from "../util/unifyRanges"; import { Target } from "../typings/target.types"; import { Action, ActionReturnValue, Graph } from "../typings/Types"; diff --git a/src/actions/SetSelection.ts b/src/actions/SetSelection.ts index 707b02f88a..38c726aeb4 100644 --- a/src/actions/SetSelection.ts +++ b/src/actions/SetSelection.ts @@ -1,5 +1,5 @@ import { Action, ActionReturnValue, Graph } from "../typings/Types"; -import { ensureSingleEditor } from "../util/targetUtils"; +import { ensureSingleEditor, getContentSelection } from "../util/targetUtils"; import { Selection } from "vscode"; import { setSelectionsAndFocusEditor } from "../util/setSelectionsAndFocusEditor"; import { Target } from "../typings/target.types"; @@ -10,9 +10,7 @@ export class SetSelection implements Action { } protected getSelection(target: Target) { - return target.isReversed - ? new Selection(target.contentRange.end, target.contentRange.start) - : new Selection(target.contentRange.start, target.contentRange.end); + return getContentSelection(target); } async run([targets]: [Target[]]): Promise { diff --git a/src/actions/actions.types.ts b/src/actions/actions.types.ts index f32259003e..c402f25d7a 100644 --- a/src/actions/actions.types.ts +++ b/src/actions/actions.types.ts @@ -6,21 +6,21 @@ export type ActionType = | "deselect" // | "editNewLineAfter" // | "editNewLineBefore" - // | "executeCommand" + | "executeCommand" // | "extractVariable" // | "findInWorkspace" // | "foldRegion" // | "followLink" | "getText" | "highlight" - // | "indentLine" + | "indentLine" // | "insertCopyAfter" // | "insertCopyBefore" // | "insertEmptyLineAfter" // | "insertEmptyLineBefore" // | "insertEmptyLinesAround" // | "moveToTarget" - // | "outdentLine" + | "outdentLine" // | "pasteFromClipboard" | "remove" // | "replace" diff --git a/src/core/commandRunner/CommandRunner.ts b/src/core/commandRunner/CommandRunner.ts index 2df4582ef8..b4259cff80 100644 --- a/src/core/commandRunner/CommandRunner.ts +++ b/src/core/commandRunner/CommandRunner.ts @@ -66,7 +66,7 @@ export default class CommandRunner { const { spokenForm, action: actionName, - targets: partialTargets, + targets: partialTargetDescs, extraArgs, usePrePhraseSnapshot, } = commandComplete; @@ -81,8 +81,8 @@ export default class CommandRunner { throw new Error(`Unknown action ${actionName}`); } - const targets = inferFullTargets( - partialTargets, + const targetDescs = inferFullTargets( + partialTargetDescs, // TODO [] // action.getTargetPreferences(...extraArgs) @@ -90,7 +90,7 @@ export default class CommandRunner { if (this.graph.debug.active) { this.graph.debug.log("Full targets:"); - this.graph.debug.log(JSON.stringify(targets, null, 3)); + this.graph.debug.log(JSON.stringify(targetDescs, null, 3)); } const processedTargetsContext: ProcessedTargetsContext = { @@ -100,11 +100,11 @@ export default class CommandRunner { getNodeAtLocation: this.graph.getNodeAtLocation, }; - const selections = processTargets(processedTargetsContext, targets); + const targets = processTargets(processedTargetsContext, targetDescs); if (this.graph.testCaseRecorder.isActive()) { const context = { - targets, + targets: targetDescs, thatMark: this.thatMark, sourceMark: this.sourceMark, hatTokenMap: readableHatMap, @@ -120,7 +120,7 @@ export default class CommandRunner { returnValue, thatMark: newThatMark, sourceMark: newSourceMark, - } = await action.run(selections, ...extraArgs); + } = await action.run(targets, ...extraArgs); this.thatMark.set(newThatMark); this.sourceMark.set(newSourceMark); diff --git a/src/core/updateSelections/updateRanges.ts b/src/core/updateSelections/updateRanges.ts new file mode 100644 index 0000000000..a8dd34d8db --- /dev/null +++ b/src/core/updateSelections/updateRanges.ts @@ -0,0 +1,215 @@ +import { flatten } from "lodash"; +import { + DecorationRangeBehavior, + Range, + TextDocument, + TextEditor, +} from "vscode"; +import { Edit } from "../../typings/Types"; +import { FullRangeInfo, RangeInfo } from "../../typings/updateSelections"; +import { performDocumentEdits } from "../../util/performDocumentEdits"; +import { RangeUpdater } from "./RangeUpdater"; + +/** + * Given a selection, this function creates a `SelectionInfo` object that can + * be passed in to any of the commands that update selections. + * + * @param document The document containing the selection + * @param range The range + * @param rangeBehavior How selection should behave with respect to insertions on either end + * @returns An object that can be used for selection tracking + */ +function getRangeInfo( + document: TextDocument, + range: Range, + rangeBehavior: DecorationRangeBehavior +): FullRangeInfo { + return { + range: new Range(range.start, range.end), + expansionBehavior: { + start: { + type: + rangeBehavior === DecorationRangeBehavior.ClosedClosed || + rangeBehavior === DecorationRangeBehavior.ClosedOpen + ? "closed" + : "open", + }, + end: { + type: + rangeBehavior === DecorationRangeBehavior.ClosedClosed || + rangeBehavior === DecorationRangeBehavior.OpenClosed + ? "closed" + : "open", + }, + }, + offsets: { + start: document.offsetAt(range.start), + end: document.offsetAt(range.end), + }, + text: document.getText(range), + }; +} + +/** + * Creates SelectionInfo objects for all selections in a list of lists. + * + * @param document The document containing the selections + * @param rangeMatrix A list of lists of selections + * @param rangeBehavior How selections should behave with respect to insertions on either end + * @returns A list of lists of selection info objects + */ +function rangesToRangeInfos( + document: TextDocument, + rangeMatrix: (readonly Range[])[], + rangeBehavior: DecorationRangeBehavior = DecorationRangeBehavior.ClosedClosed +): FullRangeInfo[][] { + return rangeMatrix.map((ranges) => + ranges.map((range) => getRangeInfo(document, range, rangeBehavior)) + ); +} + +function rangeInfosToRanges(rangeInfoMatrix: RangeInfo[][]): Range[][] { + return rangeInfoMatrix.map((rangeInfos) => + rangeInfos.map(({ range }) => range) + ); +} + +/** + * Calls the given function and updates the given selections based on the + * changes that occurred as a result of calling function. + * @param rangeUpdater A RangeUpdate instance that will perform actual range updating + * @param func The function to call + * @param document The document containing the selections + * @param rangeMatrix A matrix of selections to update + * @returns The initial selections updated based upon what happened in the function + */ +export async function callFunctionAndUpdateRanges( + rangeUpdater: RangeUpdater, + func: () => Thenable, + document: TextDocument, + rangeMatrix: (readonly Range[])[] +): Promise { + const rangeInfoMatrix = rangesToRangeInfos(document, rangeMatrix); + + return await callFunctionAndUpdateSelectionInfos( + rangeUpdater, + func, + document, + rangeInfoMatrix + ); +} + +/** + * Calls the given function and updates the given selections based on the + * changes that occurred as a result of calling function. + * @param rangeUpdater A RangeUpdate instance that will perform actual range updating + * @param func The function to call + * @param document The document containing the selections + * @param selectionMatrix A matrix of selection info objects to update + * @returns The initial selections updated based upon what happened in the function + */ +export async function callFunctionAndUpdateSelectionInfos( + rangeUpdater: RangeUpdater, + func: () => Thenable, + document: TextDocument, + rangeInfoMatrix: FullRangeInfo[][] +) { + const unsubscribe = rangeUpdater.registerRangeInfoList( + document, + flatten(rangeInfoMatrix) + ); + + await func(); + + unsubscribe(); + + return rangeInfosToRanges(rangeInfoMatrix); +} + +/** + * Performs a list of edits and returns the given selections updated based on + * the applied edits + * @param rangeUpdater A RangeUpdate instance that will perform actual range updating + * @param editor The editor containing the selections + * @param edits A list of edits to apply + * @param originalRanges The selections to update + * @returns The updated selections + */ +export async function performEditsAndUpdateRanges( + rangeUpdater: RangeUpdater, + editor: TextEditor, + edits: Edit[], + originalRanges: (readonly Range[])[] +) { + const document = editor.document; + const selectionInfoMatrix = rangesToRangeInfos(document, originalRanges); + + await performEditsAndUpdateFullSelectionInfos( + rangeUpdater, + editor, + edits, + selectionInfoMatrix + ); + + return rangeInfosToRanges(selectionInfoMatrix); +} + +/** + * Performs a list of edits and returns the given selections updated based on + * the applied edits + * @param rangeUpdater A RangeUpdate instance that will perform actual range updating + * @param editor The editor containing the selections + * @param edits A list of edits to apply + * @param originalRangeInfos The selection info objects to update + * @returns The updated selections + */ +export async function performEditsAndUpdateFullSelectionInfos( + rangeUpdater: RangeUpdater, + editor: TextEditor, + edits: Edit[], + originalRangeInfos: FullRangeInfo[][] +) { + // NB: We do everything using VSCode listeners. We can associate changes + // with our changes just by looking at their offets / text in order to + // recover isReplace. We need to do this because VSCode does some fancy + // stuff, and returns the changes in a nice order + // Note that some additional weird edits like whitespace things can be + // created by VSCode I believe, and they change order, so we can't just zip + // their changes with ours. + // Their ordering basically is reverse document order, unless edits are at + // the same location, in which case they're in reverse order of the changes + // as you created them. + // See + // https://github.com/microsoft/vscode/blob/174db5eb992d880adcc42c41d83a0e6cb6b92474/src/vs/editor/common/core/range.ts#L430-L440 + // and + // https://github.com/microsoft/vscode/blob/174db5eb992d880adcc42c41d83a0e6cb6b92474/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer.ts#L598-L604 + // See also + // https://github.com/microsoft/vscode/blob/174db5eb992d880adcc42c41d83a0e6cb6b92474/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer.ts#L464 + // - We have a component on the graph called graph.rangeUpdater + // - It supports registering a list of selections to keep up-to-date, and + // it returns a dispose function. + // - It also has a function that allows callers to register isReplace edits, + // and it will look those up when it receives edits in order to set that + // field. + + const func = async () => { + const wereEditsApplied = await performDocumentEdits( + rangeUpdater, + editor, + edits + ); + + if (!wereEditsApplied) { + throw new Error("Could not apply edits"); + } + }; + + await callFunctionAndUpdateSelectionInfos( + rangeUpdater, + func, + editor.document, + originalRangeInfos + ); + + return rangeInfosToRanges(originalRangeInfos); +} diff --git a/src/core/updateSelections/updateSelections.ts b/src/core/updateSelections/updateSelections.ts index d4a17b15d4..db18afeac2 100644 --- a/src/core/updateSelections/updateSelections.ts +++ b/src/core/updateSelections/updateSelections.ts @@ -1,13 +1,18 @@ -import { flatten } from "lodash"; import { + Selection, + TextEditor, + TextDocument, DecorationRangeBehavior, Range, - TextDocument, - TextEditor, } from "vscode"; -import { Edit } from "../../typings/Types"; -import { FullRangeInfo, RangeInfo } from "../../typings/updateSelections"; +import { flatten } from "lodash"; +import { + FullSelectionInfo, + SelectionInfo, +} from "../../typings/updateSelections"; import { performDocumentEdits } from "../../util/performDocumentEdits"; +import { isForward } from "../../util/selectionUtils"; +import { Edit } from "../../typings/Types"; import { RangeUpdater } from "./RangeUpdater"; /** @@ -15,17 +20,18 @@ import { RangeUpdater } from "./RangeUpdater"; * be passed in to any of the commands that update selections. * * @param document The document containing the selection - * @param range The range + * @param selection The selection * @param rangeBehavior How selection should behave with respect to insertions on either end * @returns An object that can be used for selection tracking */ -export function getRangeInfo( +export function getSelectionInfo( document: TextDocument, - range: Range, + selection: Selection, rangeBehavior: DecorationRangeBehavior -): FullRangeInfo { +): FullSelectionInfo { return { - range: new Range(range.start, range.end), + range: new Range(selection.start, selection.end), + isForward: isForward(selection), expansionBehavior: { start: { type: @@ -43,10 +49,10 @@ export function getRangeInfo( }, }, offsets: { - start: document.offsetAt(range.start), - end: document.offsetAt(range.end), + start: document.offsetAt(selection.start), + end: document.offsetAt(selection.end), }, - text: document.getText(range), + text: document.getText(selection), }; } @@ -54,28 +60,30 @@ export function getRangeInfo( * Creates SelectionInfo objects for all selections in a list of lists. * * @param document The document containing the selections - * @param rangeMatrix A list of lists of selections + * @param selectionMatrix A list of lists of selections * @param rangeBehavior How selections should behave with respect to insertions on either end * @returns A list of lists of selection info objects */ -export function rangesToRangeInfos( +export function selectionsToSelectionInfos( document: TextDocument, - rangeMatrix: (readonly Range[])[], + selectionMatrix: (readonly Selection[])[], rangeBehavior: DecorationRangeBehavior = DecorationRangeBehavior.ClosedClosed -): FullRangeInfo[][] { - return rangeMatrix.map((ranges) => - ranges.map((range) => getRangeInfo(document, range, rangeBehavior)) +): FullSelectionInfo[][] { + return selectionMatrix.map((selections) => + selections.map((selection) => + getSelectionInfo(document, selection, rangeBehavior) + ) ); } -function fillOutRangeInfos( +function fillOutSelectionInfos( document: TextDocument, - rangeInfoMatrix: RangeInfo[][] -): rangeInfoMatrix is FullRangeInfo[][] { - rangeInfoMatrix.forEach((rangeInfos) => - rangeInfos.map((rangeInfo) => { - const { range } = rangeInfo; - Object.assign(rangeInfo, { + selectionInfoMatrix: SelectionInfo[][] +): selectionInfoMatrix is FullSelectionInfo[][] { + selectionInfoMatrix.forEach((selectionInfos) => + selectionInfos.map((selectionInfo) => { + const { range } = selectionInfo; + Object.assign(selectionInfo, { offsets: { start: document.offsetAt(range.start), end: document.offsetAt(range.end), @@ -87,9 +95,13 @@ function fillOutRangeInfos( return true; } -function rangeInfosToRanges(rangeInfoMatrix: RangeInfo[][]): Range[][] { - return rangeInfoMatrix.map((rangeInfos) => - rangeInfos.map(({ range }) => range) +function selectionInfosToSelections( + selectionInfoMatrix: SelectionInfo[][] +): Selection[][] { + return selectionInfoMatrix.map((selectionInfos) => + selectionInfos.map(({ range: { start, end }, isForward }) => + isForward ? new Selection(start, end) : new Selection(end, start) + ) ); } @@ -99,22 +111,25 @@ function rangeInfosToRanges(rangeInfoMatrix: RangeInfo[][]): Range[][] { * @param rangeUpdater A RangeUpdate instance that will perform actual range updating * @param func The function to call * @param document The document containing the selections - * @param rangeMatrix A matrix of selections to update + * @param selectionMatrix A matrix of selections to update * @returns The initial selections updated based upon what happened in the function */ export async function callFunctionAndUpdateSelections( rangeUpdater: RangeUpdater, func: () => Thenable, document: TextDocument, - rangeMatrix: (readonly Range[])[] -): Promise { - const rangeInfoMatrix = rangesToRangeInfos(document, rangeMatrix); + selectionMatrix: (readonly Selection[])[] +): Promise { + const selectionInfoMatrix = selectionsToSelectionInfos( + document, + selectionMatrix + ); return await callFunctionAndUpdateSelectionInfos( rangeUpdater, func, document, - rangeInfoMatrix + selectionInfoMatrix ); } @@ -131,18 +146,18 @@ export async function callFunctionAndUpdateSelectionInfos( rangeUpdater: RangeUpdater, func: () => Thenable, document: TextDocument, - rangeInfoMatrix: FullRangeInfo[][] + selectionInfoMatrix: FullSelectionInfo[][] ) { const unsubscribe = rangeUpdater.registerRangeInfoList( document, - flatten(rangeInfoMatrix) + flatten(selectionInfoMatrix) ); await func(); unsubscribe(); - return rangeInfosToRanges(rangeInfoMatrix); + return selectionInfosToSelections(selectionInfoMatrix); } /** @@ -151,17 +166,20 @@ export async function callFunctionAndUpdateSelectionInfos( * @param rangeUpdater A RangeUpdate instance that will perform actual range updating * @param editor The editor containing the selections * @param edits A list of edits to apply - * @param originalRanges The selections to update + * @param originalSelections The selections to update * @returns The updated selections */ -export async function performEditsAndUpdateRanges( +export async function performEditsAndUpdateSelections( rangeUpdater: RangeUpdater, editor: TextEditor, edits: Edit[], - originalRanges: (readonly Range[])[] + originalSelections: (readonly Selection[])[] ) { const document = editor.document; - const selectionInfoMatrix = rangesToRangeInfos(document, originalRanges); + const selectionInfoMatrix = selectionsToSelectionInfos( + document, + originalSelections + ); await performEditsAndUpdateFullSelectionInfos( rangeUpdater, @@ -170,7 +188,7 @@ export async function performEditsAndUpdateRanges( selectionInfoMatrix ); - return rangeInfosToRanges(selectionInfoMatrix); + return selectionInfosToSelections(selectionInfoMatrix); } // TODO: Remove this function if we don't end up using it for the next couple use cases, eg `that` mark and cursor history @@ -178,15 +196,15 @@ export async function performEditsAndUpdateSelectionInfos( rangeUpdater: RangeUpdater, editor: TextEditor, edits: Edit[], - originalRangeInfos: RangeInfo[][] + originalSelectionInfos: SelectionInfo[][] ) { - fillOutRangeInfos(editor.document, originalRangeInfos); + fillOutSelectionInfos(editor.document, originalSelectionInfos); return await performEditsAndUpdateFullSelectionInfos( rangeUpdater, editor, edits, - originalRangeInfos as FullRangeInfo[][] + originalSelectionInfos as FullSelectionInfo[][] ); } @@ -196,14 +214,14 @@ export async function performEditsAndUpdateSelectionInfos( * @param rangeUpdater A RangeUpdate instance that will perform actual range updating * @param editor The editor containing the selections * @param edits A list of edits to apply - * @param originalRangeInfos The selection info objects to update + * @param originalSelectionInfos The selection info objects to update * @returns The updated selections */ export async function performEditsAndUpdateFullSelectionInfos( rangeUpdater: RangeUpdater, editor: TextEditor, edits: Edit[], - originalRangeInfos: FullRangeInfo[][] + originalSelectionInfos: FullSelectionInfo[][] ) { // NB: We do everything using VSCode listeners. We can associate changes // with our changes just by looking at their offets / text in order to @@ -244,8 +262,8 @@ export async function performEditsAndUpdateFullSelectionInfos( rangeUpdater, func, editor.document, - originalRangeInfos + originalSelectionInfos ); - return rangeInfosToRanges(originalRangeInfos); + return selectionInfosToSelections(originalSelectionInfos); } diff --git a/src/util/targetUtils.ts b/src/util/targetUtils.ts index d425c46cef..43cb7ca9af 100644 --- a/src/util/targetUtils.ts +++ b/src/util/targetUtils.ts @@ -100,6 +100,23 @@ export function getContentRange(target: Target) { return target.contentRange; } +export function getContentText(target: Target) { + return target.editor.document.getText(target.contentRange); +} + +export function getContentSelection(target: Target) { + return target.isReversed + ? new Selection(target.contentRange.end, target.contentRange.start) + : new Selection(target.contentRange.start, target.contentRange.end); +} + +// export function createSelections( +// targets: Target[], +// ranges: Range[] +// ) { + +// } + export function createThatMark( targets: Target[], ranges?: Range[] From 70107097a10acc6e46e5ee6435c81ccee30fac62 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 15 May 2022 22:52:35 +0200 Subject: [PATCH 045/314] Added follow action --- src/actions/Actions.ts | 3 +- src/actions/FollowLink.ts | 97 ++++++++++++++++-------------------- src/actions/actions.types.ts | 2 +- src/util/targetUtils.ts | 7 --- 4 files changed, 47 insertions(+), 62 deletions(-) diff --git a/src/actions/Actions.ts b/src/actions/Actions.ts index 2f7e683298..6f67fa9e2b 100644 --- a/src/actions/Actions.ts +++ b/src/actions/Actions.ts @@ -2,6 +2,7 @@ import { ActionRecord, Graph } from "../typings/Types"; import Clear from "./Clear"; import Deselect from "./Deselect"; import ExecuteCommand from "./ExecuteCommand"; +import FollowLink from "./FollowLink"; import GetText from "./GetText"; import Highlight from "./Highlight"; import { IndentLines, OutdentLines } from "./Indent"; @@ -25,7 +26,7 @@ class Actions implements ActionRecord { // extractVariable = new ExtractVariable(this.graph); // findInWorkspace = new FindInFiles(this.graph); // foldRegion = new Fold(this.graph); - // followLink = new FollowLink(this.graph); + followLink = new FollowLink(this.graph); getText = new GetText(this.graph); highlight = new Highlight(this.graph); indentLine = new IndentLines(this.graph); diff --git a/src/actions/FollowLink.ts b/src/actions/FollowLink.ts index a6ee0ef294..a113275c4e 100644 --- a/src/actions/FollowLink.ts +++ b/src/actions/FollowLink.ts @@ -1,59 +1,50 @@ -// 1import { env, Uri, window } from "vscode"; -// import { -// Action, -// ActionPreferences, -// ActionReturnValue, -// Graph, -// Target, -// } from "../typings/Types"; -// import displayPendingEditDecorations from "../util/editDisplayUtils"; -// import { getLinkForTarget } from "../util/getLinks"; -// import { ensureSingleTarget } from "../util/targetUtils"; +import { env, Uri, window } from "vscode"; +import { Target } from "../typings/target.types"; +import { Action, ActionReturnValue, Graph } from "../typings/Types"; +import displayPendingEditDecorations from "../util/editDisplayUtils"; +import { getLinkForTarget } from "../util/getLinks"; +import { createThatMark, ensureSingleTarget } from "../util/targetUtils"; -// export default class FollowLink implements Action { -// getTargetPreferences: () => ActionPreferences[] = () => [ -// { insideOutsideType: "inside" }, -// ]; +export default class FollowLink implements Action { + constructor(private graph: Graph) { + this.run = this.run.bind(this); + } -// constructor(private graph: Graph) { -// this.run = this.run.bind(this); -// } + async run([targets]: [Target[]]): Promise { + const target = ensureSingleTarget(targets); -// async run([targets]: [Target[]]): Promise { -// const target = ensureSingleTarget(targets); + await displayPendingEditDecorations( + targets, + this.graph.editStyles.referenced + ); -// await displayPendingEditDecorations( -// targets, -// this.graph.editStyles.referenced -// ); + const link = await getLinkForTarget(target); + if (link) { + await this.openUri(link.target!); + } else { + await this.graph.actions.executeCommand.run( + [targets], + "editor.action.revealDefinition", + { restoreSelection: false } + ); + } -// const link = await getLinkForTarget(target); -// if (link) { -// await this.openUri(link.target!); -// } else { -// await this.graph.actions.executeCommand.run( -// [targets], -// "editor.action.revealDefinition", -// { restoreSelection: false } -// ); -// } + return { + thatMark: createThatMark(targets), + }; + } -// return { -// thatMark: targets.map((target) => target.selection), -// }; -// } - -// private async openUri(uri: Uri) { -// switch (uri.scheme) { -// case "http": -// case "https": -// await env.openExternal(uri); -// break; -// case "file": -// await window.showTextDocument(uri); -// break; -// default: -// throw Error(`Unknown uri scheme '${uri.scheme}'`); -// } -// } -// } + private async openUri(uri: Uri) { + switch (uri.scheme) { + case "http": + case "https": + await env.openExternal(uri); + break; + case "file": + await window.showTextDocument(uri); + break; + default: + throw Error(`Unknown uri scheme '${uri.scheme}'`); + } + } +} diff --git a/src/actions/actions.types.ts b/src/actions/actions.types.ts index c402f25d7a..a7f38490c8 100644 --- a/src/actions/actions.types.ts +++ b/src/actions/actions.types.ts @@ -10,7 +10,7 @@ export type ActionType = // | "extractVariable" // | "findInWorkspace" // | "foldRegion" - // | "followLink" + | "followLink" | "getText" | "highlight" | "indentLine" diff --git a/src/util/targetUtils.ts b/src/util/targetUtils.ts index 43cb7ca9af..13271dcff6 100644 --- a/src/util/targetUtils.ts +++ b/src/util/targetUtils.ts @@ -110,13 +110,6 @@ export function getContentSelection(target: Target) { : new Selection(target.contentRange.start, target.contentRange.end); } -// export function createSelections( -// targets: Target[], -// ranges: Range[] -// ) { - -// } - export function createThatMark( targets: Target[], ranges?: Range[] From 2ad914593317e4be5cc1348882a1b292f7a33009 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 15 May 2022 22:56:54 +0200 Subject: [PATCH 046/314] Added find action --- src/actions/Actions.ts | 3 ++- src/actions/Find.ts | 49 +++++++++++++++--------------------- src/actions/actions.types.ts | 2 +- 3 files changed, 23 insertions(+), 31 deletions(-) diff --git a/src/actions/Actions.ts b/src/actions/Actions.ts index 6f67fa9e2b..7de8acac12 100644 --- a/src/actions/Actions.ts +++ b/src/actions/Actions.ts @@ -2,6 +2,7 @@ import { ActionRecord, Graph } from "../typings/Types"; import Clear from "./Clear"; import Deselect from "./Deselect"; import ExecuteCommand from "./ExecuteCommand"; +import { FindInFiles } from "./Find"; import FollowLink from "./FollowLink"; import GetText from "./GetText"; import Highlight from "./Highlight"; @@ -24,7 +25,7 @@ class Actions implements ActionRecord { // editNewLineBefore = new EditNewLineAbove(this.graph); executeCommand = new ExecuteCommand(this.graph); // extractVariable = new ExtractVariable(this.graph); - // findInWorkspace = new FindInFiles(this.graph); + findInWorkspace = new FindInFiles(this.graph); // foldRegion = new Fold(this.graph); followLink = new FollowLink(this.graph); getText = new GetText(this.graph); diff --git a/src/actions/Find.ts b/src/actions/Find.ts index 8a942fc609..379d760710 100644 --- a/src/actions/Find.ts +++ b/src/actions/Find.ts @@ -1,34 +1,25 @@ -// import { -// Action, -// ActionReturnValue, -// ActionPreferences, -// Graph, -// Target, -// } from "../typings/Types"; -// import { commands } from "vscode"; -// import { ensureSingleTarget } from "../util/targetUtils"; +import { commands } from "vscode"; +import { Target } from "../typings/target.types"; +import { Action, ActionReturnValue, Graph } from "../typings/Types"; +import { ensureSingleTarget } from "../util/targetUtils"; -// export class FindInFiles implements Action { -// getTargetPreferences: () => ActionPreferences[] = () => [ -// { insideOutsideType: "inside" }, -// ]; +export class FindInFiles implements Action { + constructor(private graph: Graph) { + this.run = this.run.bind(this); + } -// constructor(private graph: Graph) { -// this.run = this.run.bind(this); -// } + async run([targets]: [Target[]]): Promise { + ensureSingleTarget(targets); -// async run([targets]: [Target[]]): Promise { -// ensureSingleTarget(targets); + const { + returnValue: [query], + thatMark, + } = await this.graph.actions.getText.run([targets]); -// const { -// returnValue: [query], -// thatMark, -// } = await this.graph.actions.getText.run([targets]); + await commands.executeCommand("workbench.action.findInFiles", { + query, + }); -// await commands.executeCommand("workbench.action.findInFiles", { -// query, -// }); - -// return { thatMark }; -// } -// } + return { thatMark }; + } +} diff --git a/src/actions/actions.types.ts b/src/actions/actions.types.ts index a7f38490c8..17de7289ba 100644 --- a/src/actions/actions.types.ts +++ b/src/actions/actions.types.ts @@ -8,7 +8,7 @@ export type ActionType = // | "editNewLineBefore" | "executeCommand" // | "extractVariable" - // | "findInWorkspace" + | "findInWorkspace" // | "foldRegion" | "followLink" | "getText" From fe34cfc18fbace90d3c10282b9c269504190f6bb Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 15 May 2022 23:02:55 +0200 Subject: [PATCH 047/314] Added fold action --- src/actions/Actions.ts | 5 +- src/actions/Fold.ts | 122 ++++++++++++++++------------------- src/actions/actions.types.ts | 3 +- 3 files changed, 62 insertions(+), 68 deletions(-) diff --git a/src/actions/Actions.ts b/src/actions/Actions.ts index 7de8acac12..4e82b4f48d 100644 --- a/src/actions/Actions.ts +++ b/src/actions/Actions.ts @@ -3,6 +3,7 @@ import Clear from "./Clear"; import Deselect from "./Deselect"; import ExecuteCommand from "./ExecuteCommand"; import { FindInFiles } from "./Find"; +import { Fold, Unfold } from "./Fold"; import FollowLink from "./FollowLink"; import GetText from "./GetText"; import Highlight from "./Highlight"; @@ -26,7 +27,7 @@ class Actions implements ActionRecord { executeCommand = new ExecuteCommand(this.graph); // extractVariable = new ExtractVariable(this.graph); findInWorkspace = new FindInFiles(this.graph); - // foldRegion = new Fold(this.graph); + foldRegion = new Fold(this.graph); followLink = new FollowLink(this.graph); getText = new GetText(this.graph); highlight = new Highlight(this.graph); @@ -56,7 +57,7 @@ class Actions implements ActionRecord { // swapTargets = new Swap(this.graph); // toggleLineBreakpoint = new SetBreakpoint(this.graph); // toggleLineComment = new CommentLines(this.graph); - // unfoldRegion = new Unfold(this.graph); + unfoldRegion = new Unfold(this.graph); // wrapWithPairedDelimiter = new Wrap(this.graph); // wrapWithSnippet = new WrapWithSnippet(this.graph); // diff --git a/src/actions/Fold.ts b/src/actions/Fold.ts index 328c8a0a4c..49b61df121 100644 --- a/src/actions/Fold.ts +++ b/src/actions/Fold.ts @@ -1,74 +1,66 @@ -// import { commands, window } from "vscode"; -// import { -// Action, -// ActionPreferences, -// ActionReturnValue, -// Graph, -// Target, -// } from "../typings/Types"; -// import { focusEditor } from "../util/setSelectionsAndFocusEditor"; -// import { ensureSingleEditor } from "../util/targetUtils"; +import { commands, window } from "vscode"; +import { Target } from "../typings/target.types"; +import { Action, ActionReturnValue, Graph } from "../typings/Types"; +import { focusEditor } from "../util/setSelectionsAndFocusEditor"; +import { + createThatMark, + ensureSingleEditor, + getContentRange, +} from "../util/targetUtils"; -// class FoldAction implements Action { -// getTargetPreferences: () => ActionPreferences[] = () => [ -// { insideOutsideType: "inside" }, -// ]; +class FoldAction implements Action { + constructor(private command: string) { + this.run = this.run.bind(this); + } -// constructor(private command: string) { -// this.run = this.run.bind(this); -// } + async run([targets]: [Target[], Target[]]): Promise { + const originalEditor = window.activeTextEditor; + const editor = ensureSingleEditor(targets); -// async run([targets]: [ -// Target[], -// Target[] -// ]): Promise { -// const originalEditor = window.activeTextEditor; -// const editor = ensureSingleEditor(targets); + if (originalEditor !== editor) { + await focusEditor(editor); + } -// if (originalEditor !== editor) { -// await focusEditor(editor); -// } + const singleLineTargets = targets.filter( + (target) => getContentRange(target).isSingleLine + ); + const multiLineTargets = targets.filter( + (target) => !getContentRange(target).isSingleLine + ); + // Don't mix multi and single line targets. + // This is probably the result of an "every" command + // and folding the single line targets will fold the parent as well + const selectedTargets = multiLineTargets.length + ? multiLineTargets + : singleLineTargets; -// const singleLineTargets = targets.filter( -// (target) => target.selection.selection.isSingleLine -// ); -// const multiLineTargets = targets.filter( -// (target) => !target.selection.selection.isSingleLine -// ); -// // Don't mix multi and single line targets. -// // This is probably the result of an "every" command -// // and folding the single line targets will fold the parent as well -// const selectedTargets = multiLineTargets.length -// ? multiLineTargets -// : singleLineTargets; + await commands.executeCommand(this.command, { + levels: 1, + direction: "down", + selectionLines: selectedTargets.map( + (target) => getContentRange(target).start.line + ), + }); -// await commands.executeCommand(this.command, { -// levels: 1, -// direction: "down", -// selectionLines: selectedTargets.map( -// (target) => target.selection.selection.start.line -// ), -// }); + // If necessary focus back original editor + if (originalEditor != null && originalEditor !== editor) { + await focusEditor(originalEditor); + } -// // If necessary focus back original editor -// if (originalEditor != null && originalEditor !== editor) { -// await focusEditor(originalEditor); -// } + return { + thatMark: createThatMark(targets), + }; + } +} -// return { -// thatMark: targets.map((target) => target.selection), -// }; -// } -// } +export class Fold extends FoldAction { + constructor(_graph: Graph) { + super("editor.fold"); + } +} -// export class Fold extends FoldAction { -// constructor(_graph: Graph) { -// super("editor.fold"); -// } -// } - -// export class Unfold extends FoldAction { -// constructor(_graph: Graph) { -// super("editor.unfold"); -// } -// } +export class Unfold extends FoldAction { + constructor(_graph: Graph) { + super("editor.unfold"); + } +} diff --git a/src/actions/actions.types.ts b/src/actions/actions.types.ts index 17de7289ba..cf4a50e870 100644 --- a/src/actions/actions.types.ts +++ b/src/actions/actions.types.ts @@ -9,7 +9,7 @@ export type ActionType = | "executeCommand" // | "extractVariable" | "findInWorkspace" - // | "foldRegion" + | "foldRegion" | "followLink" | "getText" | "highlight" @@ -21,6 +21,7 @@ export type ActionType = // | "insertEmptyLinesAround" // | "moveToTarget" | "outdentLine" + | "unfoldRegion" // | "pasteFromClipboard" | "remove" // | "replace" From 55b23d0c8b10f1bc813c10152330c8ee233f6713 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 15 May 2022 23:12:02 +0200 Subject: [PATCH 048/314] Added scroll actions --- src/actions/Actions.ts | 7 +- src/actions/Fold.ts | 12 +-- src/actions/Scroll.ts | 177 ++++++++++++++++------------------- src/actions/actions.types.ts | 6 +- src/util/editDisplayUtils.ts | 12 +-- 5 files changed, 99 insertions(+), 115 deletions(-) diff --git a/src/actions/Actions.ts b/src/actions/Actions.ts index 4e82b4f48d..36286e7fb6 100644 --- a/src/actions/Actions.ts +++ b/src/actions/Actions.ts @@ -9,6 +9,7 @@ import GetText from "./GetText"; import Highlight from "./Highlight"; import { IndentLines, OutdentLines } from "./Indent"; import Remove from "./Remove"; +import { ScrollToBottom, ScrollToCenter, ScrollToTop } from "./Scroll"; import { SetSelection, SetSelectionAfter, @@ -47,9 +48,9 @@ class Actions implements ActionRecord { // randomizeTargets = new Random(this.graph); // reverseTargets = new Reverse(this.graph); // rewrapWithPairedDelimiter = new Rewrap(this.graph); - // scrollToBottom = new ScrollToBottom(this.graph); - // scrollToCenter = new ScrollToCenter(this.graph); - // scrollToTop = new ScrollToTop(this.graph); + scrollToBottom = new ScrollToBottom(this.graph); + scrollToCenter = new ScrollToCenter(this.graph); + scrollToTop = new ScrollToTop(this.graph); setSelection = new SetSelection(this.graph); setSelectionAfter = new SetSelectionAfter(this.graph); setSelectionBefore = new SetSelectionBefore(this.graph); diff --git a/src/actions/Fold.ts b/src/actions/Fold.ts index 49b61df121..d3bf36f4bd 100644 --- a/src/actions/Fold.ts +++ b/src/actions/Fold.ts @@ -2,11 +2,7 @@ import { commands, window } from "vscode"; import { Target } from "../typings/target.types"; import { Action, ActionReturnValue, Graph } from "../typings/Types"; import { focusEditor } from "../util/setSelectionsAndFocusEditor"; -import { - createThatMark, - ensureSingleEditor, - getContentRange, -} from "../util/targetUtils"; +import { createThatMark, ensureSingleEditor } from "../util/targetUtils"; class FoldAction implements Action { constructor(private command: string) { @@ -22,10 +18,10 @@ class FoldAction implements Action { } const singleLineTargets = targets.filter( - (target) => getContentRange(target).isSingleLine + (target) => target.contentRange.isSingleLine ); const multiLineTargets = targets.filter( - (target) => !getContentRange(target).isSingleLine + (target) => !target.contentRange.isSingleLine ); // Don't mix multi and single line targets. // This is probably the result of an "every" command @@ -38,7 +34,7 @@ class FoldAction implements Action { levels: 1, direction: "down", selectionLines: selectedTargets.map( - (target) => getContentRange(target).start.line + (target) => target.contentRange.start.line ), }); diff --git a/src/actions/Scroll.ts b/src/actions/Scroll.ts index 026f64f9ed..a224237aef 100644 --- a/src/actions/Scroll.ts +++ b/src/actions/Scroll.ts @@ -1,109 +1,96 @@ -// import { -// Action, -// ActionPreferences, -// ActionReturnValue, -// Graph, -// Target, -// } from "../typings/Types"; -// import { groupBy } from "../util/itertools"; -// import { commands, window } from "vscode"; -// import { focusEditor } from "../util/setSelectionsAndFocusEditor"; -// import { displayPendingEditDecorationsForSelection } from "../util/editDisplayUtils"; +import { commands, window } from "vscode"; +import { Target } from "../typings/target.types"; +import { Action, ActionReturnValue, Graph } from "../typings/Types"; +import { displayPendingEditDecorationsForTargets } from "../util/editDisplayUtils"; +import { groupBy } from "../util/itertools"; +import { focusEditor } from "../util/setSelectionsAndFocusEditor"; +import { createThatMark } from "../util/targetUtils"; -// class Scroll implements Action { -// getTargetPreferences: () => ActionPreferences[] = () => [ -// { insideOutsideType: "inside" }, -// ]; +class Scroll implements Action { + constructor(private graph: Graph, private at: string) { + this.run = this.run.bind(this); + } -// constructor(private graph: Graph, private at: string) { -// this.run = this.run.bind(this); -// } + async run([targets]: [Target[]]): Promise { + const selectionGroups = groupBy(targets, (t: Target) => t.editor); -// async run([targets]: [Target[]]): Promise { -// const selectionGroups = groupBy( -// targets, -// (t: Target) => t.selection.editor -// ); + const lines = Array.from(selectionGroups, ([editor, targets]) => { + return { lineNumber: getLineNumber(targets, this.at), editor }; + }); -// const lines = Array.from(selectionGroups, ([editor, targets]) => { -// return { lineNumber: getLineNumber(targets, this.at), editor }; -// }); + const originalEditor = window.activeTextEditor; -// const originalEditor = window.activeTextEditor; + for (const lineWithEditor of lines) { + // For reveal line to the work we have to have the correct editor focused + if (lineWithEditor.editor !== window.activeTextEditor) { + await focusEditor(lineWithEditor.editor); + } + await commands.executeCommand("revealLine", { + lineNumber: lineWithEditor.lineNumber, + at: this.at, + }); + } -// for (const lineWithEditor of lines) { -// // For reveal line to the work we have to have the correct editor focused -// if (lineWithEditor.editor !== window.activeTextEditor) { -// await focusEditor(lineWithEditor.editor); -// } -// await commands.executeCommand("revealLine", { -// lineNumber: lineWithEditor.lineNumber, -// at: this.at, -// }); -// } + // If necessary focus back original editor + if (originalEditor != null && originalEditor !== window.activeTextEditor) { + await focusEditor(originalEditor); + } -// // If necessary focus back original editor -// if (originalEditor != null && originalEditor !== window.activeTextEditor) { -// await focusEditor(originalEditor); -// } + const decorationTargets = targets.filter((target) => { + const visibleRanges = target.editor.visibleRanges; + const startLine = visibleRanges[0].start.line; + const endLine = visibleRanges[visibleRanges.length - 1].end.line; + // Don't show decorations for selections that are larger than the visible range + return ( + target.contentRange.start.line > startLine || + target.contentRange.end.line < endLine || + (target.contentRange.start.line === startLine && + target.contentRange.end.line === endLine) + ); + }); -// const decorationSelections = targets -// .map((target) => target.selection) -// .filter((selection) => { -// const visibleRanges = selection.editor.visibleRanges; -// const startLine = visibleRanges[0].start.line; -// const endLine = visibleRanges[visibleRanges.length - 1].end.line; -// // Don't show decorations for selections that are larger than the visible range -// return ( -// selection.selection.start.line > startLine || -// selection.selection.end.line < endLine || -// (selection.selection.start.line === startLine && -// selection.selection.end.line === endLine) -// ); -// }); + await displayPendingEditDecorationsForTargets( + decorationTargets, + this.graph.editStyles.referenced.line + ); -// await displayPendingEditDecorationsForSelection( -// decorationSelections, -// this.graph.editStyles.referenced.line -// ); + return { + thatMark: createThatMark(targets), + }; + } +} -// return { -// thatMark: targets.map((target) => target.selection), -// }; -// } -// } +export class ScrollToTop extends Scroll { + constructor(graph: Graph) { + super(graph, "top"); + } +} -// export class ScrollToTop extends Scroll { -// constructor(graph: Graph) { -// super(graph, "top"); -// } -// } +export class ScrollToCenter extends Scroll { + constructor(graph: Graph) { + super(graph, "center"); + } +} -// export class ScrollToCenter extends Scroll { -// constructor(graph: Graph) { -// super(graph, "center"); -// } -// } +export class ScrollToBottom extends Scroll { + constructor(graph: Graph) { + super(graph, "bottom"); + } +} -// export class ScrollToBottom extends Scroll { -// constructor(graph: Graph) { -// super(graph, "bottom"); -// } -// } +function getLineNumber(targets: Target[], at: string) { + let startLine = Number.MAX_SAFE_INTEGER; + let endLine = 0; + targets.forEach((target: Target) => { + startLine = Math.min(startLine, target.contentRange.start.line); + endLine = Math.max(endLine, target.contentRange.end.line); + }); -// function getLineNumber(targets: Target[], at: string) { -// let startLine = Number.MAX_SAFE_INTEGER; -// let endLine = 0; -// targets.forEach((t: Target) => { -// startLine = Math.min(startLine, t.selection.selection.start.line); -// endLine = Math.max(endLine, t.selection.selection.end.line); -// }); - -// if (at === "top") { -// return startLine; -// } -// if (at === "bottom") { -// return endLine; -// } -// return Math.floor((startLine + endLine) / 2); -// } + if (at === "top") { + return startLine; + } + if (at === "bottom") { + return endLine; + } + return Math.floor((startLine + endLine) / 2); +} diff --git a/src/actions/actions.types.ts b/src/actions/actions.types.ts index cf4a50e870..9991e07c94 100644 --- a/src/actions/actions.types.ts +++ b/src/actions/actions.types.ts @@ -28,9 +28,9 @@ export type ActionType = // | "replaceWithTarget" // | "reverseTargets" // | "rewrapWithPairedDelimiter" - // | "scrollToBottom" - // | "scrollToCenter" - // | "scrollToTop" + | "scrollToBottom" + | "scrollToCenter" + | "scrollToTop" | "setSelection" | "setSelectionAfter" | "setSelectionBefore"; diff --git a/src/util/editDisplayUtils.ts b/src/util/editDisplayUtils.ts index 7dec84323e..096243943d 100644 --- a/src/util/editDisplayUtils.ts +++ b/src/util/editDisplayUtils.ts @@ -23,17 +23,17 @@ export async function decorationSleep() { await sleep(getPendingEditDecorationTime()); } -export async function displayPendingEditDecorationsForSelection( - selections: SelectionWithEditor[], +export async function displayPendingEditDecorationsForTargets( + targets: Target[], style: TextEditorDecorationType ) { await runForEachEditor( - selections, + targets, (selection) => selection.editor, async (editor, selections) => { editor.setDecorations( style, - selections.map((selection) => selection.selection) + selections.map((target) => target.contentRange) ); } ); @@ -41,8 +41,8 @@ export async function displayPendingEditDecorationsForSelection( await decorationSleep(); await runForEachEditor( - selections, - (selection) => selection.editor, + targets, + (target) => target.editor, async (editor) => { editor.setDecorations(style, []); } From bb0717ffc1c6b0b3ecd951dec60775395104a3e1 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 15 May 2022 23:32:14 +0200 Subject: [PATCH 049/314] Added comment action --- src/actions/Actions.ts | 8 ++++--- src/actions/Clear.ts | 3 ++- src/actions/CommandAction.ts | 3 ++- src/actions/Comment.ts | 14 +++++------ src/actions/Deselect.ts | 3 ++- src/actions/ExecuteCommand.ts | 3 ++- src/actions/Find.ts | 3 ++- src/actions/Fold.ts | 3 ++- src/actions/FollowLink.ts | 3 ++- src/actions/GetText.ts | 3 ++- src/actions/Highlight.ts | 3 ++- src/actions/Remove.ts | 3 ++- src/actions/Scroll.ts | 3 ++- src/actions/SetSelection.ts | 3 ++- .../{SetBreakpoint.ts => ToggleBreakpoint.ts} | 7 ++---- src/actions/actions.types.ts | 24 +++++++++++++++++++ src/typings/Types.ts | 21 +--------------- 17 files changed, 63 insertions(+), 47 deletions(-) rename src/actions/{SetBreakpoint.ts => ToggleBreakpoint.ts} (93%) diff --git a/src/actions/Actions.ts b/src/actions/Actions.ts index 36286e7fb6..8e77254e97 100644 --- a/src/actions/Actions.ts +++ b/src/actions/Actions.ts @@ -1,5 +1,7 @@ -import { ActionRecord, Graph } from "../typings/Types"; +import { Graph } from "../typings/Types"; +import { ActionRecord } from "./actions.types"; import Clear from "./Clear"; +import { CommentLines } from "./Comment"; import Deselect from "./Deselect"; import ExecuteCommand from "./ExecuteCommand"; import { FindInFiles } from "./Find"; @@ -56,8 +58,8 @@ class Actions implements ActionRecord { setSelectionBefore = new SetSelectionBefore(this.graph); // sortTargets = new Sort(this.graph); // swapTargets = new Swap(this.graph); - // toggleLineBreakpoint = new SetBreakpoint(this.graph); - // toggleLineComment = new CommentLines(this.graph); + // toggleLineBreakpoint = new ToggleBreakpoint(this.graph); + toggleLineComment = new CommentLines(this.graph); unfoldRegion = new Unfold(this.graph); // wrapWithPairedDelimiter = new Wrap(this.graph); // wrapWithSnippet = new WrapWithSnippet(this.graph); diff --git a/src/actions/Clear.ts b/src/actions/Clear.ts index 44608b52c1..b3ae468327 100644 --- a/src/actions/Clear.ts +++ b/src/actions/Clear.ts @@ -1,7 +1,8 @@ import { Target } from "../typings/target.types"; -import { Action, ActionReturnValue, Graph } from "../typings/Types"; +import { Graph } from "../typings/Types"; import { setSelectionsAndFocusEditor } from "../util/setSelectionsAndFocusEditor"; import { ensureSingleEditor } from "../util/targetUtils"; +import { Action, ActionReturnValue } from "./actions.types"; export default class Clear implements Action { constructor(private graph: Graph) { diff --git a/src/actions/CommandAction.ts b/src/actions/CommandAction.ts index 93fa7c9f62..e73579644e 100644 --- a/src/actions/CommandAction.ts +++ b/src/actions/CommandAction.ts @@ -2,7 +2,7 @@ import { flatten } from "lodash"; import { commands, window } from "vscode"; import { callFunctionAndUpdateSelections } from "../core/updateSelections/updateSelections"; import { Target } from "../typings/target.types"; -import { Action, ActionReturnValue, Graph } from "../typings/Types"; +import { Graph } from "../typings/Types"; import displayPendingEditDecorations from "../util/editDisplayUtils"; import { focusEditor, @@ -13,6 +13,7 @@ import { getContentSelection, runOnTargetsForEachEditor, } from "../util/targetUtils"; +import { Action, ActionReturnValue } from "./actions.types"; export interface CommandOptions { command?: string; diff --git a/src/actions/Comment.ts b/src/actions/Comment.ts index cb0f951c01..bfb93a6c19 100644 --- a/src/actions/Comment.ts +++ b/src/actions/Comment.ts @@ -1,8 +1,8 @@ -// import { Graph } from "../typings/Types"; -// import CommandAction from "./CommandAction"; +import { Graph } from "../typings/Types"; +import CommandAction from "./CommandAction"; -// export class CommentLines extends CommandAction { -// constructor(graph: Graph) { -// super(graph, { command: "editor.action.commentLine" }); -// } -// } +export class CommentLines extends CommandAction { + constructor(graph: Graph) { + super(graph, { command: "editor.action.commentLine" }); + } +} diff --git a/src/actions/Deselect.ts b/src/actions/Deselect.ts index 6c26789c9e..e6ff981df1 100644 --- a/src/actions/Deselect.ts +++ b/src/actions/Deselect.ts @@ -1,7 +1,8 @@ import { Selection } from "vscode"; import { Target } from "../typings/target.types"; -import { Action, ActionReturnValue, Graph } from "../typings/Types"; +import { Graph } from "../typings/Types"; import { createThatMark, runOnTargetsForEachEditor } from "../util/targetUtils"; +import { Action, ActionReturnValue } from "./actions.types"; export default class Deselect implements Action { constructor(private graph: Graph) { diff --git a/src/actions/ExecuteCommand.ts b/src/actions/ExecuteCommand.ts index 5bd31b4ffb..3120b199bb 100644 --- a/src/actions/ExecuteCommand.ts +++ b/src/actions/ExecuteCommand.ts @@ -1,5 +1,6 @@ import { Target } from "../typings/target.types"; -import { Action, ActionReturnValue, Graph } from "../typings/Types"; +import { Graph } from "../typings/Types"; +import { Action, ActionReturnValue } from "./actions.types"; import CommandAction, { CommandOptions } from "./CommandAction"; export default class ExecuteCommand implements Action { diff --git a/src/actions/Find.ts b/src/actions/Find.ts index 379d760710..f4c1e7c626 100644 --- a/src/actions/Find.ts +++ b/src/actions/Find.ts @@ -1,7 +1,8 @@ import { commands } from "vscode"; import { Target } from "../typings/target.types"; -import { Action, ActionReturnValue, Graph } from "../typings/Types"; +import { Graph } from "../typings/Types"; import { ensureSingleTarget } from "../util/targetUtils"; +import { Action, ActionReturnValue } from "./actions.types"; export class FindInFiles implements Action { constructor(private graph: Graph) { diff --git a/src/actions/Fold.ts b/src/actions/Fold.ts index d3bf36f4bd..05529ad784 100644 --- a/src/actions/Fold.ts +++ b/src/actions/Fold.ts @@ -1,8 +1,9 @@ import { commands, window } from "vscode"; import { Target } from "../typings/target.types"; -import { Action, ActionReturnValue, Graph } from "../typings/Types"; +import { Graph } from "../typings/Types"; import { focusEditor } from "../util/setSelectionsAndFocusEditor"; import { createThatMark, ensureSingleEditor } from "../util/targetUtils"; +import { Action, ActionReturnValue } from "./actions.types"; class FoldAction implements Action { constructor(private command: string) { diff --git a/src/actions/FollowLink.ts b/src/actions/FollowLink.ts index a113275c4e..2008b84cb9 100644 --- a/src/actions/FollowLink.ts +++ b/src/actions/FollowLink.ts @@ -1,9 +1,10 @@ import { env, Uri, window } from "vscode"; import { Target } from "../typings/target.types"; -import { Action, ActionReturnValue, Graph } from "../typings/Types"; +import { Graph } from "../typings/Types"; import displayPendingEditDecorations from "../util/editDisplayUtils"; import { getLinkForTarget } from "../util/getLinks"; import { createThatMark, ensureSingleTarget } from "../util/targetUtils"; +import { Action, ActionReturnValue } from "./actions.types"; export default class FollowLink implements Action { constructor(private graph: Graph) { diff --git a/src/actions/GetText.ts b/src/actions/GetText.ts index 588c746bf0..c32afa2fc3 100644 --- a/src/actions/GetText.ts +++ b/src/actions/GetText.ts @@ -1,11 +1,12 @@ import { Target } from "../typings/target.types"; -import { Action, ActionReturnValue, Graph } from "../typings/Types"; +import { Graph } from "../typings/Types"; import displayPendingEditDecorations from "../util/editDisplayUtils"; import { createThatMark, ensureSingleTarget, getContentText, } from "../util/targetUtils"; +import { Action, ActionReturnValue } from "./actions.types"; export default class GetText implements Action { constructor(private graph: Graph) { diff --git a/src/actions/Highlight.ts b/src/actions/Highlight.ts index f6612a2917..db37097d2b 100644 --- a/src/actions/Highlight.ts +++ b/src/actions/Highlight.ts @@ -1,8 +1,9 @@ import { EditStyleName } from "../core/editStyles"; import { Target } from "../typings/target.types"; -import { Action, ActionReturnValue, Graph } from "../typings/Types"; +import { Graph } from "../typings/Types"; import { clearDecorations, setDecorations } from "../util/editDisplayUtils"; import { createThatMark } from "../util/targetUtils"; +import { Action, ActionReturnValue } from "./actions.types"; export default class Highlight implements Action { constructor(private graph: Graph) { diff --git a/src/actions/Remove.ts b/src/actions/Remove.ts index e021031043..0434f4ae2b 100644 --- a/src/actions/Remove.ts +++ b/src/actions/Remove.ts @@ -2,7 +2,7 @@ import { flatten } from "lodash"; import { performEditsAndUpdateRanges } from "../core/updateSelections/updateRanges"; // import { unifyTargets } from "../util/unifyRanges"; import { Target } from "../typings/target.types"; -import { Action, ActionReturnValue, Graph } from "../typings/Types"; +import { Graph } from "../typings/Types"; import displayPendingEditDecorations from "../util/editDisplayUtils"; import { @@ -10,6 +10,7 @@ import { getContentRange, runOnTargetsForEachEditor, } from "../util/targetUtils"; +import { Action, ActionReturnValue } from "./actions.types"; export default class Delete implements Action { constructor(private graph: Graph) { diff --git a/src/actions/Scroll.ts b/src/actions/Scroll.ts index a224237aef..ceec3706c1 100644 --- a/src/actions/Scroll.ts +++ b/src/actions/Scroll.ts @@ -1,10 +1,11 @@ import { commands, window } from "vscode"; import { Target } from "../typings/target.types"; -import { Action, ActionReturnValue, Graph } from "../typings/Types"; +import { Graph } from "../typings/Types"; import { displayPendingEditDecorationsForTargets } from "../util/editDisplayUtils"; import { groupBy } from "../util/itertools"; import { focusEditor } from "../util/setSelectionsAndFocusEditor"; import { createThatMark } from "../util/targetUtils"; +import { Action, ActionReturnValue } from "./actions.types"; class Scroll implements Action { constructor(private graph: Graph, private at: string) { diff --git a/src/actions/SetSelection.ts b/src/actions/SetSelection.ts index 38c726aeb4..a0b75882a2 100644 --- a/src/actions/SetSelection.ts +++ b/src/actions/SetSelection.ts @@ -1,8 +1,9 @@ -import { Action, ActionReturnValue, Graph } from "../typings/Types"; import { ensureSingleEditor, getContentSelection } from "../util/targetUtils"; import { Selection } from "vscode"; import { setSelectionsAndFocusEditor } from "../util/setSelectionsAndFocusEditor"; import { Target } from "../typings/target.types"; +import { Graph } from "../typings/Types"; +import { Action, ActionReturnValue } from "./actions.types"; export class SetSelection implements Action { constructor(private graph: Graph) { diff --git a/src/actions/SetBreakpoint.ts b/src/actions/ToggleBreakpoint.ts similarity index 93% rename from src/actions/SetBreakpoint.ts rename to src/actions/ToggleBreakpoint.ts index d29d70f91b..8a542f05ce 100644 --- a/src/actions/SetBreakpoint.ts +++ b/src/actions/ToggleBreakpoint.ts @@ -25,7 +25,7 @@ // ); // } -// export default class SetBreakpoint implements Action { +// export default class ToggleBreakpoint implements Action { // getTargetPreferences: () => ActionPreferences[] = () => [ // { insideOutsideType: "inside", selectionType: "line" }, // ]; @@ -34,10 +34,7 @@ // this.run = this.run.bind(this); // } -// async run([targets]: [ -// Target[], -// Target[] -// ]): Promise { +// async run([targets]: [Target[], Target[]]): Promise { // await displayPendingEditDecorations( // targets, // this.graph.editStyles.referenced diff --git a/src/actions/actions.types.ts b/src/actions/actions.types.ts index 9991e07c94..2c629bdd66 100644 --- a/src/actions/actions.types.ts +++ b/src/actions/actions.types.ts @@ -1,3 +1,6 @@ +import { Target } from "../typings/target.types"; +import { SelectionWithEditor } from "../typings/Types"; + export type ActionType = // | "callAsFunction" | "clearAndSetSelection" @@ -24,6 +27,8 @@ export type ActionType = | "unfoldRegion" // | "pasteFromClipboard" | "remove" + // |"toggleLineBreakpoint" + | "toggleLineComment" // | "replace" // | "replaceWithTarget" // | "reverseTargets" @@ -34,3 +39,22 @@ export type ActionType = | "setSelection" | "setSelectionAfter" | "setSelectionBefore"; + +export interface ActionReturnValue { + returnValue?: any; + thatMark?: SelectionWithEditor[]; + sourceMark?: SelectionWithEditor[]; +} + +export interface Action { + run(targets: Target[][], ...args: any[]): Promise; + + /** + * Used to define default values for parts of target during inference. + * @param args Extra args to command + */ + // TODO + // getTargetPreferences(...args: any[]): ActionPreferences[]; +} + +export type ActionRecord = Record; diff --git a/src/typings/Types.ts b/src/typings/Types.ts index 2b3fc331d6..520343ac01 100644 --- a/src/typings/Types.ts +++ b/src/typings/Types.ts @@ -11,7 +11,7 @@ import { Snippets } from "../core/Snippets"; import { RangeUpdater } from "../core/updateSelections/RangeUpdater"; import { TestCaseRecorder } from "../testUtil/TestCaseRecorder"; import { CommandServerApi } from "../util/getExtensionApi"; -import { ActionType } from "../actions/actions.types"; +import { ActionRecord, ActionType } from "../actions/actions.types"; import { Target } from "./target.types"; import { FullRangeInfo } from "./updateSelections"; @@ -96,25 +96,6 @@ export interface SelectionWithContext { context: SelectionContext; } -export interface ActionReturnValue { - returnValue?: any; - thatMark?: SelectionWithEditor[]; - sourceMark?: SelectionWithEditor[]; -} - -export interface Action { - run(targets: Target[][], ...args: any[]): Promise; - - /** - * Used to define default values for parts of target during inference. - * @param args Extra args to command - */ - // TODO - // getTargetPreferences(...args: any[]): ActionPreferences[]; -} - -export type ActionRecord = Record; - export interface Graph { /** * Keeps a map from action names to objects that implement the given action From 85647ccbfd91c6144d7ea7878739e8532b5e4c35 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 15 May 2022 23:42:34 +0200 Subject: [PATCH 050/314] Added actions insert empty lines --- src/actions/Actions.ts | 11 +- src/actions/InsertEmptyLines.ts | 201 ++++++++++++++++---------------- src/util/editDisplayUtils.ts | 26 +++++ 3 files changed, 132 insertions(+), 106 deletions(-) diff --git a/src/actions/Actions.ts b/src/actions/Actions.ts index 8e77254e97..e6b52535f9 100644 --- a/src/actions/Actions.ts +++ b/src/actions/Actions.ts @@ -10,6 +10,11 @@ import FollowLink from "./FollowLink"; import GetText from "./GetText"; import Highlight from "./Highlight"; import { IndentLines, OutdentLines } from "./Indent"; +import { + InsertEmptyLineAbove, + InsertEmptyLineBelow, + InsertEmptyLinesAround, +} from "./InsertEmptyLines"; import Remove from "./Remove"; import { ScrollToBottom, ScrollToCenter, ScrollToTop } from "./Scroll"; import { @@ -37,9 +42,9 @@ class Actions implements ActionRecord { indentLine = new IndentLines(this.graph); // insertCopyAfter = new CopyLinesDown(this.graph); // insertCopyBefore = new CopyLinesUp(this.graph); - // insertEmptyLineAfter = new InsertEmptyLineBelow(this.graph); - // insertEmptyLineBefore = new InsertEmptyLineAbove(this.graph); - // insertEmptyLinesAround = new InsertEmptyLinesAround(this.graph); + insertEmptyLineAfter = new InsertEmptyLineBelow(this.graph); + insertEmptyLineBefore = new InsertEmptyLineAbove(this.graph); + insertEmptyLinesAround = new InsertEmptyLinesAround(this.graph); // moveToTarget = new Move(this.graph); outdentLine = new OutdentLines(this.graph); // pasteFromClipboard = new Paste(this.graph); diff --git a/src/actions/InsertEmptyLines.ts b/src/actions/InsertEmptyLines.ts index 08f1fbb71e..ff9197685d 100644 --- a/src/actions/InsertEmptyLines.ts +++ b/src/actions/InsertEmptyLines.ts @@ -1,117 +1,112 @@ -// import { -// Action, -// ActionPreferences, -// ActionReturnValue, -// Graph, -// Target, -// } from "../typings/Types"; -// import { Selection, Range } from "vscode"; -// import { displayPendingEditDecorationsForSelection } from "../util/editDisplayUtils"; -// import { runOnTargetsForEachEditor } from "../util/targetUtils"; -// import { flatten } from "lodash"; -// import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; +import { flatten } from "lodash"; +import { Range, Selection } from "vscode"; +import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; +import { Target } from "../typings/target.types"; +import { Graph } from "../typings/Types"; +import { displayPendingEditDecorationsForSelection } from "../util/editDisplayUtils"; +import { + getContentSelection, + runOnTargetsForEachEditor, +} from "../util/targetUtils"; +import { Action, ActionReturnValue } from "./actions.types"; -// class InsertEmptyLines implements Action { -// getTargetPreferences: () => ActionPreferences[] = () => [ -// { insideOutsideType: "inside" }, -// ]; +class InsertEmptyLines implements Action { + constructor( + private graph: Graph, + private insertAbove: boolean, + private insertBelow: boolean + ) { + this.run = this.run.bind(this); + } -// constructor( -// private graph: Graph, -// private insertAbove: boolean, -// private insertBelow: boolean -// ) { -// this.run = this.run.bind(this); -// } + private getRanges(targets: Target[]) { + let lines = targets.flatMap((target) => { + const lines = []; + if (this.insertAbove) { + lines.push(target.contentRange.start.line); + } + if (this.insertBelow) { + lines.push(target.contentRange.end.line + 1); + } + return lines; + }); + // Remove duplicates + lines = [...new Set(lines)]; -// private getRanges(targets: Target[]) { -// let lines = targets.flatMap((target) => { -// const lines = []; -// if (this.insertAbove) { -// lines.push(target.selection.selection.start.line); -// } -// if (this.insertBelow) { -// lines.push(target.selection.selection.end.line + 1); -// } -// return lines; -// }); -// // Remove duplicates -// lines = [...new Set(lines)]; + return lines.map((line) => new Range(line, 0, line, 0)); + } -// return lines.map((line) => new Range(line, 0, line, 0)); -// } + private getEdits(ranges: Range[]) { + return ranges.map((range) => ({ + range, + text: "\n", + })); + } -// private getEdits(ranges: Range[]) { -// return ranges.map((range) => ({ -// range, -// text: "\n", -// })); -// } + async run([targets]: [Target[]]): Promise { + const results = flatten( + await runOnTargetsForEachEditor(targets, async (editor, targets) => { + const ranges = this.getRanges(targets); + const edits = this.getEdits(ranges); -// async run([targets]: [Target[]]): Promise { -// const results = flatten( -// await runOnTargetsForEachEditor(targets, async (editor, targets) => { -// const ranges = this.getRanges(targets); -// const edits = this.getEdits(ranges); + const [updatedSelections, lineSelections, updatedOriginalSelections] = + await performEditsAndUpdateSelections( + this.graph.rangeUpdater, + editor, + edits, + [ + targets.map((target) => getContentSelection(target)), + ranges.map((range) => new Selection(range.start, range.end)), + editor.selections, + ] + ); -// const [updatedSelections, lineSelections, updatedOriginalSelections] = -// await performEditsAndUpdateSelections( -// this.graph.rangeUpdater, -// editor, -// edits, -// [ -// targets.map((target) => target.selection.selection), -// ranges.map((range) => new Selection(range.start, range.end)), -// editor.selections, -// ] -// ); + editor.selections = updatedOriginalSelections; -// editor.selections = updatedOriginalSelections; + return { + thatMark: updatedSelections.map((selection) => ({ + editor, + selection, + })), + lineSelections: lineSelections.map((selection, index) => ({ + editor, + selection: + ranges[index].start.line < editor.document.lineCount - 1 + ? new Selection( + selection.start.translate({ lineDelta: -1 }), + selection.end.translate({ lineDelta: -1 }) + ) + : selection, + })), + }; + }) + ); -// return { -// thatMark: updatedSelections.map((selection) => ({ -// editor, -// selection, -// })), -// lineSelections: lineSelections.map((selection, index) => ({ -// editor, -// selection: -// ranges[index].start.line < editor.document.lineCount - 1 -// ? new Selection( -// selection.start.translate({ lineDelta: -1 }), -// selection.end.translate({ lineDelta: -1 }) -// ) -// : selection, -// })), -// }; -// }) -// ); + await displayPendingEditDecorationsForSelection( + results.flatMap((result) => result.lineSelections), + this.graph.editStyles.justAdded.line + ); -// await displayPendingEditDecorationsForSelection( -// results.flatMap((result) => result.lineSelections), -// this.graph.editStyles.justAdded.line -// ); + const thatMark = results.flatMap((result) => result.thatMark); -// const thatMark = results.flatMap((result) => result.thatMark); + return { thatMark }; + } +} -// return { thatMark }; -// } -// } +export class InsertEmptyLinesAround extends InsertEmptyLines { + constructor(graph: Graph) { + super(graph, true, true); + } +} -// export class InsertEmptyLinesAround extends InsertEmptyLines { -// constructor(graph: Graph) { -// super(graph, true, true); -// } -// } +export class InsertEmptyLineAbove extends InsertEmptyLines { + constructor(graph: Graph) { + super(graph, true, false); + } +} -// export class InsertEmptyLineAbove extends InsertEmptyLines { -// constructor(graph: Graph) { -// super(graph, true, false); -// } -// } - -// export class InsertEmptyLineBelow extends InsertEmptyLines { -// constructor(graph: Graph) { -// super(graph, false, true); -// } -// } +export class InsertEmptyLineBelow extends InsertEmptyLines { + constructor(graph: Graph) { + super(graph, false, true); + } +} diff --git a/src/util/editDisplayUtils.ts b/src/util/editDisplayUtils.ts index 096243943d..4eb89605d6 100644 --- a/src/util/editDisplayUtils.ts +++ b/src/util/editDisplayUtils.ts @@ -49,6 +49,32 @@ export async function displayPendingEditDecorationsForTargets( ); } +export async function displayPendingEditDecorationsForSelection( + selections: SelectionWithEditor[], + style: TextEditorDecorationType +) { + await runForEachEditor( + selections, + (selection) => selection.editor, + async (editor, selections) => { + editor.setDecorations( + style, + selections.map((selection) => selection.selection) + ); + } + ); + + await decorationSleep(); + + await runForEachEditor( + selections, + (selection) => selection.editor, + async (editor) => { + editor.setDecorations(style, []); + } + ); +} + export default async function displayPendingEditDecorations( targets: Target[], editStyle: EditStyle, From b1b711c96260da7646963812677fbf9f5cb13d81 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 00:26:41 +0200 Subject: [PATCH 051/314] Added cut copy paste actions --- src/actions/Actions.ts | 7 +- src/actions/CutCopyPaste.ts | 122 +++++++++++++++----------------- src/actions/InsertEmptyLines.ts | 8 +-- src/actions/Remove.ts | 23 +----- src/actions/actions.types.ts | 6 +- src/typings/Types.ts | 5 ++ src/util/editDisplayUtils.ts | 14 ++-- src/util/targetUtils.ts | 56 ++++++++------- 8 files changed, 114 insertions(+), 127 deletions(-) diff --git a/src/actions/Actions.ts b/src/actions/Actions.ts index e6b52535f9..5537631bbb 100644 --- a/src/actions/Actions.ts +++ b/src/actions/Actions.ts @@ -2,6 +2,7 @@ import { Graph } from "../typings/Types"; import { ActionRecord } from "./actions.types"; import Clear from "./Clear"; import { CommentLines } from "./Comment"; +import { Copy, Cut, Paste } from "./CutCopyPaste"; import Deselect from "./Deselect"; import ExecuteCommand from "./ExecuteCommand"; import { FindInFiles } from "./Find"; @@ -28,8 +29,8 @@ class Actions implements ActionRecord { // callAsFunction = new Call(this.graph); clearAndSetSelection = new Clear(this.graph); - // copyToClipboard = new Copy(this.graph); - // cutToClipboard = new Cut(this.graph); + copyToClipboard = new Copy(this.graph); + cutToClipboard = new Cut(this.graph); // editNewLineAfter = new EditNewLineBelow(this.graph); // editNewLineBefore = new EditNewLineAbove(this.graph); executeCommand = new ExecuteCommand(this.graph); @@ -47,7 +48,7 @@ class Actions implements ActionRecord { insertEmptyLinesAround = new InsertEmptyLinesAround(this.graph); // moveToTarget = new Move(this.graph); outdentLine = new OutdentLines(this.graph); - // pasteFromClipboard = new Paste(this.graph); + pasteFromClipboard = new Paste(this.graph); remove = new Remove(this.graph); deselect = new Deselect(this.graph); // replace = new Replace(this.graph); diff --git a/src/actions/CutCopyPaste.ts b/src/actions/CutCopyPaste.ts index c5b448258f..a82a8288ae 100644 --- a/src/actions/CutCopyPaste.ts +++ b/src/actions/CutCopyPaste.ts @@ -1,73 +1,67 @@ -// import { -// Action, -// ActionPreferences, -// ActionReturnValue, -// Graph, -// Target, -// } from "../typings/Types"; -// import { performInsideOutsideAdjustment } from "../util/performInsideOutsideAdjustment"; -// import CommandAction from "./CommandAction"; -// import displayPendingEditDecorations from "../util/editDisplayUtils"; -// import { getOutsideOverflow } from "../util/targetUtils"; -// import { zip } from "lodash"; +import { Target } from "../typings/target.types"; +import { Graph } from "../typings/Types"; +import displayPendingEditDecorations from "../util/editDisplayUtils"; +import { getOutsideOverflow, getRemovalRange } from "../util/targetUtils"; +import { Action, ActionReturnValue } from "./actions.types"; +import CommandAction from "./CommandAction"; -// export class Cut implements Action { -// getTargetPreferences: () => ActionPreferences[] = () => [ -// { insideOutsideType: null }, -// ]; +export class Cut implements Action { + constructor(private graph: Graph) { + this.run = this.run.bind(this); + } -// constructor(private graph: Graph) { -// this.run = this.run.bind(this); -// } + async run([targets]: [Target[]]): Promise { + const overflowTargets = targets.flatMap((target) => + getOutsideOverflow( + target.editor, + target.contentRange, + getRemovalRange(target) + ).map( + (overflow): Target => ({ + editor: target.editor, + contentRange: overflow, + isReversed: false, + }) + ) + ); -// async run([targets]: [Target[]]): Promise { -// const insideTargets = targets.map((target) => -// performInsideOutsideAdjustment(target, "inside") -// ); -// const outsideTargets = targets.map((target) => -// performInsideOutsideAdjustment(target, "outside") -// ); -// const outsideTargetDecorations = zip(insideTargets, outsideTargets).flatMap( -// ([inside, outside]) => getOutsideOverflow(inside!, outside!) -// ); -// const options = { showDecorations: false }; + await Promise.all([ + displayPendingEditDecorations(targets, this.graph.editStyles.referenced), + displayPendingEditDecorations( + overflowTargets, + this.graph.editStyles.pendingDelete + ), + ]); -// await Promise.all([ -// displayPendingEditDecorations( -// insideTargets, -// this.graph.editStyles.referenced -// ), -// displayPendingEditDecorations( -// outsideTargetDecorations, -// this.graph.editStyles.pendingDelete -// ), -// ]); + const options = { showDecorations: false }; -// await this.graph.actions.copyToClipboard.run([insideTargets], options); + await this.graph.actions.copyToClipboard.run([targets], options); -// const { thatMark } = await this.graph.actions.remove.run( -// [outsideTargets], -// options -// ); + const { thatMark } = await this.graph.actions.remove.run( + [overflowTargets], + options + ); -// return { thatMark }; -// } -// } + return { thatMark }; + } +} -// export class Copy extends CommandAction { -// constructor(graph: Graph) { -// super(graph, { -// command: "editor.action.clipboardCopyAction", -// ensureSingleEditor: true, -// }); -// } -// } +export class Copy extends CommandAction { + constructor(graph: Graph) { + super(graph, { + command: "editor.action.clipboardCopyAction", + ensureSingleEditor: true, + showDecorations: true, + }); + } +} -// export class Paste extends CommandAction { -// constructor(graph: Graph) { -// super(graph, { -// command: "editor.action.clipboardPasteAction", -// ensureSingleEditor: true, -// }); -// } -// } +export class Paste extends CommandAction { + constructor(graph: Graph) { + super(graph, { + command: "editor.action.clipboardPasteAction", + ensureSingleEditor: true, + showDecorations: true, + }); + } +} diff --git a/src/actions/InsertEmptyLines.ts b/src/actions/InsertEmptyLines.ts index ff9197685d..95a5e12213 100644 --- a/src/actions/InsertEmptyLines.ts +++ b/src/actions/InsertEmptyLines.ts @@ -3,7 +3,7 @@ import { Range, Selection } from "vscode"; import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; -import { displayPendingEditDecorationsForSelection } from "../util/editDisplayUtils"; +import { displayPendingEditDecorationsForRanges } from "../util/editDisplayUtils"; import { getContentSelection, runOnTargetsForEachEditor, @@ -70,9 +70,9 @@ class InsertEmptyLines implements Action { })), lineSelections: lineSelections.map((selection, index) => ({ editor, - selection: + range: ranges[index].start.line < editor.document.lineCount - 1 - ? new Selection( + ? new Range( selection.start.translate({ lineDelta: -1 }), selection.end.translate({ lineDelta: -1 }) ) @@ -82,7 +82,7 @@ class InsertEmptyLines implements Action { }) ); - await displayPendingEditDecorationsForSelection( + await displayPendingEditDecorationsForRanges( results.flatMap((result) => result.lineSelections), this.graph.editStyles.justAdded.line ); diff --git a/src/actions/Remove.ts b/src/actions/Remove.ts index 0434f4ae2b..748493cb53 100644 --- a/src/actions/Remove.ts +++ b/src/actions/Remove.ts @@ -8,6 +8,8 @@ import displayPendingEditDecorations from "../util/editDisplayUtils"; import { createThatMark, getContentRange, + getRemovalHighlightRange, + getRemovalRange, runOnTargetsForEachEditor, } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; @@ -58,24 +60,3 @@ export default class Delete implements Action { return { thatMark }; } } - -function getRemovalRange(target: Target) { - const removalRange = target.removalRange ?? target.contentRange; - const delimiterRange = - target.trailingDelimiterRange ?? target.leadingDelimiterRange; - return delimiterRange != null - ? removalRange.union(delimiterRange) - : removalRange; -} - -function getRemovalHighlightRange(target: Target) { - const removalRange = target.removalRange ?? target.contentRange; - const delimiterRange = - target.trailingDelimiterHighlightRange ?? - target.trailingDelimiterRange ?? - target.leadingDelimiterHighlightRange ?? - target.leadingDelimiterRange; - return delimiterRange != null - ? removalRange.union(delimiterRange) - : removalRange; -} diff --git a/src/actions/actions.types.ts b/src/actions/actions.types.ts index 2c629bdd66..51dc1498ea 100644 --- a/src/actions/actions.types.ts +++ b/src/actions/actions.types.ts @@ -4,8 +4,8 @@ import { SelectionWithEditor } from "../typings/Types"; export type ActionType = // | "callAsFunction" | "clearAndSetSelection" - // | "copyToClipboard" - // | "cutToClipboard" + | "copyToClipboard" + | "cutToClipboard" | "deselect" // | "editNewLineAfter" // | "editNewLineBefore" @@ -25,7 +25,7 @@ export type ActionType = // | "moveToTarget" | "outdentLine" | "unfoldRegion" - // | "pasteFromClipboard" + | "pasteFromClipboard" | "remove" // |"toggleLineBreakpoint" | "toggleLineComment" diff --git a/src/typings/Types.ts b/src/typings/Types.ts index 520343ac01..3303053b23 100644 --- a/src/typings/Types.ts +++ b/src/typings/Types.ts @@ -35,6 +35,11 @@ export interface SelectionWithEditor { editor: vscode.TextEditor; } +export interface RangeWithEditor { + range: vscode.Range; + editor: vscode.TextEditor; +} + export interface SelectionContext { isInDelimitedList?: boolean; containingListDelimiter?: string | null; diff --git a/src/util/editDisplayUtils.ts b/src/util/editDisplayUtils.ts index 4eb89605d6..4e6d153d3b 100644 --- a/src/util/editDisplayUtils.ts +++ b/src/util/editDisplayUtils.ts @@ -2,7 +2,7 @@ import { Range, TextEditorDecorationType, window, workspace } from "vscode"; import { EditStyle } from "../core/editStyles"; import isTesting from "../testUtil/isTesting"; import { Target } from "../typings/target.types"; -import { SelectionWithEditor } from "../typings/Types"; +import { RangeWithEditor } from "../typings/Types"; import sleep from "./sleep"; import { getContentRange, @@ -49,17 +49,17 @@ export async function displayPendingEditDecorationsForTargets( ); } -export async function displayPendingEditDecorationsForSelection( - selections: SelectionWithEditor[], +export async function displayPendingEditDecorationsForRanges( + ranges: RangeWithEditor[], style: TextEditorDecorationType ) { await runForEachEditor( - selections, + ranges, (selection) => selection.editor, - async (editor, selections) => { + async (editor, ranges) => { editor.setDecorations( style, - selections.map((selection) => selection.selection) + ranges.map((range) => range.range) ); } ); @@ -67,7 +67,7 @@ export async function displayPendingEditDecorationsForSelection( await decorationSleep(); await runForEachEditor( - selections, + ranges, (selection) => selection.editor, async (editor) => { editor.setDecorations(style, []); diff --git a/src/util/targetUtils.ts b/src/util/targetUtils.ts index 13271dcff6..5759190d57 100644 --- a/src/util/targetUtils.ts +++ b/src/util/targetUtils.ts @@ -1,5 +1,5 @@ import { zip } from "lodash"; -import { Position, Range, Selection, TextEditor } from "vscode"; +import { Range, Selection, TextEditor } from "vscode"; import { Target } from "../typings/target.types"; import { SelectionWithEditor } from "../typings/Types"; import { groupBy } from "./itertools"; @@ -63,39 +63,24 @@ export function groupForEachEditor( }); } -/** Get the possible leading and trailing overflow ranges of the outside target compared to the inside target */ +/** Get the possible leading and trailing overflow ranges of the outside range compared to the inside range */ export function getOutsideOverflow( - insideTarget: Target, - outsideTarget: Target -): Target[] { - const { start: insideStart, end: insideEnd } = insideTarget.contentRange; - const { start: outsideStart, end: outsideEnd } = outsideTarget.contentRange; + editor: TextEditor, + insideRange: Range, + outsideRange: Range +): Range[] { + const { start: insideStart, end: insideEnd } = insideRange; + const { start: outsideStart, end: outsideEnd } = outsideRange; const result = []; if (outsideStart.isBefore(insideStart)) { - result.push( - createTypeSelection(insideTarget.editor, outsideStart, insideStart) - ); + result.push(new Range(outsideStart, insideStart)); } if (outsideEnd.isAfter(insideEnd)) { - result.push( - createTypeSelection(insideTarget.editor, insideEnd, outsideEnd) - ); + result.push(new Range(insideEnd, outsideEnd)); } return result; } -function createTypeSelection( - editor: TextEditor, - start: Position, - end: Position -): Target { - return { - editor, - contentRange: new Range(start, end), - isReversed: false, - }; -} - export function getContentRange(target: Target) { return target.contentRange; } @@ -129,3 +114,24 @@ export function createThatMark( : new Selection(target.contentRange.start, target.contentRange.end), })); } + +export function getRemovalRange(target: Target) { + const removalRange = target.removalRange ?? target.contentRange; + const delimiterRange = + target.trailingDelimiterRange ?? target.leadingDelimiterRange; + return delimiterRange != null + ? removalRange.union(delimiterRange) + : removalRange; +} + +export function getRemovalHighlightRange(target: Target) { + const removalRange = target.removalRange ?? target.contentRange; + const delimiterRange = + target.trailingDelimiterHighlightRange ?? + target.trailingDelimiterRange ?? + target.leadingDelimiterHighlightRange ?? + target.leadingDelimiterRange; + return delimiterRange != null + ? removalRange.union(delimiterRange) + : removalRange; +} From 0860c81570365d27ee04867828e1047b974182c0 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 00:30:16 +0200 Subject: [PATCH 052/314] Added extract action --- src/actions/Actions.ts | 3 ++- src/actions/ExtractVariable.ts | 46 ++++++++++++++-------------------- src/actions/actions.types.ts | 2 +- 3 files changed, 22 insertions(+), 29 deletions(-) diff --git a/src/actions/Actions.ts b/src/actions/Actions.ts index 5537631bbb..20bd9a03f5 100644 --- a/src/actions/Actions.ts +++ b/src/actions/Actions.ts @@ -5,6 +5,7 @@ import { CommentLines } from "./Comment"; import { Copy, Cut, Paste } from "./CutCopyPaste"; import Deselect from "./Deselect"; import ExecuteCommand from "./ExecuteCommand"; +import ExtractVariable from "./ExtractVariable"; import { FindInFiles } from "./Find"; import { Fold, Unfold } from "./Fold"; import FollowLink from "./FollowLink"; @@ -34,7 +35,7 @@ class Actions implements ActionRecord { // editNewLineAfter = new EditNewLineBelow(this.graph); // editNewLineBefore = new EditNewLineAbove(this.graph); executeCommand = new ExecuteCommand(this.graph); - // extractVariable = new ExtractVariable(this.graph); + extractVariable = new ExtractVariable(this.graph); findInWorkspace = new FindInFiles(this.graph); foldRegion = new Fold(this.graph); followLink = new FollowLink(this.graph); diff --git a/src/actions/ExtractVariable.ts b/src/actions/ExtractVariable.ts index d57fdd9b76..c48e54b239 100644 --- a/src/actions/ExtractVariable.ts +++ b/src/actions/ExtractVariable.ts @@ -1,32 +1,24 @@ -// import { -// Action, -// ActionPreferences, -// ActionReturnValue, -// Graph, -// Target, -// } from "../typings/Types"; -// import { ensureSingleTarget } from "../util/targetUtils"; -// import { commands } from "vscode"; +import { commands } from "vscode"; +import { Target } from "../typings/target.types"; +import { Graph } from "../typings/Types"; +import { ensureSingleTarget } from "../util/targetUtils"; +import { Action, ActionReturnValue } from "./actions.types"; -// export default class ExtractVariable implements Action { -// getTargetPreferences: () => ActionPreferences[] = () => [ -// { insideOutsideType: "inside" }, -// ]; +export default class ExtractVariable implements Action { + constructor(private graph: Graph) { + this.run = this.run.bind(this); + } -// constructor(private graph: Graph) { -// this.run = this.run.bind(this); -// } + async run([targets]: [Target[]]): Promise { + ensureSingleTarget(targets); -// async run([targets]: [Target[]]): Promise { -// ensureSingleTarget(targets); + await this.graph.actions.setSelection.run([targets]); -// await this.graph.actions.setSelection.run([targets]); + await commands.executeCommand("editor.action.codeAction", { + kind: "refactor.extract.constant", + preferred: true, + }); -// await commands.executeCommand("editor.action.codeAction", { -// kind: "refactor.extract.constant", -// preferred: true, -// }); - -// return {}; -// } -// } + return {}; + } +} diff --git a/src/actions/actions.types.ts b/src/actions/actions.types.ts index 51dc1498ea..13581df0f3 100644 --- a/src/actions/actions.types.ts +++ b/src/actions/actions.types.ts @@ -10,7 +10,7 @@ export type ActionType = // | "editNewLineAfter" // | "editNewLineBefore" | "executeCommand" - // | "extractVariable" + | "extractVariable" | "findInWorkspace" | "foldRegion" | "followLink" From d0d0319a765bb4496d6928af1353d5d4a75c7078 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 00:39:36 +0200 Subject: [PATCH 053/314] Updated cut --- src/actions/CutCopyPaste.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/actions/CutCopyPaste.ts b/src/actions/CutCopyPaste.ts index a82a8288ae..87bfb3b2ac 100644 --- a/src/actions/CutCopyPaste.ts +++ b/src/actions/CutCopyPaste.ts @@ -1,7 +1,10 @@ import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; import displayPendingEditDecorations from "../util/editDisplayUtils"; -import { getOutsideOverflow, getRemovalRange } from "../util/targetUtils"; +import { + getOutsideOverflow, + getRemovalHighlightRange, +} from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; import CommandAction from "./CommandAction"; @@ -15,10 +18,11 @@ export class Cut implements Action { getOutsideOverflow( target.editor, target.contentRange, - getRemovalRange(target) + getRemovalHighlightRange(target) ).map( (overflow): Target => ({ editor: target.editor, + scopeType: target.scopeType, contentRange: overflow, isReversed: false, }) @@ -38,7 +42,7 @@ export class Cut implements Action { await this.graph.actions.copyToClipboard.run([targets], options); const { thatMark } = await this.graph.actions.remove.run( - [overflowTargets], + [targets], options ); From e4c3181901dee603c47e9afc5703423f3130a484 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 01:08:43 +0200 Subject: [PATCH 054/314] Updated migration --- .../upgradeV1ToV2/upgradeV1ToV2.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts index e323dc9005..5f57c3790a 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts @@ -94,7 +94,19 @@ function upgradePrimitiveTarget( } if (position && position !== "contents") { - modifiers.push({ type: "position", position: position }); + if (position === "before") { + if (insideOutsideType === "inside") { + modifiers.push({ type: "position", position: "start" }); + } else { + modifiers.push({ type: "position", position: "before" }); + } + } else { + if (insideOutsideType === "inside") { + modifiers.push({ type: "position", position: "end" }); + } else { + modifiers.push({ type: "position", position: "after" }); + } + } } return { From 12028efe32b0790fb0ffb186f8b35caed8e26fd0 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 01:10:57 +0200 Subject: [PATCH 055/314] Added leading and trailing delimiter to position stage --- src/processTargets/modifiers/PositionStage.ts | 20 +++++++++++++++++++ src/typings/target.types.ts | 5 +++++ 2 files changed, 25 insertions(+) diff --git a/src/processTargets/modifiers/PositionStage.ts b/src/processTargets/modifiers/PositionStage.ts index 3b4dadab2d..56bc347035 100644 --- a/src/processTargets/modifiers/PositionStage.ts +++ b/src/processTargets/modifiers/PositionStage.ts @@ -9,10 +9,20 @@ export default class implements ModifierStage { run(context: ProcessedTargetsContext, target: Target): Target { const res = { editor: target.editor, + position: this.modifier.position, isReversed: false, }; switch (this.modifier.position) { case "before": + return { + ...res, + contentRange: new Range( + target.contentRange.start, + target.contentRange.start + ), + leadingDelimiterRange: target.leadingDelimiterRange, + }; + case "start": return { ...res, @@ -21,7 +31,17 @@ export default class implements ModifierStage { target.contentRange.start ), }; + case "after": + return { + ...res, + contentRange: new Range( + target.contentRange.end, + target.contentRange.end + ), + trailingDelimiterRange: target.trailingDelimiterRange, + }; + case "end": return { ...res, diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index d8af71d72c..38f113beeb 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -258,6 +258,11 @@ export interface Target { */ scopeType?: ScopeType; + /** + * The current position + */ + position?: Position; + /** * If this selection has a delimiter. For example, new line for a line or paragraph and comma for a list or argument */ From 2f4205b78cfa534e2c67407740d0b766ebfa239d Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 01:16:54 +0200 Subject: [PATCH 056/314] Clean up position stage --- src/processTargets/modifiers/PositionStage.ts | 49 +++++++++---------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/src/processTargets/modifiers/PositionStage.ts b/src/processTargets/modifiers/PositionStage.ts index 56bc347035..33d01b6531 100644 --- a/src/processTargets/modifiers/PositionStage.ts +++ b/src/processTargets/modifiers/PositionStage.ts @@ -7,48 +7,47 @@ export default class implements ModifierStage { constructor(private modifier: PositionModifier) {} run(context: ProcessedTargetsContext, target: Target): Target { - const res = { + const { + contentRange, + leadingDelimiterRange, + leadingDelimiterHighlightRange, + trailingDelimiterRange, + trailingDelimiterHighlightRange, + } = target; + + const common = { editor: target.editor, position: this.modifier.position, isReversed: false, }; + switch (this.modifier.position) { case "before": return { - ...res, - contentRange: new Range( - target.contentRange.start, - target.contentRange.start - ), - leadingDelimiterRange: target.leadingDelimiterRange, + ...common, + contentRange: new Range(contentRange.start, contentRange.start), + leadingDelimiterRange, + leadingDelimiterHighlightRange, }; - case "start": + case "after": return { - ...res, - contentRange: new Range( - target.contentRange.start, - target.contentRange.start - ), + ...common, + contentRange: new Range(contentRange.end, contentRange.end), + trailingDelimiterRange, + trailingDelimiterHighlightRange, }; - case "after": + case "start": return { - ...res, - contentRange: new Range( - target.contentRange.end, - target.contentRange.end - ), - trailingDelimiterRange: target.trailingDelimiterRange, + ...common, + contentRange: new Range(contentRange.start, contentRange.start), }; case "end": return { - ...res, - contentRange: new Range( - target.contentRange.end, - target.contentRange.end - ), + ...common, + contentRange: new Range(contentRange.end, contentRange.end), }; } } From cf755e22de1cdb2a967c158452dc1e011b45ecf6 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 01:20:58 +0200 Subject: [PATCH 057/314] Added replace action --- src/actions/Actions.ts | 3 +- src/actions/Replace.ts | 147 +++++++++++++++++------------------ src/actions/actions.types.ts | 2 +- src/util/targetUtils.ts | 12 +++ 4 files changed, 86 insertions(+), 78 deletions(-) diff --git a/src/actions/Actions.ts b/src/actions/Actions.ts index 20bd9a03f5..75eaa5aa7c 100644 --- a/src/actions/Actions.ts +++ b/src/actions/Actions.ts @@ -18,6 +18,7 @@ import { InsertEmptyLinesAround, } from "./InsertEmptyLines"; import Remove from "./Remove"; +import Replace from "./Replace"; import { ScrollToBottom, ScrollToCenter, ScrollToTop } from "./Scroll"; import { SetSelection, @@ -52,7 +53,7 @@ class Actions implements ActionRecord { pasteFromClipboard = new Paste(this.graph); remove = new Remove(this.graph); deselect = new Deselect(this.graph); - // replace = new Replace(this.graph); + replace = new Replace(this.graph); // replaceWithTarget = new Bring(this.graph); // randomizeTargets = new Random(this.graph); // reverseTargets = new Reverse(this.graph); diff --git a/src/actions/Replace.ts b/src/actions/Replace.ts index 3fabfda529..129af01d41 100644 --- a/src/actions/Replace.ts +++ b/src/actions/Replace.ts @@ -1,86 +1,81 @@ -// import { -// Action, -// ActionPreferences, -// ActionReturnValue, -// Graph, -// Target, -// } from "../typings/Types"; -// import displayPendingEditDecorations from "../util/editDisplayUtils"; -// import { runForEachEditor } from "../util/targetUtils"; -// import { flatten, zip } from "lodash"; -// import { maybeAddDelimiter } from "../util/getTextWithPossibleDelimiter"; -// import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; +import { zip, flatten } from "lodash"; +import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; +import { Target } from "../typings/target.types"; +import { Graph } from "../typings/Types"; +import displayPendingEditDecorations from "../util/editDisplayUtils"; +import { + getContentSelection, + maybeAddDelimiter, + runForEachEditor, +} from "../util/targetUtils"; +import { Action, ActionReturnValue } from "./actions.types"; -// type RangeGenerator = { start: number }; +type RangeGenerator = { start: number }; -// export default class implements Action { -// getTargetPreferences: () => ActionPreferences[] = () => [ -// { insideOutsideType: null }, -// ]; +export default class implements Action { + constructor(private graph: Graph) { + this.run = this.run.bind(this); + } -// constructor(private graph: Graph) { -// this.run = this.run.bind(this); -// } + private getTexts( + targets: Target[], + replaceWith: string[] | RangeGenerator + ): string[] { + if (Array.isArray(replaceWith)) { + // Broadcast single text to each target + if (replaceWith.length === 1) { + return Array(targets.length).fill(replaceWith[0]); + } + return replaceWith; + } + const numbers = []; + for (let i = 0; i < targets.length; ++i) { + numbers[i] = (replaceWith.start + i).toString(); + } + return numbers; + } -// private getTexts( -// targets: Target[], -// replaceWith: string[] | RangeGenerator -// ): string[] { -// if (Array.isArray(replaceWith)) { -// // Broadcast single text to each target -// if (replaceWith.length === 1) { -// return Array(targets.length).fill(replaceWith[0]); -// } -// return replaceWith; -// } -// const numbers = []; -// for (let i = 0; i < targets.length; ++i) { -// numbers[i] = (replaceWith.start + i).toString(); -// } -// return numbers; -// } + async run( + [targets]: [Target[]], + replaceWith: string[] | RangeGenerator + ): Promise { + await displayPendingEditDecorations( + targets, + this.graph.editStyles.pendingModification0 + ); -// async run( -// [targets]: [Target[]], -// replaceWith: string[] | RangeGenerator -// ): Promise { -// await displayPendingEditDecorations( -// targets, -// this.graph.editStyles.pendingModification0 -// ); + const texts = this.getTexts(targets, replaceWith); -// const texts = this.getTexts(targets, replaceWith); + if (targets.length !== texts.length) { + throw new Error("Targets and texts must have same length"); + } -// if (targets.length !== texts.length) { -// throw new Error("Targets and texts must have same length"); -// } + const edits = zip(targets, texts).map(([target, text]) => ({ + editor: target!.editor, + range: target!.contentRange, + text: maybeAddDelimiter(text!, target!), + })); -// const edits = zip(targets, texts).map(([target, text]) => ({ -// editor: target!.selection.editor, -// range: target!.selection.selection, -// text: maybeAddDelimiter(text!, target!), -// })); + const thatMark = flatten( + await runForEachEditor( + edits, + (edit) => edit.editor, + async (editor, edits) => { + const [updatedSelections] = await performEditsAndUpdateSelections( + this.graph.rangeUpdater, + editor, + edits, + [targets.map((target) => getContentSelection(target))] + ); -// const thatMark = flatten( -// await runForEachEditor( -// edits, -// (edit) => edit.editor, -// async (editor, edits) => { -// const [updatedSelections] = await performEditsAndUpdateSelections( -// this.graph.rangeUpdater, -// editor, -// edits, -// [targets.map((target) => target.selection.selection)] -// ); + return updatedSelections.map((selection) => ({ + editor, + selection, + })); + } + ) + ); -// return updatedSelections.map((selection) => ({ -// editor, -// selection, -// })); -// } -// ) -// ); - -// return { thatMark }; -// } -// } + return { thatMark }; + } +} diff --git a/src/actions/actions.types.ts b/src/actions/actions.types.ts index 13581df0f3..3e4acc1cd3 100644 --- a/src/actions/actions.types.ts +++ b/src/actions/actions.types.ts @@ -29,7 +29,7 @@ export type ActionType = | "remove" // |"toggleLineBreakpoint" | "toggleLineComment" - // | "replace" + | "replace" // | "replaceWithTarget" // | "reverseTargets" // | "rewrapWithPairedDelimiter" diff --git a/src/util/targetUtils.ts b/src/util/targetUtils.ts index 5759190d57..d60efd911a 100644 --- a/src/util/targetUtils.ts +++ b/src/util/targetUtils.ts @@ -135,3 +135,15 @@ export function getRemovalHighlightRange(target: Target) { ? removalRange.union(delimiterRange) : removalRange; } + +export function maybeAddDelimiter(text: string, target: Target) { + if (target.delimiter != null) { + if (target.position === "before") { + return text + target.delimiter; + } + if (target.position === "after") { + return target.delimiter + text; + } + } + return text; +} From e4ea0c87d0efc714bcd65f102cb651682d58bafe Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 01:27:10 +0200 Subject: [PATCH 058/314] Added sort actions --- src/actions/Actions.ts | 7 +-- src/actions/Sort.ts | 86 ++++++++++++++++-------------------- src/actions/actions.types.ts | 4 +- 3 files changed, 46 insertions(+), 51 deletions(-) diff --git a/src/actions/Actions.ts b/src/actions/Actions.ts index 75eaa5aa7c..025f28770d 100644 --- a/src/actions/Actions.ts +++ b/src/actions/Actions.ts @@ -25,6 +25,7 @@ import { SetSelectionAfter, SetSelectionBefore, } from "./SetSelection"; +import { Random, Reverse, Sort } from "./Sort"; class Actions implements ActionRecord { constructor(private graph: Graph) {} @@ -55,8 +56,8 @@ class Actions implements ActionRecord { deselect = new Deselect(this.graph); replace = new Replace(this.graph); // replaceWithTarget = new Bring(this.graph); - // randomizeTargets = new Random(this.graph); - // reverseTargets = new Reverse(this.graph); + randomizeTargets = new Random(this.graph); + reverseTargets = new Reverse(this.graph); // rewrapWithPairedDelimiter = new Rewrap(this.graph); scrollToBottom = new ScrollToBottom(this.graph); scrollToCenter = new ScrollToCenter(this.graph); @@ -64,7 +65,7 @@ class Actions implements ActionRecord { setSelection = new SetSelection(this.graph); setSelectionAfter = new SetSelectionAfter(this.graph); setSelectionBefore = new SetSelectionBefore(this.graph); - // sortTargets = new Sort(this.graph); + sortTargets = new Sort(this.graph); // swapTargets = new Swap(this.graph); // toggleLineBreakpoint = new ToggleBreakpoint(this.graph); toggleLineComment = new CommentLines(this.graph); diff --git a/src/actions/Sort.ts b/src/actions/Sort.ts index b937076147..0f0191194a 100644 --- a/src/actions/Sort.ts +++ b/src/actions/Sort.ts @@ -1,47 +1,39 @@ -// import { shuffle } from "lodash"; -// import { -// Action, -// ActionReturnValue, -// ActionPreferences, -// Graph, -// Target, -// } from "../typings/Types"; - -// export class Sort implements Action { -// getTargetPreferences: () => ActionPreferences[] = () => [ -// { insideOutsideType: "inside" }, -// ]; - -// constructor(private graph: Graph) { -// this.run = this.run.bind(this); -// } - -// protected sortTexts(texts: string[]) { -// return texts.sort(); -// } - -// async run(targets: Target[][]): Promise { -// const { returnValue: unsortedTexts } = await this.graph.actions.getText.run( -// targets, -// { -// showDecorations: false, -// } -// ); - -// const sortedTexts = this.sortTexts(unsortedTexts); - -// return this.graph.actions.replace.run(targets, sortedTexts); -// } -// } - -// export class Reverse extends Sort { -// protected sortTexts(texts: string[]) { -// return texts.reverse(); -// } -// } - -// export class Random extends Sort { -// protected sortTexts(texts: string[]) { -// return shuffle(texts); -// } -// } +import { shuffle } from "lodash"; +import { Target } from "../typings/target.types"; +import { Graph } from "../typings/Types"; +import { Action, ActionReturnValue } from "./actions.types"; + +export class Sort implements Action { + constructor(private graph: Graph) { + this.run = this.run.bind(this); + } + + protected sortTexts(texts: string[]) { + return texts.sort(); + } + + async run(targets: Target[][]): Promise { + const { returnValue: unsortedTexts } = await this.graph.actions.getText.run( + targets, + { + showDecorations: false, + } + ); + + const sortedTexts = this.sortTexts(unsortedTexts); + + return this.graph.actions.replace.run(targets, sortedTexts); + } +} + +export class Reverse extends Sort { + protected sortTexts(texts: string[]) { + return texts.reverse(); + } +} + +export class Random extends Sort { + protected sortTexts(texts: string[]) { + return shuffle(texts); + } +} diff --git a/src/actions/actions.types.ts b/src/actions/actions.types.ts index 3e4acc1cd3..fed5f47f23 100644 --- a/src/actions/actions.types.ts +++ b/src/actions/actions.types.ts @@ -31,7 +31,9 @@ export type ActionType = | "toggleLineComment" | "replace" // | "replaceWithTarget" - // | "reverseTargets" + | "reverseTargets" + | "randomizeTargets" + | "sortTargets" // | "rewrapWithPairedDelimiter" | "scrollToBottom" | "scrollToCenter" From a28e50136e3ce1dcfd66c1c3a3fdce30a568e9cb Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 01:58:42 +0200 Subject: [PATCH 059/314] Fixes to unify ranges --- src/actions/Actions.ts | 5 +- src/actions/CopyLines.ts | 249 +++++++++--------- src/actions/Remove.ts | 6 +- src/actions/actions.types.ts | 10 +- .../upgradeV1ToV2/upgradeV1ToV2.ts | 2 +- src/util/expandToContainingLine.ts | 10 - src/util/unifyRanges.ts | 207 ++++++++------- 7 files changed, 242 insertions(+), 247 deletions(-) delete mode 100644 src/util/expandToContainingLine.ts diff --git a/src/actions/Actions.ts b/src/actions/Actions.ts index 025f28770d..c028ae8249 100644 --- a/src/actions/Actions.ts +++ b/src/actions/Actions.ts @@ -2,6 +2,7 @@ import { Graph } from "../typings/Types"; import { ActionRecord } from "./actions.types"; import Clear from "./Clear"; import { CommentLines } from "./Comment"; +import { CopyLinesDown, CopyLinesUp } from "./CopyLines"; import { Copy, Cut, Paste } from "./CutCopyPaste"; import Deselect from "./Deselect"; import ExecuteCommand from "./ExecuteCommand"; @@ -44,8 +45,8 @@ class Actions implements ActionRecord { getText = new GetText(this.graph); highlight = new Highlight(this.graph); indentLine = new IndentLines(this.graph); - // insertCopyAfter = new CopyLinesDown(this.graph); - // insertCopyBefore = new CopyLinesUp(this.graph); + insertCopyAfter = new CopyLinesDown(this.graph); + insertCopyBefore = new CopyLinesUp(this.graph); insertEmptyLineAfter = new InsertEmptyLineBelow(this.graph); insertEmptyLineBefore = new InsertEmptyLineAbove(this.graph); insertEmptyLinesAround = new InsertEmptyLinesAround(this.graph); diff --git a/src/actions/CopyLines.ts b/src/actions/CopyLines.ts index b372a5f18b..082c6afb1c 100644 --- a/src/actions/CopyLines.ts +++ b/src/actions/CopyLines.ts @@ -1,138 +1,139 @@ -// import { -// Action, -// ActionPreferences, -// ActionReturnValue, -// Graph, -// Target, -// } from "../typings/Types"; -// import { Range, Selection, TextEditor } from "vscode"; -// import { displayPendingEditDecorationsForSelection } from "../util/editDisplayUtils"; -// import { runOnTargetsForEachEditor } from "../util/targetUtils"; -// import { flatten } from "lodash"; -// import unifyRanges from "../util/unifyRanges"; -// import expandToContainingLine from "../util/expandToContainingLine"; -// import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; +import { flatten } from "lodash"; +import { Range, Selection, TextEditor } from "vscode"; +import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; +import { Target } from "../typings/target.types"; +import { Graph } from "../typings/Types"; +import { displayPendingEditDecorationsForRanges } from "../util/editDisplayUtils"; +import { runOnTargetsForEachEditor } from "../util/targetUtils"; +import unifyRanges from "../util/unifyRanges"; +import { Action, ActionReturnValue } from "./actions.types"; -// class CopyLines implements Action { -// getTargetPreferences: () => ActionPreferences[] = () => [ -// { insideOutsideType: "inside" }, -// ]; +class CopyLines implements Action { + constructor(private graph: Graph, private isUp: boolean) { + this.run = this.run.bind(this); + } -// constructor(private graph: Graph, private isUp: boolean) { -// this.run = this.run.bind(this); -// } + private getRanges(editor: TextEditor, targets: Target[]) { + const paragraphTargets = targets.filter( + (target) => target.scopeType === "paragraph" + ); + const ranges = targets.map((target) => + expandToContainingLine(editor, target.contentRange) + ); + const unifiedRanges = unifyRanges(ranges); + return unifiedRanges.map((range) => ({ + range, + isParagraph: + paragraphTargets.find((target) => target.contentRange.isEqual(range)) != + null, + })); + } -// private getRanges(editor: TextEditor, targets: Target[]) { -// const paragraphTargets = targets.filter( -// (target) => target.selectionType === "paragraph" -// ); -// const ranges = targets.map((target) => -// expandToContainingLine(editor, target.selection.selection) -// ); -// const unifiedRanges = unifyRanges(ranges); -// return unifiedRanges.map((range) => ({ -// range, -// isParagraph: -// paragraphTargets.find((target) => -// target.selection.selection.isEqual(range) -// ) != null, -// })); -// } + private getEdits( + editor: TextEditor, + ranges: { range: Range; isParagraph: boolean }[] + ) { + return ranges.map(({ range, isParagraph }) => { + const delimiter = isParagraph ? "\n\n" : "\n"; + let text = editor.document.getText(range); + const length = text.length; + text = this.isUp ? `${delimiter}${text}` : `${text}${delimiter}`; + const newRange = this.isUp + ? new Range(range.end, range.end) + : new Range(range.start, range.start); + return { + edit: { + editor, + range: newRange, + text, + isReplace: this.isUp, + }, + offset: delimiter.length, + length, + }; + }); + } -// private getEdits( -// editor: TextEditor, -// ranges: { range: Range; isParagraph: boolean }[] -// ) { -// return ranges.map(({ range, isParagraph }) => { -// const delimiter = isParagraph ? "\n\n" : "\n"; -// let text = editor.document.getText(range); -// const length = text.length; -// text = this.isUp ? `${delimiter}${text}` : `${text}${delimiter}`; -// const newRange = this.isUp -// ? new Range(range.end, range.end) -// : new Range(range.start, range.start); -// return { -// edit: { -// editor, -// range: newRange, -// text, -// isReplace: this.isUp, -// }, -// offset: delimiter.length, -// length, -// }; -// }); -// } + async run([targets]: [Target[]]): Promise { + const results = flatten( + await runOnTargetsForEachEditor(targets, async (editor, targets) => { + const ranges = this.getRanges(editor, targets); + const editWrappers = this.getEdits(editor, ranges); + const rangeSelections = ranges.map( + ({ range }) => new Selection(range.start, range.end) + ); -// async run([targets]: [Target[]]): Promise { -// const results = flatten( -// await runOnTargetsForEachEditor(targets, async (editor, targets) => { -// const ranges = this.getRanges(editor, targets); -// const editWrappers = this.getEdits(editor, ranges); -// const rangeSelections = ranges.map( -// ({ range }) => new Selection(range.start, range.end) -// ); + const [editorSelections, copySelections] = + await performEditsAndUpdateSelections( + this.graph.rangeUpdater, + editor, + editWrappers.map((wrapper) => wrapper.edit), + [editor.selections, rangeSelections] + ); -// const [editorSelections, copySelections] = -// await performEditsAndUpdateSelections( -// this.graph.rangeUpdater, -// editor, -// editWrappers.map((wrapper) => wrapper.edit), -// [editor.selections, rangeSelections] -// ); + editor.selections = editorSelections; + editor.revealRange(copySelections[0]); -// editor.selections = editorSelections; -// editor.revealRange(copySelections[0]); + let sourceSelections; + if (this.isUp) { + sourceSelections = editWrappers.map((wrapper) => { + const startIndex = + editor.document.offsetAt(wrapper.edit.range.start) + + wrapper.offset; + const endIndex = startIndex + wrapper.length; + return new Selection( + editor.document.positionAt(startIndex), + editor.document.positionAt(endIndex) + ); + }); + } else { + sourceSelections = rangeSelections; + } -// let sourceSelections; -// if (this.isUp) { -// sourceSelections = editWrappers.map((wrapper) => { -// const startIndex = -// editor.document.offsetAt(wrapper.edit.range.start) + -// wrapper.offset; -// const endIndex = startIndex + wrapper.length; -// return new Selection( -// editor.document.positionAt(startIndex), -// editor.document.positionAt(endIndex) -// ); -// }); -// } else { -// sourceSelections = rangeSelections; -// } + return { + sourceMark: sourceSelections.map((selection) => ({ + editor, + selection, + })), + thatMark: copySelections.map((selection) => ({ + editor, + selection, + })), + }; + }) + ); -// return { -// sourceMark: sourceSelections.map((selection) => ({ -// editor, -// selection, -// })), -// thatMark: copySelections.map((selection) => ({ -// editor, -// selection, -// })), -// }; -// }) -// ); + await displayPendingEditDecorationsForRanges( + results.flatMap((result) => + result.thatMark.map((that) => ({ + editor: that.editor, + range: that.selection, + })) + ), + this.graph.editStyles.justAdded.token + ); -// await displayPendingEditDecorationsForSelection( -// results.flatMap((result) => result.thatMark), -// this.graph.editStyles.justAdded.token -// ); + const sourceMark = results.flatMap((result) => result.sourceMark); + const thatMark = results.flatMap((result) => result.thatMark); -// const sourceMark = results.flatMap((result) => result.sourceMark); -// const thatMark = results.flatMap((result) => result.thatMark); + return { sourceMark, thatMark }; + } +} -// return { sourceMark, thatMark }; -// } -// } +export class CopyLinesUp extends CopyLines { + constructor(graph: Graph) { + super(graph, true); + } +} -// export class CopyLinesUp extends CopyLines { -// constructor(graph: Graph) { -// super(graph, true); -// } -// } +export class CopyLinesDown extends CopyLines { + constructor(graph: Graph) { + super(graph, false); + } +} -// export class CopyLinesDown extends CopyLines { -// constructor(graph: Graph) { -// super(graph, false); -// } -// } +function expandToContainingLine(editor: TextEditor, range: Range) { + const start = range.start.with({ character: 0 }); + const end = editor.document.lineAt(range.end).range.end; + return new Range(start, end); +} diff --git a/src/actions/Remove.ts b/src/actions/Remove.ts index 748493cb53..2006355c6d 100644 --- a/src/actions/Remove.ts +++ b/src/actions/Remove.ts @@ -1,10 +1,8 @@ import { flatten } from "lodash"; import { performEditsAndUpdateRanges } from "../core/updateSelections/updateRanges"; -// import { unifyTargets } from "../util/unifyRanges"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; import displayPendingEditDecorations from "../util/editDisplayUtils"; - import { createThatMark, getContentRange, @@ -12,6 +10,7 @@ import { getRemovalRange, runOnTargetsForEachEditor, } from "../util/targetUtils"; +import { unifyTargets } from "../util/unifyRanges"; import { Action, ActionReturnValue } from "./actions.types"; export default class Delete implements Action { @@ -24,8 +23,7 @@ export default class Delete implements Action { { showDecorations = true, contentOnly = false } = {} ): Promise { // Unify overlapping targets. - // TODO - // targets = unifyTargets(targets); + targets = unifyTargets(targets); if (showDecorations) { await displayPendingEditDecorations( diff --git a/src/actions/actions.types.ts b/src/actions/actions.types.ts index fed5f47f23..4712954822 100644 --- a/src/actions/actions.types.ts +++ b/src/actions/actions.types.ts @@ -17,11 +17,11 @@ export type ActionType = | "getText" | "highlight" | "indentLine" - // | "insertCopyAfter" - // | "insertCopyBefore" - // | "insertEmptyLineAfter" - // | "insertEmptyLineBefore" - // | "insertEmptyLinesAround" + | "insertCopyAfter" + | "insertCopyBefore" + | "insertEmptyLineAfter" + | "insertEmptyLineBefore" + | "insertEmptyLinesAround" // | "moveToTarget" | "outdentLine" | "unfoldRegion" diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts index 5f57c3790a..e6c850ab39 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts @@ -112,7 +112,7 @@ function upgradePrimitiveTarget( return { ...rest, // Modifiers are processed backwards - modifiers: modifiers.reverse(), + modifiers: modifiers.length ? modifiers.reverse() : undefined, }; } diff --git a/src/util/expandToContainingLine.ts b/src/util/expandToContainingLine.ts deleted file mode 100644 index f17690cea1..0000000000 --- a/src/util/expandToContainingLine.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Range, TextEditor } from "vscode"; - -export default function expandToContainingLine( - editor: TextEditor, - range: Range -) { - const start = range.start.with({ character: 0 }); - const end = editor.document.lineAt(range.end).range.end; - return new Range(start, end); -} diff --git a/src/util/unifyRanges.ts b/src/util/unifyRanges.ts index 0285ff06a7..780e4f3edb 100644 --- a/src/util/unifyRanges.ts +++ b/src/util/unifyRanges.ts @@ -1,107 +1,112 @@ -// TODO -// import { Range } from "vscode"; -// import { Target } from "../typings/Types"; -// import { performInsideOutsideAdjustment } from "./performInsideOutsideAdjustment"; -// import { groupTargetsForEachEditor } from "./targetUtils"; +import { Range } from "vscode"; +import { Target } from "../typings/target.types"; +import { getRemovalRange, groupTargetsForEachEditor } from "./targetUtils"; -// /** Unifies overlapping/intersecting ranges */ -// export default function unifyRanges(ranges: Range[]): Range[] { -// if (ranges.length < 2) { -// return ranges; -// } -// let run = true; -// while (run) { -// [ranges, run] = unifyRangesOnePass(ranges); -// } -// return ranges; -// } +/** Unifies overlapping/intersecting ranges */ +export default function unifyRanges(ranges: Range[]): Range[] { + if (ranges.length < 2) { + return ranges; + } + let run = true; + while (run) { + [ranges, run] = unifyRangesOnePass(ranges); + } + return ranges; +} -// function unifyRangesOnePass(ranges: Range[]): [Range[], boolean] { -// if (ranges.length < 2) { -// return [ranges, false]; -// } -// const result: Range[] = []; -// let madeChanges = false; -// ranges.forEach((range) => { -// const index = result.findIndex((r) => r.intersection(range) != null); -// // Update existing intersecting range -// if (index > -1) { -// result[index] = result[index].union(range); -// madeChanges = true; -// } -// // Add new range -// else { -// result.push(range); -// } -// }); -// return [result, madeChanges]; -// } +function unifyRangesOnePass(ranges: Range[]): [Range[], boolean] { + if (ranges.length < 2) { + return [ranges, false]; + } + const result: Range[] = []; + let madeChanges = false; + ranges.forEach((range) => { + const index = result.findIndex((r) => r.intersection(range) != null); + // Update existing intersecting range + if (index > -1) { + result[index] = result[index].union(range); + madeChanges = true; + } + // Add new range + else { + result.push(range); + } + }); + return [result, madeChanges]; +} -// /** -// * Unifies overlapping/intersecting targets -// * FIXME This code probably needs to update once we have objected oriented targets -// * https://github.com/cursorless-dev/cursorless/issues/210 -// */ -// export function unifyTargets(targets: Target[]): Target[] { -// if (targets.length < 2) { -// return targets; -// } -// return groupTargetsForEachEditor(targets).flatMap(([_editor, targets]) => { -// if (targets.length < 2) { -// return targets; -// } -// let results = [...targets]; -// results.sort((a, b) => -// a.contentRange.start.compareTo(b.contentRange.start) -// ); -// let run = true; -// // Merge targets untill there are no overlaps/intersections -// while (run) { -// [results, run] = unifyTargetsOnePass(results); -// } -// return results; -// }); -// } +/** + * Unifies overlapping/intersecting targets + * FIXME This code probably needs to update once we have objected oriented targets + * https://github.com/cursorless-dev/cursorless/issues/210 + */ +export function unifyTargets(targets: Target[]): Target[] { + if (targets.length < 2) { + return targets; + } + return groupTargetsForEachEditor(targets).flatMap(([_editor, targets]) => { + if (targets.length < 2) { + return targets; + } + let results = [...targets]; + results.sort((a, b) => + a.contentRange.start.compareTo(b.contentRange.start) + ); + let run = true; + // Merge targets untill there are no overlaps/intersections + while (run) { + [results, run] = unifyTargetsOnePass(results); + } + return results; + }); +} -// function unifyTargetsOnePass( -// targets: Target[] -// ): [Target[], boolean] { -// if (targets.length < 2) { -// return [targets, false]; -// } -// const results: Target[] = []; -// let currentGroup: Target[] = []; -// targets.forEach((target) => { -// // No intersection. Mark start of new group -// if ( -// currentGroup.length && -// !intersects(currentGroup[currentGroup.length - 1], target) -// ) { -// results.push(mergeTargets(currentGroup)); -// currentGroup = [target]; -// } else { -// currentGroup.push(target); -// } -// }); -// results.push(mergeTargets(currentGroup)); -// return [results, results.length !== targets.length]; -// } +function unifyTargetsOnePass(targets: Target[]): [Target[], boolean] { + if (targets.length < 2) { + return [targets, false]; + } + const results: Target[] = []; + let currentGroup: Target[] = []; + targets.forEach((target) => { + // No intersection. Mark start of new group + if ( + currentGroup.length && + !intersects(currentGroup[currentGroup.length - 1], target) + ) { + results.push(mergeTargets(currentGroup)); + currentGroup = [target]; + } else { + currentGroup.push(target); + } + }); + results.push(mergeTargets(currentGroup)); + return [results, results.length !== targets.length]; +} -// function mergeTargets(targets: Target[]): Target { -// if (targets.length === 1) { -// return targets[0]; -// } -// const first = targets[0]; -// const last = targets[targets.length - 1]; -// const typeSelection: Target = { -// editor: first.editor, -// contentRange: new Range(first.contentRange.start, last.contentRange.end), -// leadingDelimiterRange: first.leadingDelimiterRange, -// trailingDelimiterRange: last.trailingDelimiterRange, -// }; -// return performInsideOutsideAdjustment(typeSelection); -// } +function mergeTargets(targets: Target[]): Target { + if (targets.length === 1) { + return targets[0]; + } + const first = targets[0]; + const last = targets[targets.length - 1]; + return { + editor: first.editor, + isReversed: first.isReversed, + contentRange: new Range( + getContentRange(first).start, + getContentRange(last).end + ), + leadingDelimiterRange: first.leadingDelimiterRange, + leadingDelimiterHighlightRange: first.leadingDelimiterHighlightRange, + trailingDelimiterRange: last.trailingDelimiterRange, + trailingDelimiterHighlightRange: last.trailingDelimiterHighlightRange, + }; +} -// function intersects(targetA: Target, targetB: Target) { -// return !!targetA.contentRange.intersection(targetB.contentRange); -// } +function intersects(targetA: Target, targetB: Target) { + return !!getRemovalRange(targetA).intersection(getRemovalRange(targetB)); +} + +function getContentRange(target: Target) { + return target.removalRange ?? target.contentRange; +} From fdfd915fb46b27a7c13851049d3ed98f7abeef35 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 02:05:46 +0200 Subject: [PATCH 060/314] Added toggle breakpoint action --- src/actions/Actions.ts | 3 +- src/actions/ToggleBreakpoint.ts | 121 +++++++++++++++----------------- src/actions/actions.types.ts | 2 +- src/util/editDisplayUtils.ts | 16 +---- src/util/targetUtils.ts | 11 +++ 5 files changed, 74 insertions(+), 79 deletions(-) diff --git a/src/actions/Actions.ts b/src/actions/Actions.ts index c028ae8249..281ea57332 100644 --- a/src/actions/Actions.ts +++ b/src/actions/Actions.ts @@ -27,6 +27,7 @@ import { SetSelectionBefore, } from "./SetSelection"; import { Random, Reverse, Sort } from "./Sort"; +import ToggleBreakpoint from "./ToggleBreakpoint"; class Actions implements ActionRecord { constructor(private graph: Graph) {} @@ -68,7 +69,7 @@ class Actions implements ActionRecord { setSelectionBefore = new SetSelectionBefore(this.graph); sortTargets = new Sort(this.graph); // swapTargets = new Swap(this.graph); - // toggleLineBreakpoint = new ToggleBreakpoint(this.graph); + toggleLineBreakpoint = new ToggleBreakpoint(this.graph); toggleLineComment = new CommentLines(this.graph); unfoldRegion = new Unfold(this.graph); // wrapWithPairedDelimiter = new Wrap(this.graph); diff --git a/src/actions/ToggleBreakpoint.ts b/src/actions/ToggleBreakpoint.ts index 8a542f05ce..b58062ae5b 100644 --- a/src/actions/ToggleBreakpoint.ts +++ b/src/actions/ToggleBreakpoint.ts @@ -1,71 +1,64 @@ -// import { -// Action, -// ActionPreferences, -// ActionReturnValue, -// Graph, -// Target, -// } from "../typings/Types"; -// import { -// SourceBreakpoint, -// Location, -// debug, -// Uri, -// Range, -// Breakpoint, -// } from "vscode"; -// import displayPendingEditDecorations from "../util/editDisplayUtils"; -// import { isLineSelectionType } from "../util/selectionType"; +import { + Uri, + Range, + debug, + SourceBreakpoint, + Breakpoint, + Location, +} from "vscode"; +import { Target } from "../typings/target.types"; +import { Graph } from "../typings/Types"; +import displayPendingEditDecorations from "../util/editDisplayUtils"; +import { createThatMark, isLineScopeType } from "../util/targetUtils"; +import { Action, ActionReturnValue } from "./actions.types"; -// function getBreakpoints(uri: Uri, range: Range) { -// return debug.breakpoints.filter( -// (breakpoint) => -// breakpoint instanceof SourceBreakpoint && -// breakpoint.location.uri.toString() === uri.toString() && -// breakpoint.location.range.intersection(range) != null -// ); -// } +function getBreakpoints(uri: Uri, range: Range) { + return debug.breakpoints.filter( + (breakpoint) => + breakpoint instanceof SourceBreakpoint && + breakpoint.location.uri.toString() === uri.toString() && + breakpoint.location.range.intersection(range) != null + ); +} -// export default class ToggleBreakpoint implements Action { -// getTargetPreferences: () => ActionPreferences[] = () => [ -// { insideOutsideType: "inside", selectionType: "line" }, -// ]; +// TODO preference for scope type line +export default class ToggleBreakpoint implements Action { + constructor(private graph: Graph) { + this.run = this.run.bind(this); + } -// constructor(private graph: Graph) { -// this.run = this.run.bind(this); -// } + async run([targets]: [Target[], Target[]]): Promise { + await displayPendingEditDecorations( + targets, + this.graph.editStyles.referenced + ); -// async run([targets]: [Target[], Target[]]): Promise { -// await displayPendingEditDecorations( -// targets, -// this.graph.editStyles.referenced -// ); + const toAdd: Breakpoint[] = []; + const toRemove: Breakpoint[] = []; -// const toAdd: Breakpoint[] = []; -// const toRemove: Breakpoint[] = []; + targets.forEach((target) => { + let range = target.contentRange; + // The action preference give us line content but line breakpoints are registered on character 0 + if (isLineScopeType(target)) { + range = range.with(range.start.with(undefined, 0), undefined); + } + const uri = target.editor.document.uri; + const existing = getBreakpoints(uri, range); + if (existing.length > 0) { + toRemove.push(...existing); + } else { + if (isLineScopeType(target)) { + range = range.with(undefined, range.end.with(undefined, 0)); + } + toAdd.push(new SourceBreakpoint(new Location(uri, range))); + } + }); -// targets.forEach((target) => { -// let range: Range = target.selection.selection; -// // The action preference give us line content but line breakpoints are registered on character 0 -// if (isLineSelectionType(target.selectionType)) { -// range = range.with(range.start.with(undefined, 0), undefined); -// } -// const uri = target.selection.editor.document.uri; -// const existing = getBreakpoints(uri, range); -// if (existing.length > 0) { -// toRemove.push(...existing); -// } else { -// if (isLineSelectionType(target.selectionType)) { -// range = range.with(undefined, range.end.with(undefined, 0)); -// } -// toAdd.push(new SourceBreakpoint(new Location(uri, range))); -// } -// }); + debug.addBreakpoints(toAdd); + debug.removeBreakpoints(toRemove); -// debug.addBreakpoints(toAdd); -// debug.removeBreakpoints(toRemove); - -// const thatMark = targets.map((target) => target.selection); - -// return { thatMark }; -// } -// } + return { + thatMark: createThatMark(targets), + }; + } +} diff --git a/src/actions/actions.types.ts b/src/actions/actions.types.ts index 4712954822..307826df0b 100644 --- a/src/actions/actions.types.ts +++ b/src/actions/actions.types.ts @@ -27,7 +27,7 @@ export type ActionType = | "unfoldRegion" | "pasteFromClipboard" | "remove" - // |"toggleLineBreakpoint" + | "toggleLineBreakpoint" | "toggleLineComment" | "replace" // | "replaceWithTarget" diff --git a/src/util/editDisplayUtils.ts b/src/util/editDisplayUtils.ts index 4e6d153d3b..17d7658d54 100644 --- a/src/util/editDisplayUtils.ts +++ b/src/util/editDisplayUtils.ts @@ -6,6 +6,7 @@ import { RangeWithEditor } from "../typings/Types"; import sleep from "./sleep"; import { getContentRange, + isLineScopeType, runForEachEditor, runOnTargetsForEachEditor, } from "./targetUtils"; @@ -107,23 +108,12 @@ export async function setDecorations( } else { editor.setDecorations( editStyle.token, - targets.filter((target) => !useLineDecorations(target)).map(getRange) + targets.filter((target) => !isLineScopeType(target)).map(getRange) ); editor.setDecorations( editStyle.line, - targets.filter((target) => useLineDecorations(target)).map(getRange) + targets.filter((target) => isLineScopeType(target)).map(getRange) ); } }); } - -function useLineDecorations(target: Target) { - switch (target.scopeType) { - case "line": - case "paragraph": - case "document": - return true; - default: - return false; - } -} diff --git a/src/util/targetUtils.ts b/src/util/targetUtils.ts index d60efd911a..e27077cc64 100644 --- a/src/util/targetUtils.ts +++ b/src/util/targetUtils.ts @@ -147,3 +147,14 @@ export function maybeAddDelimiter(text: string, target: Target) { } return text; } + +export function isLineScopeType(target: Target) { + switch (target.scopeType) { + case "line": + case "paragraph": + case "document": + return true; + default: + return false; + } +} From 7bdf6b4685fe09558ba153f3db9687eb99ae2276 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 04:06:48 +0200 Subject: [PATCH 061/314] Added edit new line commands --- src/actions/Actions.ts | 5 +- src/actions/EditNewLine.ts | 182 ++++++++++++++++++++--------------- src/actions/Replace.ts | 2 +- src/actions/actions.types.ts | 4 +- 4 files changed, 108 insertions(+), 85 deletions(-) diff --git a/src/actions/Actions.ts b/src/actions/Actions.ts index 281ea57332..59020dc2bb 100644 --- a/src/actions/Actions.ts +++ b/src/actions/Actions.ts @@ -5,6 +5,7 @@ import { CommentLines } from "./Comment"; import { CopyLinesDown, CopyLinesUp } from "./CopyLines"; import { Copy, Cut, Paste } from "./CutCopyPaste"; import Deselect from "./Deselect"; +import { EditNewLineAbove, EditNewLineBelow } from "./EditNewLine"; import ExecuteCommand from "./ExecuteCommand"; import ExtractVariable from "./ExtractVariable"; import { FindInFiles } from "./Find"; @@ -36,8 +37,8 @@ class Actions implements ActionRecord { clearAndSetSelection = new Clear(this.graph); copyToClipboard = new Copy(this.graph); cutToClipboard = new Cut(this.graph); - // editNewLineAfter = new EditNewLineBelow(this.graph); - // editNewLineBefore = new EditNewLineAbove(this.graph); + editNewLineAfter = new EditNewLineBelow(this.graph); + editNewLineBefore = new EditNewLineAbove(this.graph); executeCommand = new ExecuteCommand(this.graph); extractVariable = new ExtractVariable(this.graph); findInWorkspace = new FindInFiles(this.graph); diff --git a/src/actions/EditNewLine.ts b/src/actions/EditNewLine.ts index 0179f75426..8f9a124a0c 100644 --- a/src/actions/EditNewLine.ts +++ b/src/actions/EditNewLine.ts @@ -1,91 +1,113 @@ -// import { -// Action, -// ActionPreferences, -// ActionReturnValue, -// Graph, -// Target, -// } from "../typings/Types"; -// import { commands, Selection, TextEditor } from "vscode"; -// import { getNotebookFromCellDocument } from "../util/notebook"; +import { commands, Position, Range, Selection, TextEditor } from "vscode"; +import { Target } from "../typings/target.types"; +import { Graph } from "../typings/Types"; +import { getNotebookFromCellDocument } from "../util/notebook"; +import { createThatMark, runOnTargetsForEachEditor } from "../util/targetUtils"; +import { Action, ActionReturnValue } from "./actions.types"; -// class EditNewLine implements Action { -// getTargetPreferences: () => ActionPreferences[] = () => [ -// { insideOutsideType: "inside" }, -// ]; +class EditNewLine implements Action { + constructor(private graph: Graph, private isAbove: boolean) { + this.run = this.run.bind(this); + } -// constructor(private graph: Graph, private isAbove: boolean) { -// this.run = this.run.bind(this); -// } + private isNotebookEditor(editor: TextEditor) { + return getNotebookFromCellDocument(editor.document) != null; + } -// private correctForParagraph(targets: Target[]) { -// targets.forEach((target) => { -// let { start, end } = target.selection.selection; -// if (target.selectionType === "paragraph") { -// if ( -// this.isAbove && -// target.selectionContext.leadingDelimiterRange != null -// ) { -// start = start.translate({ lineDelta: -1 }); -// } else if ( -// !this.isAbove && -// target.selectionContext.trailingDelimiterRange != null -// ) { -// end = end.translate({ lineDelta: 1 }); -// } -// target.selection.selection = new Selection(start, end); -// } -// }); -// } + private getCommand(target: Target) { + if (target.isNotebookCell) { + if (this.isNotebookEditor(target.editor)) { + return this.isAbove + ? "notebook.cell.insertCodeCellAbove" + : "notebook.cell.insertCodeCellBelow"; + } + return this.isAbove + ? "jupyter.insertCellAbove" + : "jupyter.insertCellBelow"; + } + return null; + } -// private isNotebookEditor(editor: TextEditor) { -// return getNotebookFromCellDocument(editor.document) != null; -// } + async run([targets]: [Target[]]): Promise { + const command = this.getCommand(targets[0]); + if (command) { + if (this.isAbove) { + await this.graph.actions.setSelectionBefore.run([targets]); + } else { + await this.graph.actions.setSelectionAfter.run([targets]); + } + await commands.executeCommand(command); + return { thatMark: createThatMark(targets) }; + } -// private getCommand(target: Target) { -// if (target.selectionContext.isNotebookCell) { -// if (this.isNotebookEditor(target.selection.editor)) { -// return this.isAbove -// ? "notebook.cell.insertCodeCellAbove" -// : "notebook.cell.insertCodeCellBelow"; -// } -// return this.isAbove -// ? "jupyter.insertCellAbove" -// : "jupyter.insertCellBelow"; -// } -// return this.isAbove -// ? "editor.action.insertLineBefore" -// : "editor.action.insertLineAfter"; -// } + const thatMark = await runOnTargetsForEachEditor( + targets, + async (editor, targets) => { + const edits = targets.map((target) => { + const delimiter = target.scopeType === "paragraph" ? "\n\n" : "\n"; + const lineNumber = this.isAbove + ? target.contentRange.start.line + : target.contentRange.end.line; + const line = editor.document.lineAt(lineNumber); + const { firstNonWhitespaceCharacterIndex } = line; + const padding = line.text.slice(0, firstNonWhitespaceCharacterIndex); + const text = this.isAbove ? padding + delimiter : delimiter + padding; + const position = this.isAbove ? line.range.start : line.range.end; + const lineDelta = delimiter.length; + return { + contentRange: target.contentRange, + lineDelta, + firstNonWhitespaceCharacterIndex, + position, + text, + }; + }); -// async run([targets]: [Target[]]): Promise { -// this.correctForParagraph(targets); + await editor.edit((editBuilder) => { + edits.forEach((edit) => { + editBuilder.insert(edit.position, edit.text); + }); + }); -// if (this.isAbove) { -// await this.graph.actions.setSelectionBefore.run([targets]); -// } else { -// await this.graph.actions.setSelectionAfter.run([targets]); -// } + editor.selections = edits.map((edit) => { + const selectionLineNum = this.isAbove + ? edit.position.line + : edit.position.line + edit.lineDelta; + const positionSelection = new Position( + selectionLineNum, + edit.firstNonWhitespaceCharacterIndex + ); + return new Selection(positionSelection, positionSelection); + }); -// const command = this.getCommand(targets[0]); -// await commands.executeCommand(command); + const thatMarkRanges = edits.map((edit) => { + const { contentRange, lineDelta } = edit; + return this.isAbove + ? new Range( + contentRange.start.translate({ lineDelta }), + contentRange.end.translate({ lineDelta }) + ) + : contentRange; + }); -// return { -// thatMark: targets.map((target) => ({ -// selection: target.selection.editor.selection, -// editor: target.selection.editor, -// })), -// }; -// } -// } + return createThatMark(targets, thatMarkRanges); + } + ); -// export class EditNewLineAbove extends EditNewLine { -// constructor(graph: Graph) { -// super(graph, true); -// } -// } + return { + thatMark: thatMark.flat(), + }; + } +} -// export class EditNewLineBelow extends EditNewLine { -// constructor(graph: Graph) { -// super(graph, false); -// } -// } +export class EditNewLineAbove extends EditNewLine { + constructor(graph: Graph) { + super(graph, true); + } +} + +export class EditNewLineBelow extends EditNewLine { + constructor(graph: Graph) { + super(graph, false); + } +} diff --git a/src/actions/Replace.ts b/src/actions/Replace.ts index 129af01d41..2e46d53af1 100644 --- a/src/actions/Replace.ts +++ b/src/actions/Replace.ts @@ -65,7 +65,7 @@ export default class implements Action { this.graph.rangeUpdater, editor, edits, - [targets.map((target) => getContentSelection(target))] + [targets.map(getContentSelection)] ); return updatedSelections.map((selection) => ({ diff --git a/src/actions/actions.types.ts b/src/actions/actions.types.ts index 307826df0b..2cddcc713d 100644 --- a/src/actions/actions.types.ts +++ b/src/actions/actions.types.ts @@ -7,8 +7,8 @@ export type ActionType = | "copyToClipboard" | "cutToClipboard" | "deselect" - // | "editNewLineAfter" - // | "editNewLineBefore" + | "editNewLineAfter" + | "editNewLineBefore" | "executeCommand" | "extractVariable" | "findInWorkspace" From f696815f9c8beffd446fa3a0def33e63199cc357 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 04:11:58 +0200 Subject: [PATCH 062/314] Added action wrap --- src/actions/Actions.ts | 3 +- src/actions/Wrap.ts | 222 +++++++++++++++++------------------ src/actions/actions.types.ts | 1 + 3 files changed, 110 insertions(+), 116 deletions(-) diff --git a/src/actions/Actions.ts b/src/actions/Actions.ts index 59020dc2bb..b220785775 100644 --- a/src/actions/Actions.ts +++ b/src/actions/Actions.ts @@ -29,6 +29,7 @@ import { } from "./SetSelection"; import { Random, Reverse, Sort } from "./Sort"; import ToggleBreakpoint from "./ToggleBreakpoint"; +import Wrap from "./Wrap"; class Actions implements ActionRecord { constructor(private graph: Graph) {} @@ -73,7 +74,7 @@ class Actions implements ActionRecord { toggleLineBreakpoint = new ToggleBreakpoint(this.graph); toggleLineComment = new CommentLines(this.graph); unfoldRegion = new Unfold(this.graph); - // wrapWithPairedDelimiter = new Wrap(this.graph); + wrapWithPairedDelimiter = new Wrap(this.graph); // wrapWithSnippet = new WrapWithSnippet(this.graph); // } diff --git a/src/actions/Wrap.ts b/src/actions/Wrap.ts index e2f41cec43..4d34ba99fc 100644 --- a/src/actions/Wrap.ts +++ b/src/actions/Wrap.ts @@ -1,126 +1,118 @@ -// import { DecorationRangeBehavior, Selection } from "vscode"; -// import { flatten } from "lodash"; -// import { -// Action, -// ActionPreferences, -// ActionReturnValue, -// Edit, -// Graph, -// SelectionWithEditor, -// Target, -// } from "../typings/Types"; -// import { runOnTargetsForEachEditor } from "../util/targetUtils"; -// import { decorationSleep } from "../util/editDisplayUtils"; -// import { FullSelectionInfo } from "../typings/updateSelections"; -// import { -// getSelectionInfo, -// performEditsAndUpdateFullSelectionInfos, -// } from "../core/updateSelections/updateSelections"; +import { flatten } from "lodash"; +import { DecorationRangeBehavior, Selection } from "vscode"; +import { + getSelectionInfo, + performEditsAndUpdateFullSelectionInfos, +} from "../core/updateSelections/updateSelections"; +import { Target } from "../typings/target.types"; +import { Edit, Graph, SelectionWithEditor } from "../typings/Types"; +import { FullSelectionInfo } from "../typings/updateSelections"; +import { decorationSleep } from "../util/editDisplayUtils"; +import { + getContentSelection, + runOnTargetsForEachEditor, +} from "../util/targetUtils"; +import { Action, ActionReturnValue } from "./actions.types"; -// export default class Wrap implements Action { -// getTargetPreferences: () => ActionPreferences[] = () => [ -// { insideOutsideType: "inside" }, -// ]; +export default class Wrap implements Action { + constructor(private graph: Graph) { + this.run = this.run.bind(this); + } -// constructor(private graph: Graph) { -// this.run = this.run.bind(this); -// } + async run( + [targets]: [Target[]], + left: string, + right: string + ): Promise { + const thatMark = flatten( + await runOnTargetsForEachEditor( + targets, + async (editor, targets) => { + const { document } = editor; + const boundaries = targets.map((target) => ({ + start: new Selection( + target.contentRange.start, + target.contentRange.start + ), + end: new Selection( + target.contentRange.end, + target.contentRange.end + ), + })); -// async run( -// [targets]: [Target[]], -// left: string, -// right: string -// ): Promise { -// const thatMark = flatten( -// await runOnTargetsForEachEditor( -// targets, -// async (editor, targets) => { -// const { document } = editor; -// const boundaries = targets.map((target) => ({ -// start: new Selection( -// target.selection.selection.start, -// target.selection.selection.start -// ), -// end: new Selection( -// target.selection.selection.end, -// target.selection.selection.end -// ), -// })); + const edits: Edit[] = boundaries.flatMap(({ start, end }) => [ + { + text: left, + range: start, + }, + { + text: right, + range: end, + isReplace: true, + }, + ]); -// const edits: Edit[] = boundaries.flatMap(({ start, end }) => [ -// { -// text: left, -// range: start, -// }, -// { -// text: right, -// range: end, -// isReplace: true, -// }, -// ]); + const delimiterSelectionInfos: FullSelectionInfo[] = + boundaries.flatMap(({ start, end }) => { + return [ + getSelectionInfo( + document, + start, + DecorationRangeBehavior.OpenClosed + ), + getSelectionInfo( + document, + end, + DecorationRangeBehavior.ClosedOpen + ), + ]; + }); -// const delimiterSelectionInfos: FullSelectionInfo[] = -// boundaries.flatMap(({ start, end }) => { -// return [ -// getSelectionInfo( -// document, -// start, -// DecorationRangeBehavior.OpenClosed -// ), -// getSelectionInfo( -// document, -// end, -// DecorationRangeBehavior.ClosedOpen -// ), -// ]; -// }); + const cursorSelectionInfos = editor.selections.map((selection) => + getSelectionInfo( + document, + selection, + DecorationRangeBehavior.ClosedClosed + ) + ); -// const cursorSelectionInfos = editor.selections.map((selection) => -// getSelectionInfo( -// document, -// selection, -// DecorationRangeBehavior.ClosedClosed -// ) -// ); + const thatMarkSelectionInfos = targets.map((target) => + getSelectionInfo( + document, + getContentSelection(target), + DecorationRangeBehavior.OpenOpen + ) + ); -// const thatMarkSelectionInfos = targets.map( -// ({ selection: { selection } }) => -// getSelectionInfo( -// document, -// selection, -// DecorationRangeBehavior.OpenOpen -// ) -// ); + const [delimiterSelections, cursorSelections, thatMarkSelections] = + await performEditsAndUpdateFullSelectionInfos( + this.graph.rangeUpdater, + editor, + edits, + [ + delimiterSelectionInfos, + cursorSelectionInfos, + thatMarkSelectionInfos, + ] + ); -// const [delimiterSelections, cursorSelections, thatMarkSelections] = -// await performEditsAndUpdateFullSelectionInfos( -// this.graph.rangeUpdater, -// editor, -// edits, -// [ -// delimiterSelectionInfos, -// cursorSelectionInfos, -// thatMarkSelectionInfos, -// ] -// ); + editor.selections = cursorSelections; -// editor.selections = cursorSelections; + editor.setDecorations( + this.graph.editStyles.justAdded.token, + delimiterSelections + ); + await decorationSleep(); + editor.setDecorations(this.graph.editStyles.justAdded.token, []); -// editor.setDecorations( -// this.graph.editStyles.justAdded.token, -// delimiterSelections -// ); -// await decorationSleep(); -// editor.setDecorations(this.graph.editStyles.justAdded.token, []); + return thatMarkSelections.map((selection) => ({ + editor, + selection, + })); + } + ) + ); -// return thatMarkSelections.map((selection) => ({ -// editor, -// selection, -// })); -// } -// ) -// ); - -// return { thatMark }; -// } -// } + return { thatMark }; + } +} diff --git a/src/actions/actions.types.ts b/src/actions/actions.types.ts index 2cddcc713d..675896fa00 100644 --- a/src/actions/actions.types.ts +++ b/src/actions/actions.types.ts @@ -35,6 +35,7 @@ export type ActionType = | "randomizeTargets" | "sortTargets" // | "rewrapWithPairedDelimiter" + | "wrapWithPairedDelimiter" | "scrollToBottom" | "scrollToCenter" | "scrollToTop" From 9eba8fcc75dc6a281af9c40df5c6f396a7b22766 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 04:52:45 +0200 Subject: [PATCH 063/314] Updated token stage --- src/actions/Actions.ts | 3 +- src/actions/Call.ts | 61 ++++----- src/actions/actions.types.ts | 2 +- .../upgradeV1ToV2/upgradeV1ToV2.ts | 12 +- src/core/inferFullTargets.ts | 13 +- src/processTargets/getMarkStage.ts | 3 - src/processTargets/marks/CursorTokenStage.ts | 128 ------------------ src/processTargets/modifiers/TokenStage.ts | 102 +++++++++++++- src/typings/target.types.ts | 5 - 9 files changed, 148 insertions(+), 181 deletions(-) delete mode 100644 src/processTargets/marks/CursorTokenStage.ts diff --git a/src/actions/Actions.ts b/src/actions/Actions.ts index b220785775..4b5f350f3e 100644 --- a/src/actions/Actions.ts +++ b/src/actions/Actions.ts @@ -1,5 +1,6 @@ import { Graph } from "../typings/Types"; import { ActionRecord } from "./actions.types"; +import Call from "./Call"; import Clear from "./Clear"; import { CommentLines } from "./Comment"; import { CopyLinesDown, CopyLinesUp } from "./CopyLines"; @@ -34,7 +35,7 @@ import Wrap from "./Wrap"; class Actions implements ActionRecord { constructor(private graph: Graph) {} - // callAsFunction = new Call(this.graph); + callAsFunction = new Call(this.graph); clearAndSetSelection = new Clear(this.graph); copyToClipboard = new Copy(this.graph); cutToClipboard = new Cut(this.graph); diff --git a/src/actions/Call.ts b/src/actions/Call.ts index 2b39f0a5f3..ff07daf74a 100644 --- a/src/actions/Call.ts +++ b/src/actions/Call.ts @@ -1,39 +1,30 @@ -// import { -// Action, -// ActionReturnValue, -// ActionPreferences, -// Graph, -// Target, -// } from "../typings/Types"; -// import { ensureSingleTarget } from "../util/targetUtils"; +import { Target } from "../typings/target.types"; +import { Graph } from "../typings/Types"; +import { ensureSingleTarget } from "../util/targetUtils"; +import { Action, ActionReturnValue } from "./actions.types"; -// export default class Call implements Action { -// getTargetPreferences: () => ActionPreferences[] = () => [ -// { insideOutsideType: "inside" }, -// { insideOutsideType: "inside" }, -// ]; +export default class Call implements Action { + constructor(private graph: Graph) { + this.run = this.run.bind(this); + } -// constructor(private graph: Graph) { -// this.run = this.run.bind(this); -// } + async run([sources, destinations]: [ + Target[], + Target[] + ]): Promise { + ensureSingleTarget(sources); -// async run([sources, destinations]: [ -// Target[], -// Target[] -// ]): Promise { -// ensureSingleTarget(sources); + const { returnValue: texts } = await this.graph.actions.getText.run( + [sources], + { + showDecorations: false, + } + ); -// const { returnValue: texts } = await this.graph.actions.getText.run( -// [sources], -// { -// showDecorations: false, -// } -// ); - -// return this.graph.actions.wrapWithPairedDelimiter.run( -// [destinations], -// texts[0] + "(", -// ")" -// ); -// } -// } + return this.graph.actions.wrapWithPairedDelimiter.run( + [destinations], + texts[0] + "(", + ")" + ); + } +} diff --git a/src/actions/actions.types.ts b/src/actions/actions.types.ts index 675896fa00..264e57a5bf 100644 --- a/src/actions/actions.types.ts +++ b/src/actions/actions.types.ts @@ -2,7 +2,7 @@ import { Target } from "../typings/target.types"; import { SelectionWithEditor } from "../typings/Types"; export type ActionType = - // | "callAsFunction" + | "callAsFunction" | "clearAndSetSelection" | "copyToClipboard" | "cutToClipboard" diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts index e6c850ab39..7de119c9e5 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts @@ -65,6 +65,7 @@ function upgradePrimitiveTarget( target: PartialPrimitiveTargetV0V1 ): PartialPrimitiveTargetDesc { const { + mark, insideOutsideType, modifier, isImplicit, @@ -74,6 +75,10 @@ function upgradePrimitiveTarget( } = target; const modifiers: Modifier[] = []; + if (selectionType) { + modifiers.push({ type: "containingScope", scopeType: selectionType }); + } + if (modifier) { const mod = upgradeModifier(modifier); if (mod) { @@ -85,10 +90,6 @@ function upgradePrimitiveTarget( } } - if (selectionType) { - modifiers.push({ type: "containingScope", scopeType: selectionType }); - } - if (isImplicit) { modifiers.push({ type: "toRawSelection" }); } @@ -109,8 +110,11 @@ function upgradePrimitiveTarget( } } + const newMark = mark?.type === "cursorToken" ? undefined : mark; + return { ...rest, + mark: newMark, // Modifiers are processed backwards modifiers: modifiers.length ? modifiers.reverse() : undefined, }; diff --git a/src/core/inferFullTargets.ts b/src/core/inferFullTargets.ts index 8c3792708b..e2c0946b96 100644 --- a/src/core/inferFullTargets.ts +++ b/src/core/inferFullTargets.ts @@ -103,17 +103,24 @@ function inferRangeTarget( function inferPrimitiveTarget( target: PartialPrimitiveTargetDesc, previousTargets: PartialTargetDesc[], + // TODO ActionPreferences actionPreferences: ActionPreferences ): PrimitiveTargetDesc { + const hasPosition = !!target.modifiers?.find( + (modifier) => modifier.type === "position" + ); + + // Position without a mark can be something like "take air past end of line" const mark = target.mark ?? - getPreviousAttribute(previousTargets, "mark") ?? { type: "cursor" }; + (hasPosition ? getPreviousAttribute(previousTargets, "mark") : null) ?? { + type: "cursor", + }; + const modifiers = target.modifiers ?? getPreviousAttribute(previousTargets, "modifiers") ?? []; - // TODO ActionPreferences - return { type: target.type, mark, diff --git a/src/processTargets/getMarkStage.ts b/src/processTargets/getMarkStage.ts index b8650f0711..afc6c25356 100644 --- a/src/processTargets/getMarkStage.ts +++ b/src/processTargets/getMarkStage.ts @@ -1,6 +1,5 @@ import { Mark } from "../typings/target.types"; import CursorStage from "./marks/CursorStage"; -import CursorTokenStage from "./marks/CursorTokenStage"; import DecoratedSymbolStage from "./marks/DecoratedSymbolStage"; import LineNumberStage from "./marks/LineNumberStage"; import NothingStage from "./marks/NothingStage"; @@ -12,8 +11,6 @@ export default (mark: Mark): MarkStage => { switch (mark.type) { case "cursor": return new CursorStage(mark); - case "cursorToken": - return new CursorTokenStage(mark); case "that": return new ThatStage(mark); case "source": diff --git a/src/processTargets/marks/CursorTokenStage.ts b/src/processTargets/marks/CursorTokenStage.ts deleted file mode 100644 index 587030db6c..0000000000 --- a/src/processTargets/marks/CursorTokenStage.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { Range, window } from "vscode"; -import { CursorTokenMark, Target } from "../../typings/target.types"; -import { SelectionWithEditor } from "../../typings/Types"; -import { getTokensInRange, PartialToken } from "../../util/getTokensInRange"; -import { isReversed } from "../../util/selectionUtils"; -import { getTokenContext } from "../modifiers/TokenStage"; -import { MarkStage } from "../PipelineStages.types"; - -export default class implements MarkStage { - constructor(private modifier: CursorTokenMark) {} - - run(): Target[] { - const editor = window.activeTextEditor; - if (editor == null) { - return []; - } - return editor.selections.map((selection) => { - const contentRange = getTokenRangeForSelection({ - editor, - selection, - }); - return { - editor, - isReversed: isReversed(selection), - contentRange, - ...getTokenContext(editor, contentRange), - }; - }); - } -} - -/** - * Given a selection returns a new range which contains the tokens - * intersecting the given selection. Uses heuristics to tie break when the - * given selection is empty and abuts 2 adjacent tokens - * @param selection Selection to operate on - * @returns Modified range - */ -function getTokenRangeForSelection(selection: SelectionWithEditor): Range { - let tokens = getTokenIntersectionsForSelection(selection); - // Use single token for overlapping or adjacent range - if (selection.selection.isEmpty) { - // If multiple matches sort and take the first - tokens.sort(({ token: a }, { token: b }) => { - // First sort on alphanumeric - const aIsAlphaNum = isAlphaNum(a.text); - const bIsAlphaNum = isAlphaNum(b.text); - if (aIsAlphaNum && !bIsAlphaNum) { - return -1; - } - if (bIsAlphaNum && !aIsAlphaNum) { - return 1; - } - // Second sort on length - const lengthDiff = b.text.length - a.text.length; - if (lengthDiff !== 0) { - return lengthDiff; - } - // Lastly sort on start position. ie leftmost - return a.offsets.start - b.offsets.start; - }); - tokens = tokens.slice(0, 1); - } - // Use tokens for overlapping ranges - else { - tokens = tokens.filter((token) => !token.intersection.isEmpty); - tokens.sort((a, b) => a.token.offsets.start - b.token.offsets.start); - } - if (tokens.length < 1) { - throw new Error("Couldn't find token in selection"); - } - const start = tokens[0].token.range.start; - const end = tokens[tokens.length - 1].token.range.end; - return new Range(start, end); -} - -/** - * Returns tokens that intersect with the selection that may be relevant for - * expanding the selection to its containing token. - * @param selection The selection - * @returns All tokens that intersect with the selection and are on the same line as the start or endpoint of the selection - */ -function getTokenIntersectionsForSelection(selection: SelectionWithEditor) { - const tokens = getRelevantTokens(selection); - - const tokenIntersections: { token: PartialToken; intersection: Range }[] = []; - - tokens.forEach((token) => { - const intersection = token.range.intersection(selection.selection); - if (intersection != null) { - tokenIntersections.push({ token, intersection }); - } - }); - - return tokenIntersections; -} - -/** - * Given a selection, finds all tokens that we might use to expand the - * selection. Just looks at tokens on the same line as the start and end of the - * selection, because we assume that a token cannot span multiple lines. - * @param selection The selection we care about - * @returns A list of tokens that we might expand to - */ -function getRelevantTokens(selection: SelectionWithEditor) { - const startLine = selection.selection.start.line; - const endLine = selection.selection.end.line; - - let tokens = getTokensInRange( - selection.editor, - selection.editor.document.lineAt(startLine).range - ); - - if (endLine !== startLine) { - tokens.push( - ...getTokensInRange( - selection.editor, - selection.editor.document.lineAt(endLine).range - ) - ); - } - - return tokens; -} - -function isAlphaNum(text: string) { - return /^\w+$/.test(text); -} diff --git a/src/processTargets/modifiers/TokenStage.ts b/src/processTargets/modifiers/TokenStage.ts index 11a70a1221..1d0df76d23 100644 --- a/src/processTargets/modifiers/TokenStage.ts +++ b/src/processTargets/modifiers/TokenStage.ts @@ -5,16 +5,21 @@ import { Target, } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; +import { getTokensInRange, PartialToken } from "../../util/getTokensInRange"; import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} run(context: ProcessedTargetsContext, target: Target): Target { + const contentRange = getTokenRangeForSelection( + target.editor, + target.contentRange + ); return { editor: target.editor, isReversed: target.isReversed, - contentRange: target.contentRange, + contentRange, ...getTokenContext(target.editor, target.contentRange), }; } @@ -69,3 +74,98 @@ export function getTokenContext( : undefined, }; } + +/** + * Given a selection returns a new range which contains the tokens + * intersecting the given selection. Uses heuristics to tie break when the + * given selection is empty and abuts 2 adjacent tokens + * @param selection Selection to operate on + * @returns Modified range + */ +function getTokenRangeForSelection(editor: TextEditor, range: Range): Range { + let tokens = getTokenIntersectionsForSelection(editor, range); + // Use single token for overlapping or adjacent range + if (range.isEmpty) { + // If multiple matches sort and take the first + tokens.sort(({ token: a }, { token: b }) => { + // First sort on alphanumeric + const aIsAlphaNum = isAlphaNum(a.text); + const bIsAlphaNum = isAlphaNum(b.text); + if (aIsAlphaNum && !bIsAlphaNum) { + return -1; + } + if (bIsAlphaNum && !aIsAlphaNum) { + return 1; + } + // Second sort on length + const lengthDiff = b.text.length - a.text.length; + if (lengthDiff !== 0) { + return lengthDiff; + } + // Lastly sort on start position. ie leftmost + return a.offsets.start - b.offsets.start; + }); + tokens = tokens.slice(0, 1); + } + // Use tokens for overlapping ranges + else { + tokens = tokens.filter((token) => !token.intersection.isEmpty); + tokens.sort((a, b) => a.token.offsets.start - b.token.offsets.start); + } + if (tokens.length < 1) { + throw new Error("Couldn't find token in selection"); + } + const start = tokens[0].token.range.start; + const end = tokens[tokens.length - 1].token.range.end; + return new Range(start, end); +} + +/** + * Returns tokens that intersect with the selection that may be relevant for + * expanding the selection to its containing token. + * @param selection The selection + * @returns All tokens that intersect with the selection and are on the same line as the start or endpoint of the selection + */ +function getTokenIntersectionsForSelection(editor: TextEditor, range: Range) { + const tokens = getRelevantTokens(editor, range); + + const tokenIntersections: { token: PartialToken; intersection: Range }[] = []; + + tokens.forEach((token) => { + const intersection = token.range.intersection(range); + if (intersection != null) { + tokenIntersections.push({ token, intersection }); + } + }); + + return tokenIntersections; +} + +/** + * Given a selection, finds all tokens that we might use to expand the + * selection. Just looks at tokens on the same line as the start and end of the + * selection, because we assume that a token cannot span multiple lines. + * @param selection The selection we care about + * @returns A list of tokens that we might expand to + */ +function getRelevantTokens(editor: TextEditor, range: Range) { + const startLine = range.start.line; + const endLine = range.end.line; + + let tokens = getTokensInRange( + editor, + editor.document.lineAt(startLine).range + ); + + if (endLine !== startLine) { + tokens.push( + ...getTokensInRange(editor, editor.document.lineAt(endLine).range) + ); + } + + return tokens; +} + +function isAlphaNum(text: string) { + return /^\w+$/.test(text); +} diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 38f113beeb..3e46aa02e8 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -5,10 +5,6 @@ export interface CursorMark { type: "cursor"; } -export interface CursorTokenMark { - type: "cursorToken"; -} - export interface ThatMark { type: "that"; } @@ -46,7 +42,6 @@ export interface LineNumberMark { export type Mark = | CursorMark - | CursorTokenMark | ThatMark | SourceMark // | LastCursorPositionMark Not implemented yet From c5212318fe93818d1c158c341816414a217ab482 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 04:59:07 +0200 Subject: [PATCH 064/314] Added missing action types --- src/actions/Actions.ts | 81 ++++++++++++++++++------------------ src/actions/actions.types.ts | 74 ++++++++++++++++---------------- 2 files changed, 78 insertions(+), 77 deletions(-) diff --git a/src/actions/Actions.ts b/src/actions/Actions.ts index 4b5f350f3e..b81ff556d9 100644 --- a/src/actions/Actions.ts +++ b/src/actions/Actions.ts @@ -35,49 +35,48 @@ import Wrap from "./Wrap"; class Actions implements ActionRecord { constructor(private graph: Graph) {} - callAsFunction = new Call(this.graph); - clearAndSetSelection = new Clear(this.graph); - copyToClipboard = new Copy(this.graph); - cutToClipboard = new Cut(this.graph); - editNewLineAfter = new EditNewLineBelow(this.graph); - editNewLineBefore = new EditNewLineAbove(this.graph); - executeCommand = new ExecuteCommand(this.graph); - extractVariable = new ExtractVariable(this.graph); - findInWorkspace = new FindInFiles(this.graph); - foldRegion = new Fold(this.graph); - followLink = new FollowLink(this.graph); - getText = new GetText(this.graph); - highlight = new Highlight(this.graph); - indentLine = new IndentLines(this.graph); - insertCopyAfter = new CopyLinesDown(this.graph); - insertCopyBefore = new CopyLinesUp(this.graph); - insertEmptyLineAfter = new InsertEmptyLineBelow(this.graph); - insertEmptyLineBefore = new InsertEmptyLineAbove(this.graph); - insertEmptyLinesAround = new InsertEmptyLinesAround(this.graph); - // moveToTarget = new Move(this.graph); - outdentLine = new OutdentLines(this.graph); - pasteFromClipboard = new Paste(this.graph); - remove = new Remove(this.graph); - deselect = new Deselect(this.graph); - replace = new Replace(this.graph); + // wrapWithSnippet = new WrapWithSnippet(this.graph); + wrapWithPairedDelimiter = new Wrap(this.graph); + unfoldRegion = new Unfold(this.graph); + toggleLineComment = new CommentLines(this.graph); + toggleLineBreakpoint = new ToggleBreakpoint(this.graph); + // swapTargets = new Swap(this.graph); + sortTargets = new Sort(this.graph); + setSelectionBefore = new SetSelectionBefore(this.graph); + setSelectionAfter = new SetSelectionAfter(this.graph); + setSelection = new SetSelection(this.graph); + scrollToTop = new ScrollToTop(this.graph); + scrollToCenter = new ScrollToCenter(this.graph); + scrollToBottom = new ScrollToBottom(this.graph); + // rewrapWithPairedDelimiter = new Rewrap(this.graph); + reverseTargets = new Reverse(this.graph); // replaceWithTarget = new Bring(this.graph); + replace = new Replace(this.graph); + remove = new Remove(this.graph); randomizeTargets = new Random(this.graph); - reverseTargets = new Reverse(this.graph); - // rewrapWithPairedDelimiter = new Rewrap(this.graph); - scrollToBottom = new ScrollToBottom(this.graph); - scrollToCenter = new ScrollToCenter(this.graph); - scrollToTop = new ScrollToTop(this.graph); - setSelection = new SetSelection(this.graph); - setSelectionAfter = new SetSelectionAfter(this.graph); - setSelectionBefore = new SetSelectionBefore(this.graph); - sortTargets = new Sort(this.graph); - // swapTargets = new Swap(this.graph); - toggleLineBreakpoint = new ToggleBreakpoint(this.graph); - toggleLineComment = new CommentLines(this.graph); - unfoldRegion = new Unfold(this.graph); - wrapWithPairedDelimiter = new Wrap(this.graph); - // wrapWithSnippet = new WrapWithSnippet(this.graph); - // + pasteFromClipboard = new Paste(this.graph); + outdentLine = new OutdentLines(this.graph); + // moveToTarget = new Move(this.graph); + insertEmptyLinesAround = new InsertEmptyLinesAround(this.graph); + insertEmptyLineBefore = new InsertEmptyLineAbove(this.graph); + insertEmptyLineAfter = new InsertEmptyLineBelow(this.graph); + insertCopyBefore = new CopyLinesUp(this.graph); + insertCopyAfter = new CopyLinesDown(this.graph); + indentLine = new IndentLines(this.graph); + highlight = new Highlight(this.graph); + getText = new GetText(this.graph); + followLink = new FollowLink(this.graph); + foldRegion = new Fold(this.graph); + findInWorkspace = new FindInFiles(this.graph); + extractVariable = new ExtractVariable(this.graph); + executeCommand = new ExecuteCommand(this.graph); + editNewLineBefore = new EditNewLineAbove(this.graph); + editNewLineAfter = new EditNewLineBelow(this.graph); + deselect = new Deselect(this.graph); + cutToClipboard = new Cut(this.graph); + copyToClipboard = new Copy(this.graph); + clearAndSetSelection = new Clear(this.graph); + callAsFunction = new Call(this.graph); } export default Actions; diff --git a/src/actions/actions.types.ts b/src/actions/actions.types.ts index 264e57a5bf..61aec0d318 100644 --- a/src/actions/actions.types.ts +++ b/src/actions/actions.types.ts @@ -2,46 +2,48 @@ import { Target } from "../typings/target.types"; import { SelectionWithEditor } from "../typings/Types"; export type ActionType = - | "callAsFunction" - | "clearAndSetSelection" - | "copyToClipboard" - | "cutToClipboard" - | "deselect" - | "editNewLineAfter" - | "editNewLineBefore" - | "executeCommand" - | "extractVariable" - | "findInWorkspace" - | "foldRegion" - | "followLink" - | "getText" - | "highlight" - | "indentLine" - | "insertCopyAfter" - | "insertCopyBefore" - | "insertEmptyLineAfter" - | "insertEmptyLineBefore" - | "insertEmptyLinesAround" - // | "moveToTarget" - | "outdentLine" + | "wrapWithSnippet" + | "wrapWithPairedDelimiter" | "unfoldRegion" - | "pasteFromClipboard" - | "remove" - | "toggleLineBreakpoint" | "toggleLineComment" - | "replace" - // | "replaceWithTarget" - | "reverseTargets" - | "randomizeTargets" + | "toggleLineBreakpoint" + | "swapTargets" | "sortTargets" - // | "rewrapWithPairedDelimiter" - | "wrapWithPairedDelimiter" - | "scrollToBottom" - | "scrollToCenter" - | "scrollToTop" - | "setSelection" + | "setSelectionBefore" | "setSelectionAfter" - | "setSelectionBefore"; + | "setSelection" + | "scrollToTop" + | "scrollToCenter" + | "scrollToBottom" + | "rewrapWithPairedDelimiter" + | "reverseTargets" + | "replaceWithTarget" + | "replace" + | "remove" + | "randomizeTargets" + | "pasteFromClipboard" + | "outdentLine" + | "moveToTarget" + | "insertEmptyLinesAround" + | "insertEmptyLineBefore" + | "insertEmptyLineAfter" + | "insertCopyBefore" + | "insertCopyAfter" + | "indentLine" + | "highlight" + | "getText" + | "followLink" + | "foldRegion" + | "findInWorkspace" + | "extractVariable" + | "executeCommand" + | "editNewLineBefore" + | "editNewLineAfter" + | "deselect" + | "cutToClipboard" + | "copyToClipboard" + | "clearAndSetSelection" + | "callAsFunction"; export interface ActionReturnValue { returnValue?: any; From b632a0a18065a59eab38d807c21f703b7622bfd3 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 05:07:49 +0200 Subject: [PATCH 065/314] Sorted action names --- src/actions/Actions.ts | 82 ++++++++++++++++++------------------ src/actions/actions.types.ts | 82 ++++++++++++++++++------------------ 2 files changed, 82 insertions(+), 82 deletions(-) diff --git a/src/actions/Actions.ts b/src/actions/Actions.ts index b81ff556d9..56483cb03d 100644 --- a/src/actions/Actions.ts +++ b/src/actions/Actions.ts @@ -35,48 +35,48 @@ import Wrap from "./Wrap"; class Actions implements ActionRecord { constructor(private graph: Graph) {} - // wrapWithSnippet = new WrapWithSnippet(this.graph); - wrapWithPairedDelimiter = new Wrap(this.graph); - unfoldRegion = new Unfold(this.graph); - toggleLineComment = new CommentLines(this.graph); - toggleLineBreakpoint = new ToggleBreakpoint(this.graph); - // swapTargets = new Swap(this.graph); - sortTargets = new Sort(this.graph); - setSelectionBefore = new SetSelectionBefore(this.graph); - setSelectionAfter = new SetSelectionAfter(this.graph); - setSelection = new SetSelection(this.graph); - scrollToTop = new ScrollToTop(this.graph); - scrollToCenter = new ScrollToCenter(this.graph); - scrollToBottom = new ScrollToBottom(this.graph); - // rewrapWithPairedDelimiter = new Rewrap(this.graph); - reverseTargets = new Reverse(this.graph); - // replaceWithTarget = new Bring(this.graph); - replace = new Replace(this.graph); - remove = new Remove(this.graph); - randomizeTargets = new Random(this.graph); - pasteFromClipboard = new Paste(this.graph); - outdentLine = new OutdentLines(this.graph); - // moveToTarget = new Move(this.graph); - insertEmptyLinesAround = new InsertEmptyLinesAround(this.graph); - insertEmptyLineBefore = new InsertEmptyLineAbove(this.graph); - insertEmptyLineAfter = new InsertEmptyLineBelow(this.graph); - insertCopyBefore = new CopyLinesUp(this.graph); - insertCopyAfter = new CopyLinesDown(this.graph); - indentLine = new IndentLines(this.graph); - highlight = new Highlight(this.graph); - getText = new GetText(this.graph); - followLink = new FollowLink(this.graph); - foldRegion = new Fold(this.graph); - findInWorkspace = new FindInFiles(this.graph); - extractVariable = new ExtractVariable(this.graph); - executeCommand = new ExecuteCommand(this.graph); - editNewLineBefore = new EditNewLineAbove(this.graph); - editNewLineAfter = new EditNewLineBelow(this.graph); - deselect = new Deselect(this.graph); - cutToClipboard = new Cut(this.graph); - copyToClipboard = new Copy(this.graph); - clearAndSetSelection = new Clear(this.graph); callAsFunction = new Call(this.graph); + clearAndSetSelection = new Clear(this.graph); + copyToClipboard = new Copy(this.graph); + cutToClipboard = new Cut(this.graph); + deselect = new Deselect(this.graph); + editNewLineAfter = new EditNewLineBelow(this.graph); + editNewLineBefore = new EditNewLineAbove(this.graph); + executeCommand = new ExecuteCommand(this.graph); + extractVariable = new ExtractVariable(this.graph); + findInWorkspace = new FindInFiles(this.graph); + foldRegion = new Fold(this.graph); + followLink = new FollowLink(this.graph); + getText = new GetText(this.graph); + highlight = new Highlight(this.graph); + indentLine = new IndentLines(this.graph); + insertCopyAfter = new CopyLinesDown(this.graph); + insertCopyBefore = new CopyLinesUp(this.graph); + insertEmptyLineAfter = new InsertEmptyLineBelow(this.graph); + insertEmptyLineBefore = new InsertEmptyLineAbove(this.graph); + insertEmptyLinesAround = new InsertEmptyLinesAround(this.graph); + // moveToTarget = new Move(this.graph); + outdentLine = new OutdentLines(this.graph); + pasteFromClipboard = new Paste(this.graph); + randomizeTargets = new Random(this.graph); + remove = new Remove(this.graph); + replace = new Replace(this.graph); + // replaceWithTarget = new Bring(this.graph); + reverseTargets = new Reverse(this.graph); + // rewrapWithPairedDelimiter = new Rewrap(this.graph); + scrollToBottom = new ScrollToBottom(this.graph); + scrollToCenter = new ScrollToCenter(this.graph); + scrollToTop = new ScrollToTop(this.graph); + setSelection = new SetSelection(this.graph); + setSelectionAfter = new SetSelectionAfter(this.graph); + setSelectionBefore = new SetSelectionBefore(this.graph); + sortTargets = new Sort(this.graph); + // swapTargets = new Swap(this.graph); + toggleLineBreakpoint = new ToggleBreakpoint(this.graph); + toggleLineComment = new CommentLines(this.graph); + unfoldRegion = new Unfold(this.graph); + wrapWithPairedDelimiter = new Wrap(this.graph); + // wrapWithSnippet = new WrapWithSnippet(this.graph); } export default Actions; diff --git a/src/actions/actions.types.ts b/src/actions/actions.types.ts index 61aec0d318..f44c3108ac 100644 --- a/src/actions/actions.types.ts +++ b/src/actions/actions.types.ts @@ -2,48 +2,48 @@ import { Target } from "../typings/target.types"; import { SelectionWithEditor } from "../typings/Types"; export type ActionType = - | "wrapWithSnippet" - | "wrapWithPairedDelimiter" - | "unfoldRegion" - | "toggleLineComment" - | "toggleLineBreakpoint" - | "swapTargets" - | "sortTargets" - | "setSelectionBefore" - | "setSelectionAfter" - | "setSelection" - | "scrollToTop" - | "scrollToCenter" - | "scrollToBottom" - | "rewrapWithPairedDelimiter" - | "reverseTargets" - | "replaceWithTarget" - | "replace" - | "remove" - | "randomizeTargets" - | "pasteFromClipboard" - | "outdentLine" - | "moveToTarget" - | "insertEmptyLinesAround" - | "insertEmptyLineBefore" - | "insertEmptyLineAfter" - | "insertCopyBefore" - | "insertCopyAfter" - | "indentLine" - | "highlight" - | "getText" - | "followLink" - | "foldRegion" - | "findInWorkspace" - | "extractVariable" - | "executeCommand" - | "editNewLineBefore" - | "editNewLineAfter" - | "deselect" - | "cutToClipboard" - | "copyToClipboard" + | "callAsFunction" | "clearAndSetSelection" - | "callAsFunction"; + | "copyToClipboard" + | "cutToClipboard" + | "deselect" + | "editNewLineAfter" + | "editNewLineBefore" + | "executeCommand" + | "extractVariable" + | "findInWorkspace" + | "foldRegion" + | "followLink" + | "getText" + | "highlight" + | "indentLine" + | "insertCopyAfter" + | "insertCopyBefore" + | "insertEmptyLineAfter" + | "insertEmptyLineBefore" + | "insertEmptyLinesAround" + // | "moveToTarget" + | "outdentLine" + | "pasteFromClipboard" + | "randomizeTargets" + | "remove" + | "replace" + // | "replaceWithTarget" + | "reverseTargets" + // | "rewrapWithPairedDelimiter" + | "scrollToBottom" + | "scrollToCenter" + | "scrollToTop" + | "setSelection" + | "setSelectionAfter" + | "setSelectionBefore" + | "sortTargets" + // | "swapTargets" + | "toggleLineBreakpoint" + | "toggleLineComment" + | "unfoldRegion" + | "wrapWithPairedDelimiter"; +// | "wrapWithSnippet"; export interface ActionReturnValue { returnValue?: any; From 3ce918abce58c7533e833fcba368bb0610b50913 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 05:32:37 +0200 Subject: [PATCH 066/314] Added move bring swap actions --- src/actions/Actions.ts | 7 +- src/actions/BringMoveSwap.ts | 606 +++++++++++++++++------------------ src/actions/actions.types.ts | 6 +- src/util/targetUtils.ts | 10 + 4 files changed, 311 insertions(+), 318 deletions(-) diff --git a/src/actions/Actions.ts b/src/actions/Actions.ts index 56483cb03d..2ab5b61581 100644 --- a/src/actions/Actions.ts +++ b/src/actions/Actions.ts @@ -1,5 +1,6 @@ import { Graph } from "../typings/Types"; import { ActionRecord } from "./actions.types"; +import { Move, Bring, Swap } from "./BringMoveSwap"; import Call from "./Call"; import Clear from "./Clear"; import { CommentLines } from "./Comment"; @@ -55,13 +56,13 @@ class Actions implements ActionRecord { insertEmptyLineAfter = new InsertEmptyLineBelow(this.graph); insertEmptyLineBefore = new InsertEmptyLineAbove(this.graph); insertEmptyLinesAround = new InsertEmptyLinesAround(this.graph); - // moveToTarget = new Move(this.graph); + moveToTarget = new Move(this.graph); outdentLine = new OutdentLines(this.graph); pasteFromClipboard = new Paste(this.graph); randomizeTargets = new Random(this.graph); remove = new Remove(this.graph); replace = new Replace(this.graph); - // replaceWithTarget = new Bring(this.graph); + replaceWithTarget = new Bring(this.graph); reverseTargets = new Reverse(this.graph); // rewrapWithPairedDelimiter = new Rewrap(this.graph); scrollToBottom = new ScrollToBottom(this.graph); @@ -71,7 +72,7 @@ class Actions implements ActionRecord { setSelectionAfter = new SetSelectionAfter(this.graph); setSelectionBefore = new SetSelectionBefore(this.graph); sortTargets = new Sort(this.graph); - // swapTargets = new Swap(this.graph); + swapTargets = new Swap(this.graph); toggleLineBreakpoint = new ToggleBreakpoint(this.graph); toggleLineComment = new CommentLines(this.graph); unfoldRegion = new Unfold(this.graph); diff --git a/src/actions/BringMoveSwap.ts b/src/actions/BringMoveSwap.ts index 4115484aed..bb1c30e9a3 100644 --- a/src/actions/BringMoveSwap.ts +++ b/src/actions/BringMoveSwap.ts @@ -1,312 +1,294 @@ -// import { -// Action, -// ActionPreferences, -// ActionReturnValue, -// Graph, -// Target, -// Edit, -// } from "../typings/Types"; -// import { runForEachEditor } from "../util/targetUtils"; -// import update from "immutability-helper"; -// import displayPendingEditDecorations from "../util/editDisplayUtils"; -// import { performOutsideAdjustment } from "../util/performInsideOutsideAdjustment"; -// import { flatten } from "lodash"; -// import { Selection, TextEditor, DecorationRangeBehavior } from "vscode"; - -// import { -// getTextWithPossibleDelimiter, -// maybeAddDelimiter, -// } from "../util/getTextWithPossibleDelimiter"; -// import { -// getSelectionInfo, -// performEditsAndUpdateFullSelectionInfos, -// } from "../core/updateSelections/updateSelections"; -// import { unifyTargets } from "../util/unifyRanges"; - -// type ActionType = "bring" | "move" | "swap"; - -// interface ExtendedEdit extends Edit { -// editor: TextEditor; -// isSource: boolean; -// originalSelection: Target; -// } - -// interface MarkEntry { -// editor: TextEditor; -// selection: Selection; -// isSource: boolean; -// typedSelection: Target; -// } - -// class BringMoveSwap implements Action { -// getTargetPreferences: () => ActionPreferences[] = () => [ -// { insideOutsideType: null }, -// { insideOutsideType: null }, -// ]; - -// constructor(private graph: Graph, private type: ActionType) { -// this.run = this.run.bind(this); -// } - -// private broadcastSource( -// sources: Target[], -// destinations: Target[] -// ) { -// if (sources.length === 1 && this.type !== "swap") { -// // If there is only one source target, expand it to same length as -// // destination target -// return Array(destinations.length).fill(sources[0]); -// } -// return sources; -// } - -// private getDecorationStyles() { -// let sourceStyle; -// if (this.type === "bring") { -// sourceStyle = this.graph.editStyles.referenced; -// } else if (this.type === "move") { -// sourceStyle = this.graph.editStyles.pendingDelete; -// } -// // NB this.type === "swap" -// else { -// sourceStyle = this.graph.editStyles.pendingModification1; -// } -// return { -// sourceStyle, -// destinationStyle: this.graph.editStyles.pendingModification0, -// }; -// } - -// private async decorateTargets( -// sources: Target[], -// destinations: Target[] -// ) { -// const decorationTypes = this.getDecorationStyles(); -// await Promise.all([ -// displayPendingEditDecorations(sources, decorationTypes.sourceStyle), -// displayPendingEditDecorations( -// destinations, -// decorationTypes.destinationStyle -// ), -// ]); -// } - -// private getEdits( -// sources: Target[], -// destinations: Target[] -// ): ExtendedEdit[] { -// const usedSources: Target[] = []; -// const results: ExtendedEdit[] = []; -// const zipSources = -// sources.length !== destinations.length && -// destinations.length === 1 && -// this.type !== "swap"; - -// sources.forEach((source, i) => { -// let destination = destinations[i]; -// if ((source == null || destination == null) && !zipSources) { -// throw new Error("Targets must have same number of args"); -// } - -// if (destination != null) { -// let text: string; -// if (zipSources) { -// text = sources -// .map((source, i) => { -// let text = source.selection.editor.document.getText( -// source.selection.selection -// ); -// const selectionContext = destination.selectionContext -// .isRawSelection -// ? source.selectionContext -// : destination.selectionContext; -// return i > 0 && selectionContext.containingListDelimiter -// ? selectionContext.containingListDelimiter + text -// : text; -// }) -// .join(""); -// text = maybeAddDelimiter(text, destination); -// } else { -// // Get text adjusting for destination position -// text = getTextWithPossibleDelimiter(source, destination); -// } -// // Add destination edit -// results.push({ -// range: destination.selection.selection, -// text, -// editor: destination.selection.editor, -// originalSelection: destination, -// isSource: false, -// isReplace: destination.position === "after", -// }); -// } else { -// destination = destinations[0]; -// } - -// // Add source edit -// // Prevent multiple instances of the same expanded source. -// if (!usedSources.includes(source)) { -// usedSources.push(source); -// if (this.type !== "move") { -// results.push({ -// range: source.selection.selection, -// text: destination.selection.editor.document.getText( -// destination.selection.selection -// ), -// editor: source.selection.editor, -// originalSelection: source, -// isSource: true, -// isReplace: false, -// }); -// } -// } -// }); - -// if (this.type === "move") { -// let outsideSources = usedSources.map(performOutsideAdjustment); -// // Unify overlapping targets. -// outsideSources = unifyTargets(outsideSources); -// outsideSources.forEach((source) => { -// results.push({ -// range: source.selection.selection, -// text: "", -// editor: source.selection.editor, -// originalSelection: source, -// isSource: true, -// isReplace: false, -// }); -// }); -// } - -// return results; -// } - -// private async performEditsAndComputeThatMark( -// edits: ExtendedEdit[] -// ): Promise { -// return flatten( -// await runForEachEditor( -// edits, -// (edit) => edit.editor, -// async (editor, edits) => { -// // For bring we don't want to update the sources -// const filteredEdits = -// this.type !== "bring" -// ? edits -// : edits.filter(({ isSource }) => !isSource); - -// const editSelectionInfos = edits.map(({ originalSelection }) => -// getSelectionInfo( -// editor.document, -// originalSelection.selection.selection, -// DecorationRangeBehavior.OpenOpen -// ) -// ); - -// const cursorSelectionInfos = editor.selections.map((selection) => -// getSelectionInfo( -// editor.document, -// selection, -// DecorationRangeBehavior.ClosedClosed -// ) -// ); - -// const [updatedEditSelections, cursorSelections]: Selection[][] = -// await performEditsAndUpdateFullSelectionInfos( -// this.graph.rangeUpdater, -// editor, -// filteredEdits, -// [editSelectionInfos, cursorSelectionInfos] -// ); - -// editor.selections = cursorSelections; - -// return edits.map((edit, index) => { -// const selection = updatedEditSelections[index]; -// return { -// editor, -// selection, -// isSource: edit!.isSource, -// typedSelection: update(edit!.originalSelection, { -// selection: { -// selection: { $set: selection! }, -// }, -// }), -// }; -// }); -// } -// ) -// ); -// } - -// private async decorateThatMark(thatMark: MarkEntry[]) { -// const decorationTypes = this.getDecorationStyles(); -// return Promise.all([ -// displayPendingEditDecorations( -// thatMark -// .filter(({ isSource }) => isSource) -// .map(({ typedSelection }) => typedSelection), -// decorationTypes.sourceStyle -// ), -// displayPendingEditDecorations( -// thatMark -// .filter(({ isSource }) => !isSource) -// .map(({ typedSelection }) => typedSelection), -// decorationTypes.destinationStyle -// ), -// ]); -// } - -// private calculateMarks(markEntries: MarkEntry[]) { -// // Only swap has sources as a "that" mark -// const thatMark = -// this.type === "swap" -// ? markEntries -// : markEntries.filter(({ isSource }) => !isSource); - -// // Only swap doesn't have a source mark -// const sourceMark = -// this.type === "swap" -// ? [] -// : markEntries.filter(({ isSource }) => isSource); - -// return { thatMark, sourceMark }; -// } - -// async run([sources, destinations]: [ -// Target[], -// Target[] -// ]): Promise { -// sources = this.broadcastSource(sources, destinations); - -// await this.decorateTargets(sources, destinations); - -// const edits = this.getEdits(sources, destinations); - -// const markEntries = await this.performEditsAndComputeThatMark(edits); - -// const { thatMark, sourceMark } = this.calculateMarks(markEntries); - -// await this.decorateThatMark(thatMark); - -// return { thatMark, sourceMark }; -// } -// } - -// export class Bring extends BringMoveSwap { -// constructor(graph: Graph) { -// super(graph, "bring"); -// } -// } - -// export class Move extends BringMoveSwap { -// constructor(graph: Graph) { -// super(graph, "move"); -// } -// } - -// export class Swap extends BringMoveSwap { -// constructor(graph: Graph) { -// super(graph, "swap"); -// } -// } +import { flatten } from "lodash"; +import { DecorationRangeBehavior, Selection, TextEditor } from "vscode"; +import { + getSelectionInfo, + performEditsAndUpdateFullSelectionInfos, +} from "../core/updateSelections/updateSelections"; +import { Target } from "../typings/target.types"; +import { Edit, Graph } from "../typings/Types"; +import displayPendingEditDecorations from "../util/editDisplayUtils"; +import { + getContentRange, + getContentSelection, + getContentText, + getRemovalRange, + getTextWithPossibleDelimiter, + maybeAddDelimiter, + runForEachEditor, +} from "../util/targetUtils"; +import { unifyTargets } from "../util/unifyRanges"; +import { Action, ActionReturnValue } from "./actions.types"; + +type ActionType = "bring" | "move" | "swap"; + +interface ExtendedEdit extends Edit { + editor: TextEditor; + isSource: boolean; + originalSelection: Target; +} + +interface MarkEntry { + editor: TextEditor; + selection: Selection; + isSource: boolean; + typedSelection: Target; +} + +class BringMoveSwap implements Action { + constructor(private graph: Graph, private type: ActionType) { + this.run = this.run.bind(this); + } + + private broadcastSource(sources: Target[], destinations: Target[]) { + if (sources.length === 1 && this.type !== "swap") { + // If there is only one source target, expand it to same length as + // destination target + return Array(destinations.length).fill(sources[0]); + } + return sources; + } + + private getDecorationStyles() { + let sourceStyle; + let getSourceRangeCallback; + if (this.type === "bring") { + sourceStyle = this.graph.editStyles.referenced; + getSourceRangeCallback = getContentRange; + } else if (this.type === "move") { + sourceStyle = this.graph.editStyles.pendingDelete; + getSourceRangeCallback = getRemovalRange; + } + // NB this.type === "swap" + else { + sourceStyle = this.graph.editStyles.pendingModification1; + getSourceRangeCallback = getContentRange; + } + return { + sourceStyle, + destinationStyle: this.graph.editStyles.pendingModification0, + getSourceRangeCallback, + }; + } + + private async decorateTargets(sources: Target[], destinations: Target[]) { + const decorationTypes = this.getDecorationStyles(); + await Promise.all([ + displayPendingEditDecorations( + sources, + decorationTypes.sourceStyle, + decorationTypes.getSourceRangeCallback + ), + displayPendingEditDecorations( + destinations, + decorationTypes.destinationStyle + ), + ]); + } + + private getEdits(sources: Target[], destinations: Target[]): ExtendedEdit[] { + const usedSources: Target[] = []; + const results: ExtendedEdit[] = []; + const zipSources = + sources.length !== destinations.length && + destinations.length === 1 && + this.type !== "swap"; + + sources.forEach((source, i) => { + let destination = destinations[i]; + if ((source == null || destination == null) && !zipSources) { + throw new Error("Targets must have same number of args"); + } + + if (destination != null) { + let text: string; + if (zipSources) { + text = sources + .map((source, i) => { + const text = getContentText(source); + const containingListDelimiter = + destination.delimiter ?? source.delimiter; + return i > 0 && containingListDelimiter + ? containingListDelimiter + text + : text; + }) + .join(""); + text = maybeAddDelimiter(text, destination); + } else { + // Get text adjusting for destination position + text = getTextWithPossibleDelimiter(source, destination); + } + // Add destination edit + results.push({ + range: destination.contentRange, + text, + editor: destination.editor, + originalSelection: destination, + isSource: false, + isReplace: destination.position === "after", + }); + } else { + destination = destinations[0]; + } + + // Add source edit + // Prevent multiple instances of the same expanded source. + if (!usedSources.includes(source)) { + usedSources.push(source); + if (this.type !== "move") { + results.push({ + range: source.contentRange, + text: getContentText(destination), + editor: source.editor, + originalSelection: source, + isSource: true, + isReplace: false, + }); + } + } + }); + + if (this.type === "move") { + // Unify overlapping targets. + unifyTargets(usedSources).forEach((source) => { + results.push({ + range: getRemovalRange(source), + text: "", + editor: source.editor, + originalSelection: source, + isSource: true, + isReplace: false, + }); + }); + } + + return results; + } + + private async performEditsAndComputeThatMark( + edits: ExtendedEdit[] + ): Promise { + return flatten( + await runForEachEditor( + edits, + (edit) => edit.editor, + async (editor, edits) => { + // For bring we don't want to update the sources + const filteredEdits = + this.type !== "bring" + ? edits + : edits.filter(({ isSource }) => !isSource); + + const editSelectionInfos = edits.map(({ originalSelection }) => + getSelectionInfo( + editor.document, + getContentSelection(originalSelection), + DecorationRangeBehavior.OpenOpen + ) + ); + + const cursorSelectionInfos = editor.selections.map((selection) => + getSelectionInfo( + editor.document, + selection, + DecorationRangeBehavior.ClosedClosed + ) + ); + + const [updatedEditSelections, cursorSelections]: Selection[][] = + await performEditsAndUpdateFullSelectionInfos( + this.graph.rangeUpdater, + editor, + filteredEdits, + [editSelectionInfos, cursorSelectionInfos] + ); + + editor.selections = cursorSelections; + + return edits.map((edit, index) => { + const selection = updatedEditSelections[index]; + return { + editor, + selection, + isSource: edit!.isSource, + typedSelection: { + ...edit!.originalSelection, + contentRange: selection, + }, + }; + }); + } + ) + ); + } + + private async decorateThatMark(thatMark: MarkEntry[]) { + const decorationTypes = this.getDecorationStyles(); + return Promise.all([ + displayPendingEditDecorations( + thatMark + .filter(({ isSource }) => isSource) + .map(({ typedSelection }) => typedSelection), + decorationTypes.sourceStyle + ), + displayPendingEditDecorations( + thatMark + .filter(({ isSource }) => !isSource) + .map(({ typedSelection }) => typedSelection), + decorationTypes.destinationStyle + ), + ]); + } + + private calculateMarks(markEntries: MarkEntry[]) { + // Only swap has sources as a "that" mark + const thatMark = + this.type === "swap" + ? markEntries + : markEntries.filter(({ isSource }) => !isSource); + + // Only swap doesn't have a source mark + const sourceMark = + this.type === "swap" + ? [] + : markEntries.filter(({ isSource }) => isSource); + + return { thatMark, sourceMark }; + } + + async run([sources, destinations]: [ + Target[], + Target[] + ]): Promise { + sources = this.broadcastSource(sources, destinations); + + await this.decorateTargets(sources, destinations); + + const edits = this.getEdits(sources, destinations); + + const markEntries = await this.performEditsAndComputeThatMark(edits); + + const { thatMark, sourceMark } = this.calculateMarks(markEntries); + + await this.decorateThatMark(thatMark); + + return { thatMark, sourceMark }; + } +} + +export class Bring extends BringMoveSwap { + constructor(graph: Graph) { + super(graph, "bring"); + } +} + +export class Move extends BringMoveSwap { + constructor(graph: Graph) { + super(graph, "move"); + } +} + +export class Swap extends BringMoveSwap { + constructor(graph: Graph) { + super(graph, "swap"); + } +} diff --git a/src/actions/actions.types.ts b/src/actions/actions.types.ts index f44c3108ac..948c156d71 100644 --- a/src/actions/actions.types.ts +++ b/src/actions/actions.types.ts @@ -22,13 +22,13 @@ export type ActionType = | "insertEmptyLineAfter" | "insertEmptyLineBefore" | "insertEmptyLinesAround" - // | "moveToTarget" + | "moveToTarget" | "outdentLine" | "pasteFromClipboard" | "randomizeTargets" | "remove" | "replace" - // | "replaceWithTarget" + | "replaceWithTarget" | "reverseTargets" // | "rewrapWithPairedDelimiter" | "scrollToBottom" @@ -38,7 +38,7 @@ export type ActionType = | "setSelectionAfter" | "setSelectionBefore" | "sortTargets" - // | "swapTargets" + | "swapTargets" | "toggleLineBreakpoint" | "toggleLineComment" | "unfoldRegion" diff --git a/src/util/targetUtils.ts b/src/util/targetUtils.ts index e27077cc64..9f59bfd010 100644 --- a/src/util/targetUtils.ts +++ b/src/util/targetUtils.ts @@ -136,6 +136,16 @@ export function getRemovalHighlightRange(target: Target) { : removalRange; } +/** Get text from selection. Possibly add delimiter for positions before/after */ +export function getTextWithPossibleDelimiter( + source: Target, + destination: Target +) { + const sourceText = getContentText(source); + return maybeAddDelimiter(sourceText, destination); +} + +/** Possibly add delimiter for positions before/after */ export function maybeAddDelimiter(text: string, target: Target) { if (target.delimiter != null) { if (target.position === "before") { From 210527072d80899066aab7f818b6f7e442e62457 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 05:59:04 +0200 Subject: [PATCH 067/314] Updated action names and position stage --- src/actions/BringMoveSwap.ts | 3 +- .../canonicalizeActionName.ts | 53 +++++++++---------- src/processTargets/modifiers/PositionStage.ts | 3 ++ 3 files changed, 31 insertions(+), 28 deletions(-) diff --git a/src/actions/BringMoveSwap.ts b/src/actions/BringMoveSwap.ts index bb1c30e9a3..76ce4f0f21 100644 --- a/src/actions/BringMoveSwap.ts +++ b/src/actions/BringMoveSwap.ts @@ -124,7 +124,8 @@ class BringMoveSwap implements Action { editor: destination.editor, originalSelection: destination, isSource: false, - isReplace: destination.position === "after", + isReplace: + destination.position === "after" || destination.position === "end", }); } else { destination = destinations[0]; diff --git a/src/core/commandVersionUpgrades/canonicalizeActionName.ts b/src/core/commandVersionUpgrades/canonicalizeActionName.ts index b30ba22861..ee945da816 100644 --- a/src/core/commandVersionUpgrades/canonicalizeActionName.ts +++ b/src/core/commandVersionUpgrades/canonicalizeActionName.ts @@ -1,33 +1,32 @@ import { ActionType } from "../../actions/actions.types"; const actionAliasToCanonicalName: Record = { - // TODO - // bring: "replaceWithTarget", - // call: "callAsFunction", - // clear: "clearAndSetSelection", - // commentLines: "toggleLineComment", - // copy: "copyToClipboard", - // cut: "cutToClipboard", - // delete: "remove", - // editNewLineAbove: "editNewLineBefore", - // editNewLineBelow: "editNewLineAfter", - // findInFiles: "findInWorkspace", - // fold: "foldRegion", - // indentLines: "indentLine", - // insertEmptyLineAbove: "insertEmptyLineBefore", - // insertEmptyLineBelow: "insertEmptyLineAfter", - // insertLineAfter: "editNewLineAfter", - // insertLineBefore: "editNewLineBefore", - // move: "moveToTarget", - // outdentLines: "outdentLine", - // paste: "pasteFromClipboard", - // reverse: "reverseTargets", - // setBreakpoint: "toggleLineBreakpoint", - // sort: "sortTargets", - // swap: "swapTargets", - // unfold: "unfoldRegion", - // use: "replaceWithTarget", - // wrap: "wrapWithPairedDelimiter", + bring: "replaceWithTarget", + call: "callAsFunction", + clear: "clearAndSetSelection", + commentLines: "toggleLineComment", + copy: "copyToClipboard", + cut: "cutToClipboard", + delete: "remove", + editNewLineAbove: "editNewLineBefore", + editNewLineBelow: "editNewLineAfter", + findInFiles: "findInWorkspace", + fold: "foldRegion", + indentLines: "indentLine", + insertEmptyLineAbove: "insertEmptyLineBefore", + insertEmptyLineBelow: "insertEmptyLineAfter", + insertLineAfter: "editNewLineAfter", + insertLineBefore: "editNewLineBefore", + move: "moveToTarget", + outdentLines: "outdentLine", + paste: "pasteFromClipboard", + reverse: "reverseTargets", + setBreakpoint: "toggleLineBreakpoint", + sort: "sortTargets", + swap: "swapTargets", + unfold: "unfoldRegion", + use: "replaceWithTarget", + wrap: "wrapWithPairedDelimiter", }; export default function canonicalizeActionName(actionName: string) { diff --git a/src/processTargets/modifiers/PositionStage.ts b/src/processTargets/modifiers/PositionStage.ts index 33d01b6531..57141d66d4 100644 --- a/src/processTargets/modifiers/PositionStage.ts +++ b/src/processTargets/modifiers/PositionStage.ts @@ -9,6 +9,7 @@ export default class implements ModifierStage { run(context: ProcessedTargetsContext, target: Target): Target { const { contentRange, + delimiter, leadingDelimiterRange, leadingDelimiterHighlightRange, trailingDelimiterRange, @@ -26,6 +27,7 @@ export default class implements ModifierStage { return { ...common, contentRange: new Range(contentRange.start, contentRange.start), + delimiter, leadingDelimiterRange, leadingDelimiterHighlightRange, }; @@ -34,6 +36,7 @@ export default class implements ModifierStage { return { ...common, contentRange: new Range(contentRange.end, contentRange.end), + delimiter, trailingDelimiterRange, trailingDelimiterHighlightRange, }; From b4b1dccbe9113846a91fcf779f9adb40ee1725aa Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 10:44:09 +0200 Subject: [PATCH 068/314] Updated update range code --- src/actions/Remove.ts | 17 +- src/core/commandRunner/CommandRunner.ts | 1 + src/core/updateSelections/updateRanges.ts | 215 ------------------ src/core/updateSelections/updateSelections.ts | 85 +++++-- src/processTargets/modifiers/PositionStage.ts | 2 +- src/typings/Types.ts | 3 +- src/util/editDisplayUtils.ts | 4 +- 7 files changed, 87 insertions(+), 240 deletions(-) delete mode 100644 src/core/updateSelections/updateRanges.ts diff --git a/src/actions/Remove.ts b/src/actions/Remove.ts index 2006355c6d..1cfc5bd6f7 100644 --- a/src/actions/Remove.ts +++ b/src/actions/Remove.ts @@ -1,5 +1,5 @@ import { flatten } from "lodash"; -import { performEditsAndUpdateRanges } from "../core/updateSelections/updateRanges"; +import { performEditsAndUpdateRanges } from "../core/updateSelections/updateSelections"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; import displayPendingEditDecorations from "../util/editDisplayUtils"; @@ -36,13 +36,18 @@ export default class Delete implements Action { const thatMark = flatten( await runOnTargetsForEachEditor(targets, async (editor, targets) => { - const ranges = targets.map( - contentOnly ? getContentRange : getRemovalRange - ); - const edits = ranges.map((range) => ({ - range, + const getRangeCallback = contentOnly + ? getContentRange + : getRemovalRange; + const edits = targets.map((target) => ({ + range: getRangeCallback(target), text: "", })); + // const ranges = targets.map((target) => ({ + // range: getRangeCallback(target), + // isReversed: target.isReversed, + // })); + const ranges = edits.map((edit) => edit.range); const [updatedRanges] = await performEditsAndUpdateRanges( this.graph.rangeUpdater, diff --git a/src/core/commandRunner/CommandRunner.ts b/src/core/commandRunner/CommandRunner.ts index b4259cff80..31478d1e3e 100644 --- a/src/core/commandRunner/CommandRunner.ts +++ b/src/core/commandRunner/CommandRunner.ts @@ -78,6 +78,7 @@ export default class CommandRunner { const action = this.graph.actions[actionName]; if (action == null) { + return; // TODO throw new Error(`Unknown action ${actionName}`); } diff --git a/src/core/updateSelections/updateRanges.ts b/src/core/updateSelections/updateRanges.ts deleted file mode 100644 index a8dd34d8db..0000000000 --- a/src/core/updateSelections/updateRanges.ts +++ /dev/null @@ -1,215 +0,0 @@ -import { flatten } from "lodash"; -import { - DecorationRangeBehavior, - Range, - TextDocument, - TextEditor, -} from "vscode"; -import { Edit } from "../../typings/Types"; -import { FullRangeInfo, RangeInfo } from "../../typings/updateSelections"; -import { performDocumentEdits } from "../../util/performDocumentEdits"; -import { RangeUpdater } from "./RangeUpdater"; - -/** - * Given a selection, this function creates a `SelectionInfo` object that can - * be passed in to any of the commands that update selections. - * - * @param document The document containing the selection - * @param range The range - * @param rangeBehavior How selection should behave with respect to insertions on either end - * @returns An object that can be used for selection tracking - */ -function getRangeInfo( - document: TextDocument, - range: Range, - rangeBehavior: DecorationRangeBehavior -): FullRangeInfo { - return { - range: new Range(range.start, range.end), - expansionBehavior: { - start: { - type: - rangeBehavior === DecorationRangeBehavior.ClosedClosed || - rangeBehavior === DecorationRangeBehavior.ClosedOpen - ? "closed" - : "open", - }, - end: { - type: - rangeBehavior === DecorationRangeBehavior.ClosedClosed || - rangeBehavior === DecorationRangeBehavior.OpenClosed - ? "closed" - : "open", - }, - }, - offsets: { - start: document.offsetAt(range.start), - end: document.offsetAt(range.end), - }, - text: document.getText(range), - }; -} - -/** - * Creates SelectionInfo objects for all selections in a list of lists. - * - * @param document The document containing the selections - * @param rangeMatrix A list of lists of selections - * @param rangeBehavior How selections should behave with respect to insertions on either end - * @returns A list of lists of selection info objects - */ -function rangesToRangeInfos( - document: TextDocument, - rangeMatrix: (readonly Range[])[], - rangeBehavior: DecorationRangeBehavior = DecorationRangeBehavior.ClosedClosed -): FullRangeInfo[][] { - return rangeMatrix.map((ranges) => - ranges.map((range) => getRangeInfo(document, range, rangeBehavior)) - ); -} - -function rangeInfosToRanges(rangeInfoMatrix: RangeInfo[][]): Range[][] { - return rangeInfoMatrix.map((rangeInfos) => - rangeInfos.map(({ range }) => range) - ); -} - -/** - * Calls the given function and updates the given selections based on the - * changes that occurred as a result of calling function. - * @param rangeUpdater A RangeUpdate instance that will perform actual range updating - * @param func The function to call - * @param document The document containing the selections - * @param rangeMatrix A matrix of selections to update - * @returns The initial selections updated based upon what happened in the function - */ -export async function callFunctionAndUpdateRanges( - rangeUpdater: RangeUpdater, - func: () => Thenable, - document: TextDocument, - rangeMatrix: (readonly Range[])[] -): Promise { - const rangeInfoMatrix = rangesToRangeInfos(document, rangeMatrix); - - return await callFunctionAndUpdateSelectionInfos( - rangeUpdater, - func, - document, - rangeInfoMatrix - ); -} - -/** - * Calls the given function and updates the given selections based on the - * changes that occurred as a result of calling function. - * @param rangeUpdater A RangeUpdate instance that will perform actual range updating - * @param func The function to call - * @param document The document containing the selections - * @param selectionMatrix A matrix of selection info objects to update - * @returns The initial selections updated based upon what happened in the function - */ -export async function callFunctionAndUpdateSelectionInfos( - rangeUpdater: RangeUpdater, - func: () => Thenable, - document: TextDocument, - rangeInfoMatrix: FullRangeInfo[][] -) { - const unsubscribe = rangeUpdater.registerRangeInfoList( - document, - flatten(rangeInfoMatrix) - ); - - await func(); - - unsubscribe(); - - return rangeInfosToRanges(rangeInfoMatrix); -} - -/** - * Performs a list of edits and returns the given selections updated based on - * the applied edits - * @param rangeUpdater A RangeUpdate instance that will perform actual range updating - * @param editor The editor containing the selections - * @param edits A list of edits to apply - * @param originalRanges The selections to update - * @returns The updated selections - */ -export async function performEditsAndUpdateRanges( - rangeUpdater: RangeUpdater, - editor: TextEditor, - edits: Edit[], - originalRanges: (readonly Range[])[] -) { - const document = editor.document; - const selectionInfoMatrix = rangesToRangeInfos(document, originalRanges); - - await performEditsAndUpdateFullSelectionInfos( - rangeUpdater, - editor, - edits, - selectionInfoMatrix - ); - - return rangeInfosToRanges(selectionInfoMatrix); -} - -/** - * Performs a list of edits and returns the given selections updated based on - * the applied edits - * @param rangeUpdater A RangeUpdate instance that will perform actual range updating - * @param editor The editor containing the selections - * @param edits A list of edits to apply - * @param originalRangeInfos The selection info objects to update - * @returns The updated selections - */ -export async function performEditsAndUpdateFullSelectionInfos( - rangeUpdater: RangeUpdater, - editor: TextEditor, - edits: Edit[], - originalRangeInfos: FullRangeInfo[][] -) { - // NB: We do everything using VSCode listeners. We can associate changes - // with our changes just by looking at their offets / text in order to - // recover isReplace. We need to do this because VSCode does some fancy - // stuff, and returns the changes in a nice order - // Note that some additional weird edits like whitespace things can be - // created by VSCode I believe, and they change order, so we can't just zip - // their changes with ours. - // Their ordering basically is reverse document order, unless edits are at - // the same location, in which case they're in reverse order of the changes - // as you created them. - // See - // https://github.com/microsoft/vscode/blob/174db5eb992d880adcc42c41d83a0e6cb6b92474/src/vs/editor/common/core/range.ts#L430-L440 - // and - // https://github.com/microsoft/vscode/blob/174db5eb992d880adcc42c41d83a0e6cb6b92474/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer.ts#L598-L604 - // See also - // https://github.com/microsoft/vscode/blob/174db5eb992d880adcc42c41d83a0e6cb6b92474/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer.ts#L464 - // - We have a component on the graph called graph.rangeUpdater - // - It supports registering a list of selections to keep up-to-date, and - // it returns a dispose function. - // - It also has a function that allows callers to register isReplace edits, - // and it will look those up when it receives edits in order to set that - // field. - - const func = async () => { - const wereEditsApplied = await performDocumentEdits( - rangeUpdater, - editor, - edits - ); - - if (!wereEditsApplied) { - throw new Error("Could not apply edits"); - } - }; - - await callFunctionAndUpdateSelectionInfos( - rangeUpdater, - func, - editor.document, - originalRangeInfos - ); - - return rangeInfosToRanges(originalRangeInfos); -} diff --git a/src/core/updateSelections/updateSelections.ts b/src/core/updateSelections/updateSelections.ts index db18afeac2..b5fd5659fc 100644 --- a/src/core/updateSelections/updateSelections.ts +++ b/src/core/updateSelections/updateSelections.ts @@ -1,18 +1,18 @@ +import { flatten } from "lodash"; import { - Selection, - TextEditor, - TextDocument, DecorationRangeBehavior, Range, + Selection, + TextDocument, + TextEditor, } from "vscode"; -import { flatten } from "lodash"; +import { Edit } from "../../typings/Types"; import { FullSelectionInfo, SelectionInfo, } from "../../typings/updateSelections"; import { performDocumentEdits } from "../../util/performDocumentEdits"; import { isForward } from "../../util/selectionUtils"; -import { Edit } from "../../typings/Types"; import { RangeUpdater } from "./RangeUpdater"; /** @@ -28,10 +28,24 @@ export function getSelectionInfo( document: TextDocument, selection: Selection, rangeBehavior: DecorationRangeBehavior +): FullSelectionInfo { + return getSelectionInfoInternal( + document, + selection, + isForward(selection), + rangeBehavior + ); +} + +function getSelectionInfoInternal( + document: TextDocument, + range: Range, + isForward: boolean, + rangeBehavior: DecorationRangeBehavior ): FullSelectionInfo { return { - range: new Range(selection.start, selection.end), - isForward: isForward(selection), + range, + isForward, expansionBehavior: { start: { type: @@ -49,10 +63,10 @@ export function getSelectionInfo( }, }, offsets: { - start: document.offsetAt(selection.start), - end: document.offsetAt(selection.end), + start: document.offsetAt(range.start), + end: document.offsetAt(range.end), }, - text: document.getText(selection), + text: document.getText(range), }; } @@ -64,7 +78,7 @@ export function getSelectionInfo( * @param rangeBehavior How selections should behave with respect to insertions on either end * @returns A list of lists of selection info objects */ -export function selectionsToSelectionInfos( +function selectionsToSelectionInfos( document: TextDocument, selectionMatrix: (readonly Selection[])[], rangeBehavior: DecorationRangeBehavior = DecorationRangeBehavior.ClosedClosed @@ -76,6 +90,18 @@ export function selectionsToSelectionInfos( ); } +function rangesToSelectionInfos( + document: TextDocument, + rangeMatrix: (readonly Range[])[], + rangeBehavior: DecorationRangeBehavior = DecorationRangeBehavior.ClosedClosed +): FullSelectionInfo[][] { + return rangeMatrix.map((ranges) => + ranges.map((range) => + getSelectionInfoInternal(document, range, false, rangeBehavior) + ) + ); +} + function fillOutSelectionInfos( document: TextDocument, selectionInfoMatrix: SelectionInfo[][] @@ -142,7 +168,7 @@ export async function callFunctionAndUpdateSelections( * @param selectionMatrix A matrix of selection info objects to update * @returns The initial selections updated based upon what happened in the function */ -export async function callFunctionAndUpdateSelectionInfos( +async function callFunctionAndUpdateSelectionInfos( rangeUpdater: RangeUpdater, func: () => Thenable, document: TextDocument, @@ -180,19 +206,50 @@ export async function performEditsAndUpdateSelections( document, originalSelections ); + return performEditsAndUpdateInternal( + rangeUpdater, + editor, + edits, + selectionInfoMatrix + ); +} - await performEditsAndUpdateFullSelectionInfos( +export async function performEditsAndUpdateRanges( + rangeUpdater: RangeUpdater, + editor: TextEditor, + edits: Edit[], + originalSelections: (readonly Range[])[] +) { + const document = editor.document; + const selectionInfoMatrix = rangesToSelectionInfos( + document, + originalSelections + ); + return performEditsAndUpdateInternal( rangeUpdater, editor, edits, selectionInfoMatrix ); +} +async function performEditsAndUpdateInternal( + rangeUpdater: RangeUpdater, + editor: TextEditor, + edits: Edit[], + selectionInfoMatrix: FullSelectionInfo[][] +) { + await performEditsAndUpdateFullSelectionInfos( + rangeUpdater, + editor, + edits, + selectionInfoMatrix + ); return selectionInfosToSelections(selectionInfoMatrix); } // TODO: Remove this function if we don't end up using it for the next couple use cases, eg `that` mark and cursor history -export async function performEditsAndUpdateSelectionInfos( +async function performEditsAndUpdateSelectionInfos( rangeUpdater: RangeUpdater, editor: TextEditor, edits: Edit[], diff --git a/src/processTargets/modifiers/PositionStage.ts b/src/processTargets/modifiers/PositionStage.ts index 57141d66d4..39a8a7711c 100644 --- a/src/processTargets/modifiers/PositionStage.ts +++ b/src/processTargets/modifiers/PositionStage.ts @@ -18,8 +18,8 @@ export default class implements ModifierStage { const common = { editor: target.editor, + isReversed: target.isReversed, position: this.modifier.position, - isReversed: false, }; switch (this.modifier.position) { diff --git a/src/typings/Types.ts b/src/typings/Types.ts index 3303053b23..62297a9ceb 100644 --- a/src/typings/Types.ts +++ b/src/typings/Types.ts @@ -1,6 +1,7 @@ import * as vscode from "vscode"; import { ExtensionContext, Location } from "vscode"; import { SyntaxNode } from "web-tree-sitter"; +import { ActionRecord } from "../actions/actions.types"; import Debug from "../core/Debug"; import Decorations from "../core/Decorations"; import { EditStyles } from "../core/editStyles"; @@ -11,8 +12,6 @@ import { Snippets } from "../core/Snippets"; import { RangeUpdater } from "../core/updateSelections/RangeUpdater"; import { TestCaseRecorder } from "../testUtil/TestCaseRecorder"; import { CommandServerApi } from "../util/getExtensionApi"; -import { ActionRecord, ActionType } from "../actions/actions.types"; -import { Target } from "./target.types"; import { FullRangeInfo } from "./updateSelections"; /** diff --git a/src/util/editDisplayUtils.ts b/src/util/editDisplayUtils.ts index 17d7658d54..2adb379e0e 100644 --- a/src/util/editDisplayUtils.ts +++ b/src/util/editDisplayUtils.ts @@ -56,7 +56,7 @@ export async function displayPendingEditDecorationsForRanges( ) { await runForEachEditor( ranges, - (selection) => selection.editor, + (range) => range.editor, async (editor, ranges) => { editor.setDecorations( style, @@ -69,7 +69,7 @@ export async function displayPendingEditDecorationsForRanges( await runForEachEditor( ranges, - (selection) => selection.editor, + (range) => range.editor, async (editor) => { editor.setDecorations(style, []); } From 3ecf7a46aad850e1346d169e20e2ae8b9ad69d85 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 10:48:37 +0200 Subject: [PATCH 069/314] Cleanup --- src/actions/Remove.ts | 4 ---- src/core/updateSelections/updateSelections.ts | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/actions/Remove.ts b/src/actions/Remove.ts index 1cfc5bd6f7..cda865edd3 100644 --- a/src/actions/Remove.ts +++ b/src/actions/Remove.ts @@ -43,10 +43,6 @@ export default class Delete implements Action { range: getRangeCallback(target), text: "", })); - // const ranges = targets.map((target) => ({ - // range: getRangeCallback(target), - // isReversed: target.isReversed, - // })); const ranges = edits.map((edit) => edit.range); const [updatedRanges] = await performEditsAndUpdateRanges( diff --git a/src/core/updateSelections/updateSelections.ts b/src/core/updateSelections/updateSelections.ts index b5fd5659fc..e74323d6fb 100644 --- a/src/core/updateSelections/updateSelections.ts +++ b/src/core/updateSelections/updateSelections.ts @@ -249,7 +249,7 @@ async function performEditsAndUpdateInternal( } // TODO: Remove this function if we don't end up using it for the next couple use cases, eg `that` mark and cursor history -async function performEditsAndUpdateSelectionInfos( +export async function performEditsAndUpdateSelectionInfos( rangeUpdater: RangeUpdater, editor: TextEditor, edits: Edit[], From 840087582b66990172a22ffd9ac9f55435611c8b Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 11:10:18 +0200 Subject: [PATCH 070/314] Cleaned up selection context --- src/languages/markdown.ts | 4 +- src/languages/php.ts | 4 +- .../modifiers/ContainingScopeStage.ts | 20 +++---- .../modifiers/SurroundingPairStage.ts | 15 +++--- ...ractSelectionFromSurroundingPairOffsets.ts | 54 +++++++------------ src/typings/Types.ts | 22 +++----- src/util/nodeSelectors.ts | 7 ++- 7 files changed, 51 insertions(+), 75 deletions(-) diff --git a/src/languages/markdown.ts b/src/languages/markdown.ts index 670f07b622..913bc00638 100644 --- a/src/languages/markdown.ts +++ b/src/languages/markdown.ts @@ -34,12 +34,12 @@ function nameExtractor( const contentRange = range.isEmpty ? range : range.with(range.start.translate(0, 1)); - const outerRange = getNodeRange(node.parent!); + const removalRange = getNodeRange(node.parent!); return { selection: new Selection(contentRange.start, contentRange.end), context: { - outerSelection: new Selection(outerRange.start, outerRange.end), + removalRange, }, }; } diff --git a/src/languages/php.ts b/src/languages/php.ts index ece2dd9b1b..9098e536c7 100644 --- a/src/languages/php.ts +++ b/src/languages/php.ts @@ -88,12 +88,12 @@ function castTypeExtractor( const contentRange = range; const leftParenRange = getNodeRange(node.previousSibling!); const rightParenRange = getNodeRange(node.nextSibling!.nextSibling!); - const outerRange = range.with(leftParenRange.start, rightParenRange.start); + const removalRange = range.with(leftParenRange.start, rightParenRange.start); return { selection: new Selection(contentRange.start, contentRange.end), context: { - outerSelection: new Selection(outerRange.start, outerRange.end), + removalRange, }, }; } diff --git a/src/processTargets/modifiers/ContainingScopeStage.ts b/src/processTargets/modifiers/ContainingScopeStage.ts index b4df75845c..520db15ee0 100644 --- a/src/processTargets/modifiers/ContainingScopeStage.ts +++ b/src/processTargets/modifiers/ContainingScopeStage.ts @@ -11,7 +11,10 @@ import { ProcessedTargetsContext, SelectionWithEditor, } from "../../typings/Types"; -import { selectionWithEditorFromRange } from "../../util/selectionUtils"; +import { + isReversed, + selectionWithEditorFromRange, +} from "../../util/selectionUtils"; import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { @@ -40,16 +43,15 @@ export default class implements ModifierStage { } return scopeNodes.map((scope) => ({ - isReversed: target.isReversed, editor: scope.selection.editor, + isReversed: isReversed(scope.selection.selection), contentRange: scope.selection.selection, - interiorRange: scope.context.interior?.at(0)?.selection, - removalRange: scope.context.outerSelection ?? undefined, - isNotebookCell: scope.context.isNotebookCell, - delimiter: scope.context.containingListDelimiter ?? undefined, - boundary: scope.context.boundary?.map((bound) => bound.selection), - leadingDelimiterRange: scope.context.leadingDelimiterRange ?? undefined, - trailingDelimiterRange: scope.context.trailingDelimiterRange ?? undefined, + interiorRange: scope.context.interior, + removalRange: scope.context.removalRange, + delimiter: scope.context.containingListDelimiter, + boundary: scope.context.boundary, + leadingDelimiterRange: scope.context.leadingDelimiterRange, + trailingDelimiterRange: scope.context.trailingDelimiterRange, })); } } diff --git a/src/processTargets/modifiers/SurroundingPairStage.ts b/src/processTargets/modifiers/SurroundingPairStage.ts index fdecb4fe52..2b22c412ac 100644 --- a/src/processTargets/modifiers/SurroundingPairStage.ts +++ b/src/processTargets/modifiers/SurroundingPairStage.ts @@ -1,6 +1,7 @@ import { Selection } from "vscode"; import { SurroundingPairModifier, Target } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; +import { isReversed } from "../../util/selectionUtils"; import { ModifierStage } from "../PipelineStages.types"; import { processSurroundingPair } from "./surroundingPair"; @@ -37,15 +38,15 @@ export default class implements ModifierStage { throw new Error("Couldn't find containing pair"); } return pairs.map((pair) => ({ - isReversed: target.isReversed, editor: pair.selection.editor, + isReversed: isReversed(pair.selection.selection), contentRange: pair.selection.selection, - interiorRange: pair.context.interior?.at(0)?.selection, - removalRange: pair.context.outerSelection ?? undefined, - delimiter: pair.context.containingListDelimiter ?? undefined, - boundary: pair.context.boundary?.map((bound) => bound.selection), - leadingDelimiterRange: pair.context.leadingDelimiterRange ?? undefined, - trailingDelimiterRange: pair.context.trailingDelimiterRange ?? undefined, + interiorRange: pair.context.interior, + removalRange: pair.context.removalRange, + delimiter: pair.context.containingListDelimiter, + boundary: pair.context.boundary, + leadingDelimiterRange: pair.context.leadingDelimiterRange, + trailingDelimiterRange: pair.context.trailingDelimiterRange, })); } } diff --git a/src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts b/src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts index e24fc05f60..8b2b36e9f7 100644 --- a/src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts +++ b/src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts @@ -1,4 +1,4 @@ -import { Selection, TextDocument } from "vscode"; +import { Range, Selection, TextDocument } from "vscode"; import { SelectionWithContext } from "../../../typings/Types"; import { SurroundingPairOffsets } from "./types"; @@ -16,43 +16,27 @@ export function extractSelectionFromSurroundingPairOffsets( baseOffset: number, surroundingPairOffsets: SurroundingPairOffsets ): SelectionWithContext[] { - const interior = [ - { - selection: new Selection( - document.positionAt( - baseOffset + surroundingPairOffsets.leftDelimiter.end - ), - document.positionAt( - baseOffset + surroundingPairOffsets.rightDelimiter.start - ) - ), - context: {}, - }, - ]; - + const interior = new Range( + document.positionAt(baseOffset + surroundingPairOffsets.leftDelimiter.end), + document.positionAt( + baseOffset + surroundingPairOffsets.rightDelimiter.start + ) + ); const boundary = [ - { - selection: new Selection( - document.positionAt( - baseOffset + surroundingPairOffsets.leftDelimiter.start - ), - document.positionAt( - baseOffset + surroundingPairOffsets.leftDelimiter.end - ) + new Range( + document.positionAt( + baseOffset + surroundingPairOffsets.leftDelimiter.start ), - context: {}, - }, - { - selection: new Selection( - document.positionAt( - baseOffset + surroundingPairOffsets.rightDelimiter.start - ), - document.positionAt( - baseOffset + surroundingPairOffsets.rightDelimiter.end - ) + document.positionAt(baseOffset + surroundingPairOffsets.leftDelimiter.end) + ), + new Range( + document.positionAt( + baseOffset + surroundingPairOffsets.rightDelimiter.start ), - context: {}, - }, + document.positionAt( + baseOffset + surroundingPairOffsets.rightDelimiter.end + ) + ), ]; return [ diff --git a/src/typings/Types.ts b/src/typings/Types.ts index 62297a9ceb..dfa026c425 100644 --- a/src/typings/Types.ts +++ b/src/typings/Types.ts @@ -40,46 +40,36 @@ export interface RangeWithEditor { } export interface SelectionContext { - isInDelimitedList?: boolean; - containingListDelimiter?: string | null; + containingListDelimiter?: string; /** * Selection used for outside selection */ - outerSelection?: vscode.Selection | null; + removalRange?: vscode.Range; /** * The range of the delimiter before the selection */ - leadingDelimiterRange?: vscode.Range | null; + leadingDelimiterRange?: vscode.Range; /** * The range of the delimiter after the selection */ - trailingDelimiterRange?: vscode.Range | null; - - isNotebookCell?: boolean; + trailingDelimiterRange?: vscode.Range; /** * Represents the boundary ranges of this selection. For example, for a * surrounding pair this would be the opening and closing delimiter. For an if * statement this would be the line of the guard as well as the closing brace. */ - boundary?: SelectionWithContext[]; + boundary?: vscode.Range[]; /** * Represents the interior ranges of this selection. For example, for a * surrounding pair this would exclude the opening and closing delimiter. For an if * statement this would be the statements in the body. */ - interior?: SelectionWithContext[]; - - /** - * Indicates that this is a raw selection with no type information so for - * example if it is the destination of a bring or move it should inherit the - * type information such as delimiters from its source - */ - isRawSelection?: boolean; + interior?: vscode.Range; } export interface ActionPreferences { diff --git a/src/util/nodeSelectors.ts b/src/util/nodeSelectors.ts index 588130d560..5423d96a34 100644 --- a/src/util/nodeSelectors.ts +++ b/src/util/nodeSelectors.ts @@ -317,9 +317,9 @@ export function delimitedSelector( getEndNode: (node: SyntaxNode) => SyntaxNode = identity ): SelectionExtractor { return (editor: TextEditor, node: SyntaxNode) => { - let containingListDelimiter: string | null = null; - let leadingDelimiterRange: Range | null = null; - let trailingDelimiterRange: Range | null = null; + let containingListDelimiter: string | undefined; + let leadingDelimiterRange: Range | undefined; + let trailingDelimiterRange: Range | undefined; const startNode = getStartNode(node); const endNode = getEndNode(node); @@ -367,7 +367,6 @@ export function delimitedSelector( new Position(endNode.endPosition.row, endNode.endPosition.column) ), context: { - isInDelimitedList: true, containingListDelimiter, leadingDelimiterRange, trailingDelimiterRange, From 73babde604f579f81957d18a0af904450d3cf87b Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 11:33:59 +0200 Subject: [PATCH 071/314] Added action preference inference --- src/actions/ToggleBreakpoint.ts | 7 +++++-- src/actions/actions.types.ts | 5 ++--- src/core/commandRunner/CommandRunner.ts | 6 +++--- src/core/inferFullTargets.ts | 26 +++++++++++++------------ src/typings/Types.ts | 2 ++ 5 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/actions/ToggleBreakpoint.ts b/src/actions/ToggleBreakpoint.ts index b58062ae5b..ee632b6c74 100644 --- a/src/actions/ToggleBreakpoint.ts +++ b/src/actions/ToggleBreakpoint.ts @@ -7,7 +7,7 @@ import { Location, } from "vscode"; import { Target } from "../typings/target.types"; -import { Graph } from "../typings/Types"; +import { ActionPreferences, Graph } from "../typings/Types"; import displayPendingEditDecorations from "../util/editDisplayUtils"; import { createThatMark, isLineScopeType } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; @@ -21,8 +21,11 @@ function getBreakpoints(uri: Uri, range: Range) { ); } -// TODO preference for scope type line export default class ToggleBreakpoint implements Action { + getTargetPreferences: () => ActionPreferences[] = () => [ + { modifiers: [{ type: "containingScope", scopeType: "line" }] }, + ]; + constructor(private graph: Graph) { this.run = this.run.bind(this); } diff --git a/src/actions/actions.types.ts b/src/actions/actions.types.ts index 948c156d71..ff4afaaf7c 100644 --- a/src/actions/actions.types.ts +++ b/src/actions/actions.types.ts @@ -1,5 +1,5 @@ import { Target } from "../typings/target.types"; -import { SelectionWithEditor } from "../typings/Types"; +import { ActionPreferences, SelectionWithEditor } from "../typings/Types"; export type ActionType = | "callAsFunction" @@ -58,8 +58,7 @@ export interface Action { * Used to define default values for parts of target during inference. * @param args Extra args to command */ - // TODO - // getTargetPreferences(...args: any[]): ActionPreferences[]; + getTargetPreferences?(...args: any[]): ActionPreferences[]; } export type ActionRecord = Record; diff --git a/src/core/commandRunner/CommandRunner.ts b/src/core/commandRunner/CommandRunner.ts index 31478d1e3e..47d404efcf 100644 --- a/src/core/commandRunner/CommandRunner.ts +++ b/src/core/commandRunner/CommandRunner.ts @@ -84,9 +84,9 @@ export default class CommandRunner { const targetDescs = inferFullTargets( partialTargetDescs, - // TODO - [] - // action.getTargetPreferences(...extraArgs) + action.getTargetPreferences + ? action.getTargetPreferences(...extraArgs) + : undefined ); if (this.graph.debug.active) { diff --git a/src/core/inferFullTargets.ts b/src/core/inferFullTargets.ts index e2c0946b96..31e5ba4e33 100644 --- a/src/core/inferFullTargets.ts +++ b/src/core/inferFullTargets.ts @@ -21,22 +21,24 @@ import { ActionPreferences } from "../typings/Types"; */ export default function inferFullTargets( targets: PartialTargetDesc[], - actionPreferences: ActionPreferences[] + actionPreferences?: ActionPreferences[] ): TargetDesc[] { - // TODO - // if (targets.length !== actionPreferences.length) { - // throw new Error("Target length is not equal to action preference length"); - // } + if ( + actionPreferences != null && + targets.length !== actionPreferences.length + ) { + throw new Error("Target length is not equal to action preference length"); + } return targets.map((target, index) => - inferTarget(target, targets.slice(0, index), actionPreferences[index]) + inferTarget(target, targets.slice(0, index), actionPreferences?.at(index)) ); } function inferTarget( target: PartialTargetDesc, previousTargets: PartialTargetDesc[], - actionPreferences: ActionPreferences + actionPreferences?: ActionPreferences ): TargetDesc { switch (target.type) { case "list": @@ -50,7 +52,7 @@ function inferTarget( function inferListTarget( target: PartialListTargetDesc, previousTargets: PartialTargetDesc[], - actionPreferences: ActionPreferences + actionPreferences?: ActionPreferences ): TargetDesc { return { ...target, @@ -67,7 +69,7 @@ function inferListTarget( function inferNonListTarget( target: PartialPrimitiveTargetDesc | PartialRangeTargetDesc, previousTargets: PartialTargetDesc[], - actionPreferences: ActionPreferences + actionPreferences?: ActionPreferences ): PrimitiveTargetDesc | RangeTargetDesc { switch (target.type) { case "primitive": @@ -80,7 +82,7 @@ function inferNonListTarget( function inferRangeTarget( target: PartialRangeTargetDesc, previousTargets: PartialTargetDesc[], - actionPreferences: ActionPreferences + actionPreferences?: ActionPreferences ): RangeTargetDesc { return { type: "range", @@ -103,8 +105,7 @@ function inferRangeTarget( function inferPrimitiveTarget( target: PartialPrimitiveTargetDesc, previousTargets: PartialTargetDesc[], - // TODO ActionPreferences - actionPreferences: ActionPreferences + actionPreferences?: ActionPreferences ): PrimitiveTargetDesc { const hasPosition = !!target.modifiers?.find( (modifier) => modifier.type === "position" @@ -119,6 +120,7 @@ function inferPrimitiveTarget( const modifiers = target.modifiers ?? getPreviousAttribute(previousTargets, "modifiers") ?? + actionPreferences?.modifiers ?? []; return { diff --git a/src/typings/Types.ts b/src/typings/Types.ts index dfa026c425..c2d288a5db 100644 --- a/src/typings/Types.ts +++ b/src/typings/Types.ts @@ -12,6 +12,7 @@ import { Snippets } from "../core/Snippets"; import { RangeUpdater } from "../core/updateSelections/RangeUpdater"; import { TestCaseRecorder } from "../testUtil/TestCaseRecorder"; import { CommandServerApi } from "../util/getExtensionApi"; +import { Modifier } from "./target.types"; import { FullRangeInfo } from "./updateSelections"; /** @@ -78,6 +79,7 @@ export interface ActionPreferences { // insideOutsideType: InsideOutsideType; // selectionType?: SelectionType; // modifier?: Modifier; + modifiers: Modifier[]; } export type SelectionWithEditorWithContext = { From 5769dd0d2dd758c3996c2ef579ccb3707cf96cbf Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 11:42:52 +0200 Subject: [PATCH 072/314] Added action wrap with snippet --- src/actions/Actions.ts | 3 +- src/actions/WrapWithSnippet.ts | 377 ++++++++++++++++----------------- src/actions/actions.types.ts | 4 +- src/typings/Types.ts | 5 - 4 files changed, 190 insertions(+), 199 deletions(-) diff --git a/src/actions/Actions.ts b/src/actions/Actions.ts index 2ab5b61581..27dad6962a 100644 --- a/src/actions/Actions.ts +++ b/src/actions/Actions.ts @@ -32,6 +32,7 @@ import { import { Random, Reverse, Sort } from "./Sort"; import ToggleBreakpoint from "./ToggleBreakpoint"; import Wrap from "./Wrap"; +import WrapWithSnippet from "./WrapWithSnippet"; class Actions implements ActionRecord { constructor(private graph: Graph) {} @@ -77,7 +78,7 @@ class Actions implements ActionRecord { toggleLineComment = new CommentLines(this.graph); unfoldRegion = new Unfold(this.graph); wrapWithPairedDelimiter = new Wrap(this.graph); - // wrapWithSnippet = new WrapWithSnippet(this.graph); + wrapWithSnippet = new WrapWithSnippet(this.graph); } export default Actions; diff --git a/src/actions/WrapWithSnippet.ts b/src/actions/WrapWithSnippet.ts index 652e986198..96995ff9e7 100644 --- a/src/actions/WrapWithSnippet.ts +++ b/src/actions/WrapWithSnippet.ts @@ -1,191 +1,186 @@ -// import { commands } from "vscode"; -// import { callFunctionAndUpdateSelections } from "../core/updateSelections/updateSelections"; -// import { SnippetDefinition } from "../typings/snippet"; -// import { -// Action, -// ActionPreferences, -// ActionReturnValue, -// Graph, -// Target, -// } from "../typings/Types"; -// import displayPendingEditDecorations from "../util/editDisplayUtils"; -// import { ensureSingleEditor } from "../util/targetUtils"; -// import { -// Placeholder, -// SnippetParser, -// TextmateSnippet, -// Variable, -// } from "../vendor/snippet/snippetParser"; -// import { KnownSnippetVariableNames } from "../vendor/snippet/snippetVariables"; - -// export default class WrapWithSnippet implements Action { -// private snippetParser = new SnippetParser(); - -// getTargetPreferences(snippetLocation: string): ActionPreferences[] { -// const [snippetName, placeholderName] = -// parseSnippetLocation(snippetLocation); - -// const snippet = this.graph.snippets.getSnippet(snippetName); - -// if (snippet == null) { -// throw new Error(`Couldn't find snippet ${snippetName}`); -// } - -// const variables = snippet.variables ?? {}; -// const defaultScopeType = variables[placeholderName]?.wrapperScopeType; - -// return [ -// { -// insideOutsideType: "inside", -// modifier: -// defaultScopeType == null -// ? undefined -// : { -// type: "containingScope", -// scopeType: defaultScopeType, -// includeSiblings: false, -// }, -// }, -// ]; -// } - -// constructor(private graph: Graph) { -// this.run = this.run.bind(this); -// } - -// async run( -// [targets]: [Target[]], -// snippetLocation: string -// ): Promise { -// const [snippetName, placeholderName] = -// parseSnippetLocation(snippetLocation); - -// const snippet = this.graph.snippets.getSnippet(snippetName)!; - -// const editor = ensureSingleEditor(targets); - -// // Find snippet definition matching context. -// // NB: We only look at the first target to create our context. This means -// // that if there are two snippets that match two different contexts, and -// // the two targets match those two different contexts, we will just use the -// // snippet that matches the first context for both targets -// const definition = findMatchingSnippetDefinition( -// targets[0], -// snippet.definitions -// ); - -// if (definition == null) { -// throw new Error("Couldn't find matching snippet definition"); -// } - -// const parsedSnippet = this.snippetParser.parse(definition.body.join("\n")); - -// transformSnippetVariables(parsedSnippet, placeholderName); - -// const snippetString = parsedSnippet.toTextmateString(); - -// await displayPendingEditDecorations( -// targets, -// this.graph.editStyles.pendingModification0 -// ); - -// const targetSelections = targets.map( -// (target) => target.selection.selection -// ); - -// await this.graph.actions.setSelection.run([targets]); - -// // NB: We used the command "editor.action.insertSnippet" instead of calling editor.insertSnippet -// // because the latter doesn't support special variables like CLIPBOARD -// const [updatedTargetSelections] = await callFunctionAndUpdateSelections( -// this.graph.rangeUpdater, -// () => -// commands.executeCommand("editor.action.insertSnippet", { -// snippet: snippetString, -// }), -// editor.document, -// [targetSelections] -// ); - -// return { -// thatMark: updatedTargetSelections.map((selection) => ({ -// editor, -// selection, -// })), -// }; -// } -// } - -// /** -// * Replaces the snippet variable with name `placeholderName` with TM_SELECTED_TEXT -// * -// * Also replaces any unknown variables with placeholders. We do this so it's -// * easier to leave one of the placeholders blank. We may make it so that you -// * can disable this with a setting in the future -// * @param parsedSnippet The parsed textmate snippet to operate on -// * @param placeholderName The variable name to replace with TM_SELECTED_TEXT -// */ -// function transformSnippetVariables( -// parsedSnippet: TextmateSnippet, -// placeholderName: string -// ) { -// var placeholderIndex = getMaxPlaceholderIndex(parsedSnippet) + 1; - -// parsedSnippet.walk((candidate) => { -// if (candidate instanceof Variable) { -// if (candidate.name === placeholderName) { -// candidate.name = "TM_SELECTED_TEXT"; -// } else if (!KnownSnippetVariableNames[candidate.name]) { -// const placeholder = new Placeholder(placeholderIndex++); -// candidate.children.forEach((child) => placeholder.appendChild(child)); -// candidate.parent.replace(candidate, [placeholder]); -// } -// } -// return true; -// }); -// } - -// function getMaxPlaceholderIndex(parsedSnippet: TextmateSnippet) { -// var placeholderIndex = 0; -// parsedSnippet.walk((candidate) => { -// if (candidate instanceof Placeholder) { -// placeholderIndex = Math.max(placeholderIndex, candidate.index); -// } -// return true; -// }); -// return placeholderIndex; -// } - -// function parseSnippetLocation(snippetLocation: string): [string, string] { -// const [snippetName, placeholderName] = snippetLocation.split("."); -// if (snippetName == null || placeholderName == null) { -// throw new Error("Snippet location missing '.'"); -// } -// return [snippetName, placeholderName]; -// } - -// function findMatchingSnippetDefinition( -// typedSelection: Target, -// definitions: SnippetDefinition[] -// ) { -// const languageId = typedSelection.selection.editor.document.languageId; - -// return definitions.find(({ scope }) => { -// if (scope == null) { -// return true; -// } - -// const { langIds, scopeType } = scope; - -// if (langIds != null && !langIds.includes(languageId)) { -// return false; -// } - -// if (scopeType != null) { -// // TODO: Implement scope types by refactoring code out of processScopeType -// throw new Error("Scope types not yet implemented"); -// } - -// return true; -// }); -// } +import { commands } from "vscode"; +import { callFunctionAndUpdateSelections } from "../core/updateSelections/updateSelections"; +import { SnippetDefinition } from "../typings/snippet"; +import { Target } from "../typings/target.types"; +import { ActionPreferences, Graph } from "../typings/Types"; +import displayPendingEditDecorations from "../util/editDisplayUtils"; +import { ensureSingleEditor, getContentSelection } from "../util/targetUtils"; +import { + Placeholder, + SnippetParser, + TextmateSnippet, + Variable, +} from "../vendor/snippet/snippetParser"; +import { KnownSnippetVariableNames } from "../vendor/snippet/snippetVariables"; +import { Action, ActionReturnValue } from "./actions.types"; + +export default class WrapWithSnippet implements Action { + private snippetParser = new SnippetParser(); + + getTargetPreferences(snippetLocation: string): ActionPreferences[] { + const [snippetName, placeholderName] = + parseSnippetLocation(snippetLocation); + + const snippet = this.graph.snippets.getSnippet(snippetName); + + if (snippet == null) { + throw new Error(`Couldn't find snippet ${snippetName}`); + } + + const variables = snippet.variables ?? {}; + const defaultScopeType = variables[placeholderName]?.wrapperScopeType; + + if (defaultScopeType == null) { + return []; + } + + return [ + { + modifiers: [ + { + type: "containingScope", + scopeType: defaultScopeType, + }, + ], + }, + ]; + } + + constructor(private graph: Graph) { + this.run = this.run.bind(this); + } + + async run( + [targets]: [Target[]], + snippetLocation: string + ): Promise { + const [snippetName, placeholderName] = + parseSnippetLocation(snippetLocation); + + const snippet = this.graph.snippets.getSnippet(snippetName)!; + + const editor = ensureSingleEditor(targets); + + // Find snippet definition matching context. + // NB: We only look at the first target to create our context. This means + // that if there are two snippets that match two different contexts, and + // the two targets match those two different contexts, we will just use the + // snippet that matches the first context for both targets + const definition = findMatchingSnippetDefinition( + targets[0], + snippet.definitions + ); + + if (definition == null) { + throw new Error("Couldn't find matching snippet definition"); + } + + const parsedSnippet = this.snippetParser.parse(definition.body.join("\n")); + + transformSnippetVariables(parsedSnippet, placeholderName); + + const snippetString = parsedSnippet.toTextmateString(); + + await displayPendingEditDecorations( + targets, + this.graph.editStyles.pendingModification0 + ); + + const targetSelections = targets.map(getContentSelection); + + await this.graph.actions.setSelection.run([targets]); + + // NB: We used the command "editor.action.insertSnippet" instead of calling editor.insertSnippet + // because the latter doesn't support special variables like CLIPBOARD + const [updatedTargetSelections] = await callFunctionAndUpdateSelections( + this.graph.rangeUpdater, + () => + commands.executeCommand("editor.action.insertSnippet", { + snippet: snippetString, + }), + editor.document, + [targetSelections] + ); + + return { + thatMark: updatedTargetSelections.map((selection) => ({ + editor, + selection, + })), + }; + } +} + +/** + * Replaces the snippet variable with name `placeholderName` with TM_SELECTED_TEXT + * + * Also replaces any unknown variables with placeholders. We do this so it's + * easier to leave one of the placeholders blank. We may make it so that you + * can disable this with a setting in the future + * @param parsedSnippet The parsed textmate snippet to operate on + * @param placeholderName The variable name to replace with TM_SELECTED_TEXT + */ +function transformSnippetVariables( + parsedSnippet: TextmateSnippet, + placeholderName: string +) { + var placeholderIndex = getMaxPlaceholderIndex(parsedSnippet) + 1; + + parsedSnippet.walk((candidate) => { + if (candidate instanceof Variable) { + if (candidate.name === placeholderName) { + candidate.name = "TM_SELECTED_TEXT"; + } else if (!KnownSnippetVariableNames[candidate.name]) { + const placeholder = new Placeholder(placeholderIndex++); + candidate.children.forEach((child) => placeholder.appendChild(child)); + candidate.parent.replace(candidate, [placeholder]); + } + } + return true; + }); +} + +function getMaxPlaceholderIndex(parsedSnippet: TextmateSnippet) { + var placeholderIndex = 0; + parsedSnippet.walk((candidate) => { + if (candidate instanceof Placeholder) { + placeholderIndex = Math.max(placeholderIndex, candidate.index); + } + return true; + }); + return placeholderIndex; +} + +function parseSnippetLocation(snippetLocation: string): [string, string] { + const [snippetName, placeholderName] = snippetLocation.split("."); + if (snippetName == null || placeholderName == null) { + throw new Error("Snippet location missing '.'"); + } + return [snippetName, placeholderName]; +} + +function findMatchingSnippetDefinition( + target: Target, + definitions: SnippetDefinition[] +) { + const languageId = target.editor.document.languageId; + + return definitions.find(({ scope }) => { + if (scope == null) { + return true; + } + + const { langIds, scopeType } = scope; + + if (langIds != null && !langIds.includes(languageId)) { + return false; + } + + if (scopeType != null) { + // TODO: Implement scope types by refactoring code out of processScopeType + throw new Error("Scope types not yet implemented"); + } + + return true; + }); +} diff --git a/src/actions/actions.types.ts b/src/actions/actions.types.ts index ff4afaaf7c..57243427e0 100644 --- a/src/actions/actions.types.ts +++ b/src/actions/actions.types.ts @@ -42,8 +42,8 @@ export type ActionType = | "toggleLineBreakpoint" | "toggleLineComment" | "unfoldRegion" - | "wrapWithPairedDelimiter"; -// | "wrapWithSnippet"; + | "wrapWithPairedDelimiter" + | "wrapWithSnippet"; export interface ActionReturnValue { returnValue?: any; diff --git a/src/typings/Types.ts b/src/typings/Types.ts index c2d288a5db..5798107a5b 100644 --- a/src/typings/Types.ts +++ b/src/typings/Types.ts @@ -74,11 +74,6 @@ export interface SelectionContext { } export interface ActionPreferences { - // TODO - // position?: Position; - // insideOutsideType: InsideOutsideType; - // selectionType?: SelectionType; - // modifier?: Modifier; modifiers: Modifier[]; } From d107a29b0e0f369b4154f03eef3a5779d173b789 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 11:56:11 +0200 Subject: [PATCH 073/314] Added action rewrap --- src/actions/Actions.ts | 5 +- src/actions/Rewrap.ts | 168 +++++++++++++++-------------------- src/actions/actions.types.ts | 2 +- 3 files changed, 78 insertions(+), 97 deletions(-) diff --git a/src/actions/Actions.ts b/src/actions/Actions.ts index 27dad6962a..c9cde79265 100644 --- a/src/actions/Actions.ts +++ b/src/actions/Actions.ts @@ -1,6 +1,6 @@ import { Graph } from "../typings/Types"; import { ActionRecord } from "./actions.types"; -import { Move, Bring, Swap } from "./BringMoveSwap"; +import { Bring, Move, Swap } from "./BringMoveSwap"; import Call from "./Call"; import Clear from "./Clear"; import { CommentLines } from "./Comment"; @@ -23,6 +23,7 @@ import { } from "./InsertEmptyLines"; import Remove from "./Remove"; import Replace from "./Replace"; +import Rewrap from "./Rewrap"; import { ScrollToBottom, ScrollToCenter, ScrollToTop } from "./Scroll"; import { SetSelection, @@ -65,7 +66,7 @@ class Actions implements ActionRecord { replace = new Replace(this.graph); replaceWithTarget = new Bring(this.graph); reverseTargets = new Reverse(this.graph); - // rewrapWithPairedDelimiter = new Rewrap(this.graph); + rewrapWithPairedDelimiter = new Rewrap(this.graph); scrollToBottom = new ScrollToBottom(this.graph); scrollToCenter = new ScrollToCenter(this.graph); scrollToTop = new ScrollToTop(this.graph); diff --git a/src/actions/Rewrap.ts b/src/actions/Rewrap.ts index 282951c1b0..9734b19719 100644 --- a/src/actions/Rewrap.ts +++ b/src/actions/Rewrap.ts @@ -1,104 +1,84 @@ -// import { flatten, zip } from "lodash"; -// import { TextEditor } from "vscode"; -// import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; -// import { -// Action, -// ActionPreferences, -// ActionReturnValue, -// Graph, -// SelectionWithContext, -// Target, -// } from "../typings/Types"; -// import displayPendingEditDecorations from "../util/editDisplayUtils"; -// import { runForEachEditor } from "../util/targetUtils"; +import { flatten, zip } from "lodash"; +import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; +import { Target } from "../typings/target.types"; +import { ActionPreferences, Graph } from "../typings/Types"; +import displayPendingEditDecorations from "../util/editDisplayUtils"; +import { getContentSelection, runForEachEditor } from "../util/targetUtils"; +import { Action, ActionReturnValue } from "./actions.types"; -// export default class Rewrap implements Action { -// getTargetPreferences: () => ActionPreferences[] = () => [ -// { -// insideOutsideType: "inside", -// modifier: { -// type: "surroundingPair", -// delimiter: "any", -// delimiterInclusion: undefined, -// }, -// }, -// ]; +export default class Rewrap implements Action { + getTargetPreferences: () => ActionPreferences[] = () => [ + { + modifiers: [ + { + type: "surroundingPair", + delimiter: "any", + }, + ], + }, + ]; -// constructor(private graph: Graph) { -// this.run = this.run.bind(this); -// } + constructor(private graph: Graph) { + this.run = this.run.bind(this); + } -// async run( -// [targets]: [Target[]], -// left: string, -// right: string -// ): Promise { -// const targetInfos = targets.flatMap((target) => { -// const boundary = target.selectionContext.boundary; + async run( + [targets]: [Target[]], + left: string, + right: string + ): Promise { + const targetInfos = targets.flatMap((target) => { + const boundary = target.boundary; -// if (boundary == null || boundary.length !== 2) { -// throw Error("Target must have an opening and closing delimiter"); -// } + if (boundary == null || boundary.length !== 2) { + throw Error("Target must have an opening and closing delimiter"); + } -// return { -// editor: target.selection.editor, -// boundary: boundary.map((edge) => -// constructSimpleTypedSelection(target.selection.editor, edge) -// ), -// targetSelection: target.selection.selection, -// }; -// }); + return { + editor: target.editor, + boundary: boundary.map((edge) => ({ + editor: target.editor, + contentRange: edge, + isReversed: target.isReversed, + })), + targetSelection: getContentSelection(target), + }; + }); -// await displayPendingEditDecorations( -// targetInfos.flatMap(({ boundary }) => boundary), -// this.graph.editStyles.pendingModification0 -// ); + await displayPendingEditDecorations( + targetInfos.flatMap(({ boundary }) => boundary), + this.graph.editStyles.pendingModification0 + ); -// const thatMark = flatten( -// await runForEachEditor( -// targetInfos, -// (targetInfo) => targetInfo.editor, -// async (editor, targetInfos) => { -// const edits = targetInfos.flatMap((targetInfo) => -// zip(targetInfo.boundary, [left, right]).map(([target, text]) => ({ -// editor, -// range: target!.selection.selection, -// text: text!, -// })) -// ); + const thatMark = flatten( + await runForEachEditor( + targetInfos, + (targetInfo) => targetInfo.editor, + async (editor, targetInfos) => { + const edits = targetInfos.flatMap((targetInfo) => + zip(targetInfo.boundary, [left, right]).map(([target, text]) => ({ + editor, + range: target!.contentRange, + text: text!, + })) + ); -// const [updatedTargetSelections] = -// await performEditsAndUpdateSelections( -// this.graph.rangeUpdater, -// editor, -// edits, -// [targetInfos.map((targetInfo) => targetInfo.targetSelection)] -// ); + const [updatedTargetSelections] = + await performEditsAndUpdateSelections( + this.graph.rangeUpdater, + editor, + edits, + [targetInfos.map((targetInfo) => targetInfo.targetSelection)] + ); -// return updatedTargetSelections.map((selection) => ({ -// editor, -// selection, -// })); -// } -// ) -// ); + return updatedTargetSelections.map((selection) => ({ + editor, + selection, + })); + } + ) + ); -// return { thatMark }; -// } -// } - -// function constructSimpleTypedSelection( -// editor: TextEditor, -// selection: SelectionWithContext -// ): Target { -// return { -// selection: { -// selection: selection.selection, -// editor, -// }, -// selectionType: "token", -// selectionContext: selection.context, -// insideOutsideType: null, -// position: "contents", -// }; -// } + return { thatMark }; + } +} diff --git a/src/actions/actions.types.ts b/src/actions/actions.types.ts index 57243427e0..18b2f663db 100644 --- a/src/actions/actions.types.ts +++ b/src/actions/actions.types.ts @@ -30,7 +30,7 @@ export type ActionType = | "replace" | "replaceWithTarget" | "reverseTargets" - // | "rewrapWithPairedDelimiter" + | "rewrapWithPairedDelimiter" | "scrollToBottom" | "scrollToCenter" | "scrollToTop" From 4889b8a0a4347a44a3a704fe646d33706d24bd30 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 12:00:36 +0200 Subject: [PATCH 074/314] Cleanup --- src/core/commandRunner/CommandRunner.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/commandRunner/CommandRunner.ts b/src/core/commandRunner/CommandRunner.ts index 47d404efcf..1a695be01d 100644 --- a/src/core/commandRunner/CommandRunner.ts +++ b/src/core/commandRunner/CommandRunner.ts @@ -78,7 +78,6 @@ export default class CommandRunner { const action = this.graph.actions[actionName]; if (action == null) { - return; // TODO throw new Error(`Unknown action ${actionName}`); } From 2f8d30349093f648b2a20eb819e0740deb9db4f4 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 12:48:38 +0200 Subject: [PATCH 075/314] Updated inference with special handling on containing scope --- src/actions/BringMoveSwap.ts | 7 ++++++- src/core/inferFullTargets.ts | 22 ++++++++++++++++++---- src/util/targetUtils.ts | 9 --------- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/actions/BringMoveSwap.ts b/src/actions/BringMoveSwap.ts index 76ce4f0f21..46b39abed2 100644 --- a/src/actions/BringMoveSwap.ts +++ b/src/actions/BringMoveSwap.ts @@ -12,7 +12,6 @@ import { getContentSelection, getContentText, getRemovalRange, - getTextWithPossibleDelimiter, maybeAddDelimiter, runForEachEditor, } from "../util/targetUtils"; @@ -293,3 +292,9 @@ export class Swap extends BringMoveSwap { super(graph, "swap"); } } + +/** Get text from selection. Possibly add delimiter for positions before/after */ +function getTextWithPossibleDelimiter(source: Target, destination: Target) { + const sourceText = getContentText(source); + return maybeAddDelimiter(sourceText, destination); +} diff --git a/src/core/inferFullTargets.ts b/src/core/inferFullTargets.ts index 31e5ba4e33..b4d5c4bbbc 100644 --- a/src/core/inferFullTargets.ts +++ b/src/core/inferFullTargets.ts @@ -117,11 +117,25 @@ function inferPrimitiveTarget( type: "cursor", }; + const previousModifiers = getPreviousAttribute(previousTargets, "modifiers"); + const modifiers = - target.modifiers ?? - getPreviousAttribute(previousTargets, "modifiers") ?? - actionPreferences?.modifiers ?? - []; + target.modifiers ?? previousModifiers ?? actionPreferences?.modifiers ?? []; + + // TODO Is this really a good solution? + // "bring line to after this" needs to inter line on second target + if ( + previousModifiers != null && + modifiers.length === 1 && + modifiers[0].type === "position" + ) { + const containingScopeModifier = previousModifiers.find( + (modifier) => modifier.type === "containingScope" + ); + if (containingScopeModifier != null) { + modifiers.push(containingScopeModifier); + } + } return { type: target.type, diff --git a/src/util/targetUtils.ts b/src/util/targetUtils.ts index 9f59bfd010..e8938f98db 100644 --- a/src/util/targetUtils.ts +++ b/src/util/targetUtils.ts @@ -136,15 +136,6 @@ export function getRemovalHighlightRange(target: Target) { : removalRange; } -/** Get text from selection. Possibly add delimiter for positions before/after */ -export function getTextWithPossibleDelimiter( - source: Target, - destination: Target -) { - const sourceText = getContentText(source); - return maybeAddDelimiter(sourceText, destination); -} - /** Possibly add delimiter for positions before/after */ export function maybeAddDelimiter(text: string, target: Target) { if (target.delimiter != null) { From 9ccf163322a366f4963c466cb323779c515dacad Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 14:26:26 +0200 Subject: [PATCH 076/314] Use range in surrounding pair --- .../modifiers/SurroundingPairStage.ts | 15 +++------- .../findSurroundingPairTextBased.ts | 10 +++---- .../modifiers/surroundingPair/index.ts | 30 ++++++++++--------- 3 files changed, 25 insertions(+), 30 deletions(-) diff --git a/src/processTargets/modifiers/SurroundingPairStage.ts b/src/processTargets/modifiers/SurroundingPairStage.ts index 2b22c412ac..b51df86e88 100644 --- a/src/processTargets/modifiers/SurroundingPairStage.ts +++ b/src/processTargets/modifiers/SurroundingPairStage.ts @@ -1,7 +1,6 @@ import { Selection } from "vscode"; import { SurroundingPairModifier, Target } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; -import { isReversed } from "../../util/selectionUtils"; import { ModifierStage } from "../PipelineStages.types"; import { processSurroundingPair } from "./surroundingPair"; @@ -22,24 +21,18 @@ export default class implements ModifierStage { constructor(private modifier: SurroundingPairModifier) {} run(context: ProcessedTargetsContext, target: Target): Target[] { - const selectionWithEditor = { - editor: target.editor, - selection: new Selection( - target.contentRange.start, - target.contentRange.end - ), - }; const pairs = processSurroundingPair( context, - selectionWithEditor, + target.editor, + target.contentRange, this.modifier ); if (pairs == null) { throw new Error("Couldn't find containing pair"); } return pairs.map((pair) => ({ - editor: pair.selection.editor, - isReversed: isReversed(pair.selection.selection), + editor: target.editor, + isReversed: target.isReversed, contentRange: pair.selection.selection, interiorRange: pair.context.interior, removalRange: pair.context.removalRange, diff --git a/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts b/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts index a4cdf7772b..ee626f37c3 100644 --- a/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts +++ b/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts @@ -59,7 +59,7 @@ const SCAN_EXPANSION_FACTOR = 3; * form of opening quote in Python. * * @param editor The text editor containing the selection - * @param selection The selection to find surrounding pair around + * @param range The selection to find surrounding pair around * @param allowableRange The range in which to look for delimiters, or the * entire document if `null` * @param delimiters The acceptable surrounding pair names @@ -67,7 +67,7 @@ const SCAN_EXPANSION_FACTOR = 3; */ export function findSurroundingPairTextBased( editor: TextEditor, - selection: Range, + range: Range, allowableRange: Range | null, delimiters: SimpleSurroundingPairName[], forceDirection: "left" | "right" | undefined @@ -98,8 +98,8 @@ export function findSurroundingPairTextBased( end: document.offsetAt(fullRange.end), }; const selectionOffsets = { - start: document.offsetAt(selection.start), - end: document.offsetAt(selection.end), + start: document.offsetAt(range.start), + end: document.offsetAt(range.end), }; /** @@ -139,7 +139,7 @@ export function findSurroundingPairTextBased( // Just bail early if the range doesn't completely contain our selection as // it is a lost cause. - if (!currentRange.contains(selection)) { + if (!currentRange.contains(range)) { continue; } diff --git a/src/processTargets/modifiers/surroundingPair/index.ts b/src/processTargets/modifiers/surroundingPair/index.ts index bba26bfbd0..e2e45145ed 100644 --- a/src/processTargets/modifiers/surroundingPair/index.ts +++ b/src/processTargets/modifiers/surroundingPair/index.ts @@ -1,4 +1,4 @@ -import { Location } from "vscode"; +import { Location, Range, Selection, TextEditor } from "vscode"; import { SyntaxNode } from "web-tree-sitter"; import getTextFragmentExtractor, { TextFragmentExtractor, @@ -9,7 +9,6 @@ import { } from "../../../typings/target.types"; import { ProcessedTargetsContext, - SelectionWithEditor, SelectionWithEditorWithContext, } from "../../../typings/Types"; import { complexDelimiterMap } from "./delimiterMaps"; @@ -31,10 +30,11 @@ import { findSurroundingPairTextBased } from "./findSurroundingPairTextBased"; */ export function processSurroundingPair( context: ProcessedTargetsContext, - selection: SelectionWithEditor, + editor: TextEditor, + range: Range, modifier: SurroundingPairModifier ): SelectionWithEditorWithContext[] | null { - const document = selection.editor.document; + const document = editor.document; const delimiters = complexDelimiterMap[ modifier.delimiter as ComplexSurroundingPairName ] ?? [modifier.delimiter]; @@ -43,9 +43,7 @@ export function processSurroundingPair( let textFragmentExtractor: TextFragmentExtractor; try { - node = context.getNodeAtLocation( - new Location(document.uri, selection.selection) - ); + node = context.getNodeAtLocation(new Location(document.uri, range)); textFragmentExtractor = getTextFragmentExtractor(document.languageId); } catch (err) { @@ -53,8 +51,8 @@ export function processSurroundingPair( // If we're in a language where we don't have a parse tree we use the text // based algorithm return findSurroundingPairTextBased( - selection.editor, - selection.selection, + editor, + range, null, delimiters, modifier.forceDirection @@ -66,11 +64,15 @@ export function processSurroundingPair( // If we have a parse tree but we are in a string node or in a comment node, // then we use the text-based algorithm - const textFragmentRange = textFragmentExtractor(node, selection); + const selectionWithEditor = { + editor, + selection: new Selection(range.start, range.end), + }; + const textFragmentRange = textFragmentExtractor(node, selectionWithEditor); if (textFragmentRange != null) { const surroundingRange = findSurroundingPairTextBased( - selection.editor, - selection.selection, + editor, + range, textFragmentRange, delimiters, modifier.forceDirection @@ -85,8 +87,8 @@ export function processSurroundingPair( // couldn't find a surrounding pair within a string or comment, we use the // parse tree-based algorithm return findSurroundingPairParseTreeBased( - selection.editor, - selection.selection, + editor, + range, node, delimiters, modifier.forceDirection From eb982227d26e9d4167ff4defb4e6a54e46193226 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 14:35:44 +0200 Subject: [PATCH 077/314] Restored old implementation of edit newline --- src/actions/EditNewLine.ts | 96 ++++++++++++-------------------------- 1 file changed, 30 insertions(+), 66 deletions(-) diff --git a/src/actions/EditNewLine.ts b/src/actions/EditNewLine.ts index 8f9a124a0c..e17e3ec70d 100644 --- a/src/actions/EditNewLine.ts +++ b/src/actions/EditNewLine.ts @@ -1,8 +1,7 @@ -import { commands, Position, Range, Selection, TextEditor } from "vscode"; +import { commands, Range, TextEditor } from "vscode"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; import { getNotebookFromCellDocument } from "../util/notebook"; -import { createThatMark, runOnTargetsForEachEditor } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; class EditNewLine implements Action { @@ -10,6 +9,20 @@ class EditNewLine implements Action { this.run = this.run.bind(this); } + private correctForParagraph(targets: Target[]) { + targets.forEach((target) => { + let { start, end } = target.contentRange; + if (target.scopeType === "paragraph") { + if (this.isAbove && target.leadingDelimiterRange != null) { + start = start.translate({ lineDelta: -1 }); + } else if (!this.isAbove && target.trailingDelimiterRange != null) { + end = end.translate({ lineDelta: 1 }); + } + target.contentRange = new Range(start, end); + } + }); + } + private isNotebookEditor(editor: TextEditor) { return getNotebookFromCellDocument(editor.document) != null; } @@ -25,77 +38,28 @@ class EditNewLine implements Action { ? "jupyter.insertCellAbove" : "jupyter.insertCellBelow"; } - return null; + return this.isAbove + ? "editor.action.insertLineBefore" + : "editor.action.insertLineAfter"; } async run([targets]: [Target[]]): Promise { - const command = this.getCommand(targets[0]); - if (command) { - if (this.isAbove) { - await this.graph.actions.setSelectionBefore.run([targets]); - } else { - await this.graph.actions.setSelectionAfter.run([targets]); - } - await commands.executeCommand(command); - return { thatMark: createThatMark(targets) }; - } + this.correctForParagraph(targets); - const thatMark = await runOnTargetsForEachEditor( - targets, - async (editor, targets) => { - const edits = targets.map((target) => { - const delimiter = target.scopeType === "paragraph" ? "\n\n" : "\n"; - const lineNumber = this.isAbove - ? target.contentRange.start.line - : target.contentRange.end.line; - const line = editor.document.lineAt(lineNumber); - const { firstNonWhitespaceCharacterIndex } = line; - const padding = line.text.slice(0, firstNonWhitespaceCharacterIndex); - const text = this.isAbove ? padding + delimiter : delimiter + padding; - const position = this.isAbove ? line.range.start : line.range.end; - const lineDelta = delimiter.length; - return { - contentRange: target.contentRange, - lineDelta, - firstNonWhitespaceCharacterIndex, - position, - text, - }; - }); - - await editor.edit((editBuilder) => { - edits.forEach((edit) => { - editBuilder.insert(edit.position, edit.text); - }); - }); - - editor.selections = edits.map((edit) => { - const selectionLineNum = this.isAbove - ? edit.position.line - : edit.position.line + edit.lineDelta; - const positionSelection = new Position( - selectionLineNum, - edit.firstNonWhitespaceCharacterIndex - ); - return new Selection(positionSelection, positionSelection); - }); - - const thatMarkRanges = edits.map((edit) => { - const { contentRange, lineDelta } = edit; - return this.isAbove - ? new Range( - contentRange.start.translate({ lineDelta }), - contentRange.end.translate({ lineDelta }) - ) - : contentRange; - }); + if (this.isAbove) { + await this.graph.actions.setSelectionBefore.run([targets]); + } else { + await this.graph.actions.setSelectionAfter.run([targets]); + } - return createThatMark(targets, thatMarkRanges); - } - ); + const command = this.getCommand(targets[0]); + await commands.executeCommand(command); return { - thatMark: thatMark.flat(), + thatMark: targets.map((target) => ({ + selection: target.editor.selection, + editor: target.editor, + })), }; } } From 977fb80a208e5265931094fd3a3bd8c568c7e189 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 15:09:14 +0200 Subject: [PATCH 078/314] Added specific action type for containing scope --- src/processTargets/getModifierStage.ts | 17 ++++++----- src/processTargets/marks/CursorStage.ts | 2 +- .../marks/DecoratedSymbolStage.ts | 2 +- src/processTargets/marks/LineNumberStage.ts | 2 +- src/processTargets/marks/SourceStage.ts | 2 +- src/processTargets/marks/ThatStage.ts | 2 +- .../modifiers/SurroundingPairStage.ts | 28 +++++++++++-------- .../ContainingScopeStage.ts | 14 ++++++---- .../{ => scopeTypeStages}/DocumentStage.ts | 13 +++++---- .../{ => scopeTypeStages}/LineStage.ts | 11 ++++---- .../NotebookCellStage.ts | 10 ++++--- .../{ => scopeTypeStages}/ParagraphStage.ts | 11 ++++---- .../{ => scopeTypeStages}/RegexStage.ts | 24 ++++++++++------ .../{ => scopeTypeStages}/TokenStage.ts | 12 ++++---- src/typings/target.types.ts | 4 +++ 15 files changed, 91 insertions(+), 63 deletions(-) rename src/processTargets/modifiers/{ => scopeTypeStages}/ContainingScopeStage.ts (85%) rename src/processTargets/modifiers/{ => scopeTypeStages}/DocumentStage.ts (76%) rename src/processTargets/modifiers/{ => scopeTypeStages}/LineStage.ts (86%) rename src/processTargets/modifiers/{ => scopeTypeStages}/NotebookCellStage.ts (54%) rename src/processTargets/modifiers/{ => scopeTypeStages}/ParagraphStage.ts (92%) rename src/processTargets/modifiers/{ => scopeTypeStages}/RegexStage.ts (68%) rename src/processTargets/modifiers/{ => scopeTypeStages}/TokenStage.ts (92%) diff --git a/src/processTargets/getModifierStage.ts b/src/processTargets/getModifierStage.ts index 4929be6c90..066c7c5956 100644 --- a/src/processTargets/getModifierStage.ts +++ b/src/processTargets/getModifierStage.ts @@ -4,19 +4,22 @@ import { Modifier, } from "../typings/target.types"; import BoundaryStage from "./modifiers/BoundaryStage"; -import ContainingScopeStage from "./modifiers/ContainingScopeStage"; -import DocumentStage from "./modifiers/DocumentStage"; +import ContainingScopeStage from "./modifiers/scopeTypeStages/ContainingScopeStage"; +import DocumentStage from "./modifiers/scopeTypeStages/DocumentStage"; import { HeadStage, TailStage } from "./modifiers/HeadTailStage"; import InteriorStage from "./modifiers/InteriorStage"; -import LineStage from "./modifiers/LineStage"; -import NotebookCellStage from "./modifiers/NotebookCellStage"; -import ParagraphStage from "./modifiers/ParagraphStage"; +import LineStage from "./modifiers/scopeTypeStages/LineStage"; +import NotebookCellStage from "./modifiers/scopeTypeStages/NotebookCellStage"; +import ParagraphStage from "./modifiers/scopeTypeStages/ParagraphStage"; import PositionStage from "./modifiers/PositionStage"; import RawSelectionStage from "./modifiers/RawSelectionStage"; -import { NonWhitespaceSequenceStage, UrlStage } from "./modifiers/RegexStage"; +import { + NonWhitespaceSequenceStage, + UrlStage, +} from "./modifiers/scopeTypeStages/RegexStage"; import SubPieceStage from "./modifiers/SubPieceStage"; import SurroundingPairStage from "./modifiers/SurroundingPairStage"; -import TokenStage from "./modifiers/TokenStage"; +import TokenStage from "./modifiers/scopeTypeStages/TokenStage"; import { ModifierStage } from "./PipelineStages.types"; export default (modifier: Modifier): ModifierStage => { diff --git a/src/processTargets/marks/CursorStage.ts b/src/processTargets/marks/CursorStage.ts index e136fa1912..0de591c263 100644 --- a/src/processTargets/marks/CursorStage.ts +++ b/src/processTargets/marks/CursorStage.ts @@ -1,7 +1,7 @@ import { window } from "vscode"; import { CursorMark, Target } from "../../typings/target.types"; import { isReversed } from "../../util/selectionUtils"; -import { getTokenContext } from "../modifiers/TokenStage"; +import { getTokenContext } from "../modifiers/scopeTypeStages/TokenStage"; import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { diff --git a/src/processTargets/marks/DecoratedSymbolStage.ts b/src/processTargets/marks/DecoratedSymbolStage.ts index 2a6c655afd..3174593fbf 100644 --- a/src/processTargets/marks/DecoratedSymbolStage.ts +++ b/src/processTargets/marks/DecoratedSymbolStage.ts @@ -1,6 +1,6 @@ import { DecoratedSymbolMark, Target } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; -import { getTokenContext } from "../modifiers/TokenStage"; +import { getTokenContext } from "../modifiers/scopeTypeStages/TokenStage"; import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { diff --git a/src/processTargets/marks/LineNumberStage.ts b/src/processTargets/marks/LineNumberStage.ts index b4c05b6801..17268bf0b3 100644 --- a/src/processTargets/marks/LineNumberStage.ts +++ b/src/processTargets/marks/LineNumberStage.ts @@ -4,7 +4,7 @@ import { LineNumberPosition, Target, } from "../../typings/target.types"; -import { getLineContext } from "../modifiers/LineStage"; +import { getLineContext } from "../modifiers/scopeTypeStages/LineStage"; import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { diff --git a/src/processTargets/marks/SourceStage.ts b/src/processTargets/marks/SourceStage.ts index 2ca22f5a5d..dd1b4b2504 100644 --- a/src/processTargets/marks/SourceStage.ts +++ b/src/processTargets/marks/SourceStage.ts @@ -1,7 +1,7 @@ import { SourceMark, Target } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { isReversed } from "../../util/selectionUtils"; -import { getTokenContext } from "../modifiers/TokenStage"; +import { getTokenContext } from "../modifiers/scopeTypeStages/TokenStage"; import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { diff --git a/src/processTargets/marks/ThatStage.ts b/src/processTargets/marks/ThatStage.ts index cea3cf698f..e684839305 100644 --- a/src/processTargets/marks/ThatStage.ts +++ b/src/processTargets/marks/ThatStage.ts @@ -1,7 +1,7 @@ import { ThatMark, Target } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { isReversed } from "../../util/selectionUtils"; -import { getTokenContext } from "../modifiers/TokenStage"; +import { getTokenContext } from "../modifiers/scopeTypeStages/TokenStage"; import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { diff --git a/src/processTargets/modifiers/SurroundingPairStage.ts b/src/processTargets/modifiers/SurroundingPairStage.ts index b51df86e88..0f9e753668 100644 --- a/src/processTargets/modifiers/SurroundingPairStage.ts +++ b/src/processTargets/modifiers/SurroundingPairStage.ts @@ -2,6 +2,7 @@ import { Selection } from "vscode"; import { SurroundingPairModifier, Target } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; +import { getTokenContext } from "./scopeTypeStages/TokenStage"; import { processSurroundingPair } from "./surroundingPair"; /** @@ -30,16 +31,21 @@ export default class implements ModifierStage { if (pairs == null) { throw new Error("Couldn't find containing pair"); } - return pairs.map((pair) => ({ - editor: target.editor, - isReversed: target.isReversed, - contentRange: pair.selection.selection, - interiorRange: pair.context.interior, - removalRange: pair.context.removalRange, - delimiter: pair.context.containingListDelimiter, - boundary: pair.context.boundary, - leadingDelimiterRange: pair.context.leadingDelimiterRange, - trailingDelimiterRange: pair.context.trailingDelimiterRange, - })); + return pairs.map((pair) => { + const context = getTokenContext(target.editor, pair.selection.selection); + return { + editor: target.editor, + isReversed: target.isReversed, + contentRange: pair.selection.selection, + interiorRange: pair.context.interior, + removalRange: pair.context.removalRange, + boundary: pair.context.boundary, + delimiter: pair.context.containingListDelimiter ?? context.delimiter, + leadingDelimiterRange: + pair.context.leadingDelimiterRange ?? context.leadingDelimiterRange, + trailingDelimiterRange: + pair.context.trailingDelimiterRange ?? context.trailingDelimiterRange, + }; + }); } } diff --git a/src/processTargets/modifiers/ContainingScopeStage.ts b/src/processTargets/modifiers/scopeTypeStages/ContainingScopeStage.ts similarity index 85% rename from src/processTargets/modifiers/ContainingScopeStage.ts rename to src/processTargets/modifiers/scopeTypeStages/ContainingScopeStage.ts index 520db15ee0..d975b8449d 100644 --- a/src/processTargets/modifiers/ContainingScopeStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ContainingScopeStage.ts @@ -1,26 +1,27 @@ import { Location, Selection } from "vscode"; import { SyntaxNode } from "web-tree-sitter"; -import { getNodeMatcher } from "../../languages/getNodeMatcher"; +import { getNodeMatcher } from "../../../languages/getNodeMatcher"; import { ContainingScopeModifier, EveryScopeModifier, + ScopeTypeTarget, Target, -} from "../../typings/target.types"; +} from "../../../typings/target.types"; import { NodeMatcher, ProcessedTargetsContext, SelectionWithEditor, -} from "../../typings/Types"; +} from "../../../typings/Types"; import { isReversed, selectionWithEditorFromRange, -} from "../../util/selectionUtils"; -import { ModifierStage } from "../PipelineStages.types"; +} from "../../../util/selectionUtils"; +import { ModifierStage } from "../../PipelineStages.types"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} - run(context: ProcessedTargetsContext, target: Target): Target[] { + run(context: ProcessedTargetsContext, target: Target): ScopeTypeTarget[] { const nodeMatcher = getNodeMatcher( target.editor.document.languageId, this.modifier.scopeType, @@ -43,6 +44,7 @@ export default class implements ModifierStage { } return scopeNodes.map((scope) => ({ + scopeType: this.modifier.scopeType, editor: scope.selection.editor, isReversed: isReversed(scope.selection.selection), contentRange: scope.selection.selection, diff --git a/src/processTargets/modifiers/DocumentStage.ts b/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts similarity index 76% rename from src/processTargets/modifiers/DocumentStage.ts rename to src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts index 9905b3f2f5..aa6493fe3c 100644 --- a/src/processTargets/modifiers/DocumentStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts @@ -2,21 +2,22 @@ import { Range, TextEditor } from "vscode"; import { ContainingScopeModifier, EveryScopeModifier, + ScopeTypeTarget, Target, -} from "../../typings/target.types"; -import { ProcessedTargetsContext } from "../../typings/Types"; -import { getDocumentRange } from "../../util/range"; -import { ModifierStage } from "../PipelineStages.types"; +} from "../../../typings/target.types"; +import { ProcessedTargetsContext } from "../../../typings/Types"; +import { getDocumentRange } from "../../../util/range"; +import { ModifierStage } from "../../PipelineStages.types"; import { fitRangeToLineContent } from "./LineStage"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} - run(context: ProcessedTargetsContext, target: Target): Target { + run(context: ProcessedTargetsContext, target: Target): ScopeTypeTarget { return { + scopeType: this.modifier.scopeType, editor: target.editor, isReversed: target.isReversed, - scopeType: "document", delimiter: "\n", contentRange: getDocumentContentRange(target.editor), removalRange: getDocumentRange(target.editor.document), diff --git a/src/processTargets/modifiers/LineStage.ts b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts similarity index 86% rename from src/processTargets/modifiers/LineStage.ts rename to src/processTargets/modifiers/scopeTypeStages/LineStage.ts index 99611f0208..3dff5688fc 100644 --- a/src/processTargets/modifiers/LineStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts @@ -2,20 +2,22 @@ import { Position, Range, TextEditor } from "vscode"; import { ContainingScopeModifier, EveryScopeModifier, + ScopeTypeTarget, Target, -} from "../../typings/target.types"; -import { ProcessedTargetsContext } from "../../typings/Types"; -import { ModifierStage } from "../PipelineStages.types"; +} from "../../../typings/target.types"; +import { ProcessedTargetsContext } from "../../../typings/Types"; +import { ModifierStage } from "../../PipelineStages.types"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} - run(context: ProcessedTargetsContext, target: Target): Target { + run(context: ProcessedTargetsContext, target: Target): ScopeTypeTarget { const contentRange = fitRangeToLineContent( target.editor, target.contentRange ); return { + scopeType: this.modifier.scopeType, editor: target.editor, isReversed: target.isReversed, contentRange, @@ -55,7 +57,6 @@ export function getLineContext( ); return { - scopeType: "line", delimiter: "\n", removalRange, leadingDelimiterHighlightRange, diff --git a/src/processTargets/modifiers/NotebookCellStage.ts b/src/processTargets/modifiers/scopeTypeStages/NotebookCellStage.ts similarity index 54% rename from src/processTargets/modifiers/NotebookCellStage.ts rename to src/processTargets/modifiers/scopeTypeStages/NotebookCellStage.ts index 528d361f0b..87e974e189 100644 --- a/src/processTargets/modifiers/NotebookCellStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/NotebookCellStage.ts @@ -1,16 +1,18 @@ import { ContainingScopeModifier, EveryScopeModifier, + ScopeTypeTarget, Target, -} from "../../typings/target.types"; -import { ProcessedTargetsContext } from "../../typings/Types"; -import { ModifierStage } from "../PipelineStages.types"; +} from "../../../typings/target.types"; +import { ProcessedTargetsContext } from "../../../typings/Types"; +import { ModifierStage } from "../../PipelineStages.types"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} - run(context: ProcessedTargetsContext, target: Target): Target { + run(context: ProcessedTargetsContext, target: Target): ScopeTypeTarget { return { + scopeType: this.modifier.scopeType, editor: target.editor, isReversed: target.isReversed, contentRange: target.contentRange, diff --git a/src/processTargets/modifiers/ParagraphStage.ts b/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts similarity index 92% rename from src/processTargets/modifiers/ParagraphStage.ts rename to src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts index f8728249af..644780bf47 100644 --- a/src/processTargets/modifiers/ParagraphStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts @@ -2,16 +2,17 @@ import { Position, Range, TextDocument } from "vscode"; import { ContainingScopeModifier, EveryScopeModifier, + ScopeTypeTarget, Target, -} from "../../typings/target.types"; -import { ProcessedTargetsContext } from "../../typings/Types"; -import { ModifierStage } from "../PipelineStages.types"; +} from "../../../typings/target.types"; +import { ProcessedTargetsContext } from "../../../typings/Types"; +import { ModifierStage } from "../../PipelineStages.types"; import { fitRangeToLineContent } from "./LineStage"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} - run(context: ProcessedTargetsContext, target: Target): Target { + run(context: ProcessedTargetsContext, target: Target): ScopeTypeTarget { const { document } = target.editor; let startLine = document.lineAt(target.contentRange.start); @@ -80,9 +81,9 @@ export default class implements ModifierStage { ); return { + scopeType: this.modifier.scopeType, editor: target.editor, isReversed: target.isReversed, - scopeType: "paragraph", delimiter: "\n\n", contentRange, removalRange, diff --git a/src/processTargets/modifiers/RegexStage.ts b/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts similarity index 68% rename from src/processTargets/modifiers/RegexStage.ts rename to src/processTargets/modifiers/scopeTypeStages/RegexStage.ts index 649b86d7ed..14ba57d6c7 100644 --- a/src/processTargets/modifiers/RegexStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts @@ -2,21 +2,27 @@ import { Position, Range, TextEditor } from "vscode"; import { ContainingScopeModifier, EveryScopeModifier, + ScopeTypeTarget, Target, -} from "../../typings/target.types"; -import { ProcessedTargetsContext } from "../../typings/Types"; -import { ModifierStage } from "../PipelineStages.types"; +} from "../../../typings/target.types"; +import { ProcessedTargetsContext } from "../../../typings/Types"; +import { ModifierStage } from "../../PipelineStages.types"; import { getTokenContext } from "./TokenStage"; class RegexStage implements ModifierStage { - constructor(private regex: RegExp, private name?: string) {} + constructor( + private modifier: ContainingScopeModifier | EveryScopeModifier, + private regex: RegExp, + private name?: string + ) {} - run(context: ProcessedTargetsContext, target: Target): Target { + run(context: ProcessedTargetsContext, target: Target): ScopeTypeTarget { const { editor } = target; const start = this.getMatch(editor, target.contentRange.start).start; const end = this.getMatch(editor, target.contentRange.end).end; const contentRange = new Range(start, end); return { + scopeType: this.modifier.scopeType, editor, isReversed: target.isReversed, contentRange, @@ -49,8 +55,8 @@ class RegexStage implements ModifierStage { } export class NonWhitespaceSequenceStage extends RegexStage { - constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) { - super(/\S+/g, "Non whitespace sequence"); + constructor(modifier: ContainingScopeModifier | EveryScopeModifier) { + super(modifier, /\S+/g, "Non whitespace sequence"); } } @@ -59,7 +65,7 @@ const URL_REGEX = /(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/g; export class UrlStage extends RegexStage { - constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) { - super(URL_REGEX, "URL"); + constructor(modifier: ContainingScopeModifier | EveryScopeModifier) { + super(modifier, URL_REGEX, "URL"); } } diff --git a/src/processTargets/modifiers/TokenStage.ts b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts similarity index 92% rename from src/processTargets/modifiers/TokenStage.ts rename to src/processTargets/modifiers/scopeTypeStages/TokenStage.ts index 1d0df76d23..de59050492 100644 --- a/src/processTargets/modifiers/TokenStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts @@ -2,21 +2,23 @@ import { Range, TextEditor } from "vscode"; import { ContainingScopeModifier, EveryScopeModifier, + ScopeTypeTarget, Target, -} from "../../typings/target.types"; -import { ProcessedTargetsContext } from "../../typings/Types"; -import { getTokensInRange, PartialToken } from "../../util/getTokensInRange"; -import { ModifierStage } from "../PipelineStages.types"; +} from "../../../typings/target.types"; +import { ProcessedTargetsContext } from "../../../typings/Types"; +import { getTokensInRange, PartialToken } from "../../../util/getTokensInRange"; +import { ModifierStage } from "../../PipelineStages.types"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} - run(context: ProcessedTargetsContext, target: Target): Target { + run(context: ProcessedTargetsContext, target: Target): ScopeTypeTarget { const contentRange = getTokenRangeForSelection( target.editor, target.contentRange ); return { + scopeType: this.modifier.scopeType, editor: target.editor, isReversed: target.isReversed, contentRange, diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 3e46aa02e8..68de519b2d 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -307,3 +307,7 @@ export interface Target { */ boundary?: Range[]; } + +export interface ScopeTypeTarget extends Target { + scopeType: ScopeType; +} From 36bfb2655e2e40dd1c6dd157c99a3916bb466c25 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 15:32:07 +0200 Subject: [PATCH 079/314] Updated document tests --- src/actions/EditNewLine.ts | 2 +- .../modifiers/SurroundingPairStage.ts | 1 - .../scopeTypeStages/ContainingScopeStage.ts | 2 +- .../modifiers/scopeTypeStages/LineStage.ts | 5 +-- .../scopeTypeStages/NotebookCellStage.ts | 2 +- .../modifiers/scopeTypeStages/TokenStage.ts | 5 +-- .../recorded/selectionTypes/chuckFile2.yml | 31 +++++++++++++++ .../recorded/selectionTypes/takeFile.yml | 39 ++++++++++++------- src/testUtil/TestCaseRecorder.ts | 2 +- src/typings/target.types.ts | 6 +-- 10 files changed, 63 insertions(+), 32 deletions(-) create mode 100644 src/test/suite/fixtures/recorded/selectionTypes/chuckFile2.yml diff --git a/src/actions/EditNewLine.ts b/src/actions/EditNewLine.ts index e17e3ec70d..3625fd0957 100644 --- a/src/actions/EditNewLine.ts +++ b/src/actions/EditNewLine.ts @@ -28,7 +28,7 @@ class EditNewLine implements Action { } private getCommand(target: Target) { - if (target.isNotebookCell) { + if (target.scopeType === "notebookCell") { if (this.isNotebookEditor(target.editor)) { return this.isAbove ? "notebook.cell.insertCodeCellAbove" diff --git a/src/processTargets/modifiers/SurroundingPairStage.ts b/src/processTargets/modifiers/SurroundingPairStage.ts index 0f9e753668..e637afe319 100644 --- a/src/processTargets/modifiers/SurroundingPairStage.ts +++ b/src/processTargets/modifiers/SurroundingPairStage.ts @@ -1,4 +1,3 @@ -import { Selection } from "vscode"; import { SurroundingPairModifier, Target } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; diff --git a/src/processTargets/modifiers/scopeTypeStages/ContainingScopeStage.ts b/src/processTargets/modifiers/scopeTypeStages/ContainingScopeStage.ts index d975b8449d..aa2b23cb42 100644 --- a/src/processTargets/modifiers/scopeTypeStages/ContainingScopeStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ContainingScopeStage.ts @@ -50,7 +50,7 @@ export default class implements ModifierStage { contentRange: scope.selection.selection, interiorRange: scope.context.interior, removalRange: scope.context.removalRange, - delimiter: scope.context.containingListDelimiter, + delimiter: scope.context.containingListDelimiter ?? "\n", boundary: scope.context.boundary, leadingDelimiterRange: scope.context.leadingDelimiterRange, trailingDelimiterRange: scope.context.trailingDelimiterRange, diff --git a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts index 3dff5688fc..db48e0ffdf 100644 --- a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts @@ -26,10 +26,7 @@ export default class implements ModifierStage { } } -export function getLineContext( - editor: TextEditor, - range: Range -): Partial { +export function getLineContext(editor: TextEditor, range: Range) { const { document } = editor; const { start, end } = range; diff --git a/src/processTargets/modifiers/scopeTypeStages/NotebookCellStage.ts b/src/processTargets/modifiers/scopeTypeStages/NotebookCellStage.ts index 87e974e189..834cd8b2a3 100644 --- a/src/processTargets/modifiers/scopeTypeStages/NotebookCellStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/NotebookCellStage.ts @@ -16,7 +16,7 @@ export default class implements ModifierStage { editor: target.editor, isReversed: target.isReversed, contentRange: target.contentRange, - isNotebookCell: true, + delimiter: "\n", }; } } diff --git a/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts index de59050492..5cdc544926 100644 --- a/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts @@ -27,10 +27,7 @@ export default class implements ModifierStage { } } -export function getTokenContext( - editor: TextEditor, - range: Range -): Partial { +export function getTokenContext(editor: TextEditor, range: Range) { const document = editor.document; const { start, end } = range; const endLine = document.lineAt(end); diff --git a/src/test/suite/fixtures/recorded/selectionTypes/chuckFile2.yml b/src/test/suite/fixtures/recorded/selectionTypes/chuckFile2.yml new file mode 100644 index 0000000000..7b919168d7 --- /dev/null +++ b/src/test/suite/fixtures/recorded/selectionTypes/chuckFile2.yml @@ -0,0 +1,31 @@ +languageId: plaintext +command: + spokenForm: chuck file + version: 2 + action: remove + targets: + - type: primitive + modifiers: + - {type: containingScope, scopeType: document} + usePrePhraseSnapshot: true +initialState: + documentContents: |2+ + + + foo + + bar + + selections: + - anchor: {line: 6, character: 0} + active: {line: 6, character: 0} + 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: containingScope, scopeType: document}]}] diff --git a/src/test/suite/fixtures/recorded/selectionTypes/takeFile.yml b/src/test/suite/fixtures/recorded/selectionTypes/takeFile.yml index 7d546f6ee1..4f843aff48 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/takeFile.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/takeFile.yml @@ -1,26 +1,37 @@ -languageId: typescript +languageId: plaintext command: - version: 1 spokenForm: take file + version: 2 action: setSelection targets: - - {type: primitive, selectionType: document} + - type: primitive + modifiers: + - {type: containingScope, scopeType: document} + usePrePhraseSnapshot: true initialState: - documentContents: | + documentContents: |2+ + + + foo + + bar - const value = "Hello world"; selections: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} + - anchor: {line: 6, character: 0} + active: {line: 6, character: 0} marks: {} finalState: - documentContents: | + documentContents: |2+ + + + foo + + bar - const value = "Hello world"; selections: - - anchor: {line: 0, character: 0} - active: {line: 2, character: 0} + - anchor: {line: 2, character: 4} + active: {line: 4, character: 7} thatMark: - - anchor: {line: 0, character: 0} - active: {line: 2, character: 0} -fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: document, position: contents, modifier: {type: identity}, insideOutsideType: inside}] + - anchor: {line: 2, character: 4} + active: {line: 4, character: 7} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: containingScope, scopeType: document}]}] diff --git a/src/testUtil/TestCaseRecorder.ts b/src/testUtil/TestCaseRecorder.ts index ed7f86dcbe..a582e7f6e5 100644 --- a/src/testUtil/TestCaseRecorder.ts +++ b/src/testUtil/TestCaseRecorder.ts @@ -289,7 +289,7 @@ export class TestCaseRecorder { if ( this.workspacePath == null || this.fixtureRoot == null || - this.workSpaceFolder !== "cursorless-vscode" + this.workSpaceFolder !== "cursorless" ) { throw new Error("Can't prompt for subdirectory"); } diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 68de519b2d..7b8fb2c9cb 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -243,11 +243,6 @@ export interface Target { */ isReversed: boolean; - /** - * If true this selection is part of a notebook cell - */ - isNotebookCell?: boolean; - /** * Is this a scope type other raw selection? */ @@ -310,4 +305,5 @@ export interface Target { export interface ScopeTypeTarget extends Target { scopeType: ScopeType; + delimiter: string; } From cda28acd7dd53621ec92a3fb1439857be5398de9 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 15:44:51 +0200 Subject: [PATCH 080/314] Added removal range on before and after positions --- src/processTargets/modifiers/PositionStage.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/processTargets/modifiers/PositionStage.ts b/src/processTargets/modifiers/PositionStage.ts index 39a8a7711c..2f8eea2785 100644 --- a/src/processTargets/modifiers/PositionStage.ts +++ b/src/processTargets/modifiers/PositionStage.ts @@ -28,7 +28,7 @@ export default class implements ModifierStage { ...common, contentRange: new Range(contentRange.start, contentRange.start), delimiter, - leadingDelimiterRange, + removalRange: leadingDelimiterRange, leadingDelimiterHighlightRange, }; @@ -37,7 +37,7 @@ export default class implements ModifierStage { ...common, contentRange: new Range(contentRange.end, contentRange.end), delimiter, - trailingDelimiterRange, + removalRange: trailingDelimiterRange, trailingDelimiterHighlightRange, }; From 0df5d75e3c7b390a86ca87cd2f1372fc3f3f7581 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 16:12:59 +0200 Subject: [PATCH 081/314] Added removal range to range target --- src/processTargets/processTargets.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index 1aec347615..9514dc2eaf 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -108,6 +108,14 @@ function processContinuousRangeTarget( activeTarget.contentRange )!; + const removalRange = unionRanges( + isForward, + excludeAnchor, + excludeActive, + anchorTarget.removalRange, + activeTarget.removalRange + ); + const interiorRange = unionRanges( isForward, excludeAnchor, @@ -131,6 +139,7 @@ function processContinuousRangeTarget( isReversed: !isForward, delimiter: anchorTarget.delimiter, contentRange, + removalRange, interiorRange, leadingDelimiterRange, trailingDelimiterRange, From 40d469f2b82ce9076769e57b0b6b36806f1e9a46 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 16:37:41 +0200 Subject: [PATCH 082/314] Fixed bug in removal range for range target --- src/processTargets/processTargets.ts | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index 9514dc2eaf..644aaa3bc6 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -108,20 +108,28 @@ function processContinuousRangeTarget( activeTarget.contentRange )!; - const removalRange = unionRanges( + const interiorRange = unionRanges( isForward, excludeAnchor, excludeActive, - anchorTarget.removalRange, - activeTarget.removalRange + anchorTarget.interiorRange, + activeTarget.interiorRange ); - const interiorRange = unionRanges( + const hasRemovalRange = + anchorTarget.removalRange != null || activeTarget.removalRange != null; + const anchorRemovalRange = hasRemovalRange + ? anchorTarget.removalRange ?? anchorTarget.contentRange + : undefined; + const activeRemovalRange = hasRemovalRange + ? activeTarget.removalRange ?? activeTarget.contentRange + : undefined; + const removalRange = unionRanges( isForward, excludeAnchor, excludeActive, - anchorTarget.interiorRange, - activeTarget.interiorRange + anchorRemovalRange, + activeRemovalRange ); const anchorContext = excludeAnchor ? undefined : anchorTarget; From 661a790a47198018b647944b77a3eca41d3bf1fc Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 17:42:12 +0200 Subject: [PATCH 083/314] A dead delimiter highlight to range target --- src/processTargets/processTargets.ts | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index 644aaa3bc6..63a2cef4e6 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -99,6 +99,8 @@ function processContinuousRangeTarget( isForward: boolean ): Target[] { const { excludeAnchor, excludeActive } = target; + const anchorContext = excludeAnchor ? undefined : anchorTarget; + const activeContext = excludeActive ? undefined : activeTarget; const contentRange = unionRanges( isForward, @@ -117,12 +119,12 @@ function processContinuousRangeTarget( ); const hasRemovalRange = - anchorTarget.removalRange != null || activeTarget.removalRange != null; + anchorContext?.removalRange != null || activeContext?.removalRange != null; const anchorRemovalRange = hasRemovalRange - ? anchorTarget.removalRange ?? anchorTarget.contentRange + ? anchorContext?.removalRange ?? anchorContext?.contentRange : undefined; const activeRemovalRange = hasRemovalRange - ? activeTarget.removalRange ?? activeTarget.contentRange + ? activeContext?.removalRange ?? activeContext?.contentRange : undefined; const removalRange = unionRanges( isForward, @@ -132,14 +134,18 @@ function processContinuousRangeTarget( activeRemovalRange ); - const anchorContext = excludeAnchor ? undefined : anchorTarget; - const activeContext = excludeActive ? undefined : activeTarget; const leadingDelimiterRange = isForward ? anchorContext?.leadingDelimiterRange : activeContext?.leadingDelimiterRange; + const leadingDelimiterHighlightRange = isForward + ? anchorContext?.leadingDelimiterHighlightRange + : activeContext?.leadingDelimiterHighlightRange; const trailingDelimiterRange = isForward ? activeContext?.trailingDelimiterRange : anchorContext?.trailingDelimiterRange; + const trailingDelimiterHighlightRange = isForward + ? activeContext?.trailingDelimiterHighlightRange + : anchorContext?.trailingDelimiterHighlightRange; return [ { @@ -150,7 +156,9 @@ function processContinuousRangeTarget( removalRange, interiorRange, leadingDelimiterRange, + leadingDelimiterHighlightRange, trailingDelimiterRange, + trailingDelimiterHighlightRange, }, ]; } From 691bb15cda065981577faeaa0aacc8dcc3cce3b5 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 18:42:55 +0200 Subject: [PATCH 084/314] Added token context to all marks --- src/processTargets/marks/CursorStage.ts | 22 ++++++---- .../marks/DecoratedSymbolStage.ts | 12 ++++-- src/processTargets/marks/LineNumberStage.ts | 5 ++- src/processTargets/marks/SourceStage.ts | 22 ++++++---- src/processTargets/marks/ThatStage.ts | 22 ++++++---- src/processTargets/modifiers/PositionStage.ts | 40 +++++++++++++------ .../modifiers/SurroundingPairStage.ts | 7 +++- .../modifiers/scopeTypeStages/RegexStage.ts | 2 +- .../modifiers/scopeTypeStages/TokenStage.ts | 22 ++++++---- 9 files changed, 101 insertions(+), 53 deletions(-) diff --git a/src/processTargets/marks/CursorStage.ts b/src/processTargets/marks/CursorStage.ts index 0de591c263..6cf2f94bbc 100644 --- a/src/processTargets/marks/CursorStage.ts +++ b/src/processTargets/marks/CursorStage.ts @@ -1,5 +1,5 @@ import { window } from "vscode"; -import { CursorMark, Target } from "../../typings/target.types"; +import { CursorMark, ScopeTypeTarget } from "../../typings/target.types"; import { isReversed } from "../../util/selectionUtils"; import { getTokenContext } from "../modifiers/scopeTypeStages/TokenStage"; import { MarkStage } from "../PipelineStages.types"; @@ -7,15 +7,21 @@ import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { constructor(private modifier: CursorMark) {} - run(): Target[] { + run(): ScopeTypeTarget[] { if (window.activeTextEditor == null) { return []; } - return window.activeTextEditor.selections.map((selection) => ({ - editor: window.activeTextEditor!, - isReversed: isReversed(selection), - contentRange: selection, - ...getTokenContext(window.activeTextEditor!, selection), - })); + return window.activeTextEditor.selections.map((selection) => { + const target = { + editor: window.activeTextEditor!, + isReversed: isReversed(selection), + contentRange: selection, + }; + return { + ...target, + ...getTokenContext(target), + scopeType: "token", + }; + }); } } diff --git a/src/processTargets/marks/DecoratedSymbolStage.ts b/src/processTargets/marks/DecoratedSymbolStage.ts index 3174593fbf..b9b833bffa 100644 --- a/src/processTargets/marks/DecoratedSymbolStage.ts +++ b/src/processTargets/marks/DecoratedSymbolStage.ts @@ -16,12 +16,16 @@ export default class implements MarkStage { `Couldn't find mark ${this.modifier.symbolColor} '${this.modifier.character}'` ); } + const target = { + editor: token.editor, + contentRange: token.range, + isReversed: false, + }; return [ { - editor: token.editor, - contentRange: token.range, - isReversed: false, - ...getTokenContext(token.editor, token.range), + ...target, + ...getTokenContext(target), + scopeType: "token", }, ]; } diff --git a/src/processTargets/marks/LineNumberStage.ts b/src/processTargets/marks/LineNumberStage.ts index 17268bf0b3..8ecddf9269 100644 --- a/src/processTargets/marks/LineNumberStage.ts +++ b/src/processTargets/marks/LineNumberStage.ts @@ -2,7 +2,7 @@ import { Range, TextEditor, window } from "vscode"; import { LineNumberMark, LineNumberPosition, - Target, + ScopeTypeTarget, } from "../../typings/target.types"; import { getLineContext } from "../modifiers/scopeTypeStages/LineStage"; import { MarkStage } from "../PipelineStages.types"; @@ -10,7 +10,7 @@ import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { constructor(private modifier: LineNumberMark) {} - run(): Target[] { + run(): ScopeTypeTarget[] { if (window.activeTextEditor == null) { return []; } @@ -27,6 +27,7 @@ export default class implements MarkStage { contentRange, isReversed: false, ...getLineContext(editor, contentRange), + scopeType: "line", }, ]; } diff --git a/src/processTargets/marks/SourceStage.ts b/src/processTargets/marks/SourceStage.ts index dd1b4b2504..096b3cb593 100644 --- a/src/processTargets/marks/SourceStage.ts +++ b/src/processTargets/marks/SourceStage.ts @@ -1,4 +1,4 @@ -import { SourceMark, Target } from "../../typings/target.types"; +import { ScopeTypeTarget, SourceMark } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { isReversed } from "../../util/selectionUtils"; import { getTokenContext } from "../modifiers/scopeTypeStages/TokenStage"; @@ -7,12 +7,18 @@ import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { constructor(private modifier: SourceMark) {} - run(context: ProcessedTargetsContext): Target[] { - return context.sourceMark.map((selection) => ({ - editor: selection.editor, - isReversed: isReversed(selection.selection), - contentRange: selection.selection, - ...getTokenContext(selection.editor, selection.selection), - })); + run(context: ProcessedTargetsContext): ScopeTypeTarget[] { + return context.sourceMark.map((selection) => { + const target = { + editor: selection.editor, + isReversed: isReversed(selection.selection), + contentRange: selection.selection, + }; + return { + ...target, + ...getTokenContext(target), + scopeType: "token", + }; + }); } } diff --git a/src/processTargets/marks/ThatStage.ts b/src/processTargets/marks/ThatStage.ts index e684839305..dbc6f1560a 100644 --- a/src/processTargets/marks/ThatStage.ts +++ b/src/processTargets/marks/ThatStage.ts @@ -1,4 +1,4 @@ -import { ThatMark, Target } from "../../typings/target.types"; +import { ScopeTypeTarget, ThatMark } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { isReversed } from "../../util/selectionUtils"; import { getTokenContext } from "../modifiers/scopeTypeStages/TokenStage"; @@ -7,12 +7,18 @@ import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { constructor(private modifier: ThatMark) {} - run(context: ProcessedTargetsContext): Target[] { - return context.thatMark.map((selection) => ({ - editor: selection.editor, - isReversed: isReversed(selection.selection), - contentRange: selection.selection, - ...getTokenContext(selection.editor, selection.selection), - })); + run(context: ProcessedTargetsContext): ScopeTypeTarget[] { + return context.thatMark.map((selection) => { + const target = { + editor: selection.editor, + isReversed: isReversed(selection.selection), + contentRange: selection.selection, + }; + return { + ...target, + ...getTokenContext(target), + scopeType: "token", + }; + }); } } diff --git a/src/processTargets/modifiers/PositionStage.ts b/src/processTargets/modifiers/PositionStage.ts index 2f8eea2785..37ab089b82 100644 --- a/src/processTargets/modifiers/PositionStage.ts +++ b/src/processTargets/modifiers/PositionStage.ts @@ -2,27 +2,43 @@ import { Range } from "vscode"; import { PositionModifier, Target } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; +import { getTokenContext } from "./scopeTypeStages/TokenStage"; export default class implements ModifierStage { constructor(private modifier: PositionModifier) {} run(context: ProcessedTargetsContext, target: Target): Target { - const { - contentRange, - delimiter, - leadingDelimiterRange, - leadingDelimiterHighlightRange, - trailingDelimiterRange, - trailingDelimiterHighlightRange, - } = target; - - const common = { + const { position } = this.modifier; + const { contentRange } = target; + + let common = { + position: this.modifier.position, editor: target.editor, isReversed: target.isReversed, - position: this.modifier.position, }; - switch (this.modifier.position) { + // TODO necessary for "chuck before [token] air" to get the correct token context + const tokenContext = + target.scopeType === "token" && + (position === "before" || position === "after") + ? getTokenContext({ ...common, contentRange }) + : undefined; + + const delimiter = tokenContext?.delimiter ?? target.delimiter; + const leadingDelimiterRange = + tokenContext?.leadingDelimiterRange ?? target.leadingDelimiterRange; + const trailingDelimiterRange = + tokenContext?.trailingDelimiterRange ?? target.trailingDelimiterRange; + const leadingDelimiterHighlightRange = + tokenContext?.leadingDelimiterRange == null + ? target.leadingDelimiterHighlightRange + : undefined; + const trailingDelimiterHighlightRange = + tokenContext?.trailingDelimiterRange == null + ? target.trailingDelimiterHighlightRange + : undefined; + + switch (position) { case "before": return { ...common, diff --git a/src/processTargets/modifiers/SurroundingPairStage.ts b/src/processTargets/modifiers/SurroundingPairStage.ts index e637afe319..0b55394500 100644 --- a/src/processTargets/modifiers/SurroundingPairStage.ts +++ b/src/processTargets/modifiers/SurroundingPairStage.ts @@ -31,14 +31,17 @@ export default class implements ModifierStage { throw new Error("Couldn't find containing pair"); } return pairs.map((pair) => { - const context = getTokenContext(target.editor, pair.selection.selection); - return { + const newTarget = { editor: target.editor, isReversed: target.isReversed, contentRange: pair.selection.selection, interiorRange: pair.context.interior, removalRange: pair.context.removalRange, boundary: pair.context.boundary, + }; + const context = getTokenContext(newTarget); + return { + ...newTarget, delimiter: pair.context.containingListDelimiter ?? context.delimiter, leadingDelimiterRange: pair.context.leadingDelimiterRange ?? context.leadingDelimiterRange, diff --git a/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts b/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts index 14ba57d6c7..29713d066d 100644 --- a/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts @@ -26,7 +26,7 @@ class RegexStage implements ModifierStage { editor, isReversed: target.isReversed, contentRange, - ...getTokenContext(target.editor, contentRange), + ...getTokenContext(target), }; } diff --git a/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts index 5cdc544926..660cbb3567 100644 --- a/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts @@ -22,14 +22,14 @@ export default class implements ModifierStage { editor: target.editor, isReversed: target.isReversed, contentRange, - ...getTokenContext(target.editor, target.contentRange), + ...getTokenContext(target), }; } } -export function getTokenContext(editor: TextEditor, range: Range) { - const document = editor.document; - const { start, end } = range; +export function getTokenContext(target: Target) { + const { document } = target.editor; + const { start, end } = target.contentRange; const endLine = document.lineAt(end); let leadingDelimiterRange, trailingDelimiterRange; @@ -58,10 +58,16 @@ export function getTokenContext(editor: TextEditor, range: Range) { ) : undefined; - const isInDelimitedList = - (leadingDelimiterRange != null || trailingDelimiterRange != null) && - (leadingDelimiterRange != null || start.character === 0) && - (trailingDelimiterRange != null || end.isEqual(endLine.range.end)); + let isInDelimitedList; + if (target.position == null) { + isInDelimitedList = + (leadingDelimiterRange != null || trailingDelimiterRange != null) && + (leadingDelimiterRange != null || start.character === 0) && + (trailingDelimiterRange != null || end.isEqual(endLine.range.end)); + } else { + isInDelimitedList = + leadingDelimiterRange != null || trailingDelimiterRange != null; + } return { delimiter: " ", From 045ff32962a5d3e45c7f91791f215e50207514e8 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 19:29:43 +0200 Subject: [PATCH 085/314] Added correct token context too regex --- .../modifiers/scopeTypeStages/ContainingScopeStage.ts | 2 +- src/processTargets/modifiers/scopeTypeStages/RegexStage.ts | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/processTargets/modifiers/scopeTypeStages/ContainingScopeStage.ts b/src/processTargets/modifiers/scopeTypeStages/ContainingScopeStage.ts index aa2b23cb42..e8312a1e9c 100644 --- a/src/processTargets/modifiers/scopeTypeStages/ContainingScopeStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ContainingScopeStage.ts @@ -28,7 +28,7 @@ export default class implements ModifierStage { this.modifier.type === "everyScope" ); const node: SyntaxNode | null = context.getNodeAtLocation( - new Location(target.editor.document.uri, target.contentRange.start) + new Location(target.editor.document.uri, target.contentRange) ); const scopeNodes = findNearestContainingAncestorNode(node, nodeMatcher, { diff --git a/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts b/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts index 29713d066d..349c9ce758 100644 --- a/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts @@ -21,12 +21,15 @@ class RegexStage implements ModifierStage { const start = this.getMatch(editor, target.contentRange.start).start; const end = this.getMatch(editor, target.contentRange.end).end; const contentRange = new Range(start, end); - return { + const newTarget = { scopeType: this.modifier.scopeType, editor, isReversed: target.isReversed, contentRange, - ...getTokenContext(target), + }; + return { + ...newTarget, + ...getTokenContext(newTarget), }; } From c47e6b5dd354478b1e0638666435c9af31a4dd22 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 19:52:55 +0200 Subject: [PATCH 086/314] Don't unifi ranges on content only removal --- src/actions/Remove.ts | 6 ++++-- .../modifiers/scopeTypeStages/ContainingScopeStage.ts | 9 +++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/actions/Remove.ts b/src/actions/Remove.ts index cda865edd3..8a002910f9 100644 --- a/src/actions/Remove.ts +++ b/src/actions/Remove.ts @@ -22,8 +22,10 @@ export default class Delete implements Action { [targets]: [Target[]], { showDecorations = true, contentOnly = false } = {} ): Promise { - // Unify overlapping targets. - targets = unifyTargets(targets); + // Unify overlapping targets because of overlapping leading and trailing delimiters. + if (!contentOnly) { + targets = unifyTargets(targets); + } if (showDecorations) { await displayPendingEditDecorations( diff --git a/src/processTargets/modifiers/scopeTypeStages/ContainingScopeStage.ts b/src/processTargets/modifiers/scopeTypeStages/ContainingScopeStage.ts index e8312a1e9c..01c60f3db9 100644 --- a/src/processTargets/modifiers/scopeTypeStages/ContainingScopeStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ContainingScopeStage.ts @@ -12,10 +12,7 @@ import { ProcessedTargetsContext, SelectionWithEditor, } from "../../../typings/Types"; -import { - isReversed, - selectionWithEditorFromRange, -} from "../../../util/selectionUtils"; +import { selectionWithEditorFromRange } from "../../../util/selectionUtils"; import { ModifierStage } from "../../PipelineStages.types"; export default class implements ModifierStage { @@ -45,8 +42,8 @@ export default class implements ModifierStage { return scopeNodes.map((scope) => ({ scopeType: this.modifier.scopeType, - editor: scope.selection.editor, - isReversed: isReversed(scope.selection.selection), + editor: target.editor, + isReversed: target.isReversed, contentRange: scope.selection.selection, interiorRange: scope.context.interior, removalRange: scope.context.removalRange, From 3c5fec45053c9f24758af87127710749b8eb7824 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 20:45:22 +0200 Subject: [PATCH 087/314] Update the test --- .../fixtures/recorded/surroundingPair/textual/takePairRound.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/suite/fixtures/recorded/surroundingPair/textual/takePairRound.yml b/src/test/suite/fixtures/recorded/surroundingPair/textual/takePairRound.yml index 61767e1f87..8eeb39647b 100644 --- a/src/test/suite/fixtures/recorded/surroundingPair/textual/takePairRound.yml +++ b/src/test/suite/fixtures/recorded/surroundingPair/textual/takePairRound.yml @@ -5,7 +5,7 @@ command: action: clearAndSetSelection targets: - type: primitive - modifier: {type: surroundingPair, delimiter: parentheses, delimiterInclusion: excludeInterior} + modifier: {type: surroundingPair, delimiter: parentheses} initialState: documentContents: () selections: From 16a3704915208746d483c625d1852798309385ad Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 21:00:19 +0200 Subject: [PATCH 088/314] Added feature to run single recorded test --- src/test/suite/index.ts | 4 +++- src/test/suite/recorded.test.ts | 3 ++- src/test/suite/runSingleRecorded.ts | 10 ++++++++++ src/test/util/getFixturePaths.ts | 11 +++++++++++ 4 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 src/test/suite/runSingleRecorded.ts diff --git a/src/test/suite/index.ts b/src/test/suite/index.ts index 2cb7d7d8b3..2aa55ad69c 100644 --- a/src/test/suite/index.ts +++ b/src/test/suite/index.ts @@ -1,6 +1,7 @@ import * as path from "path"; import * as Mocha from "mocha"; import * as glob from "glob"; +import { runSingleTest } from "./runSingleRecorded"; export function run(): Promise { // Create the mocha test @@ -12,7 +13,8 @@ export function run(): Promise { const testsRoot = path.resolve(__dirname, ".."); return new Promise((c, e) => { - glob("**/**.test.js", { cwd: testsRoot }, (err, files) => { + const pattern = runSingleTest() ? "**/recorded.test.js" : "**/**.test.js"; + glob(pattern, { cwd: testsRoot }, (err, files) => { if (err) { return e(err); } diff --git a/src/test/suite/recorded.test.ts b/src/test/suite/recorded.test.ts index ba366e2261..5f0730f023 100644 --- a/src/test/suite/recorded.test.ts +++ b/src/test/suite/recorded.test.ts @@ -24,6 +24,7 @@ import asyncSafety from "../util/asyncSafety"; import { ReadOnlyHatMap } from "../../core/IndividualHatMap"; import { openNewEditor } from "../openNewEditor"; import { getRecordedTestPaths } from "../util/getFixturePaths"; +import { runSingleTest } from "./runSingleRecorded"; function createPosition(position: PositionPlainObject) { return new vscode.Position(position.line, position.character); @@ -37,7 +38,7 @@ function createSelection(selection: SelectionPlainObject): vscode.Selection { suite("recorded test cases", async function () { this.timeout("100s"); - this.retries(5); + this.retries(runSingleTest() ? 0 : 5); teardown(() => { sinon.restore(); diff --git a/src/test/suite/runSingleRecorded.ts b/src/test/suite/runSingleRecorded.ts new file mode 100644 index 0000000000..d092380bbb --- /dev/null +++ b/src/test/suite/runSingleRecorded.ts @@ -0,0 +1,10 @@ +const filenameEnd = ""; +// const filenameEnd = "textual\\takePairRound.yml"; + +export function runSingleTest() { + return !!filenameEnd; +} + +export function getSingleTestFilename() { + return filenameEnd; +} diff --git a/src/test/util/getFixturePaths.ts b/src/test/util/getFixturePaths.ts index 3d51f33985..803535cfba 100644 --- a/src/test/util/getFixturePaths.ts +++ b/src/test/util/getFixturePaths.ts @@ -1,5 +1,9 @@ import * as path from "path"; import { walkFilesSync } from "../../testUtil/walkSync"; +import { + getSingleTestFilename, + runSingleTest, +} from "../suite/runSingleRecorded"; export function getFixturesPath() { return path.join(__dirname, "../../../src/test/suite/fixtures"); @@ -12,6 +16,13 @@ export function getFixturePath(fixturePath: string) { export function getRecordedTestPaths() { const directory = path.join(getFixturesPath(), "recorded"); + if (runSingleTest()) { + const test = walkFilesSync(directory).find((path) => + path.endsWith(getSingleTestFilename()) + ); + return test ? [test] : []; + } + return walkFilesSync(directory).filter( (path) => path.endsWith(".yml") || path.endsWith(".yaml") ); From 91c4116f9c60ce4d39394993091bda91247ed8bf Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 21:15:47 +0200 Subject: [PATCH 089/314] Updated tests --- .../recorded/surroundingPair/parseTreeParity/takePairDouble.yml | 2 +- .../recorded/surroundingPair/parseTreeParity/takePairRound.yml | 2 +- .../recorded/surroundingPair/textual/takePairDouble.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairDouble.yml b/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairDouble.yml index 4512d75e4d..7496c0978d 100644 --- a/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairDouble.yml +++ b/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairDouble.yml @@ -5,7 +5,7 @@ command: action: clearAndSetSelection targets: - type: primitive - modifier: {type: surroundingPair, delimiter: any, delimiterInclusion: excludeInterior} + modifier: {type: surroundingPair, delimiter: any} mark: {type: decoratedSymbol, symbolColor: default, character: '"'} initialState: documentContents: "\"\"" diff --git a/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairRound.yml b/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairRound.yml index 8368988817..b91e95600c 100644 --- a/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairRound.yml +++ b/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairRound.yml @@ -5,7 +5,7 @@ command: action: clearAndSetSelection targets: - type: primitive - modifier: {type: surroundingPair, delimiter: parentheses, delimiterInclusion: excludeInterior} + modifier: {type: surroundingPair, delimiter: parentheses} initialState: documentContents: () selections: diff --git a/src/test/suite/fixtures/recorded/surroundingPair/textual/takePairDouble.yml b/src/test/suite/fixtures/recorded/surroundingPair/textual/takePairDouble.yml index 00ae470728..08929808c1 100644 --- a/src/test/suite/fixtures/recorded/surroundingPair/textual/takePairDouble.yml +++ b/src/test/suite/fixtures/recorded/surroundingPair/textual/takePairDouble.yml @@ -5,7 +5,7 @@ command: action: clearAndSetSelection targets: - type: primitive - modifier: {type: surroundingPair, delimiter: any, delimiterInclusion: excludeInterior} + modifier: {type: surroundingPair, delimiter: any} mark: {type: decoratedSymbol, symbolColor: default, character: '"'} initialState: documentContents: "\"\"" From 880980d62d039b3904f334d37296d5f4bb78bd04 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 16 May 2022 21:51:47 +0200 Subject: [PATCH 090/314] Fallback on token context for containing scope --- .../scopeTypeStages/ContainingScopeStage.ts | 65 +++++++++++++++---- 1 file changed, 52 insertions(+), 13 deletions(-) diff --git a/src/processTargets/modifiers/scopeTypeStages/ContainingScopeStage.ts b/src/processTargets/modifiers/scopeTypeStages/ContainingScopeStage.ts index 01c60f3db9..a24bf744ce 100644 --- a/src/processTargets/modifiers/scopeTypeStages/ContainingScopeStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ContainingScopeStage.ts @@ -14,6 +14,7 @@ import { } from "../../../typings/Types"; import { selectionWithEditorFromRange } from "../../../util/selectionUtils"; import { ModifierStage } from "../../PipelineStages.types"; +import { getTokenContext } from "./TokenStage"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} @@ -40,22 +41,60 @@ export default class implements ModifierStage { throw new Error(`Couldn't find containing ${this.modifier.scopeType}`); } - return scopeNodes.map((scope) => ({ - scopeType: this.modifier.scopeType, - editor: target.editor, - isReversed: target.isReversed, - contentRange: scope.selection.selection, - interiorRange: scope.context.interior, - removalRange: scope.context.removalRange, - delimiter: scope.context.containingListDelimiter ?? "\n", - boundary: scope.context.boundary, - leadingDelimiterRange: scope.context.leadingDelimiterRange, - trailingDelimiterRange: scope.context.trailingDelimiterRange, - })); + // TODO Re enable when all the containing scopes have proper delimiters + // return scopeNodes.map((scope) => ({ + // scopeType: this.modifier.scopeType, + // editor: target.editor, + // isReversed: target.isReversed, + // contentRange: scope.selection.selection, + // interiorRange: scope.context.interior, + // removalRange: scope.context.removalRange, + // delimiter: scope.context.containingListDelimiter ?? "\n", + // boundary: scope.context.boundary, + // leadingDelimiterRange: scope.context.leadingDelimiterRange, + // trailingDelimiterRange: scope.context.trailingDelimiterRange, + // })); + + // For now fall back on token + return scopeNodes.map((scope) => { + const newTarget = { + scopeType: this.modifier.scopeType, + editor: target.editor, + isReversed: target.isReversed, + contentRange: scope.selection.selection, + interiorRange: scope.context.interior, + removalRange: scope.context.removalRange, + delimiter: scope.context.containingListDelimiter, + boundary: scope.context.boundary, + leadingDelimiterRange: scope.context.leadingDelimiterRange, + trailingDelimiterRange: scope.context.trailingDelimiterRange, + }; + const tokenContext = useTokenContext(newTarget) + ? getTokenContext(newTarget) + : undefined; + return { + ...newTarget, + delimiter: newTarget.delimiter ?? tokenContext?.delimiter ?? "\n", + leadingDelimiterRange: + newTarget.leadingDelimiterRange ?? + tokenContext?.leadingDelimiterRange, + trailingDelimiterRange: + newTarget.trailingDelimiterRange ?? + tokenContext?.trailingDelimiterRange, + }; + }); } } -export function findNearestContainingAncestorNode( +function useTokenContext(target: Target) { + return ( + target.delimiter == null && + target.leadingDelimiterRange == null && + target.trailingDelimiterRange == null + ); +} + +function findNearestContainingAncestorNode( startNode: SyntaxNode, nodeMatcher: NodeMatcher, selection: SelectionWithEditor From d34e2c8dd2fe2709f0ea4951ddfbeeb00c1240e7 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 17 May 2022 08:29:27 +0200 Subject: [PATCH 091/314] Updated target inference --- src/core/inferFullTargets.ts | 7 ++- src/processTargets/modifiers/PositionStage.ts | 16 +++---- .../modifiers/scopeTypeStages/TokenStage.ts | 47 ++++++++++++------- 3 files changed, 43 insertions(+), 27 deletions(-) diff --git a/src/core/inferFullTargets.ts b/src/core/inferFullTargets.ts index b4d5c4bbbc..d2c53a7783 100644 --- a/src/core/inferFullTargets.ts +++ b/src/core/inferFullTargets.ts @@ -124,10 +124,13 @@ function inferPrimitiveTarget( // TODO Is this really a good solution? // "bring line to after this" needs to inter line on second target + const modifierTypes = [ + ...new Set(modifiers.map((modifier) => modifier.type)), + ]; if ( previousModifiers != null && - modifiers.length === 1 && - modifiers[0].type === "position" + modifierTypes.length === 1 && + modifierTypes[0] === "position" ) { const containingScopeModifier = previousModifiers.find( (modifier) => modifier.type === "containingScope" diff --git a/src/processTargets/modifiers/PositionStage.ts b/src/processTargets/modifiers/PositionStage.ts index 37ab089b82..226ab491cd 100644 --- a/src/processTargets/modifiers/PositionStage.ts +++ b/src/processTargets/modifiers/PositionStage.ts @@ -2,7 +2,7 @@ import { Range } from "vscode"; import { PositionModifier, Target } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; -import { getTokenContext } from "./scopeTypeStages/TokenStage"; +import { getTokenContextUnsafe } from "./scopeTypeStages/TokenStage"; export default class implements ModifierStage { constructor(private modifier: PositionModifier) {} @@ -11,19 +11,19 @@ export default class implements ModifierStage { const { position } = this.modifier; const { contentRange } = target; - let common = { - position: this.modifier.position, - editor: target.editor, - isReversed: target.isReversed, - }; - // TODO necessary for "chuck before [token] air" to get the correct token context const tokenContext = target.scopeType === "token" && (position === "before" || position === "after") - ? getTokenContext({ ...common, contentRange }) + ? getTokenContextUnsafe(target) : undefined; + const common = { + position: this.modifier.position, + editor: target.editor, + isReversed: target.isReversed, + }; + const delimiter = tokenContext?.delimiter ?? target.delimiter; const leadingDelimiterRange = tokenContext?.leadingDelimiterRange ?? target.leadingDelimiterRange; diff --git a/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts index 660cbb3567..36c0c333bf 100644 --- a/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts @@ -27,7 +27,35 @@ export default class implements ModifierStage { } } +/** + * Get delimiter and any SAFE leading or trailing delimiter ranges + */ export function getTokenContext(target: Target) { + const { delimiter, leadingDelimiterRange, trailingDelimiterRange } = + getTokenContextUnsafe(target); + + const { start, end } = target.contentRange; + const endLine = target.editor.document.lineAt(end); + const isInDelimitedList = + (leadingDelimiterRange != null || trailingDelimiterRange != null) && + (leadingDelimiterRange != null || start.character === 0) && + (trailingDelimiterRange != null || end.isEqual(endLine.range.end)); + + return { + delimiter, + leadingDelimiterRange: isInDelimitedList + ? leadingDelimiterRange + : undefined, + trailingDelimiterRange: isInDelimitedList + ? trailingDelimiterRange + : undefined, + }; +} + +/** + * Get delimiter and ANY leading or trailing delimiter ranges + */ +export function getTokenContextUnsafe(target: Target) { const { document } = target.editor; const { start, end } = target.contentRange; const endLine = document.lineAt(end); @@ -58,25 +86,10 @@ export function getTokenContext(target: Target) { ) : undefined; - let isInDelimitedList; - if (target.position == null) { - isInDelimitedList = - (leadingDelimiterRange != null || trailingDelimiterRange != null) && - (leadingDelimiterRange != null || start.character === 0) && - (trailingDelimiterRange != null || end.isEqual(endLine.range.end)); - } else { - isInDelimitedList = - leadingDelimiterRange != null || trailingDelimiterRange != null; - } - return { delimiter: " ", - leadingDelimiterRange: isInDelimitedList - ? leadingDelimiterRange - : undefined, - trailingDelimiterRange: isInDelimitedList - ? trailingDelimiterRange - : undefined, + leadingDelimiterRange, + trailingDelimiterRange, }; } From 3d8fb7401774ff453b26ddd9c3676fc39ca72c0d Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 17 May 2022 11:33:37 +0200 Subject: [PATCH 092/314] general refactoring of removable ranges --- src/actions/EditNewLine.ts | 7 +- src/processTargets/marks/LineNumberStage.ts | 2 +- src/processTargets/modifiers/PositionStage.ts | 44 +++------ src/processTargets/modifiers/SubPieceStage.ts | 17 +++- .../modifiers/SurroundingPairStage.ts | 27 ++---- .../scopeTypeStages/ContainingScopeStage.ts | 62 ++----------- .../scopeTypeStages/DocumentStage.ts | 4 +- .../modifiers/scopeTypeStages/LineStage.ts | 32 ++++--- .../scopeTypeStages/ParagraphStage.ts | 34 +++++-- .../modifiers/scopeTypeStages/TokenStage.ts | 59 +++++------- ...ractSelectionFromSurroundingPairOffsets.ts | 2 +- src/processTargets/processTargets.ts | 31 +++---- src/typings/Types.ts | 2 +- src/typings/target.types.ts | 50 +++++----- src/util/targetUtils.ts | 93 ++++++++++++++++--- src/util/unifyRanges.ts | 10 +- 16 files changed, 243 insertions(+), 233 deletions(-) diff --git a/src/actions/EditNewLine.ts b/src/actions/EditNewLine.ts index 3625fd0957..afd24da0c9 100644 --- a/src/actions/EditNewLine.ts +++ b/src/actions/EditNewLine.ts @@ -13,9 +13,12 @@ class EditNewLine implements Action { targets.forEach((target) => { let { start, end } = target.contentRange; if (target.scopeType === "paragraph") { - if (this.isAbove && target.leadingDelimiterRange != null) { + if (this.isAbove && target.removal?.leadingDelimiterRange != null) { start = start.translate({ lineDelta: -1 }); - } else if (!this.isAbove && target.trailingDelimiterRange != null) { + } else if ( + !this.isAbove && + target.removal?.trailingDelimiterRange != null + ) { end = end.translate({ lineDelta: 1 }); } target.contentRange = new Range(start, end); diff --git a/src/processTargets/marks/LineNumberStage.ts b/src/processTargets/marks/LineNumberStage.ts index 8ecddf9269..577a864330 100644 --- a/src/processTargets/marks/LineNumberStage.ts +++ b/src/processTargets/marks/LineNumberStage.ts @@ -23,10 +23,10 @@ export default class implements MarkStage { ); return [ { + ...getLineContext(editor, contentRange), editor, contentRange, isReversed: false, - ...getLineContext(editor, contentRange), scopeType: "line", }, ]; diff --git a/src/processTargets/modifiers/PositionStage.ts b/src/processTargets/modifiers/PositionStage.ts index 226ab491cd..595222909b 100644 --- a/src/processTargets/modifiers/PositionStage.ts +++ b/src/processTargets/modifiers/PositionStage.ts @@ -2,50 +2,35 @@ import { Range } from "vscode"; import { PositionModifier, Target } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; -import { getTokenContextUnsafe } from "./scopeTypeStages/TokenStage"; export default class implements ModifierStage { constructor(private modifier: PositionModifier) {} run(context: ProcessedTargetsContext, target: Target): Target { const { position } = this.modifier; - const { contentRange } = target; - - // TODO necessary for "chuck before [token] air" to get the correct token context - const tokenContext = - target.scopeType === "token" && - (position === "before" || position === "after") - ? getTokenContextUnsafe(target) - : undefined; + const { + editor, + isReversed, + contentRange, + delimiter, + removal: { leadingDelimiterRange, trailingDelimiterRange } = {}, + } = target; const common = { position: this.modifier.position, - editor: target.editor, - isReversed: target.isReversed, + editor, + isReversed, }; - const delimiter = tokenContext?.delimiter ?? target.delimiter; - const leadingDelimiterRange = - tokenContext?.leadingDelimiterRange ?? target.leadingDelimiterRange; - const trailingDelimiterRange = - tokenContext?.trailingDelimiterRange ?? target.trailingDelimiterRange; - const leadingDelimiterHighlightRange = - tokenContext?.leadingDelimiterRange == null - ? target.leadingDelimiterHighlightRange - : undefined; - const trailingDelimiterHighlightRange = - tokenContext?.trailingDelimiterRange == null - ? target.trailingDelimiterHighlightRange - : undefined; - switch (position) { case "before": return { ...common, contentRange: new Range(contentRange.start, contentRange.start), delimiter, - removalRange: leadingDelimiterRange, - leadingDelimiterHighlightRange, + removal: { + range: leadingDelimiterRange, + }, }; case "after": @@ -53,8 +38,9 @@ export default class implements ModifierStage { ...common, contentRange: new Range(contentRange.end, contentRange.end), delimiter, - removalRange: trailingDelimiterRange, - trailingDelimiterHighlightRange, + removal: { + range: trailingDelimiterRange, + }, }; case "start": diff --git a/src/processTargets/modifiers/SubPieceStage.ts b/src/processTargets/modifiers/SubPieceStage.ts index 8c5ea8ad94..ac2aab85cf 100644 --- a/src/processTargets/modifiers/SubPieceStage.ts +++ b/src/processTargets/modifiers/SubPieceStage.ts @@ -3,6 +3,7 @@ import { Range } from "vscode"; import { SUBWORD_MATCHER } from "../../core/constants"; import { SubTokenModifier, Target } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; +import { createRemovalRange } from "../../util/targetUtils"; import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { @@ -56,6 +57,7 @@ export default class implements ModifierStage { undefined, isReversed ? pieces[activeIndex].start : pieces[activeIndex].end ); + const contentRange = new Range(anchor, active); const startIndex = Math.min(anchorIndex, activeIndex); const endIndex = Math.max(anchorIndex, activeIndex); @@ -90,13 +92,22 @@ export default class implements ModifierStage { ) : undefined; + const removalRange = createRemovalRange( + contentRange, + leadingDelimiterRange, + trailingDelimiterRange + ); + return { editor: target.editor, isReversed, - contentRange: new Range(anchor, active), + contentRange, delimiter: containingListDelimiter, - leadingDelimiterRange, - trailingDelimiterRange, + removal: { + range: removalRange, + leadingDelimiterRange, + trailingDelimiterRange, + }, }; } } diff --git a/src/processTargets/modifiers/SurroundingPairStage.ts b/src/processTargets/modifiers/SurroundingPairStage.ts index 0b55394500..8f5240fc32 100644 --- a/src/processTargets/modifiers/SurroundingPairStage.ts +++ b/src/processTargets/modifiers/SurroundingPairStage.ts @@ -1,7 +1,7 @@ import { SurroundingPairModifier, Target } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; +import { selectionWithEditorWithContextToTarget } from "../../util/targetUtils"; import { ModifierStage } from "../PipelineStages.types"; -import { getTokenContext } from "./scopeTypeStages/TokenStage"; import { processSurroundingPair } from "./surroundingPair"; /** @@ -27,27 +27,14 @@ export default class implements ModifierStage { target.contentRange, this.modifier ); + if (pairs == null) { throw new Error("Couldn't find containing pair"); } - return pairs.map((pair) => { - const newTarget = { - editor: target.editor, - isReversed: target.isReversed, - contentRange: pair.selection.selection, - interiorRange: pair.context.interior, - removalRange: pair.context.removalRange, - boundary: pair.context.boundary, - }; - const context = getTokenContext(newTarget); - return { - ...newTarget, - delimiter: pair.context.containingListDelimiter ?? context.delimiter, - leadingDelimiterRange: - pair.context.leadingDelimiterRange ?? context.leadingDelimiterRange, - trailingDelimiterRange: - pair.context.trailingDelimiterRange ?? context.trailingDelimiterRange, - }; - }); + + return pairs.map((pair) => ({ + ...selectionWithEditorWithContextToTarget(pair), + isReversed: target.isReversed, + })); } } diff --git a/src/processTargets/modifiers/scopeTypeStages/ContainingScopeStage.ts b/src/processTargets/modifiers/scopeTypeStages/ContainingScopeStage.ts index a24bf744ce..af7362c89f 100644 --- a/src/processTargets/modifiers/scopeTypeStages/ContainingScopeStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ContainingScopeStage.ts @@ -11,10 +11,11 @@ import { NodeMatcher, ProcessedTargetsContext, SelectionWithEditor, + SelectionWithEditorWithContext, } from "../../../typings/Types"; import { selectionWithEditorFromRange } from "../../../util/selectionUtils"; +import { selectionWithEditorWithContextToTarget } from "../../../util/targetUtils"; import { ModifierStage } from "../../PipelineStages.types"; -import { getTokenContext } from "./TokenStage"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} @@ -25,6 +26,7 @@ export default class implements ModifierStage { this.modifier.scopeType, this.modifier.type === "everyScope" ); + const node: SyntaxNode | null = context.getNodeAtLocation( new Location(target.editor.document.uri, target.contentRange) ); @@ -41,64 +43,20 @@ export default class implements ModifierStage { throw new Error(`Couldn't find containing ${this.modifier.scopeType}`); } - // TODO Re enable when all the containing scopes have proper delimiters - // return scopeNodes.map((scope) => ({ - // scopeType: this.modifier.scopeType, - // editor: target.editor, - // isReversed: target.isReversed, - // contentRange: scope.selection.selection, - // interiorRange: scope.context.interior, - // removalRange: scope.context.removalRange, - // delimiter: scope.context.containingListDelimiter ?? "\n", - // boundary: scope.context.boundary, - // leadingDelimiterRange: scope.context.leadingDelimiterRange, - // trailingDelimiterRange: scope.context.trailingDelimiterRange, - // })); - - // For now fall back on token - return scopeNodes.map((scope) => { - const newTarget = { - scopeType: this.modifier.scopeType, - editor: target.editor, - isReversed: target.isReversed, - contentRange: scope.selection.selection, - interiorRange: scope.context.interior, - removalRange: scope.context.removalRange, - delimiter: scope.context.containingListDelimiter, - boundary: scope.context.boundary, - leadingDelimiterRange: scope.context.leadingDelimiterRange, - trailingDelimiterRange: scope.context.trailingDelimiterRange, - }; - const tokenContext = useTokenContext(newTarget) - ? getTokenContext(newTarget) - : undefined; - return { - ...newTarget, - delimiter: newTarget.delimiter ?? tokenContext?.delimiter ?? "\n", - leadingDelimiterRange: - newTarget.leadingDelimiterRange ?? - tokenContext?.leadingDelimiterRange, - trailingDelimiterRange: - newTarget.trailingDelimiterRange ?? - tokenContext?.trailingDelimiterRange, - }; - }); + return scopeNodes.map((scope) => ({ + delimiter: "\n", + ...selectionWithEditorWithContextToTarget(scope), + scopeType: this.modifier.scopeType, + isReversed: target.isReversed, + })); } } -function useTokenContext(target: Target) { - return ( - target.delimiter == null && - target.leadingDelimiterRange == null && - target.trailingDelimiterRange == null - ); -} - function findNearestContainingAncestorNode( startNode: SyntaxNode, nodeMatcher: NodeMatcher, selection: SelectionWithEditor -) { +): SelectionWithEditorWithContext[] | null { let node: SyntaxNode | null = startNode; while (node != null) { const matches = nodeMatcher(selection, node); diff --git a/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts b/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts index aa6493fe3c..941a5e4b83 100644 --- a/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts @@ -20,7 +20,9 @@ export default class implements ModifierStage { isReversed: target.isReversed, delimiter: "\n", contentRange: getDocumentContentRange(target.editor), - removalRange: getDocumentRange(target.editor.document), + removal: { + range: getDocumentRange(target.editor.document), + }, }; } } diff --git a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts index db48e0ffdf..d6adf4d355 100644 --- a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts @@ -6,6 +6,7 @@ import { Target, } from "../../../typings/target.types"; import { ProcessedTargetsContext } from "../../../typings/Types"; +import { createRemovalRange } from "../../../util/targetUtils"; import { ModifierStage } from "../../PipelineStages.types"; export default class implements ModifierStage { @@ -30,36 +31,37 @@ export function getLineContext(editor: TextEditor, range: Range) { const { document } = editor; const { start, end } = range; - const removalRange = new Range( + const fullLineRange = new Range( new Position(start.line, 0), editor.document.lineAt(end).range.end ); const leadingDelimiterRange = start.line > 0 - ? new Range(document.lineAt(start.line - 1).range.end, removalRange.start) + ? new Range( + document.lineAt(start.line - 1).range.end, + fullLineRange.start + ) : undefined; const trailingDelimiterRange = end.line + 1 < document.lineCount - ? new Range(removalRange.end, new Position(end.line + 1, 0)) + ? new Range(fullLineRange.end, new Position(end.line + 1, 0)) : undefined; - const leadingDelimiterHighlightRange = new Range( - removalRange.start, - removalRange.start - ); - const trailingDelimiterHighlightRange = new Range( - removalRange.end, - removalRange.end + const removalRange = createRemovalRange( + fullLineRange, + leadingDelimiterRange, + trailingDelimiterRange ); return { delimiter: "\n", - removalRange, - leadingDelimiterHighlightRange, - trailingDelimiterHighlightRange, - leadingDelimiterRange, - trailingDelimiterRange, + removal: { + range: removalRange, + highlightRange: fullLineRange, + leadingDelimiterRange, + trailingDelimiterRange, + }, }; } diff --git a/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts b/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts index 644780bf47..01ea56cca3 100644 --- a/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts @@ -6,6 +6,7 @@ import { Target, } from "../../../typings/target.types"; import { ProcessedTargetsContext } from "../../../typings/Types"; +import { createRemovalRange } from "../../../util/targetUtils"; import { ModifierStage } from "../../PipelineStages.types"; import { fitRangeToLineContent } from "./LineStage"; @@ -48,7 +49,7 @@ export default class implements ModifierStage { new Range(start, end) ); - const removalRange = new Range( + const fullParagraphRange = new Range( new Position(start.line, 0), target.editor.document.lineAt(end).range.end ); @@ -58,39 +59,52 @@ export default class implements ModifierStage { const leadingDelimiterRange = getLeadingDelimiterRange( document, - removalRange, + fullParagraphRange, leadingLine?.range.end ); const trailingDelimiterRange = getTrailingDelimiterRange( document, - removalRange, + fullParagraphRange, trailingLine?.range.start ); const leadingDelimiterHighlightRange = getLeadingDelimiterRange( document, - removalRange, + fullParagraphRange, leadingLine ? new Position(leadingLine.range.end.line + 1, 0) : undefined ); const trailingDelimiterHighlightRange = getTrailingDelimiterRange( document, - removalRange, + fullParagraphRange, trailingLine ? document.lineAt(trailingLine.range.start.line - 1).range.end : undefined ); + const removalRange = createRemovalRange( + fullParagraphRange, + leadingDelimiterRange, + trailingDelimiterRange + ); + + const removalHighlightRange = createRemovalRange( + fullParagraphRange, + leadingDelimiterHighlightRange, + trailingDelimiterHighlightRange + ); + return { scopeType: this.modifier.scopeType, editor: target.editor, isReversed: target.isReversed, delimiter: "\n\n", contentRange, - removalRange, - leadingDelimiterRange, - trailingDelimiterRange, - leadingDelimiterHighlightRange, - trailingDelimiterHighlightRange, + removal: { + range: removalRange, + highlightRange: removalHighlightRange, + leadingDelimiterRange, + trailingDelimiterRange, + }, }; } } diff --git a/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts index 36c0c333bf..471601dd93 100644 --- a/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts @@ -7,6 +7,7 @@ import { } from "../../../typings/target.types"; import { ProcessedTargetsContext } from "../../../typings/Types"; import { getTokensInRange, PartialToken } from "../../../util/getTokensInRange"; +import { createRemovalRange } from "../../../util/targetUtils"; import { ModifierStage } from "../../PipelineStages.types"; export default class implements ModifierStage { @@ -17,54 +18,28 @@ export default class implements ModifierStage { target.editor, target.contentRange ); - return { + const newTarget = { scopeType: this.modifier.scopeType, editor: target.editor, isReversed: target.isReversed, contentRange, - ...getTokenContext(target), + }; + return { + ...newTarget, + ...getTokenContext(newTarget), }; } } -/** - * Get delimiter and any SAFE leading or trailing delimiter ranges - */ export function getTokenContext(target: Target) { - const { delimiter, leadingDelimiterRange, trailingDelimiterRange } = - getTokenContextUnsafe(target); - - const { start, end } = target.contentRange; - const endLine = target.editor.document.lineAt(end); - const isInDelimitedList = - (leadingDelimiterRange != null || trailingDelimiterRange != null) && - (leadingDelimiterRange != null || start.character === 0) && - (trailingDelimiterRange != null || end.isEqual(endLine.range.end)); - - return { - delimiter, - leadingDelimiterRange: isInDelimitedList - ? leadingDelimiterRange - : undefined, - trailingDelimiterRange: isInDelimitedList - ? trailingDelimiterRange - : undefined, - }; -} - -/** - * Get delimiter and ANY leading or trailing delimiter ranges - */ -export function getTokenContextUnsafe(target: Target) { const { document } = target.editor; const { start, end } = target.contentRange; const endLine = document.lineAt(end); - let leadingDelimiterRange, trailingDelimiterRange; const startLine = document.lineAt(start); const leadingText = startLine.text.slice(0, start.character); const leadingDelimiters = leadingText.match(/\s+$/); - leadingDelimiterRange = + const leadingDelimiterRange = leadingDelimiters != null ? new Range( start.line, @@ -76,7 +51,7 @@ export function getTokenContextUnsafe(target: Target) { const trailingText = endLine.text.slice(end.character); const trailingDelimiters = trailingText.match(/^\s+/); - trailingDelimiterRange = + const trailingDelimiterRange = trailingDelimiters != null ? new Range( end.line, @@ -86,10 +61,24 @@ export function getTokenContextUnsafe(target: Target) { ) : undefined; + const isInDelimitedList = + (leadingDelimiterRange != null || trailingDelimiterRange != null) && + (leadingDelimiterRange != null || start.character === 0) && + (trailingDelimiterRange != null || end.isEqual(endLine.range.end)); + + const removalRange = createRemovalRange( + target.contentRange, + isInDelimitedList ? leadingDelimiterRange : undefined, + isInDelimitedList ? trailingDelimiterRange : undefined + ); + return { delimiter: " ", - leadingDelimiterRange, - trailingDelimiterRange, + removal: { + range: removalRange, + leadingDelimiterRange, + trailingDelimiterRange, + }, }; } diff --git a/src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts b/src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts index 8b2b36e9f7..6fe22909fe 100644 --- a/src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts +++ b/src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts @@ -51,7 +51,7 @@ export function extractSelectionFromSurroundingPairOffsets( ), context: { boundary, - interior, + interiorRange: interior, }, }, ]; diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index 63a2cef4e6..ebc9ad4729 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -119,12 +119,13 @@ function processContinuousRangeTarget( ); const hasRemovalRange = - anchorContext?.removalRange != null || activeContext?.removalRange != null; + anchorContext?.removal?.range != null || + activeContext?.removal?.range != null; const anchorRemovalRange = hasRemovalRange - ? anchorContext?.removalRange ?? anchorContext?.contentRange + ? anchorContext?.removal?.range ?? anchorContext?.contentRange : undefined; const activeRemovalRange = hasRemovalRange - ? activeContext?.removalRange ?? activeContext?.contentRange + ? activeContext?.removal?.range ?? activeContext?.contentRange : undefined; const removalRange = unionRanges( isForward, @@ -135,17 +136,11 @@ function processContinuousRangeTarget( ); const leadingDelimiterRange = isForward - ? anchorContext?.leadingDelimiterRange - : activeContext?.leadingDelimiterRange; - const leadingDelimiterHighlightRange = isForward - ? anchorContext?.leadingDelimiterHighlightRange - : activeContext?.leadingDelimiterHighlightRange; + ? anchorContext?.removal?.leadingDelimiterRange + : activeContext?.removal?.leadingDelimiterRange; const trailingDelimiterRange = isForward - ? activeContext?.trailingDelimiterRange - : anchorContext?.trailingDelimiterRange; - const trailingDelimiterHighlightRange = isForward - ? activeContext?.trailingDelimiterHighlightRange - : anchorContext?.trailingDelimiterHighlightRange; + ? activeContext?.removal?.trailingDelimiterRange + : anchorContext?.removal?.trailingDelimiterRange; return [ { @@ -153,12 +148,12 @@ function processContinuousRangeTarget( isReversed: !isForward, delimiter: anchorTarget.delimiter, contentRange, - removalRange, interiorRange, - leadingDelimiterRange, - leadingDelimiterHighlightRange, - trailingDelimiterRange, - trailingDelimiterHighlightRange, + removal: { + range: removalRange, + leadingDelimiterRange, + trailingDelimiterRange, + }, }, ]; } diff --git a/src/typings/Types.ts b/src/typings/Types.ts index 5798107a5b..ed7e9fd5f5 100644 --- a/src/typings/Types.ts +++ b/src/typings/Types.ts @@ -70,7 +70,7 @@ export interface SelectionContext { * surrounding pair this would exclude the opening and closing delimiter. For an if * statement this would be the statements in the body. */ - interior?: vscode.Range; + interiorRange?: vscode.Range; } export interface ActionPreferences { diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 7b8fb2c9cb..d6794bcb04 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -270,37 +270,37 @@ export interface Target { */ interiorRange?: Range; - /** - * The range that needs to be removed - */ - removalRange?: Range; - - /** - * The range of the delimiter before the content selection - */ - leadingDelimiterRange?: Range; - - /** - * The range of the delimiter after the content selection - */ - trailingDelimiterRange?: Range; - - /** - * The range of the highlight for the leading delimiter - */ - leadingDelimiterHighlightRange?: Range; - - /** - * The range of the highlight for the trailing delimiter - */ - trailingDelimiterHighlightRange?: Range; - /** * Represents the boundary ranges of this selection. For example, for a * surrounding pair this would be the opening and closing delimiter. For an if * statement this would be the line of the guard as well as the closing brace. */ boundary?: Range[]; + + /** + * Related to removal + */ + removal?: { + /** + * The range that needs to be removed + */ + range?: Range; + + /** + * The range that needs to be highlighted on removal + */ + highlightRange?: Range; + + /** + * The range of the delimiter before the content selection + */ + leadingDelimiterRange?: Range; + + /** + * The range of the delimiter after the content selection + */ + trailingDelimiterRange?: Range; + }; } export interface ScopeTypeTarget extends Target { diff --git a/src/util/targetUtils.ts b/src/util/targetUtils.ts index e8938f98db..c5eec7be41 100644 --- a/src/util/targetUtils.ts +++ b/src/util/targetUtils.ts @@ -1,8 +1,14 @@ import { zip } from "lodash"; import { Range, Selection, TextEditor } from "vscode"; +import { getTokenContext } from "../processTargets/modifiers/scopeTypeStages/TokenStage"; import { Target } from "../typings/target.types"; -import { SelectionWithEditor } from "../typings/Types"; +import { + SelectionContext, + SelectionWithEditor, + SelectionWithEditorWithContext, +} from "../typings/Types"; import { groupBy } from "./itertools"; +import { isReversed } from "./selectionUtils"; export function ensureSingleEditor(targets: Target[]) { if (targets.length === 0) { @@ -116,24 +122,26 @@ export function createThatMark( } export function getRemovalRange(target: Target) { - const removalRange = target.removalRange ?? target.contentRange; - const delimiterRange = - target.trailingDelimiterRange ?? target.leadingDelimiterRange; + return target.removal?.range ?? target.contentRange; +} + +export function createRemovalRange( + contentRange: Range, + leadingDelimiterRange?: Range, + trailingDelimiterRange?: Range +) { + const delimiterRange = trailingDelimiterRange ?? leadingDelimiterRange; return delimiterRange != null - ? removalRange.union(delimiterRange) - : removalRange; + ? contentRange.union(delimiterRange) + : contentRange; } export function getRemovalHighlightRange(target: Target) { - const removalRange = target.removalRange ?? target.contentRange; - const delimiterRange = - target.trailingDelimiterHighlightRange ?? - target.trailingDelimiterRange ?? - target.leadingDelimiterHighlightRange ?? - target.leadingDelimiterRange; - return delimiterRange != null - ? removalRange.union(delimiterRange) - : removalRange; + return ( + target.removal?.highlightRange ?? + target.removal?.range ?? + target.contentRange + ); } /** Possibly add delimiter for positions before/after */ @@ -159,3 +167,58 @@ export function isLineScopeType(target: Target) { return false; } } + +export function selectionWithEditorWithContextToTarget( + selection: SelectionWithEditorWithContext +): Target { + // TODO Only use giving context in the future when all the containing scopes have proper delimiters. + // For now fall back on token context + const { context } = selection; + const { containingListDelimiter, interiorRange, boundary } = context; + const contentRange = selection.selection.selection; + const newTarget = { + editor: selection.selection.editor, + isReversed: isReversed(contentRange), + contentRange, + interiorRange, + boundary, + }; + + const tokenContext = useTokenContext(selection.context) + ? getTokenContext(newTarget) + : undefined; + const leadingDelimiterRange = + context.leadingDelimiterRange ?? + tokenContext?.removal.leadingDelimiterRange; + const trailingDelimiterRange = + context.trailingDelimiterRange ?? + tokenContext?.removal.trailingDelimiterRange; + const removalRange = + context.removalRange ?? + tokenContext?.removal?.range ?? + createRemovalRange( + contentRange, + leadingDelimiterRange, + trailingDelimiterRange + ); + const delimiter = tokenContext?.delimiter ?? containingListDelimiter ?? "\n"; + + return { + ...newTarget, + delimiter, + removal: { + range: removalRange, + leadingDelimiterRange, + trailingDelimiterRange, + }, + }; +} + +function useTokenContext(context: SelectionContext) { + return ( + context.containingListDelimiter == null && + context.removalRange == null && + context.leadingDelimiterRange == null && + context.trailingDelimiterRange == null + ); +} diff --git a/src/util/unifyRanges.ts b/src/util/unifyRanges.ts index 780e4f3edb..ff252967b4 100644 --- a/src/util/unifyRanges.ts +++ b/src/util/unifyRanges.ts @@ -96,10 +96,10 @@ function mergeTargets(targets: Target[]): Target { getContentRange(first).start, getContentRange(last).end ), - leadingDelimiterRange: first.leadingDelimiterRange, - leadingDelimiterHighlightRange: first.leadingDelimiterHighlightRange, - trailingDelimiterRange: last.trailingDelimiterRange, - trailingDelimiterHighlightRange: last.trailingDelimiterHighlightRange, + removal: { + leadingDelimiterRange: first.removal?.leadingDelimiterRange, + trailingDelimiterRange: last.removal?.trailingDelimiterRange, + }, }; } @@ -108,5 +108,5 @@ function intersects(targetA: Target, targetB: Target) { } function getContentRange(target: Target) { - return target.removalRange ?? target.contentRange; + return target.removal?.range ?? target.contentRange; } From 7ce940b6fae7b13ccc778668612f781f2ebd9d5d Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 17 May 2022 11:47:40 +0200 Subject: [PATCH 093/314] Updated unify removal targets --- src/actions/BringMoveSwap.ts | 4 ++-- src/actions/Remove.ts | 4 ++-- src/util/targetUtils.ts | 12 ++++-------- src/util/unifyRanges.ts | 25 ++++++++++++++----------- 4 files changed, 22 insertions(+), 23 deletions(-) diff --git a/src/actions/BringMoveSwap.ts b/src/actions/BringMoveSwap.ts index 46b39abed2..2ea73a20b8 100644 --- a/src/actions/BringMoveSwap.ts +++ b/src/actions/BringMoveSwap.ts @@ -15,7 +15,7 @@ import { maybeAddDelimiter, runForEachEditor, } from "../util/targetUtils"; -import { unifyTargets } from "../util/unifyRanges"; +import { unifyRemovalTargets } from "../util/unifyRanges"; import { Action, ActionReturnValue } from "./actions.types"; type ActionType = "bring" | "move" | "swap"; @@ -149,7 +149,7 @@ class BringMoveSwap implements Action { if (this.type === "move") { // Unify overlapping targets. - unifyTargets(usedSources).forEach((source) => { + unifyRemovalTargets(usedSources).forEach((source) => { results.push({ range: getRemovalRange(source), text: "", diff --git a/src/actions/Remove.ts b/src/actions/Remove.ts index 8a002910f9..a2d0b59c0c 100644 --- a/src/actions/Remove.ts +++ b/src/actions/Remove.ts @@ -10,7 +10,7 @@ import { getRemovalRange, runOnTargetsForEachEditor, } from "../util/targetUtils"; -import { unifyTargets } from "../util/unifyRanges"; +import { unifyRemovalTargets } from "../util/unifyRanges"; import { Action, ActionReturnValue } from "./actions.types"; export default class Delete implements Action { @@ -24,7 +24,7 @@ export default class Delete implements Action { ): Promise { // Unify overlapping targets because of overlapping leading and trailing delimiters. if (!contentOnly) { - targets = unifyTargets(targets); + targets = unifyRemovalTargets(targets); } if (showDecorations) { diff --git a/src/util/targetUtils.ts b/src/util/targetUtils.ts index c5eec7be41..46915a62c7 100644 --- a/src/util/targetUtils.ts +++ b/src/util/targetUtils.ts @@ -125,6 +125,10 @@ export function getRemovalRange(target: Target) { return target.removal?.range ?? target.contentRange; } +export function getRemovalHighlightRange(target: Target) { + return target.removal?.highlightRange ?? getRemovalRange(target); +} + export function createRemovalRange( contentRange: Range, leadingDelimiterRange?: Range, @@ -136,14 +140,6 @@ export function createRemovalRange( : contentRange; } -export function getRemovalHighlightRange(target: Target) { - return ( - target.removal?.highlightRange ?? - target.removal?.range ?? - target.contentRange - ); -} - /** Possibly add delimiter for positions before/after */ export function maybeAddDelimiter(text: string, target: Target) { if (target.delimiter != null) { diff --git a/src/util/unifyRanges.ts b/src/util/unifyRanges.ts index ff252967b4..cfa994325f 100644 --- a/src/util/unifyRanges.ts +++ b/src/util/unifyRanges.ts @@ -1,6 +1,10 @@ import { Range } from "vscode"; import { Target } from "../typings/target.types"; -import { getRemovalRange, groupTargetsForEachEditor } from "./targetUtils"; +import { + createRemovalRange, + getRemovalRange, + groupTargetsForEachEditor, +} from "./targetUtils"; /** Unifies overlapping/intersecting ranges */ export default function unifyRanges(ranges: Range[]): Range[] { @@ -40,7 +44,7 @@ function unifyRangesOnePass(ranges: Range[]): [Range[], boolean] { * FIXME This code probably needs to update once we have objected oriented targets * https://github.com/cursorless-dev/cursorless/issues/210 */ -export function unifyTargets(targets: Target[]): Target[] { +export function unifyRemovalTargets(targets: Target[]): Target[] { if (targets.length < 2) { return targets; } @@ -89,16 +93,19 @@ function mergeTargets(targets: Target[]): Target { } const first = targets[0]; const last = targets[targets.length - 1]; + const leadingDelimiterRange = first.removal?.leadingDelimiterRange; + const trailingDelimiterRange = last.removal?.trailingDelimiterRange; return { editor: first.editor, isReversed: first.isReversed, - contentRange: new Range( - getContentRange(first).start, - getContentRange(last).end + contentRange: createRemovalRange( + new Range(getRemovalRange(first).start, getRemovalRange(last).end), + leadingDelimiterRange, + trailingDelimiterRange ), removal: { - leadingDelimiterRange: first.removal?.leadingDelimiterRange, - trailingDelimiterRange: last.removal?.trailingDelimiterRange, + leadingDelimiterRange, + trailingDelimiterRange, }, }; } @@ -106,7 +113,3 @@ function mergeTargets(targets: Target[]): Target { function intersects(targetA: Target, targetB: Target) { return !!getRemovalRange(targetA).intersection(getRemovalRange(targetB)); } - -function getContentRange(target: Target) { - return target.removal?.range ?? target.contentRange; -} From fcec5b09fda47b24a106ae6a39ff154ac7808894 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 17 May 2022 11:53:59 +0200 Subject: [PATCH 094/314] Fixed that mark bug on set selection --- src/actions/SetSelection.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/actions/SetSelection.ts b/src/actions/SetSelection.ts index a0b75882a2..f40a728bdc 100644 --- a/src/actions/SetSelection.ts +++ b/src/actions/SetSelection.ts @@ -21,9 +21,9 @@ export class SetSelection implements Action { await setSelectionsAndFocusEditor(editor, selections); return { - thatMark: selections.map((selection) => ({ + thatMark: targets.map((target) => ({ editor, - selection, + selection: getContentSelection(target), })), }; } From 2b489bbda23ea1a6dbd38d97c05f598868b1b5af Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 17 May 2022 12:13:23 +0200 Subject: [PATCH 095/314] Fixed is reverse bug on vertical range targets --- 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 ebc9ad4729..0e93d7b6b3 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -203,7 +203,7 @@ function processVerticalRangeTarget( for (let i = anchorLine; true; i += delta) { results.push({ editor: anchorTarget.editor, - isReversed: !isForward, + isReversed: activeTarget.isReversed, delimiter: anchorTarget.delimiter, contentRange: new Range( i, From 204dff1e835a38379cc52739459a37c9ab7b59a3 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 17 May 2022 12:19:43 +0200 Subject: [PATCH 096/314] Fixed is reverse bug on vertical range targets --- 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 0e93d7b6b3..afc7c0f7ed 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -203,7 +203,7 @@ function processVerticalRangeTarget( for (let i = anchorLine; true; i += delta) { results.push({ editor: anchorTarget.editor, - isReversed: activeTarget.isReversed, + isReversed: anchorTarget.isReversed, delimiter: anchorTarget.delimiter, contentRange: new Range( i, From db64b726341c51f913ba3548e6fa9f0c3b66cf64 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 17 May 2022 13:09:06 +0200 Subject: [PATCH 097/314] Set empty delimiter on end of and start of positions --- src/actions/SetSelection.ts | 13 +++++++------ src/processTargets/modifiers/PositionStage.ts | 2 ++ .../scopeTypeStages/ContainingScopeStage.ts | 2 +- src/util/targetUtils.ts | 4 +--- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/actions/SetSelection.ts b/src/actions/SetSelection.ts index f40a728bdc..5a1c033a96 100644 --- a/src/actions/SetSelection.ts +++ b/src/actions/SetSelection.ts @@ -1,8 +1,12 @@ -import { ensureSingleEditor, getContentSelection } from "../util/targetUtils"; import { Selection } from "vscode"; -import { setSelectionsAndFocusEditor } from "../util/setSelectionsAndFocusEditor"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; +import { setSelectionsAndFocusEditor } from "../util/setSelectionsAndFocusEditor"; +import { + createThatMark, + ensureSingleEditor, + getContentSelection, +} from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; export class SetSelection implements Action { @@ -21,10 +25,7 @@ export class SetSelection implements Action { await setSelectionsAndFocusEditor(editor, selections); return { - thatMark: targets.map((target) => ({ - editor, - selection: getContentSelection(target), - })), + thatMark: createThatMark(targets), }; } } diff --git a/src/processTargets/modifiers/PositionStage.ts b/src/processTargets/modifiers/PositionStage.ts index 595222909b..e5aab6294d 100644 --- a/src/processTargets/modifiers/PositionStage.ts +++ b/src/processTargets/modifiers/PositionStage.ts @@ -47,12 +47,14 @@ export default class implements ModifierStage { return { ...common, contentRange: new Range(contentRange.start, contentRange.start), + delimiter: "", }; case "end": return { ...common, contentRange: new Range(contentRange.end, contentRange.end), + delimiter: "", }; } } diff --git a/src/processTargets/modifiers/scopeTypeStages/ContainingScopeStage.ts b/src/processTargets/modifiers/scopeTypeStages/ContainingScopeStage.ts index af7362c89f..a9561420f4 100644 --- a/src/processTargets/modifiers/scopeTypeStages/ContainingScopeStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ContainingScopeStage.ts @@ -44,9 +44,9 @@ export default class implements ModifierStage { } return scopeNodes.map((scope) => ({ + scopeType: this.modifier.scopeType, delimiter: "\n", ...selectionWithEditorWithContextToTarget(scope), - scopeType: this.modifier.scopeType, isReversed: target.isReversed, })); } diff --git a/src/util/targetUtils.ts b/src/util/targetUtils.ts index 46915a62c7..befe943c7d 100644 --- a/src/util/targetUtils.ts +++ b/src/util/targetUtils.ts @@ -115,9 +115,7 @@ export function createThatMark( } return targets.map((target) => ({ editor: target!.editor, - selection: target?.isReversed - ? new Selection(target.contentRange.end, target.contentRange.start) - : new Selection(target.contentRange.start, target.contentRange.end), + selection: getContentSelection(target), })); } From a5f311fe073f1ea06de8d01f789c5d673c0d34e7 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 17 May 2022 13:42:45 +0200 Subject: [PATCH 098/314] Updated test --- src/processTargets/modifiers/PositionStage.ts | 2 +- .../hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhale.yml | 4 +--- src/test/suite/runSingleRecorded.ts | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/processTargets/modifiers/PositionStage.ts b/src/processTargets/modifiers/PositionStage.ts index e5aab6294d..8fad6314e4 100644 --- a/src/processTargets/modifiers/PositionStage.ts +++ b/src/processTargets/modifiers/PositionStage.ts @@ -47,7 +47,7 @@ export default class implements ModifierStage { return { ...common, contentRange: new Range(contentRange.start, contentRange.start), - delimiter: "", + delimiter: "", // This it NOT a raw target. Joining with this should be done on empty delimiter. }; case "end": diff --git a/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhale.yml b/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhale.yml index 784ab6dbb6..2f60b6a671 100644 --- a/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhale.yml +++ b/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhale.yml @@ -50,12 +50,10 @@ finalState: end: {line: 0, character: 5} default.w: start: {line: 0, character: 7} - end: {line: 0, character: 18} + end: {line: 0, character: 12} thatMark: - anchor: {line: 0, character: 12} active: {line: 0, character: 18} - - anchor: {line: 0, character: 12} - active: {line: 0, character: 18} sourceMark: - anchor: {line: 0, character: 5} active: {line: 0, character: 6} diff --git a/src/test/suite/runSingleRecorded.ts b/src/test/suite/runSingleRecorded.ts index d092380bbb..3c9f1ff649 100644 --- a/src/test/suite/runSingleRecorded.ts +++ b/src/test/suite/runSingleRecorded.ts @@ -1,5 +1,5 @@ -const filenameEnd = ""; // const filenameEnd = "textual\\takePairRound.yml"; +const filenameEnd = ""; export function runSingleTest() { return !!filenameEnd; From ca4e6a2b6c4cce2808fa415f37b900c4137ff412 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 17 May 2022 14:00:24 +0200 Subject: [PATCH 099/314] Fixed last tests --- src/processTargets/processTargets.ts | 1 + .../bringHarpAndPointToEndOfThisAndEndOfWhaleTakeWhale.yml | 2 -- .../bringPointAndHarpToEndOfThisAndEndOfWhaleTakeWhale.yml | 4 +--- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index afc7c0f7ed..f9f986dd8c 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -205,6 +205,7 @@ function processVerticalRangeTarget( editor: anchorTarget.editor, isReversed: anchorTarget.isReversed, delimiter: anchorTarget.delimiter, + position: anchorTarget.position, contentRange: new Range( i, anchorTarget.contentRange.start.character, diff --git a/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToEndOfThisAndEndOfWhaleTakeWhale.yml b/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToEndOfThisAndEndOfWhaleTakeWhale.yml index 47adf5fb01..ba8dfd6fb6 100644 --- a/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToEndOfThisAndEndOfWhaleTakeWhale.yml +++ b/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToEndOfThisAndEndOfWhaleTakeWhale.yml @@ -54,8 +54,6 @@ finalState: thatMark: - anchor: {line: 0, character: 12} active: {line: 0, character: 18} - - anchor: {line: 0, character: 12} - active: {line: 0, character: 18} sourceMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 5} diff --git a/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhaleTakeWhale.yml b/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhaleTakeWhale.yml index a572792994..3d50804e9d 100644 --- a/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhaleTakeWhale.yml +++ b/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhaleTakeWhale.yml @@ -50,12 +50,10 @@ finalState: end: {line: 0, character: 5} default.w: start: {line: 0, character: 7} - end: {line: 0, character: 18} + end: {line: 0, character: 12} thatMark: - anchor: {line: 0, character: 12} active: {line: 0, character: 18} - - anchor: {line: 0, character: 12} - active: {line: 0, character: 18} sourceMark: - anchor: {line: 0, character: 5} active: {line: 0, character: 6} From e59fc47881cfeaf78567c7f88d693b7cb5f03fcf Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 17 May 2022 14:04:35 +0200 Subject: [PATCH 100/314] Added description to run single recorded test --- src/test/suite/index.ts | 2 +- src/test/suite/recorded.test.ts | 2 +- src/test/suite/runSingleRecorded.ts | 10 ---------- src/test/suite/runSingleRecordedTest.ts | 16 ++++++++++++++++ src/test/util/getFixturePaths.ts | 2 +- 5 files changed, 19 insertions(+), 13 deletions(-) delete mode 100644 src/test/suite/runSingleRecorded.ts create mode 100644 src/test/suite/runSingleRecordedTest.ts diff --git a/src/test/suite/index.ts b/src/test/suite/index.ts index 2aa55ad69c..11d2d54ac0 100644 --- a/src/test/suite/index.ts +++ b/src/test/suite/index.ts @@ -1,7 +1,7 @@ import * as path from "path"; import * as Mocha from "mocha"; import * as glob from "glob"; -import { runSingleTest } from "./runSingleRecorded"; +import { runSingleTest } from "./runSingleRecordedTest"; export function run(): Promise { // Create the mocha test diff --git a/src/test/suite/recorded.test.ts b/src/test/suite/recorded.test.ts index 5f0730f023..7e0bb6e351 100644 --- a/src/test/suite/recorded.test.ts +++ b/src/test/suite/recorded.test.ts @@ -24,7 +24,7 @@ import asyncSafety from "../util/asyncSafety"; import { ReadOnlyHatMap } from "../../core/IndividualHatMap"; import { openNewEditor } from "../openNewEditor"; import { getRecordedTestPaths } from "../util/getFixturePaths"; -import { runSingleTest } from "./runSingleRecorded"; +import { runSingleTest } from "./runSingleRecordedTest"; function createPosition(position: PositionPlainObject) { return new vscode.Position(position.line, position.character); diff --git a/src/test/suite/runSingleRecorded.ts b/src/test/suite/runSingleRecorded.ts deleted file mode 100644 index 3c9f1ff649..0000000000 --- a/src/test/suite/runSingleRecorded.ts +++ /dev/null @@ -1,10 +0,0 @@ -// const filenameEnd = "textual\\takePairRound.yml"; -const filenameEnd = ""; - -export function runSingleTest() { - return !!filenameEnd; -} - -export function getSingleTestFilename() { - return filenameEnd; -} diff --git a/src/test/suite/runSingleRecordedTest.ts b/src/test/suite/runSingleRecordedTest.ts new file mode 100644 index 0000000000..f9ea62d9df --- /dev/null +++ b/src/test/suite/runSingleRecordedTest.ts @@ -0,0 +1,16 @@ +/** + * Add the file path ending of a recorded test and ONLY that one will run + */ + +// example: +// const filenameEnd = "textual/takePairRound.yml"; + +const filenameEnd = ""; + +export function runSingleTest() { + return !!filenameEnd; +} + +export function getSingleTestFilename(): string { + return filenameEnd; +} diff --git a/src/test/util/getFixturePaths.ts b/src/test/util/getFixturePaths.ts index 803535cfba..83952a489b 100644 --- a/src/test/util/getFixturePaths.ts +++ b/src/test/util/getFixturePaths.ts @@ -3,7 +3,7 @@ import { walkFilesSync } from "../../testUtil/walkSync"; import { getSingleTestFilename, runSingleTest, -} from "../suite/runSingleRecorded"; +} from "../suite/runSingleRecordedTest"; export function getFixturesPath() { return path.join(__dirname, "../../../src/test/suite/fixtures"); From cc9b9f83079510483b798537bdfdb7fa314c758f Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 17 May 2022 15:46:09 +0200 Subject: [PATCH 101/314] At dead tests for bring before and after file --- .../positions/bringHarpToAfterFile.yml | 36 +++++++++++++++++++ .../positions/bringWhaleToBeforeFile.yml | 36 +++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 src/test/suite/fixtures/recorded/positions/bringHarpToAfterFile.yml create mode 100644 src/test/suite/fixtures/recorded/positions/bringWhaleToBeforeFile.yml diff --git a/src/test/suite/fixtures/recorded/positions/bringHarpToAfterFile.yml b/src/test/suite/fixtures/recorded/positions/bringHarpToAfterFile.yml new file mode 100644 index 0000000000..80c4921c3a --- /dev/null +++ b/src/test/suite/fixtures/recorded/positions/bringHarpToAfterFile.yml @@ -0,0 +1,36 @@ +languageId: plaintext +command: + spokenForm: bring harp to after file + version: 2 + action: replaceWithTarget + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: h} + - type: primitive + modifiers: + - {type: position, position: after} + - {type: containingScope, scopeType: document} + usePrePhraseSnapshot: true +initialState: + documentContents: hello world + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: + default.h: + start: {line: 0, character: 0} + end: {line: 0, character: 5} +finalState: + documentContents: |- + hello world + hello + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 0, character: 11} + active: {line: 1, character: 5} + sourceMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 5} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: h}, modifiers: []}, {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: h}, modifiers: [{type: position, position: after}, {type: containingScope, scopeType: document}]}] diff --git a/src/test/suite/fixtures/recorded/positions/bringWhaleToBeforeFile.yml b/src/test/suite/fixtures/recorded/positions/bringWhaleToBeforeFile.yml new file mode 100644 index 0000000000..fb66606d55 --- /dev/null +++ b/src/test/suite/fixtures/recorded/positions/bringWhaleToBeforeFile.yml @@ -0,0 +1,36 @@ +languageId: plaintext +command: + spokenForm: bring whale to before file + version: 2 + action: replaceWithTarget + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: w} + - type: primitive + modifiers: + - {type: position, position: before} + - {type: containingScope, scopeType: document} + usePrePhraseSnapshot: true +initialState: + documentContents: hello world + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: + default.w: + start: {line: 0, character: 6} + end: {line: 0, character: 11} +finalState: + documentContents: |- + world + hello world + selections: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} + thatMark: + - anchor: {line: 0, character: 0} + active: {line: 1, character: 0} + sourceMark: + - anchor: {line: 1, character: 6} + active: {line: 1, character: 11} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: w}, modifiers: []}, {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: w}, modifiers: [{type: position, position: before}, {type: containingScope, scopeType: document}]}] From 1abbf8a0ba975cb235480c367e534e107b602a51 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 17 May 2022 16:44:38 +0200 Subject: [PATCH 102/314] Update to removal ranges --- src/processTargets/modifiers/SubPieceStage.ts | 8 ---- .../modifiers/scopeTypeStages/LineStage.ts | 17 ++------- .../scopeTypeStages/ParagraphStage.ts | 26 ++++--------- .../modifiers/scopeTypeStages/TokenStage.ts | 11 +----- ...ractSelectionFromSurroundingPairOffsets.ts | 2 +- src/processTargets/processTargets.ts | 9 +++++ src/typings/Types.ts | 2 +- src/typings/target.types.ts | 22 ++++++++--- src/util/targetUtils.ts | 37 +++++++++---------- src/util/unifyRanges.ts | 23 +++++++----- 10 files changed, 70 insertions(+), 87 deletions(-) diff --git a/src/processTargets/modifiers/SubPieceStage.ts b/src/processTargets/modifiers/SubPieceStage.ts index ac2aab85cf..572cc59014 100644 --- a/src/processTargets/modifiers/SubPieceStage.ts +++ b/src/processTargets/modifiers/SubPieceStage.ts @@ -3,7 +3,6 @@ import { Range } from "vscode"; import { SUBWORD_MATCHER } from "../../core/constants"; import { SubTokenModifier, Target } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; -import { createRemovalRange } from "../../util/targetUtils"; import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { @@ -92,19 +91,12 @@ export default class implements ModifierStage { ) : undefined; - const removalRange = createRemovalRange( - contentRange, - leadingDelimiterRange, - trailingDelimiterRange - ); - return { editor: target.editor, isReversed, contentRange, delimiter: containingListDelimiter, removal: { - range: removalRange, leadingDelimiterRange, trailingDelimiterRange, }, diff --git a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts index d6adf4d355..d886872c1a 100644 --- a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts @@ -6,7 +6,6 @@ import { Target, } from "../../../typings/target.types"; import { ProcessedTargetsContext } from "../../../typings/Types"; -import { createRemovalRange } from "../../../util/targetUtils"; import { ModifierStage } from "../../PipelineStages.types"; export default class implements ModifierStage { @@ -31,34 +30,24 @@ export function getLineContext(editor: TextEditor, range: Range) { const { document } = editor; const { start, end } = range; - const fullLineRange = new Range( + const removalRange = new Range( new Position(start.line, 0), editor.document.lineAt(end).range.end ); const leadingDelimiterRange = start.line > 0 - ? new Range( - document.lineAt(start.line - 1).range.end, - fullLineRange.start - ) + ? new Range(document.lineAt(start.line - 1).range.end, removalRange.start) : undefined; const trailingDelimiterRange = end.line + 1 < document.lineCount - ? new Range(fullLineRange.end, new Position(end.line + 1, 0)) + ? new Range(removalRange.end, new Position(end.line + 1, 0)) : undefined; - const removalRange = createRemovalRange( - fullLineRange, - leadingDelimiterRange, - trailingDelimiterRange - ); - return { delimiter: "\n", removal: { range: removalRange, - highlightRange: fullLineRange, leadingDelimiterRange, trailingDelimiterRange, }, diff --git a/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts b/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts index 01ea56cca3..04df14c54a 100644 --- a/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts @@ -6,7 +6,6 @@ import { Target, } from "../../../typings/target.types"; import { ProcessedTargetsContext } from "../../../typings/Types"; -import { createRemovalRange } from "../../../util/targetUtils"; import { ModifierStage } from "../../PipelineStages.types"; import { fitRangeToLineContent } from "./LineStage"; @@ -49,7 +48,7 @@ export default class implements ModifierStage { new Range(start, end) ); - const fullParagraphRange = new Range( + const removalRange = new Range( new Position(start.line, 0), target.editor.document.lineAt(end).range.end ); @@ -59,40 +58,28 @@ export default class implements ModifierStage { const leadingDelimiterRange = getLeadingDelimiterRange( document, - fullParagraphRange, + removalRange, leadingLine?.range.end ); const trailingDelimiterRange = getTrailingDelimiterRange( document, - fullParagraphRange, + removalRange, trailingLine?.range.start ); const leadingDelimiterHighlightRange = getLeadingDelimiterRange( document, - fullParagraphRange, + removalRange, leadingLine ? new Position(leadingLine.range.end.line + 1, 0) : undefined ); const trailingDelimiterHighlightRange = getTrailingDelimiterRange( document, - fullParagraphRange, + removalRange, trailingLine ? document.lineAt(trailingLine.range.start.line - 1).range.end : undefined ); - const removalRange = createRemovalRange( - fullParagraphRange, - leadingDelimiterRange, - trailingDelimiterRange - ); - - const removalHighlightRange = createRemovalRange( - fullParagraphRange, - leadingDelimiterHighlightRange, - trailingDelimiterHighlightRange - ); - return { scopeType: this.modifier.scopeType, editor: target.editor, @@ -101,9 +88,10 @@ export default class implements ModifierStage { contentRange, removal: { range: removalRange, - highlightRange: removalHighlightRange, leadingDelimiterRange, trailingDelimiterRange, + leadingDelimiterHighlightRange, + trailingDelimiterHighlightRange, }, }; } diff --git a/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts index 471601dd93..2fdcb96c09 100644 --- a/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts @@ -7,7 +7,6 @@ import { } from "../../../typings/target.types"; import { ProcessedTargetsContext } from "../../../typings/Types"; import { getTokensInRange, PartialToken } from "../../../util/getTokensInRange"; -import { createRemovalRange } from "../../../util/targetUtils"; import { ModifierStage } from "../../PipelineStages.types"; export default class implements ModifierStage { @@ -61,23 +60,17 @@ export function getTokenContext(target: Target) { ) : undefined; - const isInDelimitedList = + const includeDelimitersInRemoval = (leadingDelimiterRange != null || trailingDelimiterRange != null) && (leadingDelimiterRange != null || start.character === 0) && (trailingDelimiterRange != null || end.isEqual(endLine.range.end)); - const removalRange = createRemovalRange( - target.contentRange, - isInDelimitedList ? leadingDelimiterRange : undefined, - isInDelimitedList ? trailingDelimiterRange : undefined - ); - return { delimiter: " ", removal: { - range: removalRange, leadingDelimiterRange, trailingDelimiterRange, + excludeDelimiters: !includeDelimitersInRemoval, }, }; } diff --git a/src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts b/src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts index 6fe22909fe..14b290b0b2 100644 --- a/src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts +++ b/src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts @@ -22,7 +22,7 @@ export function extractSelectionFromSurroundingPairOffsets( baseOffset + surroundingPairOffsets.rightDelimiter.start ) ); - const boundary = [ + const boundary: [Range, Range] = [ new Range( document.positionAt( baseOffset + surroundingPairOffsets.leftDelimiter.start diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index f9f986dd8c..5b13ef9aea 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -142,6 +142,13 @@ function processContinuousRangeTarget( ? activeContext?.removal?.trailingDelimiterRange : anchorContext?.removal?.trailingDelimiterRange; + const leadingDelimiterHighlightRange = isForward + ? anchorContext?.removal?.leadingDelimiterHighlightRange + : activeContext?.removal?.leadingDelimiterHighlightRange; + const trailingDelimiterHighlightRange = isForward + ? activeContext?.removal?.trailingDelimiterHighlightRange + : anchorContext?.removal?.trailingDelimiterHighlightRange; + return [ { editor: activeTarget.editor, @@ -153,6 +160,8 @@ function processContinuousRangeTarget( range: removalRange, leadingDelimiterRange, trailingDelimiterRange, + leadingDelimiterHighlightRange, + trailingDelimiterHighlightRange, }, }, ]; diff --git a/src/typings/Types.ts b/src/typings/Types.ts index ed7e9fd5f5..f026fa6b1c 100644 --- a/src/typings/Types.ts +++ b/src/typings/Types.ts @@ -63,7 +63,7 @@ export interface SelectionContext { * surrounding pair this would be the opening and closing delimiter. For an if * statement this would be the line of the guard as well as the closing brace. */ - boundary?: vscode.Range[]; + boundary?: [vscode.Range, vscode.Range]; /** * Represents the interior ranges of this selection. For example, for a diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index d6794bcb04..84900f979e 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -275,7 +275,7 @@ export interface Target { * surrounding pair this would be the opening and closing delimiter. For an if * statement this would be the line of the guard as well as the closing brace. */ - boundary?: Range[]; + boundary?: [Range, Range]; /** * Related to removal @@ -286,11 +286,6 @@ export interface Target { */ range?: Range; - /** - * The range that needs to be highlighted on removal - */ - highlightRange?: Range; - /** * The range of the delimiter before the content selection */ @@ -300,6 +295,21 @@ export interface Target { * The range of the delimiter after the content selection */ trailingDelimiterRange?: Range; + + /** + * The range that needs to be highlighted on leading delimiter removal + */ + leadingDelimiterHighlightRange?: Range; + + /** + * The range that needs to be highlighted on trailing delimiteraremoval + */ + trailingDelimiterHighlightRange?: Range; + + /** + * If true the delimiter ranges are only head to be used with positions before/after + */ + excludeDelimiters?: boolean; }; } diff --git a/src/util/targetUtils.ts b/src/util/targetUtils.ts index befe943c7d..e9b055eb40 100644 --- a/src/util/targetUtils.ts +++ b/src/util/targetUtils.ts @@ -120,20 +120,23 @@ export function createThatMark( } export function getRemovalRange(target: Target) { - return target.removal?.range ?? target.contentRange; + const contentRange = target.removal?.range ?? target.contentRange; + const delimiterRange = + target.removal?.trailingDelimiterRange ?? + target.removal?.leadingDelimiterRange; + return delimiterRange != null && !target.removal?.excludeDelimiters + ? contentRange.union(delimiterRange) + : contentRange; } export function getRemovalHighlightRange(target: Target) { - return target.removal?.highlightRange ?? getRemovalRange(target); -} - -export function createRemovalRange( - contentRange: Range, - leadingDelimiterRange?: Range, - trailingDelimiterRange?: Range -) { - const delimiterRange = trailingDelimiterRange ?? leadingDelimiterRange; - return delimiterRange != null + const contentRange = target.removal?.range ?? target.contentRange; + const delimiterRange = + target.removal?.trailingDelimiterHighlightRange ?? + target.removal?.trailingDelimiterRange ?? + target.removal?.leadingDelimiterHighlightRange ?? + target.removal?.leadingDelimiterRange; + return delimiterRange != null && !target.removal?.excludeDelimiters ? contentRange.union(delimiterRange) : contentRange; } @@ -168,7 +171,8 @@ export function selectionWithEditorWithContextToTarget( // TODO Only use giving context in the future when all the containing scopes have proper delimiters. // For now fall back on token context const { context } = selection; - const { containingListDelimiter, interiorRange, boundary } = context; + const { containingListDelimiter, interiorRange, boundary, removalRange } = + context; const contentRange = selection.selection.selection; const newTarget = { editor: selection.selection.editor, @@ -187,14 +191,6 @@ export function selectionWithEditorWithContextToTarget( const trailingDelimiterRange = context.trailingDelimiterRange ?? tokenContext?.removal.trailingDelimiterRange; - const removalRange = - context.removalRange ?? - tokenContext?.removal?.range ?? - createRemovalRange( - contentRange, - leadingDelimiterRange, - trailingDelimiterRange - ); const delimiter = tokenContext?.delimiter ?? containingListDelimiter ?? "\n"; return { @@ -204,6 +200,7 @@ export function selectionWithEditorWithContextToTarget( range: removalRange, leadingDelimiterRange, trailingDelimiterRange, + excludeDelimiters: tokenContext?.removal.excludeDelimiters, }, }; } diff --git a/src/util/unifyRanges.ts b/src/util/unifyRanges.ts index cfa994325f..900a143f86 100644 --- a/src/util/unifyRanges.ts +++ b/src/util/unifyRanges.ts @@ -1,10 +1,6 @@ import { Range } from "vscode"; import { Target } from "../typings/target.types"; -import { - createRemovalRange, - getRemovalRange, - groupTargetsForEachEditor, -} from "./targetUtils"; +import { getRemovalRange, groupTargetsForEachEditor } from "./targetUtils"; /** Unifies overlapping/intersecting ranges */ export default function unifyRanges(ranges: Range[]): Range[] { @@ -95,17 +91,22 @@ function mergeTargets(targets: Target[]): Target { const last = targets[targets.length - 1]; const leadingDelimiterRange = first.removal?.leadingDelimiterRange; const trailingDelimiterRange = last.removal?.trailingDelimiterRange; + const leadingDelimiterHighlightRange = + first.removal?.leadingDelimiterHighlightRange; + const trailingDelimiterHighlightRange = + last.removal?.trailingDelimiterHighlightRange; return { editor: first.editor, isReversed: first.isReversed, - contentRange: createRemovalRange( - new Range(getRemovalRange(first).start, getRemovalRange(last).end), - leadingDelimiterRange, - trailingDelimiterRange + contentRange: new Range( + getContentRange(first).start, + getContentRange(last).end ), removal: { leadingDelimiterRange, trailingDelimiterRange, + leadingDelimiterHighlightRange, + trailingDelimiterHighlightRange, }, }; } @@ -113,3 +114,7 @@ function mergeTargets(targets: Target[]): Target { function intersects(targetA: Target, targetB: Target) { return !!getRemovalRange(targetA).intersection(getRemovalRange(targetB)); } + +function getContentRange(target: Target) { + return target.removal?.range ?? target.contentRange; +} From ffd79eaee1bb0e745136e7545ff28360608da26a Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 17 May 2022 19:38:42 +0200 Subject: [PATCH 103/314] Mark cleanup --- src/processTargets/getModifierStage.ts | 5 +- src/processTargets/marks/CursorStage.ts | 5 +- src/processTargets/marks/SourceStage.ts | 5 +- src/processTargets/marks/ThatStage.ts | 5 +- ...Stage.ts => ContainingSyntaxScopeStage.ts} | 0 src/processTargets/processTargets.ts | 58 ++++++++++--------- src/util/filterDuplicates.ts | 8 +++ 7 files changed, 49 insertions(+), 37 deletions(-) rename src/processTargets/modifiers/scopeTypeStages/{ContainingScopeStage.ts => ContainingSyntaxScopeStage.ts} (100%) create mode 100644 src/util/filterDuplicates.ts diff --git a/src/processTargets/getModifierStage.ts b/src/processTargets/getModifierStage.ts index 066c7c5956..2a91a1c8f7 100644 --- a/src/processTargets/getModifierStage.ts +++ b/src/processTargets/getModifierStage.ts @@ -4,7 +4,7 @@ import { Modifier, } from "../typings/target.types"; import BoundaryStage from "./modifiers/BoundaryStage"; -import ContainingScopeStage from "./modifiers/scopeTypeStages/ContainingScopeStage"; +import ContainingSyntaxScopeStage from "./modifiers/scopeTypeStages/ContainingSyntaxScopeStage"; import DocumentStage from "./modifiers/scopeTypeStages/DocumentStage"; import { HeadStage, TailStage } from "./modifiers/HeadTailStage"; import InteriorStage from "./modifiers/InteriorStage"; @@ -65,6 +65,7 @@ const getContainingScopeStage = ( case "url": return new UrlStage(modifier); default: - return new ContainingScopeStage(modifier); + // Default to containing syntax scope using tree sitter + return new ContainingSyntaxScopeStage(modifier); } }; diff --git a/src/processTargets/marks/CursorStage.ts b/src/processTargets/marks/CursorStage.ts index 6cf2f94bbc..f4ac690c83 100644 --- a/src/processTargets/marks/CursorStage.ts +++ b/src/processTargets/marks/CursorStage.ts @@ -1,5 +1,5 @@ import { window } from "vscode"; -import { CursorMark, ScopeTypeTarget } from "../../typings/target.types"; +import { CursorMark, Target } from "../../typings/target.types"; import { isReversed } from "../../util/selectionUtils"; import { getTokenContext } from "../modifiers/scopeTypeStages/TokenStage"; import { MarkStage } from "../PipelineStages.types"; @@ -7,7 +7,7 @@ import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { constructor(private modifier: CursorMark) {} - run(): ScopeTypeTarget[] { + run(): Target[] { if (window.activeTextEditor == null) { return []; } @@ -20,7 +20,6 @@ export default class implements MarkStage { return { ...target, ...getTokenContext(target), - scopeType: "token", }; }); } diff --git a/src/processTargets/marks/SourceStage.ts b/src/processTargets/marks/SourceStage.ts index 096b3cb593..a7c40e9cb2 100644 --- a/src/processTargets/marks/SourceStage.ts +++ b/src/processTargets/marks/SourceStage.ts @@ -1,4 +1,4 @@ -import { ScopeTypeTarget, SourceMark } from "../../typings/target.types"; +import { SourceMark, Target } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { isReversed } from "../../util/selectionUtils"; import { getTokenContext } from "../modifiers/scopeTypeStages/TokenStage"; @@ -7,7 +7,7 @@ import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { constructor(private modifier: SourceMark) {} - run(context: ProcessedTargetsContext): ScopeTypeTarget[] { + run(context: ProcessedTargetsContext): Target[] { return context.sourceMark.map((selection) => { const target = { editor: selection.editor, @@ -17,7 +17,6 @@ export default class implements MarkStage { return { ...target, ...getTokenContext(target), - scopeType: "token", }; }); } diff --git a/src/processTargets/marks/ThatStage.ts b/src/processTargets/marks/ThatStage.ts index dbc6f1560a..b657350e72 100644 --- a/src/processTargets/marks/ThatStage.ts +++ b/src/processTargets/marks/ThatStage.ts @@ -1,4 +1,4 @@ -import { ScopeTypeTarget, ThatMark } from "../../typings/target.types"; +import { Target, ThatMark } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { isReversed } from "../../util/selectionUtils"; import { getTokenContext } from "../modifiers/scopeTypeStages/TokenStage"; @@ -7,7 +7,7 @@ import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { constructor(private modifier: ThatMark) {} - run(context: ProcessedTargetsContext): ScopeTypeTarget[] { + run(context: ProcessedTargetsContext): Target[] { return context.thatMark.map((selection) => { const target = { editor: selection.editor, @@ -17,7 +17,6 @@ export default class implements MarkStage { return { ...target, ...getTokenContext(target), - scopeType: "token", }; }); } diff --git a/src/processTargets/modifiers/scopeTypeStages/ContainingScopeStage.ts b/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts similarity index 100% rename from src/processTargets/modifiers/scopeTypeStages/ContainingScopeStage.ts rename to src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index 5b13ef9aea..5eafb47499 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -1,12 +1,13 @@ -import { isEqual, zip } from "lodash"; +import { zip } from "lodash"; import { Range } from "vscode"; import { PrimitiveTargetDesc, RangeTargetDesc, - TargetDesc, Target, + TargetDesc, } from "../typings/target.types"; import { ProcessedTargetsContext } from "../typings/Types"; +import { filterDuplicates } from "../util/filterDuplicates"; import getMarkStage from "./getMarkStage"; import getModifierStage from "./getModifierStage"; @@ -29,7 +30,7 @@ export default function ( targets: TargetDesc[] ): Target[][] { return targets.map((target) => - filterDuplicateSelections(processTarget(context, target)) + filterDuplicates(processTarget(context, target)) ); } @@ -51,10 +52,10 @@ function processTarget( function processRangeTarget( context: ProcessedTargetsContext, - target: RangeTargetDesc + targetDesc: RangeTargetDesc ): Target[] { - const anchorTargets = processPrimitiveTarget(context, target.anchor); - const activeTargets = processPrimitiveTarget(context, target.active); + const anchorTargets = processPrimitiveTarget(context, targetDesc.anchor); + const activeTargets = processPrimitiveTarget(context, targetDesc.active); return zip(anchorTargets, activeTargets).flatMap( ([anchorTarget, activeTarget]) => { @@ -68,24 +69,20 @@ function processRangeTarget( ); } - const anchorRange = anchorTarget.contentRange; - const activeRange = activeTarget.contentRange; - const isForward = anchorRange.start.isBeforeOrEqual(activeRange.start); - - switch (target.rangeType) { + switch (targetDesc.rangeType) { case "continuous": return processContinuousRangeTarget( - target, anchorTarget, activeTarget, - isForward + targetDesc.excludeAnchor, + targetDesc.excludeActive ); case "vertical": return processVerticalRangeTarget( - target, anchorTarget, activeTarget, - isForward + targetDesc.excludeAnchor, + targetDesc.excludeActive ); } } @@ -93,12 +90,12 @@ function processRangeTarget( } function processContinuousRangeTarget( - target: RangeTargetDesc, anchorTarget: Target, activeTarget: Target, - isForward: boolean + excludeAnchor: boolean, + excludeActive: boolean ): Target[] { - const { excludeAnchor, excludeActive } = target; + const isForward = calcIsForward(anchorTarget, activeTarget); const anchorContext = excludeAnchor ? undefined : anchorTarget; const activeContext = excludeActive ? undefined : activeTarget; @@ -167,6 +164,18 @@ function processContinuousRangeTarget( ]; } +export function targetsToContinuousTarget( + anchorTarget: Target, + activeTarget: Target +): Target { + return processContinuousRangeTarget( + anchorTarget, + activeTarget, + false, + false + )[0]; +} + function unionRanges( isForward: boolean, excludeAnchor: boolean, @@ -191,12 +200,12 @@ function getPosition(range: Range, isStartOfRange: boolean, exclude: boolean) { } function processVerticalRangeTarget( - target: RangeTargetDesc, anchorTarget: Target, activeTarget: Target, - isForward: boolean + excludeAnchor: boolean, + excludeActive: boolean ): Target[] { - const { excludeAnchor, excludeActive } = target; + const isForward = calcIsForward(anchorTarget, activeTarget); const delta = isForward ? 1 : -1; const anchorPosition = isForward @@ -253,9 +262,6 @@ function processPrimitiveTarget( return selections; } -function filterDuplicateSelections(selections: Target[]) { - return selections.filter( - (selection, index, selections) => - selections.findIndex((s) => isEqual(s, selection)) === index - ); +function calcIsForward(anchor: Target, active: Target) { + return anchor.contentRange.start.isBeforeOrEqual(active.contentRange.start); } diff --git a/src/util/filterDuplicates.ts b/src/util/filterDuplicates.ts new file mode 100644 index 0000000000..d04c222d59 --- /dev/null +++ b/src/util/filterDuplicates.ts @@ -0,0 +1,8 @@ +import { isEqual } from "lodash"; + +export function filterDuplicates(elements: T[]) { + return elements.filter( + (element, index, elements) => + elements.findIndex((e) => isEqual(e, element)) === index + ); +} From 625baac725f943c23ca9489de3b35b935902cf65 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 17 May 2022 22:13:55 +0200 Subject: [PATCH 104/314] Added interior only and exclude interior as proper modifiers --- .../src/modifiers/interior_boundary.py | 17 +++++ cursorless-talon/src/modifiers/sub_token.py | 2 +- .../src/modifiers/surrounding_pair.py | 18 +---- cursorless-talon/src/primitive_target.py | 1 + .../upgradeV1ToV2/upgradeV1ToV2.ts | 4 +- src/processTargets/getModifierStage.ts | 22 ++++--- src/processTargets/modifiers/BoundaryStage.ts | 18 ----- src/processTargets/modifiers/InteriorStage.ts | 65 +++++++++++++++++-- .../modifiers/SurroundingPairStage.ts | 34 ++++++---- src/typings/target.types.ts | 12 ++-- 10 files changed, 122 insertions(+), 71 deletions(-) create mode 100644 cursorless-talon/src/modifiers/interior_boundary.py delete mode 100644 src/processTargets/modifiers/BoundaryStage.ts diff --git a/cursorless-talon/src/modifiers/interior_boundary.py b/cursorless-talon/src/modifiers/interior_boundary.py new file mode 100644 index 0000000000..53fab1b88c --- /dev/null +++ b/cursorless-talon/src/modifiers/interior_boundary.py @@ -0,0 +1,17 @@ +from typing import Any +from talon import Module + +mod = Module() + +mod.list( + "cursorless_delimiter_inclusion", + desc="Inside or boundary delimiter inclusion", +) + +# TODO [{user.cursorless_delimiter_force_direction}] +@mod.capture(rule="{user.cursorless_delimiter_inclusion}") +def cursorless_delimiter_inclusion(m) -> dict[str, Any]: + """Inside or boundary delimiter inclusion""" + return { + "type": m.cursorless_delimiter_inclusion, + } diff --git a/cursorless-talon/src/modifiers/sub_token.py b/cursorless-talon/src/modifiers/sub_token.py index 7f63675db7..88e5627b5d 100644 --- a/cursorless-talon/src/modifiers/sub_token.py +++ b/cursorless-talon/src/modifiers/sub_token.py @@ -49,7 +49,7 @@ def cursorless_first_last_range(m) -> str: @mod.capture( rule=( - "( | )" + "( | ) " "{user.cursorless_subtoken_scope_type}" ) ) diff --git a/cursorless-talon/src/modifiers/surrounding_pair.py b/cursorless-talon/src/modifiers/surrounding_pair.py index f9f3302afc..24c866869e 100644 --- a/cursorless-talon/src/modifiers/surrounding_pair.py +++ b/cursorless-talon/src/modifiers/surrounding_pair.py @@ -8,11 +8,6 @@ ctx = Context() -mod.list( - "cursorless_delimiter_inclusion", - desc="Whether to include delimiters in surrounding range", -) - mod.list( "cursorless_delimiter_force_direction", desc="Can be used to force an ambiguous delimiter to extend in one direction", @@ -22,8 +17,6 @@ "right", ] -# NB: This is a hack until we support having inside and outside on arbitrary -# scope types mod.list( "cursorless_surrounding_pair_scope_type", desc="Scope types that can function as surrounding pairs", @@ -47,10 +40,7 @@ def cursorless_surrounding_pair_scope_type(m) -> str: @mod.capture( - rule=( - "[{user.cursorless_delimiter_inclusion}] [{user.cursorless_delimiter_force_direction}] | " - "{user.cursorless_delimiter_inclusion} [{user.cursorless_delimiter_force_direction}]" - ) + rule="[{user.cursorless_delimiter_force_direction}] " ) def cursorless_surrounding_pair(m) -> dict[str, Any]: """Surrounding pair modifier""" @@ -64,12 +54,6 @@ def cursorless_surrounding_pair(m) -> dict[str, Any]: "delimiter": surrounding_pair_scope_type, } - # TODO make as own modifier stage - try: - modifier["delimiterInclusion"] = m.cursorless_delimiter_inclusion - except AttributeError: - pass - try: modifier["forceDirection"] = m.cursorless_delimiter_force_direction except AttributeError: diff --git a/cursorless-talon/src/primitive_target.py b/cursorless-talon/src/primitive_target.py index 91eac64292..c1f5c9f590 100644 --- a/cursorless-talon/src/primitive_target.py +++ b/cursorless-talon/src/primitive_target.py @@ -15,6 +15,7 @@ "", # first past second word "", # matching/pair [curly, round] "", # just + "", # inside, bounds # "", # matching ] diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts index 7de119c9e5..fed198c7e7 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts @@ -49,10 +49,10 @@ function upgradeModifier(modifier: ModifierV0V1): Modifier | Modifier[] | null { case "surroundingPair": const { delimiterInclusion, ...rest } = modifier; if (delimiterInclusion === "interiorOnly") { - return [rest, { type: "interior" }]; + return [rest, { type: "interiorOnly" }]; } if (delimiterInclusion === "excludeInterior") { - return [rest, { type: "boundary" }]; + return [rest, { type: "excludeInterior" }]; } return rest; diff --git a/src/processTargets/getModifierStage.ts b/src/processTargets/getModifierStage.ts index 2a91a1c8f7..de8822c0e7 100644 --- a/src/processTargets/getModifierStage.ts +++ b/src/processTargets/getModifierStage.ts @@ -3,23 +3,25 @@ import { EveryScopeModifier, Modifier, } from "../typings/target.types"; -import BoundaryStage from "./modifiers/BoundaryStage"; +import { HeadStage, TailStage } from "./modifiers/HeadTailStage"; +import { + InteriorOnlyStage, + ExcludeInteriorStage, +} from "./modifiers/InteriorStage"; +import PositionStage from "./modifiers/PositionStage"; +import RawSelectionStage from "./modifiers/RawSelectionStage"; import ContainingSyntaxScopeStage from "./modifiers/scopeTypeStages/ContainingSyntaxScopeStage"; import DocumentStage from "./modifiers/scopeTypeStages/DocumentStage"; -import { HeadStage, TailStage } from "./modifiers/HeadTailStage"; -import InteriorStage from "./modifiers/InteriorStage"; import LineStage from "./modifiers/scopeTypeStages/LineStage"; import NotebookCellStage from "./modifiers/scopeTypeStages/NotebookCellStage"; import ParagraphStage from "./modifiers/scopeTypeStages/ParagraphStage"; -import PositionStage from "./modifiers/PositionStage"; -import RawSelectionStage from "./modifiers/RawSelectionStage"; import { NonWhitespaceSequenceStage, UrlStage, } from "./modifiers/scopeTypeStages/RegexStage"; +import TokenStage from "./modifiers/scopeTypeStages/TokenStage"; import SubPieceStage from "./modifiers/SubPieceStage"; import SurroundingPairStage from "./modifiers/SurroundingPairStage"; -import TokenStage from "./modifiers/scopeTypeStages/TokenStage"; import { ModifierStage } from "./PipelineStages.types"; export default (modifier: Modifier): ModifierStage => { @@ -36,10 +38,10 @@ export default (modifier: Modifier): ModifierStage => { return new SubPieceStage(modifier); case "surroundingPair": return new SurroundingPairStage(modifier); - case "interior": - return new InteriorStage(modifier); - case "boundary": - return new BoundaryStage(modifier); + case "interiorOnly": + return new InteriorOnlyStage(modifier); + case "excludeInterior": + return new ExcludeInteriorStage(modifier); case "containingScope": case "everyScope": return getContainingScopeStage(modifier); diff --git a/src/processTargets/modifiers/BoundaryStage.ts b/src/processTargets/modifiers/BoundaryStage.ts deleted file mode 100644 index 263df4c8ad..0000000000 --- a/src/processTargets/modifiers/BoundaryStage.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { BoundaryModifier, Target } from "../../typings/target.types"; -import { ProcessedTargetsContext } from "../../typings/Types"; -import { ModifierStage } from "../PipelineStages.types"; - -export default class implements ModifierStage { - constructor(private modifier: BoundaryModifier) {} - - run(context: ProcessedTargetsContext, target: Target): Target[] { - if (target.boundary == null) { - throw Error("No available boundary"); - } - return target.boundary.map((contentRange) => ({ - editor: target.editor, - isReversed: target.isReversed, - contentRange, - })); - } -} diff --git a/src/processTargets/modifiers/InteriorStage.ts b/src/processTargets/modifiers/InteriorStage.ts index 02ef006f33..3866876ef6 100644 --- a/src/processTargets/modifiers/InteriorStage.ts +++ b/src/processTargets/modifiers/InteriorStage.ts @@ -1,11 +1,43 @@ -import { InteriorModifier, Target } from "../../typings/target.types"; +import { + ExcludeInteriorModifier, + InteriorOnlyModifier, + Target, +} from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; +import { processedSurroundingPairTarget } from "./SurroundingPairStage"; -export default class implements ModifierStage { - constructor(private modifier: InteriorModifier) {} +abstract class InteriorStage implements ModifierStage { + abstract getTargets(target: Target): Target | Target[]; + abstract hasData(target: Target): boolean; - run(context: ProcessedTargetsContext, target: Target): Target { + run(context: ProcessedTargetsContext, target: Target): Target | Target[] { + if (this.hasData(target)) { + return this.getTargets(target); + } + return this.processSurroundingPair(context, target).flatMap((target) => + this.getTargets(target) + ); + } + + processSurroundingPair( + context: ProcessedTargetsContext, + target: Target + ): Target[] { + return processedSurroundingPairTarget( + { type: "surroundingPair", delimiter: "any" }, + context, + target + ); + } +} + +export class InteriorOnlyStage extends InteriorStage { + constructor(private modifier: InteriorOnlyModifier) { + super(); + } + + getTargets(target: Target): Target | Target[] { if (target.interiorRange == null) { throw Error("No available interior"); } @@ -15,4 +47,29 @@ export default class implements ModifierStage { contentRange: target.interiorRange, }; } + + hasData(target: Target): boolean { + return target.interiorRange != null; + } +} + +export class ExcludeInteriorStage extends InteriorStage { + constructor(private modifier: ExcludeInteriorModifier) { + super(); + } + + getTargets(target: Target): Target | Target[] { + if (target.boundary == null) { + throw Error("No available boundaries"); + } + return target.boundary.map((contentRange) => ({ + editor: target.editor, + isReversed: target.isReversed, + contentRange, + })); + } + + hasData(target: Target): boolean { + return target.boundary != null; + } } diff --git a/src/processTargets/modifiers/SurroundingPairStage.ts b/src/processTargets/modifiers/SurroundingPairStage.ts index 8f5240fc32..0ea38f23fa 100644 --- a/src/processTargets/modifiers/SurroundingPairStage.ts +++ b/src/processTargets/modifiers/SurroundingPairStage.ts @@ -21,20 +21,28 @@ export default class implements ModifierStage { constructor(private modifier: SurroundingPairModifier) {} run(context: ProcessedTargetsContext, target: Target): Target[] { - const pairs = processSurroundingPair( - context, - target.editor, - target.contentRange, - this.modifier - ); + return processedSurroundingPairTarget(this.modifier, context, target); + } +} - if (pairs == null) { - throw new Error("Couldn't find containing pair"); - } +export function processedSurroundingPairTarget( + modifier: SurroundingPairModifier, + context: ProcessedTargetsContext, + target: Target +) { + const pairs = processSurroundingPair( + context, + target.editor, + target.contentRange, + modifier + ); - return pairs.map((pair) => ({ - ...selectionWithEditorWithContextToTarget(pair), - isReversed: target.isReversed, - })); + if (pairs == null) { + throw new Error("Couldn't find containing pair"); } + + return pairs.map((pair) => ({ + ...selectionWithEditorWithContextToTarget(pair), + isReversed: target.isReversed, + })); } diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 84900f979e..9a94ff0b52 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -119,12 +119,12 @@ export interface SurroundingPairModifier { forceDirection?: SurroundingPairDirection; } -export interface InteriorModifier { - type: "interior"; +export interface InteriorOnlyModifier { + type: "interiorOnly"; } -export interface BoundaryModifier { - type: "boundary"; +export interface ExcludeInteriorModifier { + type: "excludeInterior"; } export interface ContainingScopeModifier { @@ -179,8 +179,8 @@ export interface PartialPrimitiveTargetDesc { export type Modifier = | PositionModifier | SurroundingPairModifier - | InteriorModifier - | BoundaryModifier + | InteriorOnlyModifier + | ExcludeInteriorModifier | ContainingScopeModifier | EveryScopeModifier | SubTokenModifier From 15b6d07a5ab147d4b9428f5545f7241ecf861b70 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 17 May 2022 20:14:20 +0000 Subject: [PATCH 105/314] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- cursorless-talon/src/modifiers/interior_boundary.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cursorless-talon/src/modifiers/interior_boundary.py b/cursorless-talon/src/modifiers/interior_boundary.py index 53fab1b88c..688e68957f 100644 --- a/cursorless-talon/src/modifiers/interior_boundary.py +++ b/cursorless-talon/src/modifiers/interior_boundary.py @@ -1,4 +1,5 @@ from typing import Any + from talon import Module mod = Module() From c1b4d63bf416f4648942bc205fcdc244a636fe5f Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 17 May 2022 22:31:01 +0200 Subject: [PATCH 106/314] Added support for every line --- .../modifiers/scopeTypeStages/LineStage.ts | 37 ++++++++++++++++--- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts index d886872c1a..4d5873ce3d 100644 --- a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts @@ -11,11 +11,38 @@ import { ModifierStage } from "../../PipelineStages.types"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} - run(context: ProcessedTargetsContext, target: Target): ScopeTypeTarget { - const contentRange = fitRangeToLineContent( - target.editor, - target.contentRange - ); + run( + context: ProcessedTargetsContext, + target: Target + ): ScopeTypeTarget | ScopeTypeTarget[] { + if (this.modifier.type === "everyScope") { + return this.getEveryTarget(target); + } + return this.getSingleTarget(target); + } + + getEveryTarget(target: Target): ScopeTypeTarget[] { + const { contentRange, editor } = target; + const { isEmpty } = contentRange; + const startLine = isEmpty ? 0 : contentRange.start.line; + const endLine = isEmpty + ? editor.document.lineCount - 1 + : contentRange.end.line; + const targets: ScopeTypeTarget[] = []; + + for (let i = startLine; i <= endLine; ++i) { + targets.push(this.getTargetFromRange(target, new Range(i, 0, i, 0))); + } + + return targets; + } + + getSingleTarget(target: Target): ScopeTypeTarget { + return this.getTargetFromRange(target, target.contentRange); + } + + getTargetFromRange(target: Target, range: Range): ScopeTypeTarget { + const contentRange = fitRangeToLineContent(target.editor, range); return { scopeType: this.modifier.scopeType, editor: target.editor, From d1771a024c3bec761f36e39a6f323c78b469af9c Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 17 May 2022 22:39:56 +0200 Subject: [PATCH 107/314] Only select lines with content --- .../modifiers/scopeTypeStages/LineStage.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts index 4d5873ce3d..cd7aadf1d0 100644 --- a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts @@ -31,7 +31,14 @@ export default class implements ModifierStage { const targets: ScopeTypeTarget[] = []; for (let i = startLine; i <= endLine; ++i) { - targets.push(this.getTargetFromRange(target, new Range(i, 0, i, 0))); + const line = editor.document.lineAt(i); + if (!line.isEmptyOrWhitespace) { + targets.push(this.getTargetFromRange(target, line.range)); + } + } + + if (targets.length === 0) { + throw new Error(`Couldn't find containing ${this.modifier.scopeType}`); } return targets; From d92c94219ba033dedb269c264b32f2b40389a04d Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 17 May 2022 23:13:09 +0200 Subject: [PATCH 108/314] Added take every paragraph --- .../scopeTypeStages/ParagraphStage.ts | 65 +++++++++++++++++-- 1 file changed, 61 insertions(+), 4 deletions(-) diff --git a/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts b/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts index 04df14c54a..126e6e3867 100644 --- a/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts @@ -12,10 +12,67 @@ import { fitRangeToLineContent } from "./LineStage"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} - run(context: ProcessedTargetsContext, target: Target): ScopeTypeTarget { + run( + context: ProcessedTargetsContext, + target: Target + ): ScopeTypeTarget | ScopeTypeTarget[] { + if (this.modifier.type === "everyScope") { + return this.getEveryTarget(target); + } + return this.getSingleTarget(target); + } + + getEveryTarget(target: Target): ScopeTypeTarget | ScopeTypeTarget[] { + const { contentRange, editor } = target; + const { isEmpty } = contentRange; + const { lineCount } = editor.document; + const startLine = isEmpty ? 0 : contentRange.start.line; + const endLine = isEmpty ? lineCount - 1 : contentRange.end.line; + const paragraphs: { start: number; end: number }[] = []; + const targets: ScopeTypeTarget[] = []; + let paragraphStartLine = -1; + + for (let i = 0; i < lineCount; ++i) { + const line = editor.document.lineAt(i); + if (line.isEmptyOrWhitespace || i === lineCount - 1) { + // End of paragraph + if (paragraphStartLine > -1) { + paragraphs.push({ start: paragraphStartLine, end: i - 1 }); + paragraphStartLine = -1; + } + } + // Start of paragraph + else if (paragraphStartLine < 0) { + paragraphStartLine = i; + } + } + + paragraphs.forEach((paragraph) => { + if (paragraph.end >= startLine && paragraph.start <= endLine) { + targets.push( + this.getTargetFromRange( + target, + new Range(paragraph.start, 0, paragraph.end, 0) + ) + ); + } + }); + + if (targets.length === 0) { + throw new Error(`Couldn't find containing ${this.modifier.scopeType}`); + } + + return targets; + } + + getSingleTarget(target: Target): ScopeTypeTarget { + return this.getTargetFromRange(target, target.contentRange); + } + + getTargetFromRange(target: Target, range: Range): ScopeTypeTarget { const { document } = target.editor; - let startLine = document.lineAt(target.contentRange.start); + let startLine = document.lineAt(range.start); if (!startLine.isEmptyOrWhitespace) { while (startLine.lineNumber > 0) { const line = document.lineAt(startLine.lineNumber - 1); @@ -26,7 +83,7 @@ export default class implements ModifierStage { } } const lineCount = document.lineCount; - let endLine = document.lineAt(target.contentRange.end); + let endLine = document.lineAt(range.end); if (!endLine.isEmptyOrWhitespace) { while (endLine.lineNumber + 1 < lineCount) { const line = document.lineAt(endLine.lineNumber + 1); @@ -50,7 +107,7 @@ export default class implements ModifierStage { const removalRange = new Range( new Position(start.line, 0), - target.editor.document.lineAt(end).range.end + document.lineAt(end).range.end ); const leadingLine = getPreviousNonEmptyLine(document, start.line); From fcccf12a3943365bcdee1c2c74f4242a7db994a3 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 17 May 2022 23:19:00 +0200 Subject: [PATCH 109/314] Added every file line and block tests --- .../selectionTypes/takeEveryBlock.yml | 41 ++++++++++++++++ .../selectionTypes/takeEveryBlock2.yml | 41 ++++++++++++++++ .../selectionTypes/takeEveryBlock3.yml | 41 ++++++++++++++++ .../recorded/selectionTypes/takeEveryFile.yml | 37 ++++++++++++++ .../recorded/selectionTypes/takeEveryLine.yml | 49 +++++++++++++++++++ .../selectionTypes/takeEveryLine2.yml | 45 +++++++++++++++++ .../selectionTypes/takeEveryLine3.yml | 45 +++++++++++++++++ 7 files changed, 299 insertions(+) create mode 100644 src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock.yml create mode 100644 src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock2.yml create mode 100644 src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock3.yml create mode 100644 src/test/suite/fixtures/recorded/selectionTypes/takeEveryFile.yml create mode 100644 src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine.yml create mode 100644 src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine2.yml create mode 100644 src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine3.yml diff --git a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock.yml b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock.yml new file mode 100644 index 0000000000..46733e12a5 --- /dev/null +++ b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock.yml @@ -0,0 +1,41 @@ +languageId: plaintext +command: + spokenForm: take every block + version: 2 + action: setSelection + targets: + - type: primitive + modifiers: + - {type: everyScope, scopeType: paragraph} + usePrePhraseSnapshot: true +initialState: + documentContents: | + + a + + b c + d e + f g + selections: + - anchor: {line: 6, character: 0} + active: {line: 6, character: 0} + marks: {} +finalState: + documentContents: | + + a + + b c + d e + f g + selections: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 1} + - anchor: {line: 3, character: 0} + active: {line: 5, character: 5} + thatMark: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 1} + - anchor: {line: 3, character: 0} + active: {line: 5, character: 5} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: everyScope, scopeType: paragraph}]}] diff --git a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock2.yml b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock2.yml new file mode 100644 index 0000000000..878ea84cf1 --- /dev/null +++ b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock2.yml @@ -0,0 +1,41 @@ +languageId: plaintext +command: + spokenForm: take every block + version: 2 + action: setSelection + targets: + - type: primitive + modifiers: + - {type: everyScope, scopeType: paragraph} + usePrePhraseSnapshot: true +initialState: + documentContents: | + + a + + b c + d e + f g + selections: + - anchor: {line: 4, character: 5} + active: {line: 1, character: 0} + marks: {} +finalState: + documentContents: | + + a + + b c + d e + f g + selections: + - anchor: {line: 1, character: 1} + active: {line: 1, character: 0} + - anchor: {line: 5, character: 5} + active: {line: 3, character: 0} + thatMark: + - anchor: {line: 1, character: 1} + active: {line: 1, character: 0} + - anchor: {line: 5, character: 5} + active: {line: 3, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: everyScope, scopeType: paragraph}]}] diff --git a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock3.yml b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock3.yml new file mode 100644 index 0000000000..7632670f2e --- /dev/null +++ b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock3.yml @@ -0,0 +1,41 @@ +languageId: plaintext +command: + spokenForm: take every block + version: 2 + action: setSelection + targets: + - type: primitive + modifiers: + - {type: everyScope, scopeType: paragraph} + usePrePhraseSnapshot: true +initialState: + documentContents: | + + a + + b c + d e + f g + selections: + - anchor: {line: 1, character: 0} + active: {line: 4, character: 5} + marks: {} +finalState: + documentContents: | + + a + + b c + d e + f g + selections: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 1} + - anchor: {line: 3, character: 0} + active: {line: 5, character: 5} + thatMark: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 1} + - anchor: {line: 3, character: 0} + active: {line: 5, character: 5} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: everyScope, scopeType: paragraph}]}] diff --git a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryFile.yml b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryFile.yml new file mode 100644 index 0000000000..00e8975606 --- /dev/null +++ b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryFile.yml @@ -0,0 +1,37 @@ +languageId: plaintext +command: + spokenForm: take every file + version: 2 + action: setSelection + targets: + - type: primitive + modifiers: + - {type: everyScope, scopeType: document} + usePrePhraseSnapshot: true +initialState: + documentContents: | + + a + + b c + d e + f g + selections: + - anchor: {line: 6, character: 0} + active: {line: 6, character: 0} + marks: {} +finalState: + documentContents: | + + a + + b c + d e + f g + selections: + - anchor: {line: 1, character: 0} + active: {line: 5, character: 5} + thatMark: + - anchor: {line: 1, character: 0} + active: {line: 5, character: 5} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: everyScope, scopeType: document}]}] diff --git a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine.yml b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine.yml new file mode 100644 index 0000000000..eaaf7f0b08 --- /dev/null +++ b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine.yml @@ -0,0 +1,49 @@ +languageId: plaintext +command: + spokenForm: take every line + version: 2 + action: setSelection + targets: + - type: primitive + modifiers: + - {type: everyScope, scopeType: line} + usePrePhraseSnapshot: true +initialState: + documentContents: | + + a + + b c + d e + f g + selections: + - anchor: {line: 6, character: 0} + active: {line: 6, character: 0} + marks: {} +finalState: + documentContents: | + + a + + b c + d e + f g + selections: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 1} + - anchor: {line: 3, character: 0} + active: {line: 3, character: 5} + - anchor: {line: 4, character: 0} + active: {line: 4, character: 5} + - anchor: {line: 5, character: 0} + active: {line: 5, character: 5} + thatMark: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 1} + - anchor: {line: 3, character: 0} + active: {line: 3, character: 5} + - anchor: {line: 4, character: 0} + active: {line: 4, character: 5} + - anchor: {line: 5, character: 0} + active: {line: 5, character: 5} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: everyScope, scopeType: line}]}] diff --git a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine2.yml b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine2.yml new file mode 100644 index 0000000000..0c5a94e5eb --- /dev/null +++ b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine2.yml @@ -0,0 +1,45 @@ +languageId: plaintext +command: + spokenForm: take every line + version: 2 + action: setSelection + targets: + - type: primitive + modifiers: + - {type: everyScope, scopeType: line} + usePrePhraseSnapshot: true +initialState: + documentContents: | + + a + + b c + d e + f g + selections: + - anchor: {line: 4, character: 5} + active: {line: 1, character: 0} + marks: {} +finalState: + documentContents: | + + a + + b c + d e + f g + selections: + - anchor: {line: 1, character: 1} + active: {line: 1, character: 0} + - anchor: {line: 3, character: 5} + active: {line: 3, character: 0} + - anchor: {line: 4, character: 5} + active: {line: 4, character: 0} + thatMark: + - anchor: {line: 1, character: 1} + active: {line: 1, character: 0} + - anchor: {line: 3, character: 5} + active: {line: 3, character: 0} + - anchor: {line: 4, character: 5} + active: {line: 4, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: everyScope, scopeType: line}]}] diff --git a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine3.yml b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine3.yml new file mode 100644 index 0000000000..bd926f20d2 --- /dev/null +++ b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine3.yml @@ -0,0 +1,45 @@ +languageId: plaintext +command: + spokenForm: take every line + version: 2 + action: setSelection + targets: + - type: primitive + modifiers: + - {type: everyScope, scopeType: line} + usePrePhraseSnapshot: true +initialState: + documentContents: | + + a + + b c + d e + f g + selections: + - anchor: {line: 1, character: 0} + active: {line: 4, character: 5} + marks: {} +finalState: + documentContents: | + + a + + b c + d e + f g + selections: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 1} + - anchor: {line: 3, character: 0} + active: {line: 3, character: 5} + - anchor: {line: 4, character: 0} + active: {line: 4, character: 5} + thatMark: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 1} + - anchor: {line: 3, character: 0} + active: {line: 3, character: 5} + - anchor: {line: 4, character: 0} + active: {line: 4, character: 5} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: everyScope, scopeType: line}]}] From 01e77eaad7fc487507d13ba03872cba44c8d4322 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 18 May 2022 01:24:01 +0200 Subject: [PATCH 110/314] Added take every token --- src/core/IndividualHatMap.ts | 6 +++ .../scopeTypeStages/ParagraphStage.ts | 45 +++++++++++-------- .../modifiers/scopeTypeStages/TokenStage.ts | 44 +++++++++++++++--- 3 files changed, 71 insertions(+), 24 deletions(-) diff --git a/src/core/IndividualHatMap.ts b/src/core/IndividualHatMap.ts index c506cfef25..826126c55e 100644 --- a/src/core/IndividualHatMap.ts +++ b/src/core/IndividualHatMap.ts @@ -5,6 +5,7 @@ import HatTokenMap from "./HatTokenMap"; export interface ReadOnlyHatMap { getEntries(): [string, Token][]; + getTokens(): Token[]; getToken(hatStyle: HatStyleName, character: string): Token; } @@ -49,6 +50,11 @@ export class IndividualHatMap implements ReadOnlyHatMap { return Object.entries(this.map); } + getTokens() { + this.checkExpired(); + return Object.values(this.map); + } + private addTokenByKey(key: string, token: Token) { this.map[key] = token; this.getDocumentTokenList(token.editor.document).push(token); diff --git a/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts b/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts index 126e6e3867..14f45d114a 100644 --- a/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts @@ -28,35 +28,42 @@ export default class implements ModifierStage { const { lineCount } = editor.document; const startLine = isEmpty ? 0 : contentRange.start.line; const endLine = isEmpty ? lineCount - 1 : contentRange.end.line; - const paragraphs: { start: number; end: number }[] = []; const targets: ScopeTypeTarget[] = []; - let paragraphStartLine = -1; + let paragraphStart = -1; + + const possiblyAddParagraph = ( + paragraphStart: number, + paragraphEnd: number + ) => { + // Paragraph and selection intersects + if (paragraphEnd >= startLine && paragraphStart <= endLine) { + targets.push( + this.getTargetFromRange( + target, + new Range(paragraphStart, 0, paragraphEnd, 0) + ) + ); + } + }; for (let i = 0; i < lineCount; ++i) { const line = editor.document.lineAt(i); - if (line.isEmptyOrWhitespace || i === lineCount - 1) { + if (line.isEmptyOrWhitespace) { // End of paragraph - if (paragraphStartLine > -1) { - paragraphs.push({ start: paragraphStartLine, end: i - 1 }); - paragraphStartLine = -1; + if (paragraphStart > -1) { + possiblyAddParagraph(paragraphStart, i - 1); + paragraphStart = -1; } } // Start of paragraph - else if (paragraphStartLine < 0) { - paragraphStartLine = i; + else if (paragraphStart < 0) { + paragraphStart = i; } - } - - paragraphs.forEach((paragraph) => { - if (paragraph.end >= startLine && paragraph.start <= endLine) { - targets.push( - this.getTargetFromRange( - target, - new Range(paragraph.start, 0, paragraph.end, 0) - ) - ); + // Last line is non empty. End of paragraph + if (i === lineCount - 1 && !line.isEmptyOrWhitespace) { + possiblyAddParagraph(paragraphStart, i); } - }); + } if (targets.length === 0) { throw new Error(`Couldn't find containing ${this.modifier.scopeType}`); diff --git a/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts index 2fdcb96c09..42f93984da 100644 --- a/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts @@ -12,11 +12,45 @@ import { ModifierStage } from "../../PipelineStages.types"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} - run(context: ProcessedTargetsContext, target: Target): ScopeTypeTarget { - const contentRange = getTokenRangeForSelection( - target.editor, - target.contentRange - ); + run( + context: ProcessedTargetsContext, + target: Target + ): ScopeTypeTarget | ScopeTypeTarget[] { + if (this.modifier.type === "everyScope") { + return this.getEveryTarget(context, target); + } + return this.getSingleTarget(target); + } + + getEveryTarget( + context: ProcessedTargetsContext, + target: Target + ): ScopeTypeTarget[] { + const { contentRange, editor } = target; + const { isEmpty } = contentRange; + const start = isEmpty + ? editor.document.lineAt(contentRange.start).range.start + : contentRange.start; + const end = isEmpty + ? editor.document.lineAt(contentRange.end).range.end + : contentRange.end; + + return context.hatTokenMap + .getTokens() + .filter( + ({ range }) => + // Token and selection intersects + range.end.isAfterOrEqual(start) && range.end.isBeforeOrEqual(end) + ) + .map(({ range }) => this.getTargetFromRange(target, range)); + } + + getSingleTarget(target: Target): ScopeTypeTarget { + return this.getTargetFromRange(target, target.contentRange); + } + + getTargetFromRange(target: Target, range: Range): ScopeTypeTarget { + const contentRange = getTokenRangeForSelection(target.editor, range); const newTarget = { scopeType: this.modifier.scopeType, editor: target.editor, From 66a936c55d45e1e4c4d4c4cb06e5931fa9612b08 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 18 May 2022 01:56:02 +0200 Subject: [PATCH 111/314] Added every too regex stages --- .../scopeTypeStages/NotebookCellStage.ts | 4 + .../modifiers/scopeTypeStages/RegexStage.ts | 94 +++++++++++++++---- .../modifiers/scopeTypeStages/TokenStage.ts | 8 +- 3 files changed, 87 insertions(+), 19 deletions(-) diff --git a/src/processTargets/modifiers/scopeTypeStages/NotebookCellStage.ts b/src/processTargets/modifiers/scopeTypeStages/NotebookCellStage.ts index 834cd8b2a3..5ebe6b5f93 100644 --- a/src/processTargets/modifiers/scopeTypeStages/NotebookCellStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/NotebookCellStage.ts @@ -11,6 +11,10 @@ export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} run(context: ProcessedTargetsContext, target: Target): ScopeTypeTarget { + if (this.modifier.type === "everyScope") { + throw new Error(`Every ${this.modifier.type} not yet implemented`); + } + return { scopeType: this.modifier.scopeType, editor: target.editor, diff --git a/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts b/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts index 349c9ce758..c1d914a884 100644 --- a/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts @@ -16,16 +16,62 @@ class RegexStage implements ModifierStage { private name?: string ) {} - run(context: ProcessedTargetsContext, target: Target): ScopeTypeTarget { + run( + context: ProcessedTargetsContext, + target: Target + ): ScopeTypeTarget | ScopeTypeTarget[] { + if (this.modifier.type === "everyScope") { + return this.getEveryTarget(target); + } + return this.getSingleTarget(target); + } + + getEveryTarget(target: Target): ScopeTypeTarget[] { + const { contentRange, editor } = target; + const { isEmpty } = contentRange; + const start = isEmpty + ? editor.document.lineAt(contentRange.start).range.start + : contentRange.start; + const end = isEmpty + ? editor.document.lineAt(contentRange.end).range.end + : contentRange.end; + const targets: ScopeTypeTarget[] = []; + + for (let i = start.line; i <= end.line; ++i) { + this.getMatchesForLine(editor, i) + .filter( + (range) => + // Regex match and selection intersects + range.end.isAfterOrEqual(start) && range.end.isBeforeOrEqual(end) + ) + .forEach((range) => { + targets.push(this.getTargetFromRange(target, range)); + }); + } + + if (targets.length === 0) { + if (targets.length === 0) { + throw new Error(`Couldn't find containing ${this.modifier.scopeType}`); + } + } + + return targets; + } + + getSingleTarget(target: Target): ScopeTypeTarget { const { editor } = target; - const start = this.getMatch(editor, target.contentRange.start).start; - const end = this.getMatch(editor, target.contentRange.end).end; + 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); + } + + getTargetFromRange(target: Target, range: Range): ScopeTypeTarget { const newTarget = { scopeType: this.modifier.scopeType, - editor, + editor: target.editor, isReversed: target.isReversed, - contentRange, + contentRange: range, }; return { ...newTarget, @@ -33,19 +79,31 @@ class RegexStage implements ModifierStage { }; } - getMatch(editor: TextEditor, position: Position) { - const line = editor.document.lineAt(position); - const result = [...line.text.matchAll(this.regex)] - .map( - (match) => - new Range( - position.line, - match.index!, - position.line, - match.index! + match[0].length - ) - ) - .find((range) => range.contains(position)); + getMatchForPos(editor: TextEditor, position: Position) { + const match = this.getMatchesForLine(editor, position.line).find((range) => + range.contains(position) + ); + if (match == null) { + if (this.name) { + throw new Error(`Couldn't find containing ${this.name}`); + } else { + throw new Error(`Cannot find sequence defined by regex: ${this.regex}`); + } + } + return match; + } + + getMatchesForLine(editor: TextEditor, lineNum: number) { + const line = editor.document.lineAt(lineNum); + const result = [...line.text.matchAll(this.regex)].map( + (match) => + new Range( + lineNum, + match.index!, + lineNum, + match.index! + match[0].length + ) + ); if (result == null) { if (this.name) { throw new Error(`Couldn't find containing ${this.name}`); diff --git a/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts index 42f93984da..231c7e3001 100644 --- a/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts @@ -35,7 +35,7 @@ export default class implements ModifierStage { ? editor.document.lineAt(contentRange.end).range.end : contentRange.end; - return context.hatTokenMap + const targets = context.hatTokenMap .getTokens() .filter( ({ range }) => @@ -43,6 +43,12 @@ export default class implements ModifierStage { range.end.isAfterOrEqual(start) && range.end.isBeforeOrEqual(end) ) .map(({ range }) => this.getTargetFromRange(target, range)); + + if (targets.length === 0) { + throw new Error(`Couldn't find containing ${this.modifier.scopeType}`); + } + + return targets; } getSingleTarget(target: Target): ScopeTypeTarget { From 9b7d94d5b99e1b6937a953604b926e26f1231db2 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 18 May 2022 01:59:26 +0200 Subject: [PATCH 112/314] Cleanup --- .../modifiers/scopeTypeStages/RegexStage.ts | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts b/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts index c1d914a884..4bbe013296 100644 --- a/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts @@ -38,15 +38,12 @@ class RegexStage implements ModifierStage { const targets: ScopeTypeTarget[] = []; for (let i = start.line; i <= end.line; ++i) { - this.getMatchesForLine(editor, i) - .filter( - (range) => - // Regex match and selection intersects - range.end.isAfterOrEqual(start) && range.end.isBeforeOrEqual(end) - ) - .forEach((range) => { + this.getMatchesForLine(editor, i).forEach((range) => { + // Regex match and selection intersects + if (range.end.isAfterOrEqual(start) && range.end.isBeforeOrEqual(end)) { targets.push(this.getTargetFromRange(target, range)); - }); + } + }); } if (targets.length === 0) { From b700e455e6d22c80201580060fd2007cee8fa261 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 18 May 2022 10:22:43 +0200 Subject: [PATCH 113/314] Moved example of custom test transformation to docs --- src/scripts/transformRecordedTests/index.ts | 9 +++-- .../updateSurroundingPairTest.ts | 34 ------------------- 2 files changed, 4 insertions(+), 39 deletions(-) delete mode 100644 src/scripts/transformRecordedTests/transformations/updateSurroundingPairTest.ts diff --git a/src/scripts/transformRecordedTests/index.ts b/src/scripts/transformRecordedTests/index.ts index 4d8acd7c3d..60f12074ce 100644 --- a/src/scripts/transformRecordedTests/index.ts +++ b/src/scripts/transformRecordedTests/index.ts @@ -1,14 +1,13 @@ -import { updateSurroundingPairTest } from "./transformations/updateSurroundingPairTest"; -import { FixtureTransformation } from "./types"; -import { upgrade } from "./transformations/upgrade"; +import { getRecordedTestPaths } from "../../test/util/getFixturePaths"; import { identity } from "./transformations/identity"; +import { upgrade } from "./transformations/upgrade"; import { transformFile } from "./transformFile"; -import { getRecordedTestPaths } from "../../test/util/getFixturePaths"; +import { FixtureTransformation } from "./types"; const AVAILABLE_TRANSFORMATIONS: Record = { upgrade, autoFormat: identity, - custom: updateSurroundingPairTest, + // custom: MY_CUSTOM_TRANSFORMER, }; async function main(transformationName: string | undefined) { diff --git a/src/scripts/transformRecordedTests/transformations/updateSurroundingPairTest.ts b/src/scripts/transformRecordedTests/transformations/updateSurroundingPairTest.ts deleted file mode 100644 index 840d793f79..0000000000 --- a/src/scripts/transformRecordedTests/transformations/updateSurroundingPairTest.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { TestCaseFixture } from "../../../testUtil/TestCase"; -import { transformPartialPrimitiveTargets } from "../../../util/getPrimitiveTargets"; -import { PartialPrimitiveTargetDesc } from "../../../typings/target.types"; - -// Leaving an example here in case it's helpful -export function updateSurroundingPairTest(fixture: TestCaseFixture) { - fixture.command.targets = transformPartialPrimitiveTargets( - fixture.command.targets, - (target: PartialPrimitiveTargetDesc) => { - target.modifiers?.forEach((modifier) => { - if (modifier?.type === "surroundingPair") { - // TODO - // let delimiterInclusion: DelimiterInclusion; - // switch (modifier.delimiterInclusion as any) { - // case "includeDelimiters": - // delimiterInclusion = undefined; - // break; - // case "excludeDelimiters": - // delimiterInclusion = "interiorOnly"; - // break; - // case "delimitersOnly": - // delimiterInclusion = "excludeInterior"; - // break; - // } - // modifier.delimiterInclusion = delimiterInclusion; - } - }); - - return target; - } - ); - - return fixture; -} From e85e9134a3657b26f6247ab87017f2e485858353 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 18 May 2022 21:14:18 +0200 Subject: [PATCH 114/314] Update src/core/commandVersionUpgrades/upgradeV1ToV2/commandV1.types.ts Co-authored-by: Pokey Rule <755842+pokey@users.noreply.github.com> --- .../commandVersionUpgrades/upgradeV1ToV2/commandV1.types.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/commandV1.types.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/commandV1.types.ts index 30c167bc93..40f9f6d075 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/commandV1.types.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/commandV1.types.ts @@ -1,3 +1,6 @@ +// This file contains a snapshot of all the types used by the deprecated v0 / v1 target representation, +// to be used by on-the-fly target upgrading for background compatibility + export interface CommandV1 extends CommandV0V1 { version: 1; } From ca1295f92554aa72aca6ef72aa6eaa2140ddf12d Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 18 May 2022 21:42:40 +0200 Subject: [PATCH 115/314] Update src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts Co-authored-by: Pokey Rule <755842+pokey@users.noreply.github.com> --- .../upgradeV1ToV2/upgradeV1ToV2.ts | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts index fed198c7e7..fcbd31f22c 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts @@ -34,17 +34,8 @@ function upgradeModifier(modifier: ModifierV0V1): Modifier | Modifier[] | null { return null; case "containingScope": - const mod = { - ...modifier, - scopeType: modifier.scopeType as ScopeType, - }; - if (modifier.includeSiblings) { - return { - ...mod, - type: "everyScope", - }; - } - return mod; + const {includeSiblings, scopeType, ...rest} = modifier; + return {type: includeSiblings ? "everyScope" : "containingScope", scopeType: scopeType as ScopeType, ...rest}; case "surroundingPair": const { delimiterInclusion, ...rest } = modifier; From 06adf4cdf7b044f096a7adbda4fe6ee2611e89d5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 18 May 2022 19:43:31 +0000 Subject: [PATCH 116/314] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts index fcbd31f22c..44b7f79614 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts @@ -34,8 +34,12 @@ function upgradeModifier(modifier: ModifierV0V1): Modifier | Modifier[] | null { return null; case "containingScope": - const {includeSiblings, scopeType, ...rest} = modifier; - return {type: includeSiblings ? "everyScope" : "containingScope", scopeType: scopeType as ScopeType, ...rest}; + const { includeSiblings, scopeType, ...rest } = modifier; + return { + type: includeSiblings ? "everyScope" : "containingScope", + scopeType: scopeType as ScopeType, + ...rest, + }; case "surroundingPair": const { delimiterInclusion, ...rest } = modifier; From c95e0dc973a7ece48084c56d8229d3b367870a91 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 19 May 2022 05:10:00 +0200 Subject: [PATCH 117/314] Added OO targets --- .../src/modifiers/interior_boundary.py | 6 +- src/actions/BringMoveSwap.ts | 57 +++--- src/actions/CommandAction.ts | 5 +- src/actions/CutCopyPaste.ts | 30 +-- src/actions/EditNewLine.ts | 7 +- src/actions/GetText.ts | 8 +- src/actions/InsertEmptyLines.ts | 7 +- src/actions/Replace.ts | 12 +- src/actions/Rewrap.ts | 18 +- src/actions/SetSelection.ts | 8 +- src/actions/ToggleBreakpoint.ts | 4 +- src/actions/Wrap.ts | 7 +- src/actions/WrapWithSnippet.ts | 6 +- src/core/commandRunner/CommandRunner.ts | 4 +- .../canonicalizeAndValidateCommand.ts | 6 +- .../upgradeV1ToV2/upgradeV1ToV2.ts | 15 +- src/core/inferFullTargets.ts | 18 +- src/processTargets/marks/CursorStage.ts | 13 +- .../marks/DecoratedSymbolStage.ts | 16 +- src/processTargets/marks/LineNumberStage.ts | 11 +- src/processTargets/marks/SourceStage.ts | 10 +- src/processTargets/marks/ThatStage.ts | 10 +- src/processTargets/modifiers/HeadTailStage.ts | 8 +- src/processTargets/modifiers/InteriorStage.ts | 21 +- src/processTargets/modifiers/PositionStage.ts | 45 +++-- .../modifiers/RawSelectionStage.ts | 5 +- src/processTargets/modifiers/SubPieceStage.ts | 17 +- .../modifiers/SurroundingPairStage.ts | 12 +- .../ContainingSyntaxScopeStage.ts | 17 +- .../scopeTypeStages/DocumentStage.ts | 6 +- .../modifiers/scopeTypeStages/LineStage.ts | 16 +- .../scopeTypeStages/NotebookCellStage.ts | 10 +- .../scopeTypeStages/ParagraphStage.ts | 191 ++++++++---------- .../modifiers/scopeTypeStages/RegexStage.ts | 11 +- .../modifiers/scopeTypeStages/TokenStage.ts | 36 ++-- src/processTargets/processTargets.ts | 186 ++++++++--------- src/processTargets/targets/BaseTarget.ts | 150 ++++++++++++++ src/processTargets/targets/LineTarget.ts | 17 ++ src/processTargets/targets/ScopeTypeTarget.ts | 18 ++ .../fixtures/inferFullTargets.fixture.ts | 7 +- src/testUtil/TestCase.ts | 10 +- src/testUtil/extractTargetedMarks.ts | 9 +- src/typings/target.types.ts | 80 ++++---- src/util/editDisplayUtils.ts | 19 +- src/util/getPrimitiveTargets.ts | 10 +- src/util/targetUtils.ts | 123 +++++------ src/util/unifyRanges.ts | 21 +- 47 files changed, 727 insertions(+), 596 deletions(-) create mode 100644 src/processTargets/targets/BaseTarget.ts create mode 100644 src/processTargets/targets/LineTarget.ts create mode 100644 src/processTargets/targets/ScopeTypeTarget.ts diff --git a/cursorless-talon/src/modifiers/interior_boundary.py b/cursorless-talon/src/modifiers/interior_boundary.py index 688e68957f..909b9aa6b7 100644 --- a/cursorless-talon/src/modifiers/interior_boundary.py +++ b/cursorless-talon/src/modifiers/interior_boundary.py @@ -1,5 +1,3 @@ -from typing import Any - from talon import Module mod = Module() @@ -9,9 +7,9 @@ desc="Inside or boundary delimiter inclusion", ) -# TODO [{user.cursorless_delimiter_force_direction}] + @mod.capture(rule="{user.cursorless_delimiter_inclusion}") -def cursorless_delimiter_inclusion(m) -> dict[str, Any]: +def cursorless_delimiter_inclusion(m) -> dict[str, str]: """Inside or boundary delimiter inclusion""" return { "type": m.cursorless_delimiter_inclusion, diff --git a/src/actions/BringMoveSwap.ts b/src/actions/BringMoveSwap.ts index 2ea73a20b8..bb7a13e785 100644 --- a/src/actions/BringMoveSwap.ts +++ b/src/actions/BringMoveSwap.ts @@ -9,10 +9,7 @@ import { Edit, Graph } from "../typings/Types"; import displayPendingEditDecorations from "../util/editDisplayUtils"; import { getContentRange, - getContentSelection, - getContentText, getRemovalRange, - maybeAddDelimiter, runForEachEditor, } from "../util/targetUtils"; import { unifyRemovalTargets } from "../util/unifyRanges"; @@ -23,14 +20,14 @@ type ActionType = "bring" | "move" | "swap"; interface ExtendedEdit extends Edit { editor: TextEditor; isSource: boolean; - originalSelection: Target; + originalTarget: Target; } interface MarkEntry { editor: TextEditor; selection: Selection; isSource: boolean; - typedSelection: Target; + target: Target; } class BringMoveSwap implements Action { @@ -47,7 +44,7 @@ class BringMoveSwap implements Action { return sources; } - private getDecorationStyles() { + private getDecorationContext() { let sourceStyle; let getSourceRangeCallback; if (this.type === "bring") { @@ -70,16 +67,16 @@ class BringMoveSwap implements Action { } private async decorateTargets(sources: Target[], destinations: Target[]) { - const decorationTypes = this.getDecorationStyles(); + const decorationContext = this.getDecorationContext(); await Promise.all([ displayPendingEditDecorations( sources, - decorationTypes.sourceStyle, - decorationTypes.getSourceRangeCallback + decorationContext.sourceStyle, + decorationContext.getSourceRangeCallback ), displayPendingEditDecorations( destinations, - decorationTypes.destinationStyle + decorationContext.destinationStyle ), ]); } @@ -103,7 +100,7 @@ class BringMoveSwap implements Action { if (zipSources) { text = sources .map((source, i) => { - const text = getContentText(source); + const text = source.getContentText(); const containingListDelimiter = destination.delimiter ?? source.delimiter; return i > 0 && containingListDelimiter @@ -111,7 +108,7 @@ class BringMoveSwap implements Action { : text; }) .join(""); - text = maybeAddDelimiter(text, destination); + text = destination.maybeAddDelimiter(text); } else { // Get text adjusting for destination position text = getTextWithPossibleDelimiter(source, destination); @@ -121,7 +118,7 @@ class BringMoveSwap implements Action { range: destination.contentRange, text, editor: destination.editor, - originalSelection: destination, + originalTarget: destination, isSource: false, isReplace: destination.position === "after" || destination.position === "end", @@ -137,9 +134,9 @@ class BringMoveSwap implements Action { if (this.type !== "move") { results.push({ range: source.contentRange, - text: getContentText(destination), + text: destination.getContentText(), editor: source.editor, - originalSelection: source, + originalTarget: source, isSource: true, isReplace: false, }); @@ -151,10 +148,10 @@ class BringMoveSwap implements Action { // Unify overlapping targets. unifyRemovalTargets(usedSources).forEach((source) => { results.push({ - range: getRemovalRange(source), + range: source.getRemovalRange(), text: "", editor: source.editor, - originalSelection: source, + originalTarget: source, isSource: true, isReplace: false, }); @@ -178,10 +175,10 @@ class BringMoveSwap implements Action { ? edits : edits.filter(({ isSource }) => !isSource); - const editSelectionInfos = edits.map(({ originalSelection }) => + const editSelectionInfos = edits.map(({ originalTarget }) => getSelectionInfo( editor.document, - getContentSelection(originalSelection), + originalTarget.getContentSelection(), DecorationRangeBehavior.OpenOpen ) ); @@ -204,14 +201,14 @@ class BringMoveSwap implements Action { editor.selections = cursorSelections; - return edits.map((edit, index) => { + return edits.map((edit, index): MarkEntry => { const selection = updatedEditSelections[index]; return { editor, selection, isSource: edit!.isSource, - typedSelection: { - ...edit!.originalSelection, + target: { + ...edit!.originalTarget, contentRange: selection, }, }; @@ -222,19 +219,17 @@ class BringMoveSwap implements Action { } private async decorateThatMark(thatMark: MarkEntry[]) { - const decorationTypes = this.getDecorationStyles(); + const decorationContext = this.getDecorationContext(); return Promise.all([ displayPendingEditDecorations( - thatMark - .filter(({ isSource }) => isSource) - .map(({ typedSelection }) => typedSelection), - decorationTypes.sourceStyle + thatMark.filter(({ isSource }) => isSource).map(({ target }) => target), + decorationContext.sourceStyle ), displayPendingEditDecorations( thatMark .filter(({ isSource }) => !isSource) - .map(({ typedSelection }) => typedSelection), - decorationTypes.destinationStyle + .map(({ target }) => target), + decorationContext.destinationStyle ), ]); } @@ -295,6 +290,6 @@ export class Swap extends BringMoveSwap { /** Get text from selection. Possibly add delimiter for positions before/after */ function getTextWithPossibleDelimiter(source: Target, destination: Target) { - const sourceText = getContentText(source); - return maybeAddDelimiter(sourceText, destination); + const sourceText = source.getContentText(); + return destination.maybeAddDelimiter(sourceText); } diff --git a/src/actions/CommandAction.ts b/src/actions/CommandAction.ts index e73579644e..730406afb4 100644 --- a/src/actions/CommandAction.ts +++ b/src/actions/CommandAction.ts @@ -10,7 +10,6 @@ import { } from "../util/setSelectionsAndFocusEditor"; import { ensureSingleEditor, - getContentSelection, runOnTargetsForEachEditor, } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; @@ -43,7 +42,9 @@ export default class CommandAction implements Action { await runOnTargetsForEachEditor(targets, async (editor, targets) => { const originalSelections = editor.selections; - const targetSelections = targets.map(getContentSelection); + const targetSelections = targets.map((target) => + target.getContentSelection() + ); // For command to the work we have to have the correct editor focused await setSelectionsAndFocusEditor(editor, targetSelections, false); diff --git a/src/actions/CutCopyPaste.ts b/src/actions/CutCopyPaste.ts index 87bfb3b2ac..40771b9015 100644 --- a/src/actions/CutCopyPaste.ts +++ b/src/actions/CutCopyPaste.ts @@ -1,4 +1,5 @@ import { Target } from "../typings/target.types"; +import BaseTarget from "../processTargets/targets/BaseTarget"; import { Graph } from "../typings/Types"; import displayPendingEditDecorations from "../util/editDisplayUtils"; import { @@ -14,20 +15,21 @@ export class Cut implements Action { } async run([targets]: [Target[]]): Promise { - const overflowTargets = targets.flatMap((target) => - getOutsideOverflow( - target.editor, - target.contentRange, - getRemovalHighlightRange(target) - ).map( - (overflow): Target => ({ - editor: target.editor, - scopeType: target.scopeType, - contentRange: overflow, - isReversed: false, - }) - ) - ); + const overflowTargets = targets.flatMap((target) => { + const range = getRemovalHighlightRange(target); + if (range == null) { + return []; + } + return getOutsideOverflow(target.editor, target.contentRange, range).map( + (overflow): Target => + new BaseTarget({ + editor: target.editor, + scopeType: target.scopeType, + contentRange: overflow, + isReversed: false, + }) + ); + }); await Promise.all([ displayPendingEditDecorations(targets, this.graph.editStyles.referenced), diff --git a/src/actions/EditNewLine.ts b/src/actions/EditNewLine.ts index afd24da0c9..c1f53d23e4 100644 --- a/src/actions/EditNewLine.ts +++ b/src/actions/EditNewLine.ts @@ -13,12 +13,9 @@ class EditNewLine implements Action { targets.forEach((target) => { let { start, end } = target.contentRange; if (target.scopeType === "paragraph") { - if (this.isAbove && target.removal?.leadingDelimiterRange != null) { + if (this.isAbove && target.leadingDelimiter != null) { start = start.translate({ lineDelta: -1 }); - } else if ( - !this.isAbove && - target.removal?.trailingDelimiterRange != null - ) { + } else if (!this.isAbove && target.trailingDelimiter != null) { end = end.translate({ lineDelta: 1 }); } target.contentRange = new Range(start, end); diff --git a/src/actions/GetText.ts b/src/actions/GetText.ts index c32afa2fc3..e9dabf0173 100644 --- a/src/actions/GetText.ts +++ b/src/actions/GetText.ts @@ -1,11 +1,7 @@ import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; import displayPendingEditDecorations from "../util/editDisplayUtils"; -import { - createThatMark, - ensureSingleTarget, - getContentText, -} from "../util/targetUtils"; +import { createThatMark, ensureSingleTarget } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; export default class GetText implements Action { @@ -32,7 +28,7 @@ export default class GetText implements Action { } return { - returnValue: targets.map(getContentText), + returnValue: targets.map((target) => target.getContentText()), thatMark: createThatMark(targets), }; } diff --git a/src/actions/InsertEmptyLines.ts b/src/actions/InsertEmptyLines.ts index 95a5e12213..d8a5052f00 100644 --- a/src/actions/InsertEmptyLines.ts +++ b/src/actions/InsertEmptyLines.ts @@ -4,10 +4,7 @@ import { performEditsAndUpdateSelections } from "../core/updateSelections/update import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; import { displayPendingEditDecorationsForRanges } from "../util/editDisplayUtils"; -import { - getContentSelection, - runOnTargetsForEachEditor, -} from "../util/targetUtils"; +import { runOnTargetsForEachEditor } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; class InsertEmptyLines implements Action { @@ -55,7 +52,7 @@ class InsertEmptyLines implements Action { editor, edits, [ - targets.map((target) => getContentSelection(target)), + targets.map((target) => target.getContentSelection()), ranges.map((range) => new Selection(range.start, range.end)), editor.selections, ] diff --git a/src/actions/Replace.ts b/src/actions/Replace.ts index 2e46d53af1..3762a59b16 100644 --- a/src/actions/Replace.ts +++ b/src/actions/Replace.ts @@ -1,13 +1,9 @@ -import { zip, flatten } from "lodash"; +import { flatten, zip } from "lodash"; import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; import displayPendingEditDecorations from "../util/editDisplayUtils"; -import { - getContentSelection, - maybeAddDelimiter, - runForEachEditor, -} from "../util/targetUtils"; +import { runForEachEditor } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; type RangeGenerator = { start: number }; @@ -53,7 +49,7 @@ export default class implements Action { const edits = zip(targets, texts).map(([target, text]) => ({ editor: target!.editor, range: target!.contentRange, - text: maybeAddDelimiter(text!, target!), + text: target!.maybeAddDelimiter(text!), })); const thatMark = flatten( @@ -65,7 +61,7 @@ export default class implements Action { this.graph.rangeUpdater, editor, edits, - [targets.map(getContentSelection)] + [targets.map((target) => target.getContentSelection())] ); return updatedSelections.map((selection) => ({ diff --git a/src/actions/Rewrap.ts b/src/actions/Rewrap.ts index 9734b19719..7c1129e411 100644 --- a/src/actions/Rewrap.ts +++ b/src/actions/Rewrap.ts @@ -1,9 +1,10 @@ import { flatten, zip } from "lodash"; import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; import { Target } from "../typings/target.types"; +import BaseTarget from "../processTargets/targets/BaseTarget"; import { ActionPreferences, Graph } from "../typings/Types"; import displayPendingEditDecorations from "../util/editDisplayUtils"; -import { getContentSelection, runForEachEditor } from "../util/targetUtils"; +import { runForEachEditor } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; export default class Rewrap implements Action { @@ -36,12 +37,15 @@ export default class Rewrap implements Action { return { editor: target.editor, - boundary: boundary.map((edge) => ({ - editor: target.editor, - contentRange: edge, - isReversed: target.isReversed, - })), - targetSelection: getContentSelection(target), + boundary: boundary.map( + (edge) => + new BaseTarget({ + editor: target.editor, + contentRange: edge, + isReversed: target.isReversed, + }) + ), + targetSelection: target.getContentSelection(), }; }); diff --git a/src/actions/SetSelection.ts b/src/actions/SetSelection.ts index 5a1c033a96..8ad32e2938 100644 --- a/src/actions/SetSelection.ts +++ b/src/actions/SetSelection.ts @@ -2,11 +2,7 @@ import { Selection } from "vscode"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; import { setSelectionsAndFocusEditor } from "../util/setSelectionsAndFocusEditor"; -import { - createThatMark, - ensureSingleEditor, - getContentSelection, -} from "../util/targetUtils"; +import { createThatMark, ensureSingleEditor } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; export class SetSelection implements Action { @@ -15,7 +11,7 @@ export class SetSelection implements Action { } protected getSelection(target: Target) { - return getContentSelection(target); + return target.getContentSelection(); } async run([targets]: [Target[]]): Promise { diff --git a/src/actions/ToggleBreakpoint.ts b/src/actions/ToggleBreakpoint.ts index ee632b6c74..26e7e2b866 100644 --- a/src/actions/ToggleBreakpoint.ts +++ b/src/actions/ToggleBreakpoint.ts @@ -42,7 +42,7 @@ export default class ToggleBreakpoint implements Action { targets.forEach((target) => { let range = target.contentRange; // The action preference give us line content but line breakpoints are registered on character 0 - if (isLineScopeType(target)) { + if (isLineScopeType(target.scopeType)) { range = range.with(range.start.with(undefined, 0), undefined); } const uri = target.editor.document.uri; @@ -50,7 +50,7 @@ export default class ToggleBreakpoint implements Action { if (existing.length > 0) { toRemove.push(...existing); } else { - if (isLineScopeType(target)) { + if (isLineScopeType(target.scopeType)) { range = range.with(undefined, range.end.with(undefined, 0)); } toAdd.push(new SourceBreakpoint(new Location(uri, range))); diff --git a/src/actions/Wrap.ts b/src/actions/Wrap.ts index 4d34ba99fc..5f7fbb20e6 100644 --- a/src/actions/Wrap.ts +++ b/src/actions/Wrap.ts @@ -8,10 +8,7 @@ import { Target } from "../typings/target.types"; import { Edit, Graph, SelectionWithEditor } from "../typings/Types"; import { FullSelectionInfo } from "../typings/updateSelections"; import { decorationSleep } from "../util/editDisplayUtils"; -import { - getContentSelection, - runOnTargetsForEachEditor, -} from "../util/targetUtils"; +import { runOnTargetsForEachEditor } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; export default class Wrap implements Action { @@ -79,7 +76,7 @@ export default class Wrap implements Action { const thatMarkSelectionInfos = targets.map((target) => getSelectionInfo( document, - getContentSelection(target), + target.getContentSelection(), DecorationRangeBehavior.OpenOpen ) ); diff --git a/src/actions/WrapWithSnippet.ts b/src/actions/WrapWithSnippet.ts index 96995ff9e7..85362ce258 100644 --- a/src/actions/WrapWithSnippet.ts +++ b/src/actions/WrapWithSnippet.ts @@ -4,7 +4,7 @@ import { SnippetDefinition } from "../typings/snippet"; import { Target } from "../typings/target.types"; import { ActionPreferences, Graph } from "../typings/Types"; import displayPendingEditDecorations from "../util/editDisplayUtils"; -import { ensureSingleEditor, getContentSelection } from "../util/targetUtils"; +import { ensureSingleEditor } from "../util/targetUtils"; import { Placeholder, SnippetParser, @@ -86,7 +86,9 @@ export default class WrapWithSnippet implements Action { this.graph.editStyles.pendingModification0 ); - const targetSelections = targets.map(getContentSelection); + const targetSelections = targets.map((target) => + target.getContentSelection() + ); await this.graph.actions.setSelection.run([targets]); diff --git a/src/core/commandRunner/CommandRunner.ts b/src/core/commandRunner/CommandRunner.ts index 1a695be01d..10b67721df 100644 --- a/src/core/commandRunner/CommandRunner.ts +++ b/src/core/commandRunner/CommandRunner.ts @@ -66,7 +66,7 @@ export default class CommandRunner { const { spokenForm, action: actionName, - targets: partialTargetDescs, + targets: partialTargetDescriptors, extraArgs, usePrePhraseSnapshot, } = commandComplete; @@ -82,7 +82,7 @@ export default class CommandRunner { } const targetDescs = inferFullTargets( - partialTargetDescs, + partialTargetDescriptors, action.getTargetPreferences ? action.getTargetPreferences(...extraArgs) : undefined diff --git a/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts b/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts index 0cf7d98a60..9ecd9225ea 100644 --- a/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts +++ b/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts @@ -76,7 +76,11 @@ function upgradeCommand(command: Command): CommandLatest { } } - return command as CommandLatest; // TODO Better implementation ? + if (command.version !== LATEST_VERSION) { + throw new Error("Command is not latest version"); + } + + return command; } export function validateCommand( diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts index fed198c7e7..50174b0d5b 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts @@ -28,10 +28,10 @@ export function upgradeV1ToV2(command: CommandV1): CommandV2 { }; } -function upgradeModifier(modifier: ModifierV0V1): Modifier | Modifier[] | null { +function upgradeModifier(modifier: ModifierV0V1): Modifier | Modifier[] { switch (modifier.type) { case "identity": - return null; + return []; case "containingScope": const mod = { @@ -81,12 +81,10 @@ function upgradePrimitiveTarget( if (modifier) { const mod = upgradeModifier(modifier); - if (mod) { - if (Array.isArray(mod)) { - modifiers.push(...mod); - } else { - modifiers.push(mod); - } + if (Array.isArray(mod)) { + modifiers.push(...mod); + } else { + modifiers.push(mod); } } @@ -110,6 +108,7 @@ function upgradePrimitiveTarget( } } + // Cursor token is just cursor position but treated as a token. This is done in the pipeline for normal cursor now const newMark = mark?.type === "cursorToken" ? undefined : mark; return { diff --git a/src/core/inferFullTargets.ts b/src/core/inferFullTargets.ts index d2c53a7783..f7849d3da3 100644 --- a/src/core/inferFullTargets.ts +++ b/src/core/inferFullTargets.ts @@ -3,9 +3,9 @@ import { PartialPrimitiveTargetDesc, PartialRangeTargetDesc, PartialTargetDesc, - PrimitiveTargetDesc, - RangeTargetDesc, - TargetDesc, + PrimitiveTargetDescriptor, + RangeTargetDescriptor, + TargetDescriptor, } from "../typings/target.types"; import { ActionPreferences } from "../typings/Types"; @@ -22,7 +22,7 @@ import { ActionPreferences } from "../typings/Types"; export default function inferFullTargets( targets: PartialTargetDesc[], actionPreferences?: ActionPreferences[] -): TargetDesc[] { +): TargetDescriptor[] { if ( actionPreferences != null && targets.length !== actionPreferences.length @@ -39,7 +39,7 @@ function inferTarget( target: PartialTargetDesc, previousTargets: PartialTargetDesc[], actionPreferences?: ActionPreferences -): TargetDesc { +): TargetDescriptor { switch (target.type) { case "list": return inferListTarget(target, previousTargets, actionPreferences); @@ -53,7 +53,7 @@ function inferListTarget( target: PartialListTargetDesc, previousTargets: PartialTargetDesc[], actionPreferences?: ActionPreferences -): TargetDesc { +): TargetDescriptor { return { ...target, elements: target.elements.map((element, index) => @@ -70,7 +70,7 @@ function inferNonListTarget( target: PartialPrimitiveTargetDesc | PartialRangeTargetDesc, previousTargets: PartialTargetDesc[], actionPreferences?: ActionPreferences -): PrimitiveTargetDesc | RangeTargetDesc { +): PrimitiveTargetDescriptor | RangeTargetDescriptor { switch (target.type) { case "primitive": return inferPrimitiveTarget(target, previousTargets, actionPreferences); @@ -83,7 +83,7 @@ function inferRangeTarget( target: PartialRangeTargetDesc, previousTargets: PartialTargetDesc[], actionPreferences?: ActionPreferences -): RangeTargetDesc { +): RangeTargetDescriptor { return { type: "range", excludeAnchor: target.excludeStart ?? false, @@ -106,7 +106,7 @@ function inferPrimitiveTarget( target: PartialPrimitiveTargetDesc, previousTargets: PartialTargetDesc[], actionPreferences?: ActionPreferences -): PrimitiveTargetDesc { +): PrimitiveTargetDescriptor { const hasPosition = !!target.modifiers?.find( (modifier) => modifier.type === "position" ); diff --git a/src/processTargets/marks/CursorStage.ts b/src/processTargets/marks/CursorStage.ts index f4ac690c83..b0d308ed9a 100644 --- a/src/processTargets/marks/CursorStage.ts +++ b/src/processTargets/marks/CursorStage.ts @@ -1,5 +1,6 @@ import { window } from "vscode"; import { CursorMark, Target } from "../../typings/target.types"; +import BaseTarget from "../targets/BaseTarget"; import { isReversed } from "../../util/selectionUtils"; import { getTokenContext } from "../modifiers/scopeTypeStages/TokenStage"; import { MarkStage } from "../PipelineStages.types"; @@ -12,15 +13,13 @@ export default class implements MarkStage { return []; } return window.activeTextEditor.selections.map((selection) => { - const target = { - editor: window.activeTextEditor!, + const editor = window.activeTextEditor!; + return new BaseTarget({ + ...getTokenContext(editor, selection), + editor, isReversed: isReversed(selection), contentRange: selection, - }; - return { - ...target, - ...getTokenContext(target), - }; + }); }); } } diff --git a/src/processTargets/marks/DecoratedSymbolStage.ts b/src/processTargets/marks/DecoratedSymbolStage.ts index b9b833bffa..2d8ba005e3 100644 --- a/src/processTargets/marks/DecoratedSymbolStage.ts +++ b/src/processTargets/marks/DecoratedSymbolStage.ts @@ -1,4 +1,5 @@ import { DecoratedSymbolMark, Target } from "../../typings/target.types"; +import BaseTarget from "../targets/BaseTarget"; import { ProcessedTargetsContext } from "../../typings/Types"; import { getTokenContext } from "../modifiers/scopeTypeStages/TokenStage"; import { MarkStage } from "../PipelineStages.types"; @@ -16,17 +17,14 @@ export default class implements MarkStage { `Couldn't find mark ${this.modifier.symbolColor} '${this.modifier.character}'` ); } - const target = { - editor: token.editor, - contentRange: token.range, - isReversed: false, - }; return [ - { - ...target, - ...getTokenContext(target), + new BaseTarget({ + ...getTokenContext(token.editor, token.range), scopeType: "token", - }, + editor: token.editor, + contentRange: token.range, + isReversed: false, + }), ]; } } diff --git a/src/processTargets/marks/LineNumberStage.ts b/src/processTargets/marks/LineNumberStage.ts index 577a864330..8fb3bdeaa7 100644 --- a/src/processTargets/marks/LineNumberStage.ts +++ b/src/processTargets/marks/LineNumberStage.ts @@ -1,9 +1,6 @@ import { Range, TextEditor, window } from "vscode"; -import { - LineNumberMark, - LineNumberPosition, - ScopeTypeTarget, -} from "../../typings/target.types"; +import { LineNumberMark, LineNumberPosition } from "../../typings/target.types"; +import ScopeTypeTarget from "../targets/ScopeTypeTarget"; import { getLineContext } from "../modifiers/scopeTypeStages/LineStage"; import { MarkStage } from "../PipelineStages.types"; @@ -22,13 +19,13 @@ export default class implements MarkStage { 0 ); return [ - { + new ScopeTypeTarget({ ...getLineContext(editor, contentRange), editor, contentRange, isReversed: false, scopeType: "line", - }, + }), ]; } } diff --git a/src/processTargets/marks/SourceStage.ts b/src/processTargets/marks/SourceStage.ts index a7c40e9cb2..897c2cc95a 100644 --- a/src/processTargets/marks/SourceStage.ts +++ b/src/processTargets/marks/SourceStage.ts @@ -1,4 +1,5 @@ import { SourceMark, Target } from "../../typings/target.types"; +import BaseTarget from "../targets/BaseTarget"; import { ProcessedTargetsContext } from "../../typings/Types"; import { isReversed } from "../../util/selectionUtils"; import { getTokenContext } from "../modifiers/scopeTypeStages/TokenStage"; @@ -9,15 +10,12 @@ export default class implements MarkStage { run(context: ProcessedTargetsContext): Target[] { return context.sourceMark.map((selection) => { - const target = { + return new BaseTarget({ + ...getTokenContext(selection.editor, selection.selection), editor: selection.editor, isReversed: isReversed(selection.selection), contentRange: selection.selection, - }; - return { - ...target, - ...getTokenContext(target), - }; + }); }); } } diff --git a/src/processTargets/marks/ThatStage.ts b/src/processTargets/marks/ThatStage.ts index b657350e72..0013b8e73e 100644 --- a/src/processTargets/marks/ThatStage.ts +++ b/src/processTargets/marks/ThatStage.ts @@ -1,4 +1,5 @@ import { Target, ThatMark } from "../../typings/target.types"; +import BaseTarget from "../targets/BaseTarget"; import { ProcessedTargetsContext } from "../../typings/Types"; import { isReversed } from "../../util/selectionUtils"; import { getTokenContext } from "../modifiers/scopeTypeStages/TokenStage"; @@ -9,15 +10,12 @@ export default class implements MarkStage { run(context: ProcessedTargetsContext): Target[] { return context.thatMark.map((selection) => { - const target = { + return new BaseTarget({ + ...getTokenContext(selection.editor, selection.selection), editor: selection.editor, isReversed: isReversed(selection.selection), contentRange: selection.selection, - }; - return { - ...target, - ...getTokenContext(target), - }; + }); }); } } diff --git a/src/processTargets/modifiers/HeadTailStage.ts b/src/processTargets/modifiers/HeadTailStage.ts index 39a4acb9af..2a7d9c5316 100644 --- a/src/processTargets/modifiers/HeadTailStage.ts +++ b/src/processTargets/modifiers/HeadTailStage.ts @@ -1,5 +1,6 @@ import { Position, Range, TextEditor } from "vscode"; import { HeadModifier, TailModifier, Target } from "../../typings/target.types"; +import BaseTarget from "../targets/BaseTarget"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; @@ -9,11 +10,12 @@ abstract class HeadTailStage implements ModifierStage { constructor(private isReversed: boolean) {} run(context: ProcessedTargetsContext, target: Target): Target { - return { + const contentRange = this.update(target.editor, target.contentRange); + return new BaseTarget({ editor: target.editor, isReversed: this.isReversed, - contentRange: this.update(target.editor, target.contentRange), - }; + contentRange, + }); } } diff --git a/src/processTargets/modifiers/InteriorStage.ts b/src/processTargets/modifiers/InteriorStage.ts index 3866876ef6..7f044b4aba 100644 --- a/src/processTargets/modifiers/InteriorStage.ts +++ b/src/processTargets/modifiers/InteriorStage.ts @@ -3,6 +3,7 @@ import { InteriorOnlyModifier, Target, } from "../../typings/target.types"; +import BaseTarget from "../targets/BaseTarget"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; import { processedSurroundingPairTarget } from "./SurroundingPairStage"; @@ -41,11 +42,12 @@ export class InteriorOnlyStage extends InteriorStage { if (target.interiorRange == null) { throw Error("No available interior"); } - return { + const contentRange = target.interiorRange; + return new BaseTarget({ editor: target.editor, isReversed: target.isReversed, - contentRange: target.interiorRange, - }; + contentRange, + }); } hasData(target: Target): boolean { @@ -62,11 +64,14 @@ export class ExcludeInteriorStage extends InteriorStage { if (target.boundary == null) { throw Error("No available boundaries"); } - return target.boundary.map((contentRange) => ({ - editor: target.editor, - isReversed: target.isReversed, - contentRange, - })); + return target.boundary.map( + (contentRange) => + new BaseTarget({ + editor: target.editor, + isReversed: target.isReversed, + contentRange, + }) + ); } hasData(target: Target): boolean { diff --git a/src/processTargets/modifiers/PositionStage.ts b/src/processTargets/modifiers/PositionStage.ts index 8fad6314e4..90fdca5a80 100644 --- a/src/processTargets/modifiers/PositionStage.ts +++ b/src/processTargets/modifiers/PositionStage.ts @@ -8,12 +8,14 @@ export default class implements ModifierStage { run(context: ProcessedTargetsContext, target: Target): Target { const { position } = this.modifier; + const { start, end } = target.contentRange; const { editor, isReversed, - contentRange, delimiter, - removal: { leadingDelimiterRange, trailingDelimiterRange } = {}, + scopeType, + leadingDelimiter, + trailingDelimiter, } = target; const common = { @@ -22,40 +24,41 @@ export default class implements ModifierStage { isReversed, }; + const constructor = Object.getPrototypeOf(target).constructor; + switch (position) { case "before": - return { + return new constructor({ ...common, - contentRange: new Range(contentRange.start, contentRange.start), + contentRange: new Range(start, start), delimiter, - removal: { - range: leadingDelimiterRange, - }, - }; + scopeType, + leadingDelimiter, + }); case "after": - return { + return new constructor({ ...common, - contentRange: new Range(contentRange.end, contentRange.end), + contentRange: new Range(end, end), delimiter, - removal: { - range: trailingDelimiterRange, - }, - }; + scopeType, + trailingDelimiter, + }); case "start": - return { + return new constructor({ ...common, - contentRange: new Range(contentRange.start, contentRange.start), - delimiter: "", // This it NOT a raw target. Joining with this should be done on empty delimiter. - }; + contentRange: new Range(start, start), + // This it NOT a raw target. Joining with this should be done on empty delimiter. + delimiter: "", + }); case "end": - return { + return new constructor({ ...common, - contentRange: new Range(contentRange.end, contentRange.end), + contentRange: new Range(end, end), delimiter: "", - }; + }); } } } diff --git a/src/processTargets/modifiers/RawSelectionStage.ts b/src/processTargets/modifiers/RawSelectionStage.ts index 1f7a79007b..1753fa2d4f 100644 --- a/src/processTargets/modifiers/RawSelectionStage.ts +++ b/src/processTargets/modifiers/RawSelectionStage.ts @@ -1,4 +1,5 @@ import { RawSelectionModifier, Target } from "../../typings/target.types"; +import BaseTarget from "../targets/BaseTarget"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; @@ -6,10 +7,10 @@ export default class implements ModifierStage { constructor(private modifier: RawSelectionModifier) {} run(context: ProcessedTargetsContext, target: Target): Target { - return { + return new BaseTarget({ editor: target.editor, contentRange: target.contentRange, isReversed: target.isReversed, - }; + }); } } diff --git a/src/processTargets/modifiers/SubPieceStage.ts b/src/processTargets/modifiers/SubPieceStage.ts index 572cc59014..c2eb1c0cc1 100644 --- a/src/processTargets/modifiers/SubPieceStage.ts +++ b/src/processTargets/modifiers/SubPieceStage.ts @@ -2,6 +2,7 @@ import { range } from "lodash"; import { Range } from "vscode"; import { SUBWORD_MATCHER } from "../../core/constants"; import { SubTokenModifier, Target } from "../../typings/target.types"; +import BaseTarget from "../targets/BaseTarget"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; @@ -91,15 +92,19 @@ export default class implements ModifierStage { ) : undefined; - return { + return new BaseTarget({ editor: target.editor, isReversed, contentRange, delimiter: containingListDelimiter, - removal: { - leadingDelimiterRange, - trailingDelimiterRange, - }, - }; + leadingDelimiter: + leadingDelimiterRange != null + ? { range: leadingDelimiterRange } + : undefined, + trailingDelimiter: + trailingDelimiterRange != null + ? { range: trailingDelimiterRange } + : undefined, + }); } } diff --git a/src/processTargets/modifiers/SurroundingPairStage.ts b/src/processTargets/modifiers/SurroundingPairStage.ts index 0ea38f23fa..84de77a74d 100644 --- a/src/processTargets/modifiers/SurroundingPairStage.ts +++ b/src/processTargets/modifiers/SurroundingPairStage.ts @@ -2,6 +2,7 @@ import { SurroundingPairModifier, Target } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { selectionWithEditorWithContextToTarget } from "../../util/targetUtils"; import { ModifierStage } from "../PipelineStages.types"; +import BaseTarget from "../targets/BaseTarget"; import { processSurroundingPair } from "./surroundingPair"; /** @@ -41,8 +42,11 @@ export function processedSurroundingPairTarget( throw new Error("Couldn't find containing pair"); } - return pairs.map((pair) => ({ - ...selectionWithEditorWithContextToTarget(pair), - isReversed: target.isReversed, - })); + return pairs.map( + (pair) => + new BaseTarget({ + ...selectionWithEditorWithContextToTarget(pair), + isReversed: target.isReversed, + }) + ); } diff --git a/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts b/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts index a9561420f4..67e5c8d621 100644 --- a/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts @@ -4,9 +4,9 @@ import { getNodeMatcher } from "../../../languages/getNodeMatcher"; import { ContainingScopeModifier, EveryScopeModifier, - ScopeTypeTarget, Target, } from "../../../typings/target.types"; +import ScopeTypeTarget from "../../targets/ScopeTypeTarget"; import { NodeMatcher, ProcessedTargetsContext, @@ -43,12 +43,15 @@ export default class implements ModifierStage { throw new Error(`Couldn't find containing ${this.modifier.scopeType}`); } - return scopeNodes.map((scope) => ({ - scopeType: this.modifier.scopeType, - delimiter: "\n", - ...selectionWithEditorWithContextToTarget(scope), - isReversed: target.isReversed, - })); + return scopeNodes.map( + (scope) => + new ScopeTypeTarget({ + delimiter: "\n", + ...selectionWithEditorWithContextToTarget(scope), + scopeType: this.modifier.scopeType, + isReversed: target.isReversed, + }) + ); } } diff --git a/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts b/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts index 941a5e4b83..c04dcc18ba 100644 --- a/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts @@ -2,9 +2,9 @@ import { Range, TextEditor } from "vscode"; import { ContainingScopeModifier, EveryScopeModifier, - ScopeTypeTarget, Target, } from "../../../typings/target.types"; +import ScopeTypeTarget from "../../targets/ScopeTypeTarget"; import { ProcessedTargetsContext } from "../../../typings/Types"; import { getDocumentRange } from "../../../util/range"; import { ModifierStage } from "../../PipelineStages.types"; @@ -14,7 +14,7 @@ export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} run(context: ProcessedTargetsContext, target: Target): ScopeTypeTarget { - return { + return new ScopeTypeTarget({ scopeType: this.modifier.scopeType, editor: target.editor, isReversed: target.isReversed, @@ -23,7 +23,7 @@ export default class implements ModifierStage { removal: { range: getDocumentRange(target.editor.document), }, - }; + }); } } diff --git a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts index cd7aadf1d0..29ba5c4702 100644 --- a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts @@ -2,9 +2,9 @@ import { Position, Range, TextEditor } from "vscode"; import { ContainingScopeModifier, EveryScopeModifier, - ScopeTypeTarget, Target, } from "../../../typings/target.types"; +import ScopeTypeTarget from "../../targets/ScopeTypeTarget"; import { ProcessedTargetsContext } from "../../../typings/Types"; import { ModifierStage } from "../../PipelineStages.types"; @@ -50,13 +50,13 @@ export default class implements ModifierStage { getTargetFromRange(target: Target, range: Range): ScopeTypeTarget { const contentRange = fitRangeToLineContent(target.editor, range); - return { + return new ScopeTypeTarget({ scopeType: this.modifier.scopeType, editor: target.editor, isReversed: target.isReversed, contentRange, ...getLineContext(target.editor, contentRange), - }; + }); } } @@ -82,9 +82,15 @@ export function getLineContext(editor: TextEditor, range: Range) { delimiter: "\n", removal: { range: removalRange, - leadingDelimiterRange, - trailingDelimiterRange, }, + leadingDelimiter: + leadingDelimiterRange != null + ? { range: leadingDelimiterRange } + : undefined, + trailingDelimiter: + trailingDelimiterRange != null + ? { range: trailingDelimiterRange } + : undefined, }; } diff --git a/src/processTargets/modifiers/scopeTypeStages/NotebookCellStage.ts b/src/processTargets/modifiers/scopeTypeStages/NotebookCellStage.ts index 5ebe6b5f93..51b18837ac 100644 --- a/src/processTargets/modifiers/scopeTypeStages/NotebookCellStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/NotebookCellStage.ts @@ -1,9 +1,9 @@ import { ContainingScopeModifier, EveryScopeModifier, - ScopeTypeTarget, Target, } from "../../../typings/target.types"; +import ScopeTypeTarget from "../../targets/ScopeTypeTarget"; import { ProcessedTargetsContext } from "../../../typings/Types"; import { ModifierStage } from "../../PipelineStages.types"; @@ -15,12 +15,10 @@ export default class implements ModifierStage { throw new Error(`Every ${this.modifier.type} not yet implemented`); } - return { + return new ScopeTypeTarget({ + ...target, scopeType: this.modifier.scopeType, - editor: target.editor, - isReversed: target.isReversed, - contentRange: target.contentRange, delimiter: "\n", - }; + }); } } diff --git a/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts b/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts index 14f45d114a..cf977360f7 100644 --- a/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts @@ -1,10 +1,10 @@ -import { Position, Range, TextDocument } from "vscode"; +import { Range, TextDocument, TextLine } from "vscode"; import { ContainingScopeModifier, EveryScopeModifier, - ScopeTypeTarget, Target, } from "../../../typings/target.types"; +import ScopeTypeTarget from "../../targets/ScopeTypeTarget"; import { ProcessedTargetsContext } from "../../../typings/Types"; import { ModifierStage } from "../../PipelineStages.types"; import { fitRangeToLineContent } from "./LineStage"; @@ -73,127 +73,109 @@ export default class implements ModifierStage { } getSingleTarget(target: Target): ScopeTypeTarget { - return this.getTargetFromRange(target, target.contentRange); + return this.getTargetFromRange(target); } - getTargetFromRange(target: Target, range: Range): ScopeTypeTarget { + getTargetFromRange(target: Target, range?: Range): ScopeTypeTarget { const { document } = target.editor; + const { lineAt } = document; - let startLine = document.lineAt(range.start); - if (!startLine.isEmptyOrWhitespace) { - while (startLine.lineNumber > 0) { - const line = document.lineAt(startLine.lineNumber - 1); - if (line.isEmptyOrWhitespace) { - break; - } - startLine = line; - } - } - const lineCount = document.lineCount; - let endLine = document.lineAt(range.end); - if (!endLine.isEmptyOrWhitespace) { - while (endLine.lineNumber + 1 < lineCount) { - const line = document.lineAt(endLine.lineNumber + 1); - if (line.isEmptyOrWhitespace) { - break; - } - endLine = line; - } + if (range == null) { + range = calculateRange(target); } - const start = new Position( - startLine.lineNumber, - startLine.firstNonWhitespaceCharacterIndex - ); - const end = endLine.range.end; - + const startLine = lineAt(range.start); + const endLine = lineAt(range.end); const contentRange = fitRangeToLineContent( target.editor, - new Range(start, end) - ); - - const removalRange = new Range( - new Position(start.line, 0), - document.lineAt(end).range.end - ); - - const leadingLine = getPreviousNonEmptyLine(document, start.line); - const trailingLine = getNextNonEmptyLine(document, end.line); - - const leadingDelimiterRange = getLeadingDelimiterRange( - document, - removalRange, - leadingLine?.range.end - ); - const trailingDelimiterRange = getTrailingDelimiterRange( - document, - removalRange, - trailingLine?.range.start - ); - - const leadingDelimiterHighlightRange = getLeadingDelimiterRange( - document, - removalRange, - leadingLine ? new Position(leadingLine.range.end.line + 1, 0) : undefined - ); - const trailingDelimiterHighlightRange = getTrailingDelimiterRange( - document, - removalRange, - trailingLine - ? document.lineAt(trailingLine.range.start.line - 1).range.end - : undefined + new Range(startLine.range.start, endLine.range.end) ); + const removalRange = new Range(startLine.range.start, endLine.range.end); + const leadingLine = getPreviousNonEmptyLine(document, startLine); + const trailingLine = getNextNonEmptyLine(document, endLine); + + const leadingDelimiter = (() => { + if (leadingLine != null) { + return { + range: new Range(leadingLine.range.end, startLine.range.start), + highlight: new Range( + lineAt(leadingLine.lineNumber + 1).range.start, + lineAt(startLine.lineNumber - 1).range.end + ), + }; + } + if (startLine.lineNumber > 0) { + const { start } = lineAt(0).range; + return { + range: new Range(start, startLine.range.start), + highlight: new Range( + start, + lineAt(startLine.lineNumber - 1).range.end + ), + }; + } + return undefined; + })(); + + const trailingDelimiter = (() => { + if (trailingLine != null) { + return { + range: new Range(endLine.range.end, trailingLine.range.start), + highlight: new Range( + lineAt(endLine.lineNumber + 1).range.start, + lineAt(trailingLine.lineNumber - 1).range.end + ), + }; + } + if (contentRange.end.line < document.lineCount - 1) { + const { end } = lineAt(document.lineCount - 1).range; + return { + range: new Range(endLine.range.end, end), + highlight: new Range(lineAt(endLine.lineNumber - 1).range.end, end), + }; + } + return undefined; + })(); - return { + return new ScopeTypeTarget({ scopeType: this.modifier.scopeType, editor: target.editor, isReversed: target.isReversed, delimiter: "\n\n", contentRange, - removal: { - range: removalRange, - leadingDelimiterRange, - trailingDelimiterRange, - leadingDelimiterHighlightRange, - trailingDelimiterHighlightRange, - }, - }; + removal: { range: removalRange }, + leadingDelimiter, + trailingDelimiter, + }); } } -function getLeadingDelimiterRange( - document: TextDocument, - removalRange: Range, - position?: Position -) { - const start = - position != null - ? position - : removalRange.start.line > 0 - ? new Position(0, 0) - : undefined; - return start != null ? new Range(start, removalRange.start) : undefined; -} - -function getTrailingDelimiterRange( - document: TextDocument, - removalRange: Range, - position?: Position -) { - const end = - position != null - ? position - : removalRange.end.line < document.lineCount - 1 - ? document.lineAt(document.lineCount - 1).range.end - : undefined; - return end != null ? new Range(removalRange.end, end) : undefined; +function calculateRange(target: Target) { + const { document } = target.editor; + let startLine = document.lineAt(target.contentRange.start); + if (!startLine.isEmptyOrWhitespace) { + while (startLine.lineNumber > 0) { + const line = document.lineAt(startLine.lineNumber - 1); + if (line.isEmptyOrWhitespace) { + break; + } + startLine = line; + } + } + let endLine = document.lineAt(target.contentRange.end); + if (!endLine.isEmptyOrWhitespace) { + while (endLine.lineNumber + 1 < document.lineCount) { + const line = document.lineAt(endLine.lineNumber + 1); + if (line.isEmptyOrWhitespace) { + break; + } + endLine = line; + } + } + return new Range(startLine.range.start, endLine.range.end); } -function getPreviousNonEmptyLine( - document: TextDocument, - startLineNumber: number -) { - let line = document.lineAt(startLineNumber); +function getPreviousNonEmptyLine(document: TextDocument, line: TextLine) { while (line.lineNumber > 0) { const previousLine = document.lineAt(line.lineNumber - 1); if (!previousLine.isEmptyOrWhitespace) { @@ -204,8 +186,7 @@ function getPreviousNonEmptyLine( return null; } -function getNextNonEmptyLine(document: TextDocument, startLineNumber: number) { - let line = document.lineAt(startLineNumber); +function getNextNonEmptyLine(document: TextDocument, line: TextLine) { while (line.lineNumber + 1 < document.lineCount) { const nextLine = document.lineAt(line.lineNumber + 1); if (!nextLine.isEmptyOrWhitespace) { diff --git a/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts b/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts index 4bbe013296..4800cea973 100644 --- a/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts @@ -2,9 +2,9 @@ import { Position, Range, TextEditor } from "vscode"; import { ContainingScopeModifier, EveryScopeModifier, - ScopeTypeTarget, Target, } from "../../../typings/target.types"; +import ScopeTypeTarget from "../../targets/ScopeTypeTarget"; import { ProcessedTargetsContext } from "../../../typings/Types"; import { ModifierStage } from "../../PipelineStages.types"; import { getTokenContext } from "./TokenStage"; @@ -64,16 +64,13 @@ class RegexStage implements ModifierStage { } getTargetFromRange(target: Target, range: Range): ScopeTypeTarget { - const newTarget = { + return new ScopeTypeTarget({ + ...getTokenContext(target.editor, range), scopeType: this.modifier.scopeType, editor: target.editor, isReversed: target.isReversed, contentRange: range, - }; - return { - ...newTarget, - ...getTokenContext(newTarget), - }; + }); } getMatchForPos(editor: TextEditor, position: Position) { diff --git a/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts index 231c7e3001..6d0d3a769a 100644 --- a/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts @@ -2,9 +2,9 @@ import { Range, TextEditor } from "vscode"; import { ContainingScopeModifier, EveryScopeModifier, - ScopeTypeTarget, Target, } from "../../../typings/target.types"; +import ScopeTypeTarget from "../../targets/ScopeTypeTarget"; import { ProcessedTargetsContext } from "../../../typings/Types"; import { getTokensInRange, PartialToken } from "../../../util/getTokensInRange"; import { ModifierStage } from "../../PipelineStages.types"; @@ -57,22 +57,19 @@ export default class implements ModifierStage { getTargetFromRange(target: Target, range: Range): ScopeTypeTarget { const contentRange = getTokenRangeForSelection(target.editor, range); - const newTarget = { + return new ScopeTypeTarget({ + ...getTokenContext(target.editor, contentRange), scopeType: this.modifier.scopeType, editor: target.editor, isReversed: target.isReversed, contentRange, - }; - return { - ...newTarget, - ...getTokenContext(newTarget), - }; + }); } } -export function getTokenContext(target: Target) { - const { document } = target.editor; - const { start, end } = target.contentRange; +export function getTokenContext(editor: TextEditor, contentRange: Range) { + const { document } = editor; + const { start, end } = contentRange; const endLine = document.lineAt(end); const startLine = document.lineAt(start); @@ -107,11 +104,20 @@ export function getTokenContext(target: Target) { return { delimiter: " ", - removal: { - leadingDelimiterRange, - trailingDelimiterRange, - excludeDelimiters: !includeDelimitersInRemoval, - }, + leadingDelimiter: + leadingDelimiterRange != null + ? { + range: leadingDelimiterRange, + exclude: !includeDelimitersInRemoval, + } + : undefined, + trailingDelimiter: + trailingDelimiterRange != null + ? { + range: trailingDelimiterRange, + exclude: !includeDelimitersInRemoval, + } + : undefined, }; } diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index 5eafb47499..506a14f5dd 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -1,13 +1,16 @@ import { zip } from "lodash"; import { Range } from "vscode"; import { - PrimitiveTargetDesc, - RangeTargetDesc, + PrimitiveTargetDescriptor, + RangeTargetDescriptor, + RemovalRange, Target, - TargetDesc, + TargetDescriptor, } from "../typings/target.types"; +import BaseTarget from "./targets/BaseTarget"; import { ProcessedTargetsContext } from "../typings/Types"; import { filterDuplicates } from "../util/filterDuplicates"; +import { parseRemovalRange } from "../util/targetUtils"; import getMarkStage from "./getMarkStage"; import getModifierStage from "./getModifierStage"; @@ -27,7 +30,7 @@ import getModifierStage from "./getModifierStage"; */ export default function ( context: ProcessedTargetsContext, - targets: TargetDesc[] + targets: TargetDescriptor[] ): Target[][] { return targets.map((target) => filterDuplicates(processTarget(context, target)) @@ -36,7 +39,7 @@ export default function ( function processTarget( context: ProcessedTargetsContext, - target: TargetDesc + target: TargetDescriptor ): Target[] { switch (target.type) { case "list": @@ -52,7 +55,7 @@ function processTarget( function processRangeTarget( context: ProcessedTargetsContext, - targetDesc: RangeTargetDesc + targetDesc: RangeTargetDescriptor ): Target[] { const anchorTargets = processPrimitiveTarget(context, targetDesc.anchor); const activeTargets = processPrimitiveTarget(context, targetDesc.active); @@ -96,71 +99,62 @@ function processContinuousRangeTarget( excludeActive: boolean ): Target[] { const isForward = calcIsForward(anchorTarget, activeTarget); - const anchorContext = excludeAnchor ? undefined : anchorTarget; - const activeContext = excludeActive ? undefined : activeTarget; - - const contentRange = unionRanges( - isForward, - excludeAnchor, - excludeActive, - anchorTarget.contentRange, - activeTarget.contentRange - )!; - - const interiorRange = unionRanges( - isForward, - excludeAnchor, - excludeActive, - anchorTarget.interiorRange, - activeTarget.interiorRange - ); - - const hasRemovalRange = - anchorContext?.removal?.range != null || - activeContext?.removal?.range != null; - const anchorRemovalRange = hasRemovalRange - ? anchorContext?.removal?.range ?? anchorContext?.contentRange - : undefined; - const activeRemovalRange = hasRemovalRange - ? activeContext?.removal?.range ?? activeContext?.contentRange - : undefined; - const removalRange = unionRanges( - isForward, - excludeAnchor, - excludeActive, - anchorRemovalRange, - activeRemovalRange - ); - - const leadingDelimiterRange = isForward - ? anchorContext?.removal?.leadingDelimiterRange - : activeContext?.removal?.leadingDelimiterRange; - const trailingDelimiterRange = isForward - ? activeContext?.removal?.trailingDelimiterRange - : anchorContext?.removal?.trailingDelimiterRange; - - const leadingDelimiterHighlightRange = isForward - ? anchorContext?.removal?.leadingDelimiterHighlightRange - : activeContext?.removal?.leadingDelimiterHighlightRange; - const trailingDelimiterHighlightRange = isForward - ? activeContext?.removal?.trailingDelimiterHighlightRange - : anchorContext?.removal?.trailingDelimiterHighlightRange; + const startTarget = isForward ? anchorTarget : activeTarget; + const endTarget = isForward ? activeTarget : anchorTarget; + const excludeStart = isForward ? excludeAnchor : excludeActive; + const excludeEnd = isForward ? excludeActive : excludeAnchor; + + const contentStart = excludeStart + ? startTarget.contentRange.end + : startTarget.contentRange.start; + const contentEnd = excludeEnd + ? endTarget.contentRange.start + : endTarget.contentRange.end; + const contentRange = new Range(contentStart, contentEnd); + + const removalRange = ((): RemovalRange | undefined => { + const startRange = parseRemovalRange(startTarget.removal); + const endRange = parseRemovalRange(endTarget.removal); + if (startRange == null && endRange == null) { + return undefined; + } + const startRemovalRange = + startTarget.removal?.range ?? startTarget.contentRange; + const endRemovalRange = endTarget.removal?.range ?? endTarget.contentRange; + return { + range: new Range(startRemovalRange.start, endRemovalRange.end), + }; + })(); + + const leadingDelimiterRange = excludeStart + ? startTarget.trailingDelimiter + : startTarget.leadingDelimiter; + const trailingDelimiterRange = excludeEnd + ? endTarget.leadingDelimiter + : endTarget.trailingDelimiter; + + const scopeType = + startTarget.scopeType === endTarget.scopeType + ? startTarget.scopeType + : undefined; + + // If both objects are of the same type create a new object of the same + const startConstructor = Object.getPrototypeOf(startTarget).constructor; + const endConstructor = Object.getPrototypeOf(endTarget).constructor; + const constructorFunk = + startConstructor === endConstructor ? startConstructor : BaseTarget; return [ - { + new constructorFunk({ editor: activeTarget.editor, isReversed: !isForward, delimiter: anchorTarget.delimiter, contentRange, - interiorRange, - removal: { - range: removalRange, - leadingDelimiterRange, - trailingDelimiterRange, - leadingDelimiterHighlightRange, - trailingDelimiterHighlightRange, - }, - }, + scopeType, + removal: removalRange, + leadingDelimiter: leadingDelimiterRange, + trailingDelimiter: trailingDelimiterRange, + }), ]; } @@ -176,29 +170,6 @@ export function targetsToContinuousTarget( )[0]; } -function unionRanges( - isForward: boolean, - excludeAnchor: boolean, - excludeActive: boolean, - anchor?: Range, - active?: Range -) { - if (anchor == null || active == null) { - return anchor == null ? active : anchor; - } - return new Range( - getPosition(anchor, isForward, excludeAnchor), - getPosition(active, !isForward, excludeActive) - ); -} - -function getPosition(range: Range, isStartOfRange: boolean, exclude: boolean) { - if (exclude) { - return isStartOfRange ? range.end : range.start; - } - return isStartOfRange ? range.start : range.end; -} - function processVerticalRangeTarget( anchorTarget: Target, activeTarget: Target, @@ -219,18 +190,21 @@ function processVerticalRangeTarget( const results: Target[] = []; for (let i = anchorLine; true; i += delta) { - results.push({ - editor: anchorTarget.editor, - isReversed: anchorTarget.isReversed, - delimiter: anchorTarget.delimiter, - position: anchorTarget.position, - contentRange: new Range( - i, - anchorTarget.contentRange.start.character, - i, - anchorTarget.contentRange.end.character - ), - }); + const contentRange = new Range( + i, + anchorTarget.contentRange.start.character, + i, + anchorTarget.contentRange.end.character + ); + results.push( + new BaseTarget({ + editor: anchorTarget.editor, + isReversed: anchorTarget.isReversed, + delimiter: anchorTarget.delimiter, + position: anchorTarget.position, + contentRange, + }) + ); if (i === activeLine) { return results; } @@ -239,27 +213,27 @@ function processVerticalRangeTarget( function processPrimitiveTarget( context: ProcessedTargetsContext, - target: PrimitiveTargetDesc + target: PrimitiveTargetDescriptor ): Target[] { const markStage = getMarkStage(target.mark); - let selections = markStage.run(context); + let targets = markStage.run(context); for (let i = target.modifiers.length - 1; i > -1; --i) { const modifier = target.modifiers[i]; const stage = getModifierStage(modifier); const stageSelections: Target[] = []; - for (const selection of selections) { - const stageResult = stage.run(context, selection); + for (const target of targets) { + const stageResult = stage.run(context, target); if (Array.isArray(stageResult)) { stageSelections.push(...stageResult); } else { stageSelections.push(stageResult); } } - selections = stageSelections; + targets = stageSelections; } - return selections; + return targets; } function calcIsForward(anchor: Target, active: Target) { diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts new file mode 100644 index 0000000000..93342467ed --- /dev/null +++ b/src/processTargets/targets/BaseTarget.ts @@ -0,0 +1,150 @@ +import { Range, Selection, TextEditor } from "vscode"; +import { parseRemovalRange } from "../../util/targetUtils"; +import { + Target, + ScopeType, + Position, + RemovalRange, + TargetParameters, +} from "../../typings/target.types"; + +export default class BaseTarget implements Target { + editor: TextEditor; + isReversed: boolean; + scopeType?: ScopeType; + position?: Position; + delimiter?: string; + contentRange: Range; + interiorRange?: Range; + boundary?: [Range, Range]; + removal?: RemovalRange; + leadingDelimiter?: RemovalRange; + trailingDelimiter?: RemovalRange; + + constructor(parameters: TargetParameters) { + this.editor = parameters.editor; + this.isReversed = parameters.isReversed; + this.scopeType = parameters.scopeType; + this.position = parameters.position; + this.delimiter = parameters.delimiter; + this.contentRange = parameters.contentRange; + this.interiorRange = parameters.interiorRange; + this.boundary = parameters.boundary; + this.removal = parameters.removal; + this.leadingDelimiter = parameters.leadingDelimiter; + this.trailingDelimiter = parameters.trailingDelimiter; + } + + getContentText(): string { + return this.editor.document.getText(this.contentRange); + } + + getContentSelection(): Selection { + return this.isReversed + ? new Selection(this.contentRange.end, this.contentRange.start) + : new Selection(this.contentRange.start, this.contentRange.end); + } + + /** Possibly add delimiter for positions before/after */ + maybeAddDelimiter(text: string): string { + if (this.delimiter != null) { + if (this.position === "before") { + return text + this.delimiter; + } + if (this.position === "after") { + return this.delimiter + text; + } + } + return text; + } + + protected getRemovalBeforeRange(): Range { + return this.leadingDelimiter != null + ? this.leadingDelimiter.range + : this.contentRange; + } + + protected getRemovalAfterRange(): Range { + return this.trailingDelimiter != null + ? this.trailingDelimiter.range + : this.contentRange; + } + + protected getRemovalBeforeHighlightRange(): Range | undefined { + return this.leadingDelimiter != null + ? this.leadingDelimiter.highlight ?? this.leadingDelimiter.range + : undefined; + } + + protected getRemovalAfterHighlightRange(): Range | undefined { + return this.trailingDelimiter != null + ? this.trailingDelimiter.highlight ?? this.trailingDelimiter.range + : undefined; + } + + getRemovalRange(): Range { + if (this.position === "before") { + return this.getRemovalBeforeRange(); + } + if (this.position === "after") { + return this.getRemovalAfterRange(); + } + + const removalRange = (() => { + const range = parseRemovalRange(this.removal); + if (range != null) { + return range.range; + } + return this.contentRange; + })(); + const delimiterRange = (() => { + const leadingDelimiter = parseRemovalRange(this.leadingDelimiter); + const trailingDelimiter = parseRemovalRange(this.trailingDelimiter); + if (trailingDelimiter != null) { + return trailingDelimiter.range; + } + if (leadingDelimiter != null) { + return leadingDelimiter.range; + } + return undefined; + })(); + return delimiterRange != null + ? removalRange.union(delimiterRange) + : removalRange; + } + + getRemovalHighlightRange(): Range | undefined { + if (this.position === "before") { + return this.getRemovalBeforeHighlightRange(); + } + if (this.position === "after") { + return this.getRemovalAfterHighlightRange(); + } + + const removalRange = (() => { + const range = parseRemovalRange(this.removal); + return range != null ? range.range : this.contentRange; + })(); + const delimiterRange = (() => { + const leadingDelimiter = parseRemovalRange(this.leadingDelimiter); + const trailingDelimiter = parseRemovalRange(this.trailingDelimiter); + if (trailingDelimiter != null) { + return trailingDelimiter.highlight; + } + if (leadingDelimiter) { + return leadingDelimiter.highlight; + } + return undefined; + })(); + if (removalRange != null && delimiterRange != null) { + return removalRange.union(delimiterRange); + } + if (removalRange != null) { + return removalRange; + } + if (delimiterRange != null) { + return delimiterRange; + } + return undefined; + } +} diff --git a/src/processTargets/targets/LineTarget.ts b/src/processTargets/targets/LineTarget.ts new file mode 100644 index 0000000000..c5eb75f0a1 --- /dev/null +++ b/src/processTargets/targets/LineTarget.ts @@ -0,0 +1,17 @@ +import { Range } from "vscode"; +import { TargetParameters } from "../../typings/target.types"; +import BaseTarget from "./BaseTarget"; + +export default class LineTarget extends BaseTarget { + constructor(parameters: TargetParameters) { + super(parameters); + } + + protected getRemovalBeforeHighlightRange(): Range | undefined { + return undefined; + } + + protected getRemovalAfterHighlightRange(): Range | undefined { + return undefined; + } +} diff --git a/src/processTargets/targets/ScopeTypeTarget.ts b/src/processTargets/targets/ScopeTypeTarget.ts new file mode 100644 index 0000000000..a2ca12d127 --- /dev/null +++ b/src/processTargets/targets/ScopeTypeTarget.ts @@ -0,0 +1,18 @@ +import { ScopeType, TargetParameters } from "../../typings/target.types"; +import BaseTarget from "./BaseTarget"; + +export interface ScopeTypeTargetParameters extends TargetParameters { + scopeType: ScopeType; + delimiter: string; +} + +export default class ScopeTypeTarget extends BaseTarget { + scopeType: ScopeType; + delimiter: string; + + constructor(parameters: ScopeTypeTargetParameters) { + super(parameters); + this.scopeType = parameters.scopeType; + this.delimiter = parameters.delimiter; + } +} diff --git a/src/test/suite/fixtures/inferFullTargets.fixture.ts b/src/test/suite/fixtures/inferFullTargets.fixture.ts index ce969fb87a..16e9d91fba 100644 --- a/src/test/suite/fixtures/inferFullTargets.fixture.ts +++ b/src/test/suite/fixtures/inferFullTargets.fixture.ts @@ -1,6 +1,9 @@ // @ts-nocheck import { ActionPreferences, InferenceContext } from "../../../typings/Types"; -import { PartialTargetDesc, TargetDesc } from "../../../typings/target.types"; +import { + PartialTargetDesc, + TargetDescriptor, +} from "../../../typings/target.types"; interface FixtureInput { context: InferenceContext; @@ -10,7 +13,7 @@ interface FixtureInput { interface Fixture { input: FixtureInput; - expectedOutput: TargetDesc[]; + expectedOutput: TargetDescriptor[]; } const fixture: Fixture[] = [ diff --git a/src/testUtil/TestCase.ts b/src/testUtil/TestCase.ts index 82a6f178d6..d4f4ee09cd 100644 --- a/src/testUtil/TestCase.ts +++ b/src/testUtil/TestCase.ts @@ -3,7 +3,7 @@ import * as vscode from "vscode"; import { CommandLatest } from "../core/commandRunner/command.types"; import { ReadOnlyHatMap } from "../core/IndividualHatMap"; import { ThatMark } from "../core/ThatMark"; -import { TargetDesc } from "../typings/target.types"; +import { TargetDescriptor } from "../typings/target.types"; import { Token } from "../typings/Types"; import { cleanUpTestCaseCommand } from "./cleanUpTestCaseCommand"; import { @@ -23,7 +23,7 @@ export type TestCaseCommand = CommandLatest; export type TestCaseContext = { thatMark: ThatMark; sourceMark: ThatMark; - targets: TargetDesc[]; + targets: TargetDescriptor[]; hatTokenMap: ReadOnlyHatMap; }; @@ -40,12 +40,12 @@ export type TestCaseFixture = { finalState: TestCaseSnapshot; returnValue: unknown; /** Inferred full targets added for context; not currently used in testing */ - fullTargets: TargetDesc[]; + fullTargets: TargetDescriptor[]; }; export class TestCase { languageId: string; - fullTargets: TargetDesc[]; + fullTargets: TargetDescriptor[]; initialState: TestCaseSnapshot | null = null; finalState: TestCaseSnapshot | null = null; returnValue: unknown = null; @@ -90,7 +90,7 @@ export class TestCase { return marksToPlainObject(marks); } - private includesThatMark(target: TargetDesc, type: string): boolean { + private includesThatMark(target: TargetDescriptor, type: string): boolean { if (target.type === "primitive" && target.mark.type === type) { return true; } else if (target.type === "list") { diff --git a/src/testUtil/extractTargetedMarks.ts b/src/testUtil/extractTargetedMarks.ts index 9c95d5ee66..9313180c49 100644 --- a/src/testUtil/extractTargetedMarks.ts +++ b/src/testUtil/extractTargetedMarks.ts @@ -1,9 +1,12 @@ import { ReadOnlyHatMap } from "../core/IndividualHatMap"; import HatTokenMap from "../core/HatTokenMap"; import { Token } from "../typings/Types"; -import { PrimitiveTargetDesc, TargetDesc } from "../typings/target.types"; +import { + PrimitiveTargetDescriptor, + TargetDescriptor, +} from "../typings/target.types"; -function extractPrimitiveTargetKeys(...targets: PrimitiveTargetDesc[]) { +function extractPrimitiveTargetKeys(...targets: PrimitiveTargetDescriptor[]) { const keys: string[] = []; targets.forEach((target) => { if (target.mark.type === "decoratedSymbol") { @@ -14,7 +17,7 @@ function extractPrimitiveTargetKeys(...targets: PrimitiveTargetDesc[]) { return keys; } -export function extractTargetKeys(target: TargetDesc): string[] { +export function extractTargetKeys(target: TargetDescriptor): string[] { switch (target.type) { case "primitive": return extractPrimitiveTargetKeys(target); diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 9a94ff0b52..dfccc9a7ee 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -1,4 +1,4 @@ -import { Range, TextEditor } from "vscode"; +import { Range, Selection, TextEditor } from "vscode"; import { HatStyleName } from "../core/constants"; export interface CursorMark { @@ -207,15 +207,15 @@ export type PartialTargetDesc = | PartialRangeTargetDesc | PartialListTargetDesc; -export interface PrimitiveTargetDesc extends PartialPrimitiveTargetDesc { +export interface PrimitiveTargetDescriptor extends PartialPrimitiveTargetDesc { mark: Mark; modifiers: Modifier[]; } -export interface RangeTargetDesc { +export interface RangeTargetDescriptor { type: "range"; - anchor: PrimitiveTargetDesc; - active: PrimitiveTargetDesc; + anchor: PrimitiveTargetDescriptor; + active: PrimitiveTargetDescriptor; excludeAnchor: boolean; excludeActive: boolean; rangeType: RangeType; @@ -225,14 +225,23 @@ export interface RangeTargetDesc { // vertical puts a selection on each line vertically between the two targets export type RangeType = "continuous" | "vertical"; -export interface ListTargetDesc { +export interface ListTargetDescriptor { type: "list"; - elements: (PrimitiveTargetDesc | RangeTargetDesc)[]; + elements: (PrimitiveTargetDescriptor | RangeTargetDescriptor)[]; } -export type TargetDesc = PrimitiveTargetDesc | RangeTargetDesc | ListTargetDesc; +export type TargetDescriptor = + | PrimitiveTargetDescriptor + | RangeTargetDescriptor + | ListTargetDescriptor; -export interface Target { +export interface RemovalRange { + range: Range; + highlight?: Range; + exclude?: boolean; +} + +export interface TargetParameters { /** * The text editor used for all ranges */ @@ -278,42 +287,25 @@ export interface Target { boundary?: [Range, Range]; /** - * Related to removal + * The range that needs to be removed + */ + removal?: RemovalRange; + + /** + * The range of the delimiter before the content selection */ - removal?: { - /** - * The range that needs to be removed - */ - range?: Range; - - /** - * The range of the delimiter before the content selection - */ - leadingDelimiterRange?: Range; - - /** - * The range of the delimiter after the content selection - */ - trailingDelimiterRange?: Range; - - /** - * The range that needs to be highlighted on leading delimiter removal - */ - leadingDelimiterHighlightRange?: Range; - - /** - * The range that needs to be highlighted on trailing delimiteraremoval - */ - trailingDelimiterHighlightRange?: Range; - - /** - * If true the delimiter ranges are only head to be used with positions before/after - */ - excludeDelimiters?: boolean; - }; + leadingDelimiter?: RemovalRange; + + /** + * The range of the delimiter after the content selection + */ + trailingDelimiter?: RemovalRange; } -export interface ScopeTypeTarget extends Target { - scopeType: ScopeType; - delimiter: string; +export interface Target extends TargetParameters { + getContentSelection(): Selection; + getContentText(): string; + maybeAddDelimiter(text: string): string; + getRemovalRange(): Range; + getRemovalHighlightRange(): Range | undefined; } diff --git a/src/util/editDisplayUtils.ts b/src/util/editDisplayUtils.ts index 2adb379e0e..0c6f469113 100644 --- a/src/util/editDisplayUtils.ts +++ b/src/util/editDisplayUtils.ts @@ -79,7 +79,7 @@ export async function displayPendingEditDecorationsForRanges( export default async function displayPendingEditDecorations( targets: Target[], editStyle: EditStyle, - getRange: (target: Target) => Range = getContentRange, + getRange: (target: Target) => Range | undefined = getContentRange, contentOnly?: boolean ) { await setDecorations(targets, editStyle, getRange, contentOnly); @@ -99,20 +99,29 @@ export function clearDecorations(editStyle: EditStyle) { export async function setDecorations( targets: Target[], editStyle: EditStyle, - getRange: (target: Target) => Range = getContentRange, + getRange: (target: Target) => Range | undefined = getContentRange, contentOnly?: boolean ) { await runOnTargetsForEachEditor(targets, async (editor, targets) => { if (contentOnly) { - editor.setDecorations(editStyle.token, targets.map(getRange)); + editor.setDecorations( + editStyle.token, + targets.map(getRange).filter((range): range is Range => !!range) + ); } else { editor.setDecorations( editStyle.token, - targets.filter((target) => !isLineScopeType(target)).map(getRange) + targets + .filter((target) => !isLineScopeType(target.scopeType)) + .map(getRange) + .filter((range): range is Range => !!range) ); editor.setDecorations( editStyle.line, - targets.filter((target) => isLineScopeType(target)).map(getRange) + targets + .filter((target) => isLineScopeType(target.scopeType)) + .map(getRange) + .filter((range): range is Range => !!range) ); } }); diff --git a/src/util/getPrimitiveTargets.ts b/src/util/getPrimitiveTargets.ts index 3980b34373..5d550cf608 100644 --- a/src/util/getPrimitiveTargets.ts +++ b/src/util/getPrimitiveTargets.ts @@ -2,8 +2,8 @@ import { PartialPrimitiveTargetDesc, PartialRangeTargetDesc, PartialTargetDesc, - PrimitiveTargetDesc, - TargetDesc, + PrimitiveTargetDescriptor, + TargetDescriptor, } from "../typings/target.types"; /** @@ -36,11 +36,13 @@ function getPartialPrimitiveTargetsHelper( * @param targets The targets to extract from * @returns A list of primitive targets */ -export function getPrimitiveTargets(targets: TargetDesc[]) { +export function getPrimitiveTargets(targets: TargetDescriptor[]) { return targets.flatMap(getPrimitiveTargetsHelper); } -function getPrimitiveTargetsHelper(target: TargetDesc): PrimitiveTargetDesc[] { +function getPrimitiveTargetsHelper( + target: TargetDescriptor +): PrimitiveTargetDescriptor[] { switch (target.type) { case "primitive": return [target]; diff --git a/src/util/targetUtils.ts b/src/util/targetUtils.ts index e9b055eb40..9972bcdecc 100644 --- a/src/util/targetUtils.ts +++ b/src/util/targetUtils.ts @@ -1,7 +1,12 @@ import { zip } from "lodash"; import { Range, Selection, TextEditor } from "vscode"; import { getTokenContext } from "../processTargets/modifiers/scopeTypeStages/TokenStage"; -import { Target } from "../typings/target.types"; +import { + RemovalRange, + ScopeType, + Target, + TargetParameters, +} from "../typings/target.types"; import { SelectionContext, SelectionWithEditor, @@ -91,16 +96,6 @@ export function getContentRange(target: Target) { return target.contentRange; } -export function getContentText(target: Target) { - return target.editor.document.getText(target.contentRange); -} - -export function getContentSelection(target: Target) { - return target.isReversed - ? new Selection(target.contentRange.end, target.contentRange.start) - : new Selection(target.contentRange.start, target.contentRange.end); -} - export function createThatMark( targets: Target[], ranges?: Range[] @@ -115,47 +110,32 @@ export function createThatMark( } return targets.map((target) => ({ editor: target!.editor, - selection: getContentSelection(target), + selection: target.getContentSelection(), })); } export function getRemovalRange(target: Target) { - const contentRange = target.removal?.range ?? target.contentRange; - const delimiterRange = - target.removal?.trailingDelimiterRange ?? - target.removal?.leadingDelimiterRange; - return delimiterRange != null && !target.removal?.excludeDelimiters - ? contentRange.union(delimiterRange) - : contentRange; + return target.getRemovalRange(); } export function getRemovalHighlightRange(target: Target) { - const contentRange = target.removal?.range ?? target.contentRange; - const delimiterRange = - target.removal?.trailingDelimiterHighlightRange ?? - target.removal?.trailingDelimiterRange ?? - target.removal?.leadingDelimiterHighlightRange ?? - target.removal?.leadingDelimiterRange; - return delimiterRange != null && !target.removal?.excludeDelimiters - ? contentRange.union(delimiterRange) - : contentRange; -} - -/** Possibly add delimiter for positions before/after */ -export function maybeAddDelimiter(text: string, target: Target) { - if (target.delimiter != null) { - if (target.position === "before") { - return text + target.delimiter; - } - if (target.position === "after") { - return target.delimiter + text; - } - } - return text; + return target.getRemovalHighlightRange(); +} + +export function parseRemovalRange( + range?: RemovalRange +): Required | undefined { + return range != null && !range.exclude + ? { + range: range.range, + highlight: range.highlight ?? range.range, + exclude: false, + } + : undefined; } -export function isLineScopeType(target: Target) { - switch (target.scopeType) { +export function isLineScopeType(scopeType?: ScopeType) { + switch (scopeType) { case "line": case "paragraph": case "document": @@ -167,41 +147,48 @@ export function isLineScopeType(target: Target) { export function selectionWithEditorWithContextToTarget( selection: SelectionWithEditorWithContext -): Target { +): TargetParameters { // TODO Only use giving context in the future when all the containing scopes have proper delimiters. // For now fall back on token context const { context } = selection; - const { containingListDelimiter, interiorRange, boundary, removalRange } = - context; - const contentRange = selection.selection.selection; - const newTarget = { - editor: selection.selection.editor, - isReversed: isReversed(contentRange), - contentRange, + const { + containingListDelimiter, interiorRange, boundary, - }; + removalRange, + leadingDelimiterRange, + trailingDelimiterRange, + } = context; + const { editor, selection: contentRange } = selection.selection; const tokenContext = useTokenContext(selection.context) - ? getTokenContext(newTarget) + ? getTokenContext(editor, contentRange) : undefined; - const leadingDelimiterRange = - context.leadingDelimiterRange ?? - tokenContext?.removal.leadingDelimiterRange; - const trailingDelimiterRange = - context.trailingDelimiterRange ?? - tokenContext?.removal.trailingDelimiterRange; - const delimiter = tokenContext?.delimiter ?? containingListDelimiter ?? "\n"; + + const leadingDelimiter = + tokenContext?.leadingDelimiter != null + ? tokenContext.leadingDelimiter + : leadingDelimiterRange != null + ? { range: leadingDelimiterRange } + : undefined; + + const trailingDelimiter = + tokenContext?.trailingDelimiter != null + ? tokenContext.trailingDelimiter + : trailingDelimiterRange != null + ? { range: trailingDelimiterRange } + : undefined; return { - ...newTarget, - delimiter, - removal: { - range: removalRange, - leadingDelimiterRange, - trailingDelimiterRange, - excludeDelimiters: tokenContext?.removal.excludeDelimiters, - }, + editor, + isReversed: isReversed(contentRange), + contentRange, + interiorRange, + boundary, + delimiter: tokenContext?.delimiter ?? containingListDelimiter ?? "\n", + removal: removalRange != null ? { range: removalRange } : undefined, + leadingDelimiter, + trailingDelimiter, }; } diff --git a/src/util/unifyRanges.ts b/src/util/unifyRanges.ts index 900a143f86..4c40728dfe 100644 --- a/src/util/unifyRanges.ts +++ b/src/util/unifyRanges.ts @@ -1,5 +1,6 @@ import { Range } from "vscode"; import { Target } from "../typings/target.types"; +import BaseTarget from "../processTargets/targets/BaseTarget"; import { getRemovalRange, groupTargetsForEachEditor } from "./targetUtils"; /** Unifies overlapping/intersecting ranges */ @@ -89,32 +90,22 @@ function mergeTargets(targets: Target[]): Target { } const first = targets[0]; const last = targets[targets.length - 1]; - const leadingDelimiterRange = first.removal?.leadingDelimiterRange; - const trailingDelimiterRange = last.removal?.trailingDelimiterRange; - const leadingDelimiterHighlightRange = - first.removal?.leadingDelimiterHighlightRange; - const trailingDelimiterHighlightRange = - last.removal?.trailingDelimiterHighlightRange; - return { + return new BaseTarget({ editor: first.editor, isReversed: first.isReversed, contentRange: new Range( getContentRange(first).start, getContentRange(last).end ), - removal: { - leadingDelimiterRange, - trailingDelimiterRange, - leadingDelimiterHighlightRange, - trailingDelimiterHighlightRange, - }, - }; + leadingDelimiter: first.leadingDelimiter, + trailingDelimiter: last.trailingDelimiter, + }); } function intersects(targetA: Target, targetB: Target) { return !!getRemovalRange(targetA).intersection(getRemovalRange(targetB)); } -function getContentRange(target: Target) { +function getContentRange(target: Target): Range { return target.removal?.range ?? target.contentRange; } From 470fb270c7ef2515c2edda5a49b31a5cd071d946 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 19 May 2022 05:13:52 +0200 Subject: [PATCH 118/314] Fixed merge conflict --- .../commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts index 231f351679..30ae197a30 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts @@ -33,15 +33,16 @@ function upgradeModifier(modifier: ModifierV0V1): Modifier | Modifier[] { case "identity": return []; - case "containingScope": - const { includeSiblings, scopeType, ...rest } = modifier; + case "containingScope": { + const { includeSiblings, scopeType, type, ...rest } = modifier; return { type: includeSiblings ? "everyScope" : "containingScope", scopeType: scopeType as ScopeType, ...rest, }; + } - case "surroundingPair": + case "surroundingPair": { const { delimiterInclusion, ...rest } = modifier; if (delimiterInclusion === "interiorOnly") { return [rest, { type: "interiorOnly" }]; @@ -50,6 +51,7 @@ function upgradeModifier(modifier: ModifierV0V1): Modifier | Modifier[] { return [rest, { type: "excludeInterior" }]; } return rest; + } default: return modifier; From 824f37d2e6e3eb68e4a0d59293ee43050e15a701 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 19 May 2022 05:38:08 +0200 Subject: [PATCH 119/314] Reversed order of migration modifiers --- .../upgradeV1ToV2/upgradeV1ToV2.ts | 57 +++++++++---------- 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts index 30ae197a30..7054156032 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts @@ -28,33 +28,35 @@ export function upgradeV1ToV2(command: CommandV1): CommandV2 { }; } -function upgradeModifier(modifier: ModifierV0V1): Modifier | Modifier[] { +function upgradeModifier(modifier: ModifierV0V1): Modifier[] { switch (modifier.type) { case "identity": return []; case "containingScope": { const { includeSiblings, scopeType, type, ...rest } = modifier; - return { - type: includeSiblings ? "everyScope" : "containingScope", - scopeType: scopeType as ScopeType, - ...rest, - }; + return [ + { + type: includeSiblings ? "everyScope" : "containingScope", + scopeType: scopeType as ScopeType, + ...rest, + }, + ]; } case "surroundingPair": { const { delimiterInclusion, ...rest } = modifier; if (delimiterInclusion === "interiorOnly") { - return [rest, { type: "interiorOnly" }]; + return [{ type: "interiorOnly" }, rest]; } if (delimiterInclusion === "excludeInterior") { - return [rest, { type: "excludeInterior" }]; + return [{ type: "excludeInterior" }, rest]; } - return rest; + return [rest]; } default: - return modifier; + return [modifier]; } } @@ -72,23 +74,6 @@ function upgradePrimitiveTarget( } = target; const modifiers: Modifier[] = []; - if (selectionType) { - modifiers.push({ type: "containingScope", scopeType: selectionType }); - } - - if (modifier) { - const mod = upgradeModifier(modifier); - if (Array.isArray(mod)) { - modifiers.push(...mod); - } else { - modifiers.push(mod); - } - } - - if (isImplicit) { - modifiers.push({ type: "toRawSelection" }); - } - if (position && position !== "contents") { if (position === "before") { if (insideOutsideType === "inside") { @@ -105,14 +90,24 @@ function upgradePrimitiveTarget( } } - // Cursor token is just cursor position but treated as a token. This is done in the pipeline for normal cursor now - const newMark = mark?.type === "cursorToken" ? undefined : mark; + if (isImplicit) { + modifiers.push({ type: "toRawSelection" }); + } + + if (modifier) { + modifiers.push(...upgradeModifier(modifier)); + } + + if (selectionType) { + modifiers.push({ type: "containingScope", scopeType: selectionType }); + } return { ...rest, - mark: newMark, + // Cursor token is just cursor position but treated as a token. This is done in the pipeline for normal cursor now + mark: mark?.type === "cursorToken" ? undefined : mark, // Modifiers are processed backwards - modifiers: modifiers.length ? modifiers.reverse() : undefined, + modifiers: modifiers.length ? modifiers : undefined, }; } From c9a761cf55186fa05388beae33b7d281c3db11c6 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 19 May 2022 07:01:59 +0200 Subject: [PATCH 120/314] Default to array --- cursorless-talon/src/marks/lines_number.py | 1 - src/core/commandRunner/CommandRunner.ts | 6 ++ .../canonicalizeAndValidateCommand.ts | 8 ++- .../upgradeV1ToV2/upgradeV1ToV2.ts | 22 +++++-- src/processTargets/PipelineStages.types.ts | 2 +- src/processTargets/marks/CursorStage.ts | 22 +++---- .../marks/DecoratedSymbolStage.ts | 4 +- src/processTargets/marks/LineNumberStage.ts | 25 ++++---- src/processTargets/marks/SourceStage.ts | 4 +- src/processTargets/marks/ThatStage.ts | 4 +- src/processTargets/modifiers/HeadTailStage.ts | 14 +++-- src/processTargets/modifiers/InteriorStage.ts | 20 ++++--- src/processTargets/modifiers/PositionStage.ts | 60 +++++++++++-------- .../modifiers/RawSelectionStage.ts | 14 +++-- src/processTargets/modifiers/SubPieceStage.ts | 42 ++++++++----- .../scopeTypeStages/DocumentStage.ts | 24 ++++---- .../modifiers/scopeTypeStages/LineStage.ts | 11 ++-- .../scopeTypeStages/NotebookCellStage.ts | 14 +++-- .../scopeTypeStages/ParagraphStage.ts | 9 +-- .../modifiers/scopeTypeStages/RegexStage.ts | 11 ++-- .../modifiers/scopeTypeStages/TokenStage.ts | 16 ++--- .../recorded/selectionTypes/clearLinePair.yml | 26 ++++++++ src/typings/Types.ts | 2 + src/util/targetUtils.ts | 4 +- 24 files changed, 214 insertions(+), 151 deletions(-) create mode 100644 src/test/suite/fixtures/recorded/selectionTypes/clearLinePair.yml diff --git a/cursorless-talon/src/marks/lines_number.py b/cursorless-talon/src/marks/lines_number.py index ac02618042..a6ba61f156 100644 --- a/cursorless-talon/src/marks/lines_number.py +++ b/cursorless-talon/src/marks/lines_number.py @@ -41,7 +41,6 @@ def cursorless_line_number(m) -> dict[str, Any]: "lineNumber": direction.formatter(line_number), "type": direction.type, } - # TODO: Make sure to spit out a line in the case of a line number mark return { "type": "lineNumber", "anchor": line, diff --git a/src/core/commandRunner/CommandRunner.ts b/src/core/commandRunner/CommandRunner.ts index 10b67721df..2e0b07df90 100644 --- a/src/core/commandRunner/CommandRunner.ts +++ b/src/core/commandRunner/CommandRunner.ts @@ -94,6 +94,12 @@ export default class CommandRunner { } const processedTargetsContext: ProcessedTargetsContext = { + currentSelections: + vscode.window.activeTextEditor?.selections.map((selection) => ({ + selection, + editor: vscode.window.activeTextEditor!, + })) ?? [], + currentEditor: vscode.window.activeTextEditor, hatTokenMap: readableHatMap, thatMark: this.thatMark.exists() ? this.thatMark.get() : [], sourceMark: this.sourceMark.exists() ? this.sourceMark.get() : [], diff --git a/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts b/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts index 9ecd9225ea..b202ac4846 100644 --- a/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts +++ b/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts @@ -1,6 +1,10 @@ import { commands } from "vscode"; import { ActionableError } from "../../errors"; -import { PartialTargetDesc, ScopeType } from "../../typings/target.types"; +import { + Modifier, + PartialTargetDesc, + ScopeType, +} from "../../typings/target.types"; import { ActionType } from "../../actions/actions.types"; import { getPartialPrimitiveTargets } from "../../util/getPrimitiveTargets"; import { @@ -103,7 +107,7 @@ function usesScopeType( ) { return getPartialPrimitiveTargets(partialTargets).some((partialTarget) => partialTarget.modifiers?.find( - (mod) => + (mod: Modifier) => (mod.type === "containingScope" || mod.type === "everyScope") && mod.scopeType === scopeType ) diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts index 7054156032..c6b26ce29f 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts @@ -94,20 +94,30 @@ function upgradePrimitiveTarget( modifiers.push({ type: "toRawSelection" }); } - if (modifier) { - modifiers.push(...upgradeModifier(modifier)); + if (selectionType) { + switch (selectionType) { + case "token": + if (modifier?.type === "subpiece") { + break; + } + case "line": + if (mark?.type === "lineNumber") { + break; + } + default: + modifiers.push({ type: "containingScope", scopeType: selectionType }); + } } - if (selectionType) { - modifiers.push({ type: "containingScope", scopeType: selectionType }); + if (modifier) { + modifiers.push(...upgradeModifier(modifier)); } return { ...rest, // Cursor token is just cursor position but treated as a token. This is done in the pipeline for normal cursor now mark: mark?.type === "cursorToken" ? undefined : mark, - // Modifiers are processed backwards - modifiers: modifiers.length ? modifiers : undefined, + modifiers, }; } diff --git a/src/processTargets/PipelineStages.types.ts b/src/processTargets/PipelineStages.types.ts index 7f1553428d..7055e1bec8 100644 --- a/src/processTargets/PipelineStages.types.ts +++ b/src/processTargets/PipelineStages.types.ts @@ -6,5 +6,5 @@ export interface MarkStage { } export interface ModifierStage { - run(context: ProcessedTargetsContext, target?: Target): Target | Target[]; + run(context: ProcessedTargetsContext, target?: Target): Target[]; } diff --git a/src/processTargets/marks/CursorStage.ts b/src/processTargets/marks/CursorStage.ts index b0d308ed9a..5f3512382e 100644 --- a/src/processTargets/marks/CursorStage.ts +++ b/src/processTargets/marks/CursorStage.ts @@ -1,24 +1,20 @@ -import { window } from "vscode"; import { CursorMark, Target } from "../../typings/target.types"; -import BaseTarget from "../targets/BaseTarget"; +import { ProcessedTargetsContext } from "../../typings/Types"; import { isReversed } from "../../util/selectionUtils"; -import { getTokenContext } from "../modifiers/scopeTypeStages/TokenStage"; +import { getTokenDelimiters } from "../modifiers/scopeTypeStages/TokenStage"; import { MarkStage } from "../PipelineStages.types"; +import BaseTarget from "../targets/BaseTarget"; export default class implements MarkStage { constructor(private modifier: CursorMark) {} - run(): Target[] { - if (window.activeTextEditor == null) { - return []; - } - return window.activeTextEditor.selections.map((selection) => { - const editor = window.activeTextEditor!; + run(context: ProcessedTargetsContext): Target[] { + return context.currentSelections.map((selection) => { return new BaseTarget({ - ...getTokenContext(editor, selection), - editor, - isReversed: isReversed(selection), - contentRange: selection, + ...getTokenDelimiters(selection.editor, selection.selection), + editor: selection.editor, + isReversed: isReversed(selection.selection), + contentRange: selection.selection, }); }); } diff --git a/src/processTargets/marks/DecoratedSymbolStage.ts b/src/processTargets/marks/DecoratedSymbolStage.ts index 2d8ba005e3..108480ba55 100644 --- a/src/processTargets/marks/DecoratedSymbolStage.ts +++ b/src/processTargets/marks/DecoratedSymbolStage.ts @@ -1,7 +1,7 @@ import { DecoratedSymbolMark, Target } from "../../typings/target.types"; import BaseTarget from "../targets/BaseTarget"; import { ProcessedTargetsContext } from "../../typings/Types"; -import { getTokenContext } from "../modifiers/scopeTypeStages/TokenStage"; +import { getTokenDelimiters } from "../modifiers/scopeTypeStages/TokenStage"; import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { @@ -19,7 +19,7 @@ export default class implements MarkStage { } return [ new BaseTarget({ - ...getTokenContext(token.editor, token.range), + ...getTokenDelimiters(token.editor, token.range), scopeType: "token", editor: token.editor, contentRange: token.range, diff --git a/src/processTargets/marks/LineNumberStage.ts b/src/processTargets/marks/LineNumberStage.ts index 8fb3bdeaa7..b114daa78c 100644 --- a/src/processTargets/marks/LineNumberStage.ts +++ b/src/processTargets/marks/LineNumberStage.ts @@ -1,30 +1,29 @@ -import { Range, TextEditor, window } from "vscode"; +import { TextEditor } from "vscode"; import { LineNumberMark, LineNumberPosition } from "../../typings/target.types"; -import ScopeTypeTarget from "../targets/ScopeTypeTarget"; +import { ProcessedTargetsContext } from "../../typings/Types"; import { getLineContext } from "../modifiers/scopeTypeStages/LineStage"; import { MarkStage } from "../PipelineStages.types"; +import ScopeTypeTarget from "../targets/ScopeTypeTarget"; export default class implements MarkStage { constructor(private modifier: LineNumberMark) {} - run(): ScopeTypeTarget[] { - if (window.activeTextEditor == null) { + run(context: ProcessedTargetsContext): ScopeTypeTarget[] { + if (context.currentEditor == null) { return []; } - const editor = window.activeTextEditor; - const contentRange = new Range( - getLine(editor, this.modifier.anchor), - 0, - getLine(editor, this.modifier.active), - 0 - ); + const editor = context.currentEditor; + const anchorLine = getLine(editor, this.modifier.anchor); + const activeLine = getLine(editor, this.modifier.active); + const anchorRange = editor.document.lineAt(anchorLine).range; + const activeRange = editor.document.lineAt(activeLine).range; + const contentRange = anchorRange.union(activeRange); return [ new ScopeTypeTarget({ ...getLineContext(editor, contentRange), editor, contentRange, - isReversed: false, - scopeType: "line", + isReversed: this.modifier.anchor < this.modifier.active, }), ]; } diff --git a/src/processTargets/marks/SourceStage.ts b/src/processTargets/marks/SourceStage.ts index 897c2cc95a..6c5c8573ce 100644 --- a/src/processTargets/marks/SourceStage.ts +++ b/src/processTargets/marks/SourceStage.ts @@ -2,7 +2,7 @@ import { SourceMark, Target } from "../../typings/target.types"; import BaseTarget from "../targets/BaseTarget"; import { ProcessedTargetsContext } from "../../typings/Types"; import { isReversed } from "../../util/selectionUtils"; -import { getTokenContext } from "../modifiers/scopeTypeStages/TokenStage"; +import { getTokenDelimiters } from "../modifiers/scopeTypeStages/TokenStage"; import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { @@ -11,7 +11,7 @@ export default class implements MarkStage { run(context: ProcessedTargetsContext): Target[] { return context.sourceMark.map((selection) => { return new BaseTarget({ - ...getTokenContext(selection.editor, selection.selection), + ...getTokenDelimiters(selection.editor, selection.selection), editor: selection.editor, isReversed: isReversed(selection.selection), contentRange: selection.selection, diff --git a/src/processTargets/marks/ThatStage.ts b/src/processTargets/marks/ThatStage.ts index 0013b8e73e..d84b8e872d 100644 --- a/src/processTargets/marks/ThatStage.ts +++ b/src/processTargets/marks/ThatStage.ts @@ -2,7 +2,7 @@ import { Target, ThatMark } from "../../typings/target.types"; import BaseTarget from "../targets/BaseTarget"; import { ProcessedTargetsContext } from "../../typings/Types"; import { isReversed } from "../../util/selectionUtils"; -import { getTokenContext } from "../modifiers/scopeTypeStages/TokenStage"; +import { getTokenDelimiters } from "../modifiers/scopeTypeStages/TokenStage"; import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { @@ -11,7 +11,7 @@ export default class implements MarkStage { run(context: ProcessedTargetsContext): Target[] { return context.thatMark.map((selection) => { return new BaseTarget({ - ...getTokenContext(selection.editor, selection.selection), + ...getTokenDelimiters(selection.editor, selection.selection), editor: selection.editor, isReversed: isReversed(selection.selection), contentRange: selection.selection, diff --git a/src/processTargets/modifiers/HeadTailStage.ts b/src/processTargets/modifiers/HeadTailStage.ts index 2a7d9c5316..2eca24e4d8 100644 --- a/src/processTargets/modifiers/HeadTailStage.ts +++ b/src/processTargets/modifiers/HeadTailStage.ts @@ -9,13 +9,15 @@ abstract class HeadTailStage implements ModifierStage { constructor(private isReversed: boolean) {} - run(context: ProcessedTargetsContext, target: Target): Target { + run(context: ProcessedTargetsContext, target: Target): Target[] { const contentRange = this.update(target.editor, target.contentRange); - return new BaseTarget({ - editor: target.editor, - isReversed: this.isReversed, - contentRange, - }); + return [ + new BaseTarget({ + editor: target.editor, + isReversed: this.isReversed, + contentRange, + }), + ]; } } diff --git a/src/processTargets/modifiers/InteriorStage.ts b/src/processTargets/modifiers/InteriorStage.ts index 7f044b4aba..68b478002c 100644 --- a/src/processTargets/modifiers/InteriorStage.ts +++ b/src/processTargets/modifiers/InteriorStage.ts @@ -9,10 +9,10 @@ import { ModifierStage } from "../PipelineStages.types"; import { processedSurroundingPairTarget } from "./SurroundingPairStage"; abstract class InteriorStage implements ModifierStage { - abstract getTargets(target: Target): Target | Target[]; + abstract getTargets(target: Target): Target[]; abstract hasData(target: Target): boolean; - run(context: ProcessedTargetsContext, target: Target): Target | Target[] { + run(context: ProcessedTargetsContext, target: Target): Target[] { if (this.hasData(target)) { return this.getTargets(target); } @@ -38,16 +38,18 @@ export class InteriorOnlyStage extends InteriorStage { super(); } - getTargets(target: Target): Target | Target[] { + getTargets(target: Target): Target[] { if (target.interiorRange == null) { throw Error("No available interior"); } const contentRange = target.interiorRange; - return new BaseTarget({ - editor: target.editor, - isReversed: target.isReversed, - contentRange, - }); + return [ + new BaseTarget({ + editor: target.editor, + isReversed: target.isReversed, + contentRange, + }), + ]; } hasData(target: Target): boolean { @@ -60,7 +62,7 @@ export class ExcludeInteriorStage extends InteriorStage { super(); } - getTargets(target: Target): Target | Target[] { + getTargets(target: Target): Target[] { if (target.boundary == null) { throw Error("No available boundaries"); } diff --git a/src/processTargets/modifiers/PositionStage.ts b/src/processTargets/modifiers/PositionStage.ts index 90fdca5a80..7523865d18 100644 --- a/src/processTargets/modifiers/PositionStage.ts +++ b/src/processTargets/modifiers/PositionStage.ts @@ -6,7 +6,7 @@ import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { constructor(private modifier: PositionModifier) {} - run(context: ProcessedTargetsContext, target: Target): Target { + run(context: ProcessedTargetsContext, target: Target): Target[] { const { position } = this.modifier; const { start, end } = target.contentRange; const { @@ -28,37 +28,45 @@ export default class implements ModifierStage { switch (position) { case "before": - return new constructor({ - ...common, - contentRange: new Range(start, start), - delimiter, - scopeType, - leadingDelimiter, - }); + return [ + new constructor({ + ...common, + contentRange: new Range(start, start), + delimiter, + scopeType, + leadingDelimiter, + }), + ]; case "after": - return new constructor({ - ...common, - contentRange: new Range(end, end), - delimiter, - scopeType, - trailingDelimiter, - }); + return [ + new constructor({ + ...common, + contentRange: new Range(end, end), + delimiter, + scopeType, + trailingDelimiter, + }), + ]; case "start": - return new constructor({ - ...common, - contentRange: new Range(start, start), - // This it NOT a raw target. Joining with this should be done on empty delimiter. - delimiter: "", - }); + return [ + new constructor({ + ...common, + contentRange: new Range(start, start), + // This it NOT a raw target. Joining with this should be done on empty delimiter. + delimiter: "", + }), + ]; case "end": - return new constructor({ - ...common, - contentRange: new Range(end, end), - delimiter: "", - }); + return [ + new constructor({ + ...common, + contentRange: new Range(end, end), + delimiter: "", + }), + ]; } } } diff --git a/src/processTargets/modifiers/RawSelectionStage.ts b/src/processTargets/modifiers/RawSelectionStage.ts index 1753fa2d4f..3f0c48e408 100644 --- a/src/processTargets/modifiers/RawSelectionStage.ts +++ b/src/processTargets/modifiers/RawSelectionStage.ts @@ -6,11 +6,13 @@ import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { constructor(private modifier: RawSelectionModifier) {} - run(context: ProcessedTargetsContext, target: Target): Target { - return new BaseTarget({ - editor: target.editor, - contentRange: target.contentRange, - isReversed: target.isReversed, - }); + run(context: ProcessedTargetsContext, target: Target): Target[] { + return [ + new BaseTarget({ + editor: target.editor, + contentRange: target.contentRange, + isReversed: target.isReversed, + }), + ]; } } diff --git a/src/processTargets/modifiers/SubPieceStage.ts b/src/processTargets/modifiers/SubPieceStage.ts index c2eb1c0cc1..885387a938 100644 --- a/src/processTargets/modifiers/SubPieceStage.ts +++ b/src/processTargets/modifiers/SubPieceStage.ts @@ -5,12 +5,20 @@ import { SubTokenModifier, Target } from "../../typings/target.types"; import BaseTarget from "../targets/BaseTarget"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; +import { getTokenRangeForSelection } from "./scopeTypeStages/TokenStage"; export default class implements ModifierStage { constructor(private modifier: SubTokenModifier) {} - run(context: ProcessedTargetsContext, target: Target): Target { - const token = target.editor.document.getText(target.contentRange); + run(context: ProcessedTargetsContext, target: Target): Target[] { + if (target.contentRange.isEmpty) { + target.contentRange = getTokenRangeForSelection( + target.editor, + target.contentRange + ); + } + + const token = target.getContentText(); let pieces: { start: number; end: number }[] = []; if (this.modifier.excludeActive || this.modifier.excludeAnchor) { @@ -92,19 +100,21 @@ export default class implements ModifierStage { ) : undefined; - return new BaseTarget({ - editor: target.editor, - isReversed, - contentRange, - delimiter: containingListDelimiter, - leadingDelimiter: - leadingDelimiterRange != null - ? { range: leadingDelimiterRange } - : undefined, - trailingDelimiter: - trailingDelimiterRange != null - ? { range: trailingDelimiterRange } - : undefined, - }); + return [ + new BaseTarget({ + editor: target.editor, + isReversed, + contentRange, + delimiter: containingListDelimiter, + leadingDelimiter: + leadingDelimiterRange != null + ? { range: leadingDelimiterRange } + : undefined, + trailingDelimiter: + trailingDelimiterRange != null + ? { range: trailingDelimiterRange } + : undefined, + }), + ]; } } diff --git a/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts b/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts index c04dcc18ba..a16ed5cebb 100644 --- a/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts @@ -13,17 +13,19 @@ import { fitRangeToLineContent } from "./LineStage"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} - run(context: ProcessedTargetsContext, target: Target): ScopeTypeTarget { - return new ScopeTypeTarget({ - scopeType: this.modifier.scopeType, - editor: target.editor, - isReversed: target.isReversed, - delimiter: "\n", - contentRange: getDocumentContentRange(target.editor), - removal: { - range: getDocumentRange(target.editor.document), - }, - }); + run(context: ProcessedTargetsContext, target: Target): ScopeTypeTarget[] { + return [ + new ScopeTypeTarget({ + scopeType: this.modifier.scopeType, + editor: target.editor, + isReversed: target.isReversed, + delimiter: "\n", + contentRange: getDocumentContentRange(target.editor), + removal: { + range: getDocumentRange(target.editor.document), + }, + }), + ]; } } diff --git a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts index 29ba5c4702..31368b8a1c 100644 --- a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts @@ -2,6 +2,7 @@ import { Position, Range, TextEditor } from "vscode"; import { ContainingScopeModifier, EveryScopeModifier, + ScopeType, Target, } from "../../../typings/target.types"; import ScopeTypeTarget from "../../targets/ScopeTypeTarget"; @@ -11,14 +12,11 @@ import { ModifierStage } from "../../PipelineStages.types"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} - run( - context: ProcessedTargetsContext, - target: Target - ): ScopeTypeTarget | ScopeTypeTarget[] { + run(context: ProcessedTargetsContext, target: Target): ScopeTypeTarget[] { if (this.modifier.type === "everyScope") { return this.getEveryTarget(target); } - return this.getSingleTarget(target); + return [this.getSingleTarget(target)]; } getEveryTarget(target: Target): ScopeTypeTarget[] { @@ -51,11 +49,11 @@ export default class implements ModifierStage { getTargetFromRange(target: Target, range: Range): ScopeTypeTarget { const contentRange = fitRangeToLineContent(target.editor, range); return new ScopeTypeTarget({ + ...getLineContext(target.editor, contentRange), scopeType: this.modifier.scopeType, editor: target.editor, isReversed: target.isReversed, contentRange, - ...getLineContext(target.editor, contentRange), }); } } @@ -79,6 +77,7 @@ export function getLineContext(editor: TextEditor, range: Range) { : undefined; return { + scopeType: "line" as ScopeType, delimiter: "\n", removal: { range: removalRange, diff --git a/src/processTargets/modifiers/scopeTypeStages/NotebookCellStage.ts b/src/processTargets/modifiers/scopeTypeStages/NotebookCellStage.ts index 51b18837ac..db74ff2efe 100644 --- a/src/processTargets/modifiers/scopeTypeStages/NotebookCellStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/NotebookCellStage.ts @@ -10,15 +10,17 @@ import { ModifierStage } from "../../PipelineStages.types"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} - run(context: ProcessedTargetsContext, target: Target): ScopeTypeTarget { + run(context: ProcessedTargetsContext, target: Target): ScopeTypeTarget[] { if (this.modifier.type === "everyScope") { throw new Error(`Every ${this.modifier.type} not yet implemented`); } - return new ScopeTypeTarget({ - ...target, - scopeType: this.modifier.scopeType, - delimiter: "\n", - }); + return [ + new ScopeTypeTarget({ + delimiter: "\n", + ...target, + scopeType: this.modifier.scopeType, + }), + ]; } } diff --git a/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts b/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts index cf977360f7..174e14e53e 100644 --- a/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts @@ -12,17 +12,14 @@ import { fitRangeToLineContent } from "./LineStage"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} - run( - context: ProcessedTargetsContext, - target: Target - ): ScopeTypeTarget | ScopeTypeTarget[] { + run(context: ProcessedTargetsContext, target: Target): ScopeTypeTarget[] { if (this.modifier.type === "everyScope") { return this.getEveryTarget(target); } - return this.getSingleTarget(target); + return [this.getSingleTarget(target)]; } - getEveryTarget(target: Target): ScopeTypeTarget | ScopeTypeTarget[] { + getEveryTarget(target: Target): ScopeTypeTarget[] { const { contentRange, editor } = target; const { isEmpty } = contentRange; const { lineCount } = editor.document; diff --git a/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts b/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts index 4800cea973..f88590ee79 100644 --- a/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts @@ -7,7 +7,7 @@ import { import ScopeTypeTarget from "../../targets/ScopeTypeTarget"; import { ProcessedTargetsContext } from "../../../typings/Types"; import { ModifierStage } from "../../PipelineStages.types"; -import { getTokenContext } from "./TokenStage"; +import { getTokenDelimiters } from "./TokenStage"; class RegexStage implements ModifierStage { constructor( @@ -16,14 +16,11 @@ class RegexStage implements ModifierStage { private name?: string ) {} - run( - context: ProcessedTargetsContext, - target: Target - ): ScopeTypeTarget | ScopeTypeTarget[] { + run(context: ProcessedTargetsContext, target: Target): ScopeTypeTarget[] { if (this.modifier.type === "everyScope") { return this.getEveryTarget(target); } - return this.getSingleTarget(target); + return [this.getSingleTarget(target)]; } getEveryTarget(target: Target): ScopeTypeTarget[] { @@ -65,7 +62,7 @@ class RegexStage implements ModifierStage { getTargetFromRange(target: Target, range: Range): ScopeTypeTarget { return new ScopeTypeTarget({ - ...getTokenContext(target.editor, range), + ...getTokenDelimiters(target.editor, range), scopeType: this.modifier.scopeType, editor: target.editor, isReversed: target.isReversed, diff --git a/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts index 6d0d3a769a..744cb94a6a 100644 --- a/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts @@ -12,14 +12,11 @@ import { ModifierStage } from "../../PipelineStages.types"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} - run( - context: ProcessedTargetsContext, - target: Target - ): ScopeTypeTarget | ScopeTypeTarget[] { + run(context: ProcessedTargetsContext, target: Target): ScopeTypeTarget[] { if (this.modifier.type === "everyScope") { return this.getEveryTarget(context, target); } - return this.getSingleTarget(target); + return [this.getSingleTarget(target)]; } getEveryTarget( @@ -58,7 +55,7 @@ export default class implements ModifierStage { getTargetFromRange(target: Target, range: Range): ScopeTypeTarget { const contentRange = getTokenRangeForSelection(target.editor, range); return new ScopeTypeTarget({ - ...getTokenContext(target.editor, contentRange), + ...getTokenDelimiters(target.editor, contentRange), scopeType: this.modifier.scopeType, editor: target.editor, isReversed: target.isReversed, @@ -67,7 +64,7 @@ export default class implements ModifierStage { } } -export function getTokenContext(editor: TextEditor, contentRange: Range) { +export function getTokenDelimiters(editor: TextEditor, contentRange: Range) { const { document } = editor; const { start, end } = contentRange; const endLine = document.lineAt(end); @@ -128,7 +125,10 @@ export function getTokenContext(editor: TextEditor, contentRange: Range) { * @param selection Selection to operate on * @returns Modified range */ -function getTokenRangeForSelection(editor: TextEditor, range: Range): Range { +export function getTokenRangeForSelection( + editor: TextEditor, + range: Range +): Range { let tokens = getTokenIntersectionsForSelection(editor, range); // Use single token for overlapping or adjacent range if (range.isEmpty) { diff --git a/src/test/suite/fixtures/recorded/selectionTypes/clearLinePair.yml b/src/test/suite/fixtures/recorded/selectionTypes/clearLinePair.yml new file mode 100644 index 0000000000..22df88e611 --- /dev/null +++ b/src/test/suite/fixtures/recorded/selectionTypes/clearLinePair.yml @@ -0,0 +1,26 @@ +languageId: plaintext +command: + spokenForm: clear line pair + version: 2 + action: clearAndSetSelection + targets: + - type: primitive + modifiers: + - {type: containingScope, scopeType: line} + - {type: surroundingPair, delimiter: any} + usePrePhraseSnapshot: true +initialState: + documentContents: foo (bar) baz + selections: + - anchor: {line: 0, character: 7} + active: {line: 0, character: 7} + 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: containingScope, scopeType: line}, {type: surroundingPair, delimiter: any}]}] diff --git a/src/typings/Types.ts b/src/typings/Types.ts index f026fa6b1c..c291f13e96 100644 --- a/src/typings/Types.ts +++ b/src/typings/Types.ts @@ -24,6 +24,8 @@ export interface Token extends FullRangeInfo { } export interface ProcessedTargetsContext { + currentSelections: SelectionWithEditor[]; + currentEditor: vscode.TextEditor | undefined; hatTokenMap: ReadOnlyHatMap; thatMark: SelectionWithEditor[]; sourceMark: SelectionWithEditor[]; diff --git a/src/util/targetUtils.ts b/src/util/targetUtils.ts index 9972bcdecc..34b5b42e74 100644 --- a/src/util/targetUtils.ts +++ b/src/util/targetUtils.ts @@ -1,6 +1,6 @@ import { zip } from "lodash"; import { Range, Selection, TextEditor } from "vscode"; -import { getTokenContext } from "../processTargets/modifiers/scopeTypeStages/TokenStage"; +import { getTokenDelimiters } from "../processTargets/modifiers/scopeTypeStages/TokenStage"; import { RemovalRange, ScopeType, @@ -162,7 +162,7 @@ export function selectionWithEditorWithContextToTarget( const { editor, selection: contentRange } = selection.selection; const tokenContext = useTokenContext(selection.context) - ? getTokenContext(editor, contentRange) + ? getTokenDelimiters(editor, contentRange) : undefined; const leadingDelimiter = From fe06227ea0813e88810d72f2cc34f61c63f935c3 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 19 May 2022 07:38:54 +0200 Subject: [PATCH 121/314] Cleaned up inference code --- src/core/inferFullTargets.ts | 26 +++++++++++++++----------- src/processTargets/processTargets.ts | 11 +++-------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/core/inferFullTargets.ts b/src/core/inferFullTargets.ts index f7849d3da3..c07f9ee593 100644 --- a/src/core/inferFullTargets.ts +++ b/src/core/inferFullTargets.ts @@ -113,17 +113,17 @@ function inferPrimitiveTarget( // Position without a mark can be something like "take air past end of line" const mark = target.mark ?? - (hasPosition ? getPreviousAttribute(previousTargets, "mark") : null) ?? { + (hasPosition ? getPreviousMark(previousTargets) : null) ?? { type: "cursor", }; - const previousModifiers = getPreviousAttribute(previousTargets, "modifiers"); + const previousModifiers = getPreviousModifiers(previousTargets); const modifiers = target.modifiers ?? previousModifiers ?? actionPreferences?.modifiers ?? []; // TODO Is this really a good solution? - // "bring line to after this" needs to inter line on second target + // "bring line to after this" needs to infer line on second target const modifierTypes = [ ...new Set(modifiers.map((modifier) => modifier.type)), ]; @@ -147,15 +147,19 @@ function inferPrimitiveTarget( }; } -function getPreviousAttribute( - previousTargets: PartialTargetDesc[], - attributeName: T -) { - const target = getPreviousTarget( +function getPreviousMark(previousTargets: PartialTargetDesc[]) { + return getPreviousTarget( previousTargets, - (target: PartialPrimitiveTargetDesc) => !!target[attributeName] - ); - return target != null ? target[attributeName] : null; + (target: PartialPrimitiveTargetDesc) => target.mark != null + )?.mark; +} + +function getPreviousModifiers(previousTargets: PartialTargetDesc[]) { + return getPreviousTarget( + previousTargets, + (target: PartialPrimitiveTargetDesc) => + target.modifiers != null && target.modifiers.length > 0 + )?.modifiers; } function getPreviousTarget( diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index 506a14f5dd..b3c3f5e24b 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -221,16 +221,11 @@ function processPrimitiveTarget( for (let i = target.modifiers.length - 1; i > -1; --i) { const modifier = target.modifiers[i]; const stage = getModifierStage(modifier); - const stageSelections: Target[] = []; + const stageTargets: Target[] = []; for (const target of targets) { - const stageResult = stage.run(context, target); - if (Array.isArray(stageResult)) { - stageSelections.push(...stageResult); - } else { - stageSelections.push(stageResult); - } + stageTargets.push(...stage.run(context, target)); } - targets = stageSelections; + targets = stageTargets; } return targets; From 4e9dd6fc6babcd8bd523ab3d01715ccd44f0e0a1 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 19 May 2022 08:23:26 +0200 Subject: [PATCH 122/314] Added paragraph target --- src/core/inferFullTargets.ts | 4 +- src/processTargets/marks/LineNumberStage.ts | 16 ++----- .../modifiers/scopeTypeStages/LineStage.ts | 46 ++++++++++--------- .../scopeTypeStages/ParagraphStage.ts | 15 +++--- src/processTargets/targets/BaseTarget.ts | 15 ++---- src/processTargets/targets/LineTarget.ts | 13 +++--- src/processTargets/targets/ParagraphTarget.ts | 17 +++++++ 7 files changed, 68 insertions(+), 58 deletions(-) create mode 100644 src/processTargets/targets/ParagraphTarget.ts diff --git a/src/core/inferFullTargets.ts b/src/core/inferFullTargets.ts index c07f9ee593..013c4383c6 100644 --- a/src/core/inferFullTargets.ts +++ b/src/core/inferFullTargets.ts @@ -120,7 +120,9 @@ function inferPrimitiveTarget( const previousModifiers = getPreviousModifiers(previousTargets); const modifiers = - target.modifiers ?? previousModifiers ?? actionPreferences?.modifiers ?? []; + target.modifiers != null && target.modifiers.length > 0 + ? target.modifiers + : previousModifiers ?? actionPreferences?.modifiers ?? []; // TODO Is this really a good solution? // "bring line to after this" needs to infer line on second target diff --git a/src/processTargets/marks/LineNumberStage.ts b/src/processTargets/marks/LineNumberStage.ts index b114daa78c..bdffde02ec 100644 --- a/src/processTargets/marks/LineNumberStage.ts +++ b/src/processTargets/marks/LineNumberStage.ts @@ -1,14 +1,14 @@ import { TextEditor } from "vscode"; import { LineNumberMark, LineNumberPosition } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; -import { getLineContext } from "../modifiers/scopeTypeStages/LineStage"; +import { createLineTarget } from "../modifiers/scopeTypeStages/LineStage"; import { MarkStage } from "../PipelineStages.types"; -import ScopeTypeTarget from "../targets/ScopeTypeTarget"; +import LineTarget from "../targets/LineTarget"; export default class implements MarkStage { constructor(private modifier: LineNumberMark) {} - run(context: ProcessedTargetsContext): ScopeTypeTarget[] { + run(context: ProcessedTargetsContext): LineTarget[] { if (context.currentEditor == null) { return []; } @@ -18,14 +18,8 @@ export default class implements MarkStage { const anchorRange = editor.document.lineAt(anchorLine).range; const activeRange = editor.document.lineAt(activeLine).range; const contentRange = anchorRange.union(activeRange); - return [ - new ScopeTypeTarget({ - ...getLineContext(editor, contentRange), - editor, - contentRange, - isReversed: this.modifier.anchor < this.modifier.active, - }), - ]; + const isReversed = this.modifier.anchor < this.modifier.active; + return [createLineTarget(editor, contentRange, isReversed)]; } } diff --git a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts index 31368b8a1c..2db430b298 100644 --- a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts @@ -2,31 +2,30 @@ import { Position, Range, TextEditor } from "vscode"; import { ContainingScopeModifier, EveryScopeModifier, - ScopeType, Target, } from "../../../typings/target.types"; -import ScopeTypeTarget from "../../targets/ScopeTypeTarget"; import { ProcessedTargetsContext } from "../../../typings/Types"; import { ModifierStage } from "../../PipelineStages.types"; +import LineTarget from "../../targets/LineTarget"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} - run(context: ProcessedTargetsContext, target: Target): ScopeTypeTarget[] { + run(context: ProcessedTargetsContext, target: Target): LineTarget[] { if (this.modifier.type === "everyScope") { return this.getEveryTarget(target); } return [this.getSingleTarget(target)]; } - getEveryTarget(target: Target): ScopeTypeTarget[] { + getEveryTarget(target: Target): LineTarget[] { const { contentRange, editor } = target; const { isEmpty } = contentRange; const startLine = isEmpty ? 0 : contentRange.start.line; const endLine = isEmpty ? editor.document.lineCount - 1 : contentRange.end.line; - const targets: ScopeTypeTarget[] = []; + const targets: LineTarget[] = []; for (let i = startLine; i <= endLine; ++i) { const line = editor.document.lineAt(i); @@ -42,25 +41,27 @@ export default class implements ModifierStage { return targets; } - getSingleTarget(target: Target): ScopeTypeTarget { - return this.getTargetFromRange(target, target.contentRange); + getSingleTarget(target: Target): LineTarget { + return createLineTarget( + target.editor, + target.contentRange, + target.isReversed + ); } - getTargetFromRange(target: Target, range: Range): ScopeTypeTarget { - const contentRange = fitRangeToLineContent(target.editor, range); - return new ScopeTypeTarget({ - ...getLineContext(target.editor, contentRange), - scopeType: this.modifier.scopeType, - editor: target.editor, - isReversed: target.isReversed, - contentRange, - }); + getTargetFromRange(target: Target, range: Range): LineTarget { + return createLineTarget(target.editor, range, target.isReversed); } } -export function getLineContext(editor: TextEditor, range: Range) { +export function createLineTarget( + editor: TextEditor, + range: Range, + isReversed: boolean +) { const { document } = editor; - const { start, end } = range; + const contentRange = fitRangeToLineContent(editor, range); + const { start, end } = contentRange; const removalRange = new Range( new Position(start.line, 0), @@ -76,9 +77,10 @@ export function getLineContext(editor: TextEditor, range: Range) { ? new Range(removalRange.end, new Position(end.line + 1, 0)) : undefined; - return { - scopeType: "line" as ScopeType, - delimiter: "\n", + return new LineTarget({ + editor, + contentRange, + isReversed, removal: { range: removalRange, }, @@ -90,7 +92,7 @@ export function getLineContext(editor: TextEditor, range: Range) { trailingDelimiterRange != null ? { range: trailingDelimiterRange } : undefined, - }; + }); } export function fitRangeToLineContent(editor: TextEditor, range: Range) { diff --git a/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts b/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts index 174e14e53e..419005ae9d 100644 --- a/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts @@ -4,28 +4,28 @@ import { EveryScopeModifier, Target, } from "../../../typings/target.types"; -import ScopeTypeTarget from "../../targets/ScopeTypeTarget"; import { ProcessedTargetsContext } from "../../../typings/Types"; import { ModifierStage } from "../../PipelineStages.types"; +import ParagraphTarget from "../../targets/ParagraphTarget"; import { fitRangeToLineContent } from "./LineStage"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} - run(context: ProcessedTargetsContext, target: Target): ScopeTypeTarget[] { + run(context: ProcessedTargetsContext, target: Target): ParagraphTarget[] { if (this.modifier.type === "everyScope") { return this.getEveryTarget(target); } return [this.getSingleTarget(target)]; } - getEveryTarget(target: Target): ScopeTypeTarget[] { + getEveryTarget(target: Target): ParagraphTarget[] { const { contentRange, editor } = target; const { isEmpty } = contentRange; const { lineCount } = editor.document; const startLine = isEmpty ? 0 : contentRange.start.line; const endLine = isEmpty ? lineCount - 1 : contentRange.end.line; - const targets: ScopeTypeTarget[] = []; + const targets: ParagraphTarget[] = []; let paragraphStart = -1; const possiblyAddParagraph = ( @@ -69,11 +69,11 @@ export default class implements ModifierStage { return targets; } - getSingleTarget(target: Target): ScopeTypeTarget { + getSingleTarget(target: Target): ParagraphTarget { return this.getTargetFromRange(target); } - getTargetFromRange(target: Target, range?: Range): ScopeTypeTarget { + getTargetFromRange(target: Target, range?: Range): ParagraphTarget { const { document } = target.editor; const { lineAt } = document; @@ -134,11 +134,10 @@ export default class implements ModifierStage { return undefined; })(); - return new ScopeTypeTarget({ + return new ParagraphTarget({ scopeType: this.modifier.scopeType, editor: target.editor, isReversed: target.isReversed, - delimiter: "\n\n", contentRange, removal: { range: removalRange }, leadingDelimiter, diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index 93342467ed..8fb6de27b6 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -125,6 +125,7 @@ export default class BaseTarget implements Target { const range = parseRemovalRange(this.removal); return range != null ? range.range : this.contentRange; })(); + const delimiterRange = (() => { const leadingDelimiter = parseRemovalRange(this.leadingDelimiter); const trailingDelimiter = parseRemovalRange(this.trailingDelimiter); @@ -136,15 +137,9 @@ export default class BaseTarget implements Target { } return undefined; })(); - if (removalRange != null && delimiterRange != null) { - return removalRange.union(delimiterRange); - } - if (removalRange != null) { - return removalRange; - } - if (delimiterRange != null) { - return delimiterRange; - } - return undefined; + + return delimiterRange != null + ? removalRange.union(delimiterRange) + : removalRange; } } diff --git a/src/processTargets/targets/LineTarget.ts b/src/processTargets/targets/LineTarget.ts index c5eb75f0a1..a18a9b05e0 100644 --- a/src/processTargets/targets/LineTarget.ts +++ b/src/processTargets/targets/LineTarget.ts @@ -5,13 +5,14 @@ import BaseTarget from "./BaseTarget"; export default class LineTarget extends BaseTarget { constructor(parameters: TargetParameters) { super(parameters); + this.scopeType = "line"; + this.delimiter = "\n"; } - protected getRemovalBeforeHighlightRange(): Range | undefined { - return undefined; - } - - protected getRemovalAfterHighlightRange(): Range | undefined { - return undefined; + getRemovalHighlightRange(): Range | undefined { + if (this.position != null) { + return undefined; + } + return this.contentRange; } } diff --git a/src/processTargets/targets/ParagraphTarget.ts b/src/processTargets/targets/ParagraphTarget.ts new file mode 100644 index 0000000000..b3987043bd --- /dev/null +++ b/src/processTargets/targets/ParagraphTarget.ts @@ -0,0 +1,17 @@ +import { Range } from "vscode"; +import { TargetParameters } from "../../typings/target.types"; +import BaseTarget from "./BaseTarget"; + +export default class ParagraphTarget extends BaseTarget { + constructor(parameters: TargetParameters) { + super(parameters); + this.delimiter = "\n\n"; + } + + // getRemovalHighlightRange(): Range | undefined { + // if (this.position != null) { + // return undefined; + // } + // return this.contentRange; + // } +} From c5348c23e1deb29f81a74c37306cf492de3029bc Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 19 May 2022 09:20:33 +0200 Subject: [PATCH 123/314] Better updates of new range --- src/processTargets/processTargets.ts | 42 +++++++++++++------ src/processTargets/targets/ParagraphTarget.ts | 1 - src/util/selectionUtils.ts | 26 ++++++++++++ 3 files changed, 55 insertions(+), 14 deletions(-) diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index b3c3f5e24b..e267bed433 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -13,6 +13,7 @@ import { filterDuplicates } from "../util/filterDuplicates"; import { parseRemovalRange } from "../util/targetUtils"; import getMarkStage from "./getMarkStage"; import getModifierStage from "./getModifierStage"; +import { removeDelimiterRanges } from "../util/selectionUtils"; /** * Converts the abstract target descriptions provided by the user to a concrete @@ -104,13 +105,24 @@ function processContinuousRangeTarget( const excludeStart = isForward ? excludeAnchor : excludeActive; const excludeEnd = isForward ? excludeActive : excludeAnchor; + const leadingDelimiterRange = excludeStart + ? startTarget.trailingDelimiter + : startTarget.leadingDelimiter; + const trailingDelimiterRange = excludeEnd + ? endTarget.leadingDelimiter + : endTarget.trailingDelimiter; + const contentStart = excludeStart ? startTarget.contentRange.end : startTarget.contentRange.start; const contentEnd = excludeEnd ? endTarget.contentRange.start : endTarget.contentRange.end; - const contentRange = new Range(contentStart, contentEnd); + const contentRange = removeDelimiterRanges( + new Range(contentStart, contentEnd), + leadingDelimiterRange, + trailingDelimiterRange + ); const removalRange = ((): RemovalRange | undefined => { const startRange = parseRemovalRange(startTarget.removal); @@ -119,20 +131,24 @@ function processContinuousRangeTarget( return undefined; } const startRemovalRange = - startTarget.removal?.range ?? startTarget.contentRange; - const endRemovalRange = endTarget.removal?.range ?? endTarget.contentRange; + (!excludeStart ? startRange?.range.start : null) ?? + startTarget.contentRange.end; + const endRemovalRange = + (!excludeEnd ? endRange?.range.end : null) ?? + endTarget.contentRange.start; + const removalRange = removeDelimiterRanges( + new Range(startRemovalRange, endRemovalRange), + leadingDelimiterRange, + trailingDelimiterRange + ); + if (removalRange.isEqual(contentRange)) { + return undefined; + } return { - range: new Range(startRemovalRange.start, endRemovalRange.end), + range: removalRange, }; })(); - const leadingDelimiterRange = excludeStart - ? startTarget.trailingDelimiter - : startTarget.leadingDelimiter; - const trailingDelimiterRange = excludeEnd - ? endTarget.leadingDelimiter - : endTarget.trailingDelimiter; - const scopeType = startTarget.scopeType === endTarget.scopeType ? startTarget.scopeType @@ -141,11 +157,11 @@ function processContinuousRangeTarget( // If both objects are of the same type create a new object of the same const startConstructor = Object.getPrototypeOf(startTarget).constructor; const endConstructor = Object.getPrototypeOf(endTarget).constructor; - const constructorFunk = + const constructor = startConstructor === endConstructor ? startConstructor : BaseTarget; return [ - new constructorFunk({ + new constructor({ editor: activeTarget.editor, isReversed: !isForward, delimiter: anchorTarget.delimiter, diff --git a/src/processTargets/targets/ParagraphTarget.ts b/src/processTargets/targets/ParagraphTarget.ts index b3987043bd..4a8bcb3a4b 100644 --- a/src/processTargets/targets/ParagraphTarget.ts +++ b/src/processTargets/targets/ParagraphTarget.ts @@ -1,4 +1,3 @@ -import { Range } from "vscode"; import { TargetParameters } from "../../typings/target.types"; import BaseTarget from "./BaseTarget"; diff --git a/src/util/selectionUtils.ts b/src/util/selectionUtils.ts index 254775ceee..fe2e00f930 100644 --- a/src/util/selectionUtils.ts +++ b/src/util/selectionUtils.ts @@ -1,4 +1,5 @@ import { Position, Range, Selection } from "vscode"; +import { RemovalRange } from "../typings/target.types"; import { SelectionWithEditor } from "../typings/Types"; export function isForward(selection: Selection) { @@ -37,3 +38,28 @@ function selectionFromPositions( ? new Selection(start, end) : new Selection(end, start); } + +function removeSubRange(range: Range, rangeToRemove: Range) { + const intersection = range.intersection(rangeToRemove); + if (intersection == null) { + return range; + } + if (intersection.contains(range.start)) { + return new Range(intersection.end, range.end); + } + return new Range(range.start, intersection.start); +} + +export function removeDelimiterRanges( + range: Range, + leading?: RemovalRange, + trailing?: RemovalRange +) { + if (leading != null) { + range = removeSubRange(range, leading.range); + } + if (trailing != null) { + range = removeSubRange(range, trailing.range); + } + return range; +} From affcac1639c78fda7eaf13c7bc36635a6908dae3 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 19 May 2022 13:55:57 +0200 Subject: [PATCH 124/314] oo targets past all test --- src/actions/CutCopyPaste.ts | 9 +- src/actions/Remove.ts | 5 +- src/actions/ToggleBreakpoint.ts | 14 +-- .../scopeTypeStages/DocumentStage.ts | 12 +-- .../modifiers/scopeTypeStages/LineStage.ts | 5 +- .../scopeTypeStages/ParagraphStage.ts | 16 +-- src/processTargets/processTargets.ts | 100 ++++++++++-------- src/processTargets/targets/BaseTarget.ts | 70 +++++------- src/processTargets/targets/DocumentTarget.ts | 34 ++++++ src/processTargets/targets/LineTarget.ts | 32 +++++- src/processTargets/targets/ParagraphTarget.ts | 70 ++++++++++-- .../positions/chuckBeforeBlockAir.yml | 3 +- .../recorded/selectionTypes/chuckBlockAir.yml | 5 +- src/typings/target.types.ts | 42 +++----- src/util/editDisplayUtils.ts | 5 +- src/util/selectionUtils.ts | 26 ----- src/util/targetUtils.ts | 20 +--- src/util/unifyRanges.ts | 22 ++-- 18 files changed, 267 insertions(+), 223 deletions(-) create mode 100644 src/processTargets/targets/DocumentTarget.ts diff --git a/src/actions/CutCopyPaste.ts b/src/actions/CutCopyPaste.ts index 40771b9015..59c7182967 100644 --- a/src/actions/CutCopyPaste.ts +++ b/src/actions/CutCopyPaste.ts @@ -1,11 +1,8 @@ -import { Target } from "../typings/target.types"; import BaseTarget from "../processTargets/targets/BaseTarget"; +import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; import displayPendingEditDecorations from "../util/editDisplayUtils"; -import { - getOutsideOverflow, - getRemovalHighlightRange, -} from "../util/targetUtils"; +import { getOutsideOverflow } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; import CommandAction from "./CommandAction"; @@ -16,7 +13,7 @@ export class Cut implements Action { async run([targets]: [Target[]]): Promise { const overflowTargets = targets.flatMap((target) => { - const range = getRemovalHighlightRange(target); + const range = target.getRemovalHighlightRange(); if (range == null) { return []; } diff --git a/src/actions/Remove.ts b/src/actions/Remove.ts index a2d0b59c0c..621e045b23 100644 --- a/src/actions/Remove.ts +++ b/src/actions/Remove.ts @@ -6,7 +6,6 @@ import displayPendingEditDecorations from "../util/editDisplayUtils"; import { createThatMark, getContentRange, - getRemovalHighlightRange, getRemovalRange, runOnTargetsForEachEditor, } from "../util/targetUtils"; @@ -61,3 +60,7 @@ export default class Delete implements Action { return { thatMark }; } } + +function getRemovalHighlightRange(target: Target) { + return target.getRemovalHighlightRange(); +} diff --git a/src/actions/ToggleBreakpoint.ts b/src/actions/ToggleBreakpoint.ts index 26e7e2b866..d11766c0d6 100644 --- a/src/actions/ToggleBreakpoint.ts +++ b/src/actions/ToggleBreakpoint.ts @@ -1,15 +1,15 @@ import { - Uri, - Range, - debug, - SourceBreakpoint, Breakpoint, + debug, Location, + Range, + SourceBreakpoint, + Uri, } from "vscode"; import { Target } from "../typings/target.types"; import { ActionPreferences, Graph } from "../typings/Types"; import displayPendingEditDecorations from "../util/editDisplayUtils"; -import { createThatMark, isLineScopeType } from "../util/targetUtils"; +import { createThatMark } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; function getBreakpoints(uri: Uri, range: Range) { @@ -42,7 +42,7 @@ export default class ToggleBreakpoint implements Action { targets.forEach((target) => { let range = target.contentRange; // The action preference give us line content but line breakpoints are registered on character 0 - if (isLineScopeType(target.scopeType)) { + if (target.isLine) { range = range.with(range.start.with(undefined, 0), undefined); } const uri = target.editor.document.uri; @@ -50,7 +50,7 @@ export default class ToggleBreakpoint implements Action { if (existing.length > 0) { toRemove.push(...existing); } else { - if (isLineScopeType(target.scopeType)) { + if (target.isLine) { range = range.with(undefined, range.end.with(undefined, 0)); } toAdd.push(new SourceBreakpoint(new Location(uri, range))); diff --git a/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts b/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts index a16ed5cebb..ca304596d9 100644 --- a/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts @@ -4,26 +4,20 @@ import { EveryScopeModifier, Target, } from "../../../typings/target.types"; -import ScopeTypeTarget from "../../targets/ScopeTypeTarget"; import { ProcessedTargetsContext } from "../../../typings/Types"; -import { getDocumentRange } from "../../../util/range"; import { ModifierStage } from "../../PipelineStages.types"; +import DocumentTarget from "../../targets/DocumentTarget"; import { fitRangeToLineContent } from "./LineStage"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} - run(context: ProcessedTargetsContext, target: Target): ScopeTypeTarget[] { + run(context: ProcessedTargetsContext, target: Target): DocumentTarget[] { return [ - new ScopeTypeTarget({ - scopeType: this.modifier.scopeType, + new DocumentTarget({ editor: target.editor, isReversed: target.isReversed, - delimiter: "\n", contentRange: getDocumentContentRange(target.editor), - removal: { - range: getDocumentRange(target.editor.document), - }, }), ]; } diff --git a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts index 2db430b298..082261b1a2 100644 --- a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts @@ -79,11 +79,8 @@ export function createLineTarget( return new LineTarget({ editor, - contentRange, isReversed, - removal: { - range: removalRange, - }, + contentRange, leadingDelimiter: leadingDelimiterRange != null ? { range: leadingDelimiterRange } diff --git a/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts b/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts index 419005ae9d..139043b406 100644 --- a/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts @@ -87,7 +87,6 @@ export default class implements ModifierStage { target.editor, new Range(startLine.range.start, endLine.range.end) ); - const removalRange = new Range(startLine.range.start, endLine.range.end); const leadingLine = getPreviousNonEmptyLine(document, startLine); const trailingLine = getNextNonEmptyLine(document, endLine); @@ -124,22 +123,25 @@ export default class implements ModifierStage { ), }; } - if (contentRange.end.line < document.lineCount - 1) { - const { end } = lineAt(document.lineCount - 1).range; + if (endLine.lineNumber < document.lineCount - 1) { + const lastLine = lineAt(document.lineCount - 1); + // If true there is an empty line after this one that isn't the last/final one + const highlightStart = + endLine.lineNumber !== document.lineCount - 1 + ? lineAt(endLine.lineNumber + 1).range.end + : lastLine.range.start; return { - range: new Range(endLine.range.end, end), - highlight: new Range(lineAt(endLine.lineNumber - 1).range.end, end), + range: new Range(endLine.range.end, lastLine.range.end), + highlight: new Range(highlightStart, lastLine.range.end), }; } return undefined; })(); return new ParagraphTarget({ - scopeType: this.modifier.scopeType, editor: target.editor, isReversed: target.isReversed, contentRange, - removal: { range: removalRange }, leadingDelimiter, trailingDelimiter, }); diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index e267bed433..91c1ac5fba 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -1,19 +1,17 @@ import { zip } from "lodash"; -import { Range } from "vscode"; +import { Position, Range } from "vscode"; import { PrimitiveTargetDescriptor, RangeTargetDescriptor, - RemovalRange, Target, TargetDescriptor, } from "../typings/target.types"; -import BaseTarget from "./targets/BaseTarget"; import { ProcessedTargetsContext } from "../typings/Types"; import { filterDuplicates } from "../util/filterDuplicates"; -import { parseRemovalRange } from "../util/targetUtils"; +import { ensureSingleEditor } from "../util/targetUtils"; import getMarkStage from "./getMarkStage"; import getModifierStage from "./getModifierStage"; -import { removeDelimiterRanges } from "../util/selectionUtils"; +import BaseTarget from "./targets/BaseTarget"; /** * Converts the abstract target descriptions provided by the user to a concrete @@ -99,54 +97,66 @@ function processContinuousRangeTarget( excludeAnchor: boolean, excludeActive: boolean ): Target[] { + const { document } = ensureSingleEditor([anchorTarget, activeTarget]); const isForward = calcIsForward(anchorTarget, activeTarget); const startTarget = isForward ? anchorTarget : activeTarget; const endTarget = isForward ? activeTarget : anchorTarget; const excludeStart = isForward ? excludeAnchor : excludeActive; const excludeEnd = isForward ? excludeActive : excludeAnchor; - const leadingDelimiterRange = excludeStart - ? startTarget.trailingDelimiter - : startTarget.leadingDelimiter; - const trailingDelimiterRange = excludeEnd - ? endTarget.leadingDelimiter - : endTarget.trailingDelimiter; - - const contentStart = excludeStart - ? startTarget.contentRange.end - : startTarget.contentRange.start; - const contentEnd = excludeEnd - ? endTarget.contentRange.start - : endTarget.contentRange.end; - const contentRange = removeDelimiterRanges( - new Range(contentStart, contentEnd), - leadingDelimiterRange, - trailingDelimiterRange - ); + const contentStart = (() => { + if (excludeStart) { + if (startTarget.isLine) { + return new Position(startTarget.contentRange.end.line + 1, 0); + } + return startTarget.contentRange.end; + } + return startTarget.contentRange.start; + })(); + const contentEnd = (() => { + if (excludeEnd) { + if (endTarget.isLine) { + return document.lineAt(endTarget.contentRange.start.line - 1).range.end; + } + return endTarget.contentRange.start; + } + return endTarget.contentRange.end; + })(); + const contentRange = new Range(contentStart, contentEnd); - const removalRange = ((): RemovalRange | undefined => { - const startRange = parseRemovalRange(startTarget.removal); - const endRange = parseRemovalRange(endTarget.removal); - if (startRange == null && endRange == null) { + const removalRange = (() => { + if (startTarget.removalRange == null && endTarget.removalRange == null) { return undefined; } - const startRemovalRange = - (!excludeStart ? startRange?.range.start : null) ?? - startTarget.contentRange.end; - const endRemovalRange = - (!excludeEnd ? endRange?.range.end : null) ?? - endTarget.contentRange.start; - const removalRange = removeDelimiterRanges( - new Range(startRemovalRange, endRemovalRange), - leadingDelimiterRange, - trailingDelimiterRange + const startRange = startTarget.removalRange ?? startTarget.contentRange; + const endRange = endTarget.removalRange ?? endTarget.contentRange; + return new Range( + excludeStart ? startRange.end : startRange.start, + excludeEnd ? endRange.start : endRange.end ); - if (removalRange.isEqual(contentRange)) { - return undefined; + })(); + + const leadingDelimiter = (() => { + if (excludeStart) { + if (startTarget.isLine) { + return { + range: new Range(contentRange.start, startTarget.contentRange.end), + }; + } + return startTarget.trailingDelimiter; + } + return startTarget.leadingDelimiter; + })(); + const trailingDelimiter = (() => { + if (excludeEnd) { + if (endTarget.isLine) { + return { + range: new Range(contentRange.end, endTarget.contentRange.start), + }; + } + return endTarget.leadingDelimiter; } - return { - range: removalRange, - }; + return endTarget.trailingDelimiter; })(); const scopeType = @@ -166,10 +176,10 @@ function processContinuousRangeTarget( isReversed: !isForward, delimiter: anchorTarget.delimiter, contentRange, + removalRange, scopeType, - removal: removalRange, - leadingDelimiter: leadingDelimiterRange, - trailingDelimiter: trailingDelimiterRange, + leadingDelimiter, + trailingDelimiter, }), ]; } diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index 8fb6de27b6..d2b93c5492 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -15,11 +15,12 @@ export default class BaseTarget implements Target { position?: Position; delimiter?: string; contentRange: Range; + removalRange?: Range; interiorRange?: Range; boundary?: [Range, Range]; - removal?: RemovalRange; leadingDelimiter?: RemovalRange; trailingDelimiter?: RemovalRange; + isLine?: boolean; constructor(parameters: TargetParameters) { this.editor = parameters.editor; @@ -28,9 +29,9 @@ export default class BaseTarget implements Target { this.position = parameters.position; this.delimiter = parameters.delimiter; this.contentRange = parameters.contentRange; + this.removalRange = parameters.removalRange; this.interiorRange = parameters.interiorRange; this.boundary = parameters.boundary; - this.removal = parameters.removal; this.leadingDelimiter = parameters.leadingDelimiter; this.trailingDelimiter = parameters.trailingDelimiter; } @@ -58,6 +59,26 @@ export default class BaseTarget implements Target { return text; } + protected getRemovalContentRange(): Range { + const removalRange = this.removalRange ?? this.contentRange; + const delimiter = + parseRemovalRange(this.trailingDelimiter) ?? + parseRemovalRange(this.leadingDelimiter); + return delimiter != null + ? removalRange.union(delimiter.range) + : removalRange; + } + + protected getRemovalContentHighlightRange() { + const removalRange = this.removalRange ?? this.contentRange; + const delimiter = + parseRemovalRange(this.trailingDelimiter) ?? + parseRemovalRange(this.leadingDelimiter); + return delimiter != null + ? removalRange.union(delimiter.highlight) + : removalRange; + } + protected getRemovalBeforeRange(): Range { return this.leadingDelimiter != null ? this.leadingDelimiter.range @@ -89,28 +110,7 @@ export default class BaseTarget implements Target { if (this.position === "after") { return this.getRemovalAfterRange(); } - - const removalRange = (() => { - const range = parseRemovalRange(this.removal); - if (range != null) { - return range.range; - } - return this.contentRange; - })(); - const delimiterRange = (() => { - const leadingDelimiter = parseRemovalRange(this.leadingDelimiter); - const trailingDelimiter = parseRemovalRange(this.trailingDelimiter); - if (trailingDelimiter != null) { - return trailingDelimiter.range; - } - if (leadingDelimiter != null) { - return leadingDelimiter.range; - } - return undefined; - })(); - return delimiterRange != null - ? removalRange.union(delimiterRange) - : removalRange; + return this.getRemovalContentRange(); } getRemovalHighlightRange(): Range | undefined { @@ -120,26 +120,6 @@ export default class BaseTarget implements Target { if (this.position === "after") { return this.getRemovalAfterHighlightRange(); } - - const removalRange = (() => { - const range = parseRemovalRange(this.removal); - return range != null ? range.range : this.contentRange; - })(); - - const delimiterRange = (() => { - const leadingDelimiter = parseRemovalRange(this.leadingDelimiter); - const trailingDelimiter = parseRemovalRange(this.trailingDelimiter); - if (trailingDelimiter != null) { - return trailingDelimiter.highlight; - } - if (leadingDelimiter) { - return leadingDelimiter.highlight; - } - return undefined; - })(); - - return delimiterRange != null - ? removalRange.union(delimiterRange) - : removalRange; + return this.getRemovalContentHighlightRange(); } } diff --git a/src/processTargets/targets/DocumentTarget.ts b/src/processTargets/targets/DocumentTarget.ts new file mode 100644 index 0000000000..1faf379074 --- /dev/null +++ b/src/processTargets/targets/DocumentTarget.ts @@ -0,0 +1,34 @@ +import { Range, TextEditor } from "vscode"; +import BaseTarget from "./BaseTarget"; + +interface DocumentTargetParameters { + editor: TextEditor; + isReversed: boolean; + contentRange: Range; +} + +export default class DocumentTarget extends BaseTarget { + constructor(parameters: DocumentTargetParameters) { + super(parameters); + this.scopeType = "document"; + this.delimiter = "\n"; + this.isLine = true; + } + + protected getRemovalContentRange(): Range { + if (this.position != null) { + return this.contentRange; + } + return new Range( + this.editor.document.lineAt(0).range.start, + this.editor.document.lineAt(this.editor.document.lineCount - 1).range.end + ); + } + + getRemovalHighlightRange(): Range | undefined { + if (this.position != null) { + return undefined; + } + return this.contentRange; + } +} diff --git a/src/processTargets/targets/LineTarget.ts b/src/processTargets/targets/LineTarget.ts index a18a9b05e0..5bca714565 100644 --- a/src/processTargets/targets/LineTarget.ts +++ b/src/processTargets/targets/LineTarget.ts @@ -1,12 +1,38 @@ -import { Range } from "vscode"; -import { TargetParameters } from "../../typings/target.types"; +import { Range, TextEditor } from "vscode"; +import { RemovalRange } from "../../typings/target.types"; +import { parseRemovalRange } from "../../util/targetUtils"; import BaseTarget from "./BaseTarget"; +interface LineTargetParameters { + editor: TextEditor; + isReversed: boolean; + contentRange: Range; + leadingDelimiter?: RemovalRange; + trailingDelimiter?: RemovalRange; +} + export default class LineTarget extends BaseTarget { - constructor(parameters: TargetParameters) { + constructor(parameters: LineTargetParameters) { super(parameters); this.scopeType = "line"; this.delimiter = "\n"; + this.isLine = true; + } + + protected getRemovalContentRange(): Range { + if (this.position != null) { + return this.contentRange; + } + const removalRange = new Range( + this.editor.document.lineAt(this.contentRange.start).range.start, + this.editor.document.lineAt(this.contentRange.end).range.end + ); + const delimiter = + parseRemovalRange(this.trailingDelimiter) ?? + parseRemovalRange(this.leadingDelimiter); + return delimiter != null + ? removalRange.union(delimiter.range) + : removalRange; } getRemovalHighlightRange(): Range | undefined { diff --git a/src/processTargets/targets/ParagraphTarget.ts b/src/processTargets/targets/ParagraphTarget.ts index 4a8bcb3a4b..a2056204bf 100644 --- a/src/processTargets/targets/ParagraphTarget.ts +++ b/src/processTargets/targets/ParagraphTarget.ts @@ -1,16 +1,70 @@ -import { TargetParameters } from "../../typings/target.types"; +import { Range, TextEditor } from "vscode"; +import { RemovalRange } from "../../typings/target.types"; +import { parseRemovalRange } from "../../util/targetUtils"; import BaseTarget from "./BaseTarget"; +interface ParagraphTargetParameters { + editor: TextEditor; + isReversed: boolean; + contentRange: Range; + leadingDelimiter?: RemovalRange; + trailingDelimiter?: RemovalRange; +} + export default class ParagraphTarget extends BaseTarget { - constructor(parameters: TargetParameters) { + constructor(parameters: ParagraphTargetParameters) { super(parameters); + this.scopeType = "paragraph"; this.delimiter = "\n\n"; + this.isLine = true; + } + + protected getRemovalBeforeRange(): Range { + return this.leadingDelimiter != null + ? new Range( + this.leadingDelimiter.range.start, + this.editor.document.lineAt( + this.contentRange.start.line - 1 + ).range.start + ) + : this.contentRange; } - // getRemovalHighlightRange(): Range | undefined { - // if (this.position != null) { - // return undefined; - // } - // return this.contentRange; - // } + protected getRemovalAfterRange(): Range { + return this.trailingDelimiter != null + ? this.trailingDelimiter.range + : this.contentRange; + } + + getRemovalContentRange(): Range { + const removalRange = new Range( + this.editor.document.lineAt(this.contentRange.start).range.start, + this.editor.document.lineAt(this.contentRange.end).range.end + ); + const delimiterRange = (() => { + const leadingDelimiter = parseRemovalRange(this.leadingDelimiter); + const trailingDelimiter = parseRemovalRange(this.trailingDelimiter); + if (trailingDelimiter != null) { + const { document } = this.editor; + // Trailing delimiter to end of file. Need to remove leading new line delimiter + if ( + trailingDelimiter.range.end.line === document.lineCount - 1 && + leadingDelimiter != null + ) { + return new Range( + document.lineAt(this.contentRange.start.line - 1).range.end, + trailingDelimiter.range.end + ); + } + return trailingDelimiter.range; + } + if (leadingDelimiter) { + return leadingDelimiter.range; + } + return undefined; + })(); + return delimiterRange != null + ? removalRange.union(delimiterRange) + : removalRange; + } } diff --git a/src/test/suite/fixtures/recorded/positions/chuckBeforeBlockAir.yml b/src/test/suite/fixtures/recorded/positions/chuckBeforeBlockAir.yml index 31d34664c0..879a322a89 100644 --- a/src/test/suite/fixtures/recorded/positions/chuckBeforeBlockAir.yml +++ b/src/test/suite/fixtures/recorded/positions/chuckBeforeBlockAir.yml @@ -24,7 +24,8 @@ initialState: finalState: documentContents: |- - const value = "Hello world"; const value = "Hello world"; + const value = "Hello world"; + const value = "Hello world"; selections: - anchor: {line: 0, character: 0} active: {line: 0, character: 0} diff --git a/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockAir.yml b/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockAir.yml index fd8f46eb1d..4a85bceb85 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockAir.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockAir.yml @@ -25,11 +25,10 @@ finalState: documentContents: |+ const value = "Hello world"; - selections: - anchor: {line: 0, character: 0} active: {line: 0, character: 0} thatMark: - - anchor: {line: 3, character: 0} - active: {line: 3, character: 0} + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: a}, selectionType: paragraph, position: contents, modifier: {type: identity}, insideOutsideType: outside}] diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index dfccc9a7ee..c8c6a6acd2 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -236,30 +236,25 @@ export type TargetDescriptor = | ListTargetDescriptor; export interface RemovalRange { + /** The range to be removed */ range: Range; + /** Optional highlight range to be used for highlight instead of the removal range */ highlight?: Range; + /** If true this range is excluded from delimiters by default */ exclude?: boolean; } export interface TargetParameters { - /** - * The text editor used for all ranges - */ + /** The text editor used for all ranges */ editor: TextEditor; - /** - * If true active is before anchor - */ + /** If true active is before anchor */ isReversed: boolean; - /** - * Is this a scope type other raw selection? - */ + /** Is this a scope type other raw selection? */ scopeType?: ScopeType; - /** - * The current position - */ + /** The current position */ position?: Position; /** @@ -267,11 +262,12 @@ export interface TargetParameters { */ delimiter?: string; - /** - * The range of the content - */ + /** The range of the content */ contentRange: Range; + /** The range to remove the content */ + removalRange?: Range; + /** * Represents the interior range of this selection. For example, for a * surrounding pair this would exclude the opening and closing delimiter. For an if @@ -286,23 +282,17 @@ export interface TargetParameters { */ boundary?: [Range, Range]; - /** - * The range that needs to be removed - */ - removal?: RemovalRange; - - /** - * The range of the delimiter before the content selection - */ + /** The range of the delimiter before the content selection */ leadingDelimiter?: RemovalRange; - /** - * The range of the delimiter after the content selection - */ + /** The range of the delimiter after the content selection */ trailingDelimiter?: RemovalRange; } export interface Target extends TargetParameters { + /** If true this target should be treated as a line in regards to continuous range */ + isLine?: boolean; + getContentSelection(): Selection; getContentText(): string; maybeAddDelimiter(text: string): string; diff --git a/src/util/editDisplayUtils.ts b/src/util/editDisplayUtils.ts index 0c6f469113..b549f7b049 100644 --- a/src/util/editDisplayUtils.ts +++ b/src/util/editDisplayUtils.ts @@ -6,7 +6,6 @@ import { RangeWithEditor } from "../typings/Types"; import sleep from "./sleep"; import { getContentRange, - isLineScopeType, runForEachEditor, runOnTargetsForEachEditor, } from "./targetUtils"; @@ -112,14 +111,14 @@ export async function setDecorations( editor.setDecorations( editStyle.token, targets - .filter((target) => !isLineScopeType(target.scopeType)) + .filter((target) => !target.isLine) .map(getRange) .filter((range): range is Range => !!range) ); editor.setDecorations( editStyle.line, targets - .filter((target) => isLineScopeType(target.scopeType)) + .filter((target) => target.isLine) .map(getRange) .filter((range): range is Range => !!range) ); diff --git a/src/util/selectionUtils.ts b/src/util/selectionUtils.ts index fe2e00f930..254775ceee 100644 --- a/src/util/selectionUtils.ts +++ b/src/util/selectionUtils.ts @@ -1,5 +1,4 @@ import { Position, Range, Selection } from "vscode"; -import { RemovalRange } from "../typings/target.types"; import { SelectionWithEditor } from "../typings/Types"; export function isForward(selection: Selection) { @@ -38,28 +37,3 @@ function selectionFromPositions( ? new Selection(start, end) : new Selection(end, start); } - -function removeSubRange(range: Range, rangeToRemove: Range) { - const intersection = range.intersection(rangeToRemove); - if (intersection == null) { - return range; - } - if (intersection.contains(range.start)) { - return new Range(intersection.end, range.end); - } - return new Range(range.start, intersection.start); -} - -export function removeDelimiterRanges( - range: Range, - leading?: RemovalRange, - trailing?: RemovalRange -) { - if (leading != null) { - range = removeSubRange(range, leading.range); - } - if (trailing != null) { - range = removeSubRange(range, trailing.range); - } - return range; -} diff --git a/src/util/targetUtils.ts b/src/util/targetUtils.ts index 34b5b42e74..fb47a1403a 100644 --- a/src/util/targetUtils.ts +++ b/src/util/targetUtils.ts @@ -3,7 +3,6 @@ import { Range, Selection, TextEditor } from "vscode"; import { getTokenDelimiters } from "../processTargets/modifiers/scopeTypeStages/TokenStage"; import { RemovalRange, - ScopeType, Target, TargetParameters, } from "../typings/target.types"; @@ -118,10 +117,6 @@ export function getRemovalRange(target: Target) { return target.getRemovalRange(); } -export function getRemovalHighlightRange(target: Target) { - return target.getRemovalHighlightRange(); -} - export function parseRemovalRange( range?: RemovalRange ): Required | undefined { @@ -134,17 +129,6 @@ export function parseRemovalRange( : undefined; } -export function isLineScopeType(scopeType?: ScopeType) { - switch (scopeType) { - case "line": - case "paragraph": - case "document": - return true; - default: - return false; - } -} - export function selectionWithEditorWithContextToTarget( selection: SelectionWithEditorWithContext ): TargetParameters { @@ -155,9 +139,9 @@ export function selectionWithEditorWithContextToTarget( containingListDelimiter, interiorRange, boundary, - removalRange, leadingDelimiterRange, trailingDelimiterRange, + removalRange, } = context; const { editor, selection: contentRange } = selection.selection; @@ -184,9 +168,9 @@ export function selectionWithEditorWithContextToTarget( isReversed: isReversed(contentRange), contentRange, interiorRange, + removalRange, boundary, delimiter: tokenContext?.delimiter ?? containingListDelimiter ?? "\n", - removal: removalRange != null ? { range: removalRange } : undefined, leadingDelimiter, trailingDelimiter, }; diff --git a/src/util/unifyRanges.ts b/src/util/unifyRanges.ts index 4c40728dfe..8b03f3c840 100644 --- a/src/util/unifyRanges.ts +++ b/src/util/unifyRanges.ts @@ -1,7 +1,7 @@ import { Range } from "vscode"; -import { Target } from "../typings/target.types"; import BaseTarget from "../processTargets/targets/BaseTarget"; -import { getRemovalRange, groupTargetsForEachEditor } from "./targetUtils"; +import { Target } from "../typings/target.types"; +import { groupTargetsForEachEditor } from "./targetUtils"; /** Unifies overlapping/intersecting ranges */ export default function unifyRanges(ranges: Range[]): Range[] { @@ -93,19 +93,19 @@ function mergeTargets(targets: Target[]): Target { return new BaseTarget({ editor: first.editor, isReversed: first.isReversed, - contentRange: new Range( - getContentRange(first).start, - getContentRange(last).end - ), leadingDelimiter: first.leadingDelimiter, trailingDelimiter: last.trailingDelimiter, + contentRange: new Range(first.contentRange.start, last.contentRange.end), + removalRange: + first.removalRange != null || last.removalRange != null + ? new Range( + first.removalRange?.start ?? first.contentRange.start, + last.removalRange?.end ?? last.contentRange.end + ) + : undefined, }); } function intersects(targetA: Target, targetB: Target) { - return !!getRemovalRange(targetA).intersection(getRemovalRange(targetB)); -} - -function getContentRange(target: Target): Range { - return target.removal?.range ?? target.contentRange; + return !!targetA.getRemovalRange().intersection(targetB.getRemovalRange()); } From 11b624b3ce76ecfef7b749054d5659f81145645a Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 19 May 2022 13:59:24 +0200 Subject: [PATCH 125/314] Added line and paragraph tests --- .../selectionTypes/bringHarpToAfterFile.yml | 37 +++++++++++++ .../selectionTypes/bringWhaleToBeforeFile.yml | 37 +++++++++++++ .../chuckBlockHarpBetweenFine.yml | 55 +++++++++++++++++++ .../chuckLineHarpBetweenFine.yml | 55 +++++++++++++++++++ 4 files changed, 184 insertions(+) create mode 100644 src/test/suite/fixtures/recorded/selectionTypes/bringHarpToAfterFile.yml create mode 100644 src/test/suite/fixtures/recorded/selectionTypes/bringWhaleToBeforeFile.yml create mode 100644 src/test/suite/fixtures/recorded/selectionTypes/chuckBlockHarpBetweenFine.yml create mode 100644 src/test/suite/fixtures/recorded/selectionTypes/chuckLineHarpBetweenFine.yml diff --git a/src/test/suite/fixtures/recorded/selectionTypes/bringHarpToAfterFile.yml b/src/test/suite/fixtures/recorded/selectionTypes/bringHarpToAfterFile.yml new file mode 100644 index 0000000000..9c9098eba4 --- /dev/null +++ b/src/test/suite/fixtures/recorded/selectionTypes/bringHarpToAfterFile.yml @@ -0,0 +1,37 @@ +languageId: plaintext +command: + spokenForm: bring harp to after file + version: 2 + action: replaceWithTarget + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: h} + modifiers: [] + - type: primitive + modifiers: + - {type: position, position: after} + - {type: containingScope, scopeType: document} + usePrePhraseSnapshot: true +initialState: + documentContents: hello world + selections: + - anchor: {line: 0, character: 11} + active: {line: 0, character: 11} + marks: + default.h: + start: {line: 0, character: 0} + end: {line: 0, character: 5} +finalState: + documentContents: |- + hello world + hello + selections: + - anchor: {line: 0, character: 11} + active: {line: 0, character: 11} + thatMark: + - anchor: {line: 0, character: 11} + active: {line: 1, character: 5} + sourceMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 5} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: h}, modifiers: []}, {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: h}, modifiers: [{type: position, position: after}, {type: containingScope, scopeType: document}]}] diff --git a/src/test/suite/fixtures/recorded/selectionTypes/bringWhaleToBeforeFile.yml b/src/test/suite/fixtures/recorded/selectionTypes/bringWhaleToBeforeFile.yml new file mode 100644 index 0000000000..48596f4294 --- /dev/null +++ b/src/test/suite/fixtures/recorded/selectionTypes/bringWhaleToBeforeFile.yml @@ -0,0 +1,37 @@ +languageId: plaintext +command: + spokenForm: bring whale to before file + version: 2 + action: replaceWithTarget + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: w} + modifiers: [] + - type: primitive + modifiers: + - {type: position, position: before} + - {type: containingScope, scopeType: document} + usePrePhraseSnapshot: true +initialState: + documentContents: hello world + selections: + - anchor: {line: 0, character: 11} + active: {line: 0, character: 11} + marks: + default.w: + start: {line: 0, character: 6} + end: {line: 0, character: 11} +finalState: + documentContents: |- + world + hello world + selections: + - anchor: {line: 1, character: 11} + active: {line: 1, character: 11} + thatMark: + - anchor: {line: 0, character: 0} + active: {line: 1, character: 0} + sourceMark: + - anchor: {line: 1, character: 6} + active: {line: 1, character: 11} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: w}, modifiers: []}, {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: w}, modifiers: [{type: position, position: before}, {type: containingScope, scopeType: document}]}] diff --git a/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockHarpBetweenFine.yml b/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockHarpBetweenFine.yml new file mode 100644 index 0000000000..0be22b6729 --- /dev/null +++ b/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockHarpBetweenFine.yml @@ -0,0 +1,55 @@ +languageId: plaintext +command: + spokenForm: chuck block harp between fine + version: 2 + action: remove + targets: + - type: range + start: + type: primitive + selectionType: paragraph + mark: {type: decoratedSymbol, symbolColor: default, character: h} + end: + type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: f} + excludeStart: true + excludeEnd: true + anchor: + type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: h} + modifiers: + - {type: containingScope, scopeType: paragraph} + active: + type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: f} + modifiers: [] + usePrePhraseSnapshot: true +initialState: + documentContents: | + + hello world + + + foo bar + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: + default.h: + start: {line: 1, character: 0} + end: {line: 1, character: 5} + default.f: + start: {line: 4, character: 0} + end: {line: 4, character: 3} +finalState: + documentContents: | + + hello world + foo bar + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} +fullTargets: [{type: range, excludeAnchor: true, excludeActive: true, rangeType: continuous, anchor: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: h}, modifiers: &ref_0 [{type: containingScope, scopeType: paragraph}]}, active: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: f}, modifiers: *ref_0}}] diff --git a/src/test/suite/fixtures/recorded/selectionTypes/chuckLineHarpBetweenFine.yml b/src/test/suite/fixtures/recorded/selectionTypes/chuckLineHarpBetweenFine.yml new file mode 100644 index 0000000000..e3cd997de6 --- /dev/null +++ b/src/test/suite/fixtures/recorded/selectionTypes/chuckLineHarpBetweenFine.yml @@ -0,0 +1,55 @@ +languageId: plaintext +command: + spokenForm: chuck line harp between fine + version: 2 + action: remove + targets: + - type: range + start: + type: primitive + selectionType: line + mark: {type: decoratedSymbol, symbolColor: default, character: h} + end: + type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: f} + excludeStart: true + excludeEnd: true + anchor: + type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: h} + modifiers: + - {type: containingScope, scopeType: line} + active: + type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: f} + modifiers: [] + usePrePhraseSnapshot: true +initialState: + documentContents: | + + hello world + + + foo bar + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: + default.h: + start: {line: 1, character: 0} + end: {line: 1, character: 5} + default.f: + start: {line: 4, character: 0} + end: {line: 4, character: 3} +finalState: + documentContents: | + + hello world + foo bar + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} +fullTargets: [{type: range, excludeAnchor: true, excludeActive: true, rangeType: continuous, anchor: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: h}, modifiers: &ref_0 [{type: containingScope, scopeType: line}]}, active: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: f}, modifiers: *ref_0}}] From a8b633d50d1e7afaa5bc047dcfb61a9937d2214f Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 19 May 2022 14:14:29 +0200 Subject: [PATCH 126/314] Highlight update --- src/processTargets/processTargets.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index 91c1ac5fba..b2dbe1e137 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -152,6 +152,10 @@ function processContinuousRangeTarget( if (endTarget.isLine) { return { range: new Range(contentRange.end, endTarget.contentRange.start), + highlight: new Range( + contentRange.end, + endTarget.contentRange.start.translate({ lineDelta: -1 }) + ), }; } return endTarget.leadingDelimiter; From 6616f62111717f45b75b5355e05792a2a86c8dbf Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 19 May 2022 17:10:52 +0200 Subject: [PATCH 127/314] Added script to show unused exports --- package.json | 8 +++++--- third-party-licenses.csv | 12 ++---------- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index 62c9269194..74dda50502 100644 --- a/package.json +++ b/package.json @@ -508,7 +508,8 @@ "pretest": "yarn run compile && yarn run lint && yarn run esbuild", "lint": "eslint src --ext ts", "test": "env CURSORLESS_TEST=true node ./out/test/runTest.js", - "prepare-for-extension-publish": "node ./out/scripts/prepareForExtensionPublish.js" + "prepare-for-extension-publish": "node ./out/scripts/prepareForExtensionPublish.js", + "unused-exports": "ts-unused-exports tsconfig.json" }, "devDependencies": { "@types/glob": "^7.1.3", @@ -532,11 +533,12 @@ "semver": "^7.3.5", "sinon": "^11.1.1", "typescript": "^4.5.5", - "vscode-test": "^1.4.1" + "vscode-test": "^1.4.1", + "ts-unused-exports": "8.0.0" }, "dependencies": { "@types/lodash": "^4.14.168", "immutability-helper": "^3.1.1", "lodash": "^4.17.21" } -} +} \ No newline at end of file diff --git a/third-party-licenses.csv b/third-party-licenses.csv index 2a445576df..d625ddd3d2 100644 --- a/third-party-licenses.csv +++ b/third-party-licenses.csv @@ -1,12 +1,4 @@ "module name","licenses","repository","licenseUrl","parents" -"@docusaurus/core@2.0.0-beta.17","MIT","https://github.com/facebook/docusaurus","https://github.com/facebook/docusaurus/raw/master/LICENSE","website" -"@docusaurus/preset-classic@2.0.0-beta.17","MIT","https://github.com/facebook/docusaurus","https://github.com/facebook/docusaurus/raw/master/LICENSE","website" -"@mdx-js/react@1.6.22","MIT","https://github.com/mdx-js/mdx","https://github.com/mdx-js/mdx/raw/master/license","website" -"@types/lodash@4.14.181","MIT","https://github.com/DefinitelyTyped/DefinitelyTyped","https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE","cursorless" -"clsx@1.1.1","MIT","https://github.com/lukeed/clsx","https://github.com/lukeed/clsx/raw/master/license","website" +"@types/lodash@4.14.168","MIT","https://github.com/DefinitelyTyped/DefinitelyTyped","https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE","cursorless" "immutability-helper@3.1.1","MIT","https://github.com/kolodny/immutability-helper","https://github.com/kolodny/immutability-helper/raw/master/LICENSE","cursorless" -"mdast-util-find-and-replace@2.1.0","MIT","https://github.com/syntax-tree/mdast-util-find-and-replace","https://github.com/syntax-tree/mdast-util-find-and-replace/raw/master/license","website" -"prism-react-renderer@1.3.1","MIT","https://github.com/FormidableLabs/prism-react-renderer","https://github.com/FormidableLabs/prism-react-renderer/raw/master/LICENSE","website" -"react-dom@17.0.2","MIT","https://github.com/facebook/react","https://github.com/facebook/react/raw/master/LICENSE","website" -"react@17.0.2","MIT","https://github.com/facebook/react","https://github.com/facebook/react/raw/master/LICENSE","website" -"unist-util-visit@4.1.0","MIT","https://github.com/syntax-tree/unist-util-visit","https://github.com/syntax-tree/unist-util-visit/raw/master/license","website" +"lodash@4.17.21","MIT","https://github.com/lodash/lodash","https://github.com/lodash/lodash/raw/master/LICENSE","cursorless" \ No newline at end of file From af09763cbd83438e7b204bde1764bd54cd0c346f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 19 May 2022 15:11:25 +0000 Subject: [PATCH 128/314] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- package.json | 2 +- third-party-licenses.csv | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 74dda50502..a64ef7bfd2 100644 --- a/package.json +++ b/package.json @@ -541,4 +541,4 @@ "immutability-helper": "^3.1.1", "lodash": "^4.17.21" } -} \ No newline at end of file +} diff --git a/third-party-licenses.csv b/third-party-licenses.csv index d625ddd3d2..07edceab1e 100644 --- a/third-party-licenses.csv +++ b/third-party-licenses.csv @@ -1,4 +1,4 @@ "module name","licenses","repository","licenseUrl","parents" "@types/lodash@4.14.168","MIT","https://github.com/DefinitelyTyped/DefinitelyTyped","https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE","cursorless" "immutability-helper@3.1.1","MIT","https://github.com/kolodny/immutability-helper","https://github.com/kolodny/immutability-helper/raw/master/LICENSE","cursorless" -"lodash@4.17.21","MIT","https://github.com/lodash/lodash","https://github.com/lodash/lodash/raw/master/LICENSE","cursorless" \ No newline at end of file +"lodash@4.17.21","MIT","https://github.com/lodash/lodash","https://github.com/lodash/lodash/raw/master/LICENSE","cursorless" From ab2a68445140706e62e92eadfb8dbe3c94ff11c9 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 19 May 2022 17:30:44 +0200 Subject: [PATCH 129/314] Added line 2 unused export --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 74dda50502..8187ac734f 100644 --- a/package.json +++ b/package.json @@ -509,7 +509,7 @@ "lint": "eslint src --ext ts", "test": "env CURSORLESS_TEST=true node ./out/test/runTest.js", "prepare-for-extension-publish": "node ./out/scripts/prepareForExtensionPublish.js", - "unused-exports": "ts-unused-exports tsconfig.json" + "unused-exports": "ts-unused-exports tsconfig.json --showLineNumber" }, "devDependencies": { "@types/glob": "^7.1.3", From 494e090430469cbc983e6ced44c691aae85a4b44 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 19 May 2022 17:42:04 +0200 Subject: [PATCH 130/314] Default modifiers to empty array --- cursorless-talon/src/primitive_target.py | 2 +- src/core/inferFullTargets.ts | 5 ++--- src/typings/target.types.ts | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/cursorless-talon/src/primitive_target.py b/cursorless-talon/src/primitive_target.py index c1f5c9f590..1d7ba81c03 100644 --- a/cursorless-talon/src/primitive_target.py +++ b/cursorless-talon/src/primitive_target.py @@ -41,6 +41,6 @@ def cursorless_primitive_target(m) -> dict[str, Any]: try: result["modifiers"] = m.cursorless_modifier_list except AttributeError: - pass + result["modifiers"] = [] return result diff --git a/src/core/inferFullTargets.ts b/src/core/inferFullTargets.ts index 013c4383c6..6a3bb5a74f 100644 --- a/src/core/inferFullTargets.ts +++ b/src/core/inferFullTargets.ts @@ -120,7 +120,7 @@ function inferPrimitiveTarget( const previousModifiers = getPreviousModifiers(previousTargets); const modifiers = - target.modifiers != null && target.modifiers.length > 0 + target.modifiers.length > 0 ? target.modifiers : previousModifiers ?? actionPreferences?.modifiers ?? []; @@ -159,8 +159,7 @@ function getPreviousMark(previousTargets: PartialTargetDesc[]) { function getPreviousModifiers(previousTargets: PartialTargetDesc[]) { return getPreviousTarget( previousTargets, - (target: PartialPrimitiveTargetDesc) => - target.modifiers != null && target.modifiers.length > 0 + (target: PartialPrimitiveTargetDesc) => target.modifiers.length > 0 )?.modifiers; } diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index c8c6a6acd2..52c6441c61 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -173,7 +173,7 @@ export interface PositionModifier { export interface PartialPrimitiveTargetDesc { type: "primitive"; mark?: Mark; - modifiers?: Modifier[]; + modifiers: Modifier[]; } export type Modifier = From cfef36f7cce06341076a88374a4a11f968f2fb83 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 19 May 2022 17:59:34 +0200 Subject: [PATCH 131/314] Don't use hat map --- src/core/IndividualHatMap.ts | 1 - .../modifiers/scopeTypeStages/TokenStage.ts | 17 ++++++++--------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/core/IndividualHatMap.ts b/src/core/IndividualHatMap.ts index 826126c55e..cd1888ef55 100644 --- a/src/core/IndividualHatMap.ts +++ b/src/core/IndividualHatMap.ts @@ -5,7 +5,6 @@ import HatTokenMap from "./HatTokenMap"; export interface ReadOnlyHatMap { getEntries(): [string, Token][]; - getTokens(): Token[]; getToken(hatStyle: HatStyleName, character: string): Token; } diff --git a/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts index 744cb94a6a..8fefe36b8a 100644 --- a/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts @@ -31,15 +31,11 @@ export default class implements ModifierStage { const end = isEmpty ? editor.document.lineAt(contentRange.end).range.end : contentRange.end; + const range = new Range(start, end); - const targets = context.hatTokenMap - .getTokens() - .filter( - ({ range }) => - // Token and selection intersects - range.end.isAfterOrEqual(start) && range.end.isBeforeOrEqual(end) - ) - .map(({ range }) => this.getTargetFromRange(target, range)); + const targets = getTokensInRange(editor, range).map(({ range }) => + this.getTargetFromRange(target, range) + ); if (targets.length === 0) { throw new Error(`Couldn't find containing ${this.modifier.scopeType}`); @@ -172,7 +168,10 @@ export function getTokenRangeForSelection( * @param selection The selection * @returns All tokens that intersect with the selection and are on the same line as the start or endpoint of the selection */ -function getTokenIntersectionsForSelection(editor: TextEditor, range: Range) { +export function getTokenIntersectionsForSelection( + editor: TextEditor, + range: Range +) { const tokens = getRelevantTokens(editor, range); const tokenIntersections: { token: PartialToken; intersection: Range }[] = []; From c42cd8e4a832b10f87b79cd3e608c1b1a6dd4b19 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 19 May 2022 18:06:11 +0200 Subject: [PATCH 132/314] Modifiers default to undefined --- cursorless-talon/src/primitive_target.py | 4 ++-- .../commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts | 3 ++- src/core/inferFullTargets.ts | 4 ++-- src/typings/target.types.ts | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/cursorless-talon/src/primitive_target.py b/cursorless-talon/src/primitive_target.py index 1d7ba81c03..bb9b894cca 100644 --- a/cursorless-talon/src/primitive_target.py +++ b/cursorless-talon/src/primitive_target.py @@ -5,7 +5,7 @@ mod = Module() BASE_TARGET: dict[str, Any] = {"type": "primitive"} -IMPLICIT_TARGET = {"type": "primitive", "isImplicit": True} +IMPLICIT_TARGET = {"type": "primitive"} modifiers = [ @@ -41,6 +41,6 @@ def cursorless_primitive_target(m) -> dict[str, Any]: try: result["modifiers"] = m.cursorless_modifier_list except AttributeError: - result["modifiers"] = [] + pass return result diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts index c6b26ce29f..2edb7e61cb 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts @@ -117,7 +117,8 @@ function upgradePrimitiveTarget( ...rest, // Cursor token is just cursor position but treated as a token. This is done in the pipeline for normal cursor now mark: mark?.type === "cursorToken" ? undefined : mark, - modifiers, + // Empty array of modifiers is not allowed + modifiers: modifiers.length > 0 ? modifiers : undefined, }; } diff --git a/src/core/inferFullTargets.ts b/src/core/inferFullTargets.ts index 6a3bb5a74f..a465b15f33 100644 --- a/src/core/inferFullTargets.ts +++ b/src/core/inferFullTargets.ts @@ -120,7 +120,7 @@ function inferPrimitiveTarget( const previousModifiers = getPreviousModifiers(previousTargets); const modifiers = - target.modifiers.length > 0 + target.modifiers != null ? target.modifiers : previousModifiers ?? actionPreferences?.modifiers ?? []; @@ -159,7 +159,7 @@ function getPreviousMark(previousTargets: PartialTargetDesc[]) { function getPreviousModifiers(previousTargets: PartialTargetDesc[]) { return getPreviousTarget( previousTargets, - (target: PartialPrimitiveTargetDesc) => target.modifiers.length > 0 + (target: PartialPrimitiveTargetDesc) => target.modifiers != null )?.modifiers; } diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 52c6441c61..c8c6a6acd2 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -173,7 +173,7 @@ export interface PositionModifier { export interface PartialPrimitiveTargetDesc { type: "primitive"; mark?: Mark; - modifiers: Modifier[]; + modifiers?: Modifier[]; } export type Modifier = From 8fa7add34ceac8c3ff5b9d6c68799774dbafcfb9 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 19 May 2022 18:45:09 +0200 Subject: [PATCH 133/314] Fixed is implicit inference --- cursorless-talon/src/primitive_target.py | 2 +- .../upgradeV1ToV2/upgradeStrictHere.ts | 1 + src/core/inferFullTargets.ts | 9 ++++++++- src/typings/target.types.ts | 1 + 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/cursorless-talon/src/primitive_target.py b/cursorless-talon/src/primitive_target.py index bb9b894cca..c1f5c9f590 100644 --- a/cursorless-talon/src/primitive_target.py +++ b/cursorless-talon/src/primitive_target.py @@ -5,7 +5,7 @@ mod = Module() BASE_TARGET: dict[str, Any] = {"type": "primitive"} -IMPLICIT_TARGET = {"type": "primitive"} +IMPLICIT_TARGET = {"type": "primitive", "isImplicit": True} modifiers = [ diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeStrictHere.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeStrictHere.ts index 9c2aa3512a..d960e8eb67 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeStrictHere.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeStrictHere.ts @@ -11,6 +11,7 @@ const STRICT_HERE = { }; const IMPLICIT_TARGET: PartialPrimitiveTargetDesc = { type: "primitive", + isImplicit: true, }; export const upgradeStrictHere = ( target: PartialPrimitiveTargetDesc diff --git a/src/core/inferFullTargets.ts b/src/core/inferFullTargets.ts index a465b15f33..f30076ce2a 100644 --- a/src/core/inferFullTargets.ts +++ b/src/core/inferFullTargets.ts @@ -1,4 +1,5 @@ import { + Modifier, PartialListTargetDesc, PartialPrimitiveTargetDesc, PartialRangeTargetDesc, @@ -118,11 +119,17 @@ function inferPrimitiveTarget( }; const previousModifiers = getPreviousModifiers(previousTargets); + const implicitModifiers = target.isImplicit + ? [{ type: "toRawSelection" } as Modifier] + : undefined; const modifiers = target.modifiers != null ? target.modifiers - : previousModifiers ?? actionPreferences?.modifiers ?? []; + : implicitModifiers ?? + previousModifiers ?? + actionPreferences?.modifiers ?? + []; // TODO Is this really a good solution? // "bring line to after this" needs to infer line on second target diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index c8c6a6acd2..e1a7e2a9a2 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -174,6 +174,7 @@ export interface PartialPrimitiveTargetDesc { type: "primitive"; mark?: Mark; modifiers?: Modifier[]; + isImplicit?: boolean; } export type Modifier = From 66c09edc7562e9e14ff01bffa39f0e6b4028b894 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 19 May 2022 19:27:21 +0200 Subject: [PATCH 134/314] Removed get tokens function --- src/core/IndividualHatMap.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/core/IndividualHatMap.ts b/src/core/IndividualHatMap.ts index cd1888ef55..c506cfef25 100644 --- a/src/core/IndividualHatMap.ts +++ b/src/core/IndividualHatMap.ts @@ -49,11 +49,6 @@ export class IndividualHatMap implements ReadOnlyHatMap { return Object.entries(this.map); } - getTokens() { - this.checkExpired(); - return Object.values(this.map); - } - private addTokenByKey(key: string, token: Token) { this.map[key] = token; this.getDocumentTokenList(token.editor.document).push(token); From 62491b6e0cedf3b218ced6a207877f61a62e8a6b Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 19 May 2022 19:30:39 +0200 Subject: [PATCH 135/314] Update src/core/commandVersionUpgrades/upgradeV1ToV2/commandV1.types.ts Co-authored-by: Pokey Rule <755842+pokey@users.noreply.github.com> --- .../commandVersionUpgrades/upgradeV1ToV2/commandV1.types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/commandV1.types.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/commandV1.types.ts index 40f9f6d075..fd7cb35cdf 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/commandV1.types.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/commandV1.types.ts @@ -1,5 +1,5 @@ // This file contains a snapshot of all the types used by the deprecated v0 / v1 target representation, -// to be used by on-the-fly target upgrading for background compatibility +// to be used by on-the-fly target upgrading for backwards compatibility export interface CommandV1 extends CommandV0V1 { version: 1; From 5ce6b183eeec57fd16e7c05f852e5075de47e693 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 19 May 2022 19:36:40 +0200 Subject: [PATCH 136/314] Update src/core/inferFullTargets.ts Co-authored-by: Pokey Rule <755842+pokey@users.noreply.github.com> --- src/core/inferFullTargets.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/core/inferFullTargets.ts b/src/core/inferFullTargets.ts index f30076ce2a..b0191a70ce 100644 --- a/src/core/inferFullTargets.ts +++ b/src/core/inferFullTargets.ts @@ -124,9 +124,8 @@ function inferPrimitiveTarget( : undefined; const modifiers = - target.modifiers != null - ? target.modifiers - : implicitModifiers ?? + target.modifiers ?? + implicitModifiers ?? previousModifiers ?? actionPreferences?.modifiers ?? []; From 76b2b1a9383ccecceec6871a5545c174b5193eb2 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 19 May 2022 17:37:02 +0000 Subject: [PATCH 137/314] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/core/inferFullTargets.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/inferFullTargets.ts b/src/core/inferFullTargets.ts index b0191a70ce..ae2a5aac7f 100644 --- a/src/core/inferFullTargets.ts +++ b/src/core/inferFullTargets.ts @@ -125,10 +125,10 @@ function inferPrimitiveTarget( const modifiers = target.modifiers ?? - implicitModifiers ?? - previousModifiers ?? - actionPreferences?.modifiers ?? - []; + implicitModifiers ?? + previousModifiers ?? + actionPreferences?.modifiers ?? + []; // TODO Is this really a good solution? // "bring line to after this" needs to infer line on second target From c052580e8ff186b4d616231a66e5fbd0940b4ec2 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 19 May 2022 19:46:13 +0200 Subject: [PATCH 138/314] General cleanup --- src/core/commandRunner/CommandRunner.ts | 11 +++++++---- .../canonicalizeAndValidateCommand.ts | 4 ++++ .../upgradeV1ToV2/upgradeV1ToV2.ts | 5 ----- src/core/inferFullTargets.ts | 9 ++++----- src/core/updateSelections/updateSelections.ts | 9 +++------ src/processTargets/PipelineStages.types.ts | 2 +- 6 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/core/commandRunner/CommandRunner.ts b/src/core/commandRunner/CommandRunner.ts index 2e0b07df90..5314c018e0 100644 --- a/src/core/commandRunner/CommandRunner.ts +++ b/src/core/commandRunner/CommandRunner.ts @@ -81,7 +81,7 @@ export default class CommandRunner { throw new Error(`Unknown action ${actionName}`); } - const targetDescs = inferFullTargets( + const targetDescriptors = inferFullTargets( partialTargetDescriptors, action.getTargetPreferences ? action.getTargetPreferences(...extraArgs) @@ -90,7 +90,7 @@ export default class CommandRunner { if (this.graph.debug.active) { this.graph.debug.log("Full targets:"); - this.graph.debug.log(JSON.stringify(targetDescs, null, 3)); + this.graph.debug.log(JSON.stringify(targetDescriptors, null, 3)); } const processedTargetsContext: ProcessedTargetsContext = { @@ -106,11 +106,14 @@ export default class CommandRunner { getNodeAtLocation: this.graph.getNodeAtLocation, }; - const targets = processTargets(processedTargetsContext, targetDescs); + const targets = processTargets( + processedTargetsContext, + targetDescriptors + ); if (this.graph.testCaseRecorder.isActive()) { const context = { - targets: targetDescs, + targets: targetDescriptors, thatMark: this.thatMark, sourceMark: this.sourceMark, hatTokenMap: readableHatMap, diff --git a/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts b/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts index b202ac4846..815114d1ab 100644 --- a/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts +++ b/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts @@ -77,6 +77,10 @@ function upgradeCommand(command: Command): CommandLatest { case 1: command = upgradeV1ToV2(command); break; + default: + throw new Error( + `Can't upgrade from unknown version ${command.version}` + ); } } diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts index 2edb7e61cb..7ace71b1d8 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts @@ -67,7 +67,6 @@ function upgradePrimitiveTarget( mark, insideOutsideType, modifier, - isImplicit, selectionType, position, ...rest @@ -90,10 +89,6 @@ function upgradePrimitiveTarget( } } - if (isImplicit) { - modifiers.push({ type: "toRawSelection" }); - } - if (selectionType) { switch (selectionType) { case "token": diff --git a/src/core/inferFullTargets.ts b/src/core/inferFullTargets.ts index b0191a70ce..f5d7e64283 100644 --- a/src/core/inferFullTargets.ts +++ b/src/core/inferFullTargets.ts @@ -125,12 +125,11 @@ function inferPrimitiveTarget( const modifiers = target.modifiers ?? - implicitModifiers ?? - previousModifiers ?? - actionPreferences?.modifiers ?? - []; + implicitModifiers ?? + previousModifiers ?? + actionPreferences?.modifiers ?? + []; - // TODO Is this really a good solution? // "bring line to after this" needs to infer line on second target const modifierTypes = [ ...new Set(modifiers.map((modifier) => modifier.type)), diff --git a/src/core/updateSelections/updateSelections.ts b/src/core/updateSelections/updateSelections.ts index e74323d6fb..d4890d10f9 100644 --- a/src/core/updateSelections/updateSelections.ts +++ b/src/core/updateSelections/updateSelections.ts @@ -218,13 +218,10 @@ export async function performEditsAndUpdateRanges( rangeUpdater: RangeUpdater, editor: TextEditor, edits: Edit[], - originalSelections: (readonly Range[])[] -) { + originalRanges: (readonly Range[])[] +): Promise { const document = editor.document; - const selectionInfoMatrix = rangesToSelectionInfos( - document, - originalSelections - ); + const selectionInfoMatrix = rangesToSelectionInfos(document, originalRanges); return performEditsAndUpdateInternal( rangeUpdater, editor, diff --git a/src/processTargets/PipelineStages.types.ts b/src/processTargets/PipelineStages.types.ts index 7055e1bec8..eb1e1c10c9 100644 --- a/src/processTargets/PipelineStages.types.ts +++ b/src/processTargets/PipelineStages.types.ts @@ -6,5 +6,5 @@ export interface MarkStage { } export interface ModifierStage { - run(context: ProcessedTargetsContext, target?: Target): Target[]; + run(context: ProcessedTargetsContext, target: Target): Target[]; } From b68c16e7ad370d4522b1bfa95dc38d732ffe63ea Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 19 May 2022 20:02:32 +0200 Subject: [PATCH 139/314] Added notebook cell target --- .../scopeTypeStages/NotebookCellStage.ts | 12 ++++++------ src/processTargets/targets/NotebookCellTarget.ts | 16 ++++++++++++++++ 2 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 src/processTargets/targets/NotebookCellTarget.ts diff --git a/src/processTargets/modifiers/scopeTypeStages/NotebookCellStage.ts b/src/processTargets/modifiers/scopeTypeStages/NotebookCellStage.ts index db74ff2efe..df895fa1a5 100644 --- a/src/processTargets/modifiers/scopeTypeStages/NotebookCellStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/NotebookCellStage.ts @@ -3,23 +3,23 @@ import { EveryScopeModifier, Target, } from "../../../typings/target.types"; -import ScopeTypeTarget from "../../targets/ScopeTypeTarget"; +import NotebookCellTarget from "../../targets/NotebookCellTarget"; import { ProcessedTargetsContext } from "../../../typings/Types"; import { ModifierStage } from "../../PipelineStages.types"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} - run(context: ProcessedTargetsContext, target: Target): ScopeTypeTarget[] { + run(context: ProcessedTargetsContext, target: Target): NotebookCellTarget[] { if (this.modifier.type === "everyScope") { throw new Error(`Every ${this.modifier.type} not yet implemented`); } return [ - new ScopeTypeTarget({ - delimiter: "\n", - ...target, - scopeType: this.modifier.scopeType, + new NotebookCellTarget({ + editor: target.editor, + isReversed: target.isReversed, + contentRange: target.contentRange, }), ]; } diff --git a/src/processTargets/targets/NotebookCellTarget.ts b/src/processTargets/targets/NotebookCellTarget.ts new file mode 100644 index 0000000000..bb2820cb64 --- /dev/null +++ b/src/processTargets/targets/NotebookCellTarget.ts @@ -0,0 +1,16 @@ +import { Range, TextEditor } from "vscode"; +import BaseTarget from "./BaseTarget"; + +interface NotebookCellTargetParameters { + editor: TextEditor; + isReversed: boolean; + contentRange: Range; +} + +export default class NotebookCellTarget extends BaseTarget { + constructor(parameters: NotebookCellTargetParameters) { + super(parameters); + this.scopeType = "notebookCell"; + this.delimiter = "\n"; + } +} From 8d9a8e81ce1fc2350300d039eb09cfdf4f77aecc Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Fri, 20 May 2022 13:15:48 +0200 Subject: [PATCH 140/314] Support delimiter based edit newline (#684) * Added delimiter based edit line * Added support for arbitrary delimiters * Added tests * Renamed is above to is before * Better handling of empty lines * Cleanup * Added default delimiters for some common scope types --- src/actions/EditNewLine.ts | 163 +++++++++++++----- .../ContainingSyntaxScopeStage.ts | 1 - src/processTargets/targets/BaseTarget.ts | 27 +-- src/processTargets/targets/DocumentTarget.ts | 5 + src/processTargets/targets/LineTarget.ts | 6 +- .../targets/NotebookCellTarget.ts | 19 ++ src/processTargets/targets/ParagraphTarget.ts | 16 +- src/processTargets/targets/ScopeTypeTarget.ts | 34 +++- .../fixtures/recorded/actions/drinkArg.yml | 27 +++ .../fixtures/recorded/actions/drinkBlock.yml | 29 ++++ .../fixtures/recorded/actions/pourArg.yml | 27 +++ .../fixtures/recorded/actions/pourBlock.yml | 29 ++++ src/typings/target.types.ts | 3 + src/util/targetUtils.ts | 10 +- 14 files changed, 327 insertions(+), 69 deletions(-) create mode 100644 src/test/suite/fixtures/recorded/actions/drinkArg.yml create mode 100644 src/test/suite/fixtures/recorded/actions/drinkBlock.yml create mode 100644 src/test/suite/fixtures/recorded/actions/pourArg.yml create mode 100644 src/test/suite/fixtures/recorded/actions/pourBlock.yml diff --git a/src/actions/EditNewLine.ts b/src/actions/EditNewLine.ts index c1f53d23e4..de025ec46c 100644 --- a/src/actions/EditNewLine.ts +++ b/src/actions/EditNewLine.ts @@ -1,66 +1,139 @@ -import { commands, Range, TextEditor } from "vscode"; +import { + commands as vscommands, + Position, + Range, + Selection, + TextEditor, +} from "vscode"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; -import { getNotebookFromCellDocument } from "../util/notebook"; +import { createThatMark, ensureSingleEditor } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; class EditNewLine implements Action { - constructor(private graph: Graph, private isAbove: boolean) { + constructor(private graph: Graph, private isBefore: boolean) { this.run = this.run.bind(this); } - private correctForParagraph(targets: Target[]) { - targets.forEach((target) => { - let { start, end } = target.contentRange; - if (target.scopeType === "paragraph") { - if (this.isAbove && target.leadingDelimiter != null) { - start = start.translate({ lineDelta: -1 }); - } else if (!this.isAbove && target.trailingDelimiter != null) { - end = end.translate({ lineDelta: 1 }); - } - target.contentRange = new Range(start, end); - } - }); - } + async run([targets]: [Target[]]): Promise { + const editor = ensureSingleEditor(targets); - private isNotebookEditor(editor: TextEditor) { - return getNotebookFromCellDocument(editor.document) != null; - } + const targetsWithContext = targets.map((target) => ({ + target, + context: target.getEditNewLineContext(this.isBefore), + })); + const commandTargets = targetsWithContext.filter( + ({ context }) => !!(context).command + ); + const delimiterTargets = targetsWithContext.filter( + ({ context }) => !!(context).delimiter + ); - private getCommand(target: Target) { - if (target.scopeType === "notebookCell") { - if (this.isNotebookEditor(target.editor)) { - return this.isAbove - ? "notebook.cell.insertCodeCellAbove" - : "notebook.cell.insertCodeCellBelow"; - } - return this.isAbove - ? "jupyter.insertCellAbove" - : "jupyter.insertCellBelow"; + if (commandTargets.length > 0 && delimiterTargets.length > 0) { + throw new Error("Can't insert edit using command and delimiter at once"); + } + + if (commandTargets.length > 0) { + const commands = commandTargets.map( + ({ context }) => (context).command + ); + return { + thatMark: await this.runCommand(targets, commands), + }; } - return this.isAbove - ? "editor.action.insertLineBefore" - : "editor.action.insertLineAfter"; + + return { + thatMark: await this.runDelimiter(targets, editor), + }; } - async run([targets]: [Target[]]): Promise { - this.correctForParagraph(targets); + async runDelimiter(targets: Target[], editor: TextEditor) { + const edits = targets.map((target) => { + const { contentRange } = target; + const context = target.getEditNewLineContext(this.isBefore); + const delimiter = (context).delimiter as string; - if (this.isAbove) { + // Delimiter is one or more new lines. Handle as lines. + if (delimiter.includes("\n")) { + const lineNumber = this.isBefore + ? contentRange.start.line + : contentRange.end.line; + const line = editor.document.lineAt(lineNumber); + const characterIndex = line.isEmptyOrWhitespace + ? contentRange.start.character + : line.firstNonWhitespaceCharacterIndex; + const padding = line.text.slice(0, characterIndex); + const positionSelection = new Position( + this.isBefore ? lineNumber : lineNumber + delimiter.length, + characterIndex + ); + return { + contentRange, + text: this.isBefore ? padding + delimiter : delimiter + padding, + insertPosition: this.isBefore ? line.range.start : line.range.end, + selection: new Selection(positionSelection, positionSelection), + thatMarkRange: this.isBefore + ? new Range( + contentRange.start.translate({ + lineDelta: delimiter.length, + }), + contentRange.end.translate({ + lineDelta: delimiter.length, + }) + ) + : contentRange, + }; + } + // Delimiter is something else. Handle as inline. + else { + const positionSelection = this.isBefore + ? contentRange.start + : contentRange.end.translate({ + characterDelta: delimiter.length, + }); + return { + contentRange, + text: delimiter, + insertPosition: this.isBefore ? contentRange.start : contentRange.end, + selection: new Selection(positionSelection, positionSelection), + thatMarkRange: this.isBefore + ? new Range( + contentRange.start.translate({ + characterDelta: delimiter.length, + }), + contentRange.end.translate({ + characterDelta: delimiter.length, + }) + ) + : contentRange, + }; + } + }); + + await editor.edit((editBuilder) => { + edits.forEach((edit) => { + editBuilder.replace(edit.insertPosition, edit.text); + }); + }); + + editor.selections = edits.map((edit) => edit.selection); + + const thatMarkRanges = edits.map((edit) => edit.thatMarkRange); + + return createThatMark(targets, thatMarkRanges); + } + + async runCommand(targets: Target[], commands: string[]) { + if (new Set(commands).size > 1) { + throw new Error("Can't run multiple different commands at once"); + } + if (this.isBefore) { await this.graph.actions.setSelectionBefore.run([targets]); } else { await this.graph.actions.setSelectionAfter.run([targets]); } - - const command = this.getCommand(targets[0]); - await commands.executeCommand(command); - - return { - thatMark: targets.map((target) => ({ - selection: target.editor.selection, - editor: target.editor, - })), - }; + await vscommands.executeCommand(commands[0]); + return createThatMark(targets); } } diff --git a/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts b/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts index 67e5c8d621..7453fc1fbf 100644 --- a/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts @@ -46,7 +46,6 @@ export default class implements ModifierStage { return scopeNodes.map( (scope) => new ScopeTypeTarget({ - delimiter: "\n", ...selectionWithEditorWithContextToTarget(scope), scopeType: this.modifier.scopeType, isReversed: target.isReversed, diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index d2b93c5492..501e527c6f 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -6,15 +6,16 @@ import { Position, RemovalRange, TargetParameters, + EditNewLineContext, } from "../../typings/target.types"; export default class BaseTarget implements Target { editor: TextEditor; isReversed: boolean; + contentRange: Range; + delimiter: string; scopeType?: ScopeType; position?: Position; - delimiter?: string; - contentRange: Range; removalRange?: Range; interiorRange?: Range; boundary?: [Range, Range]; @@ -25,10 +26,10 @@ export default class BaseTarget implements Target { constructor(parameters: TargetParameters) { this.editor = parameters.editor; this.isReversed = parameters.isReversed; + this.contentRange = parameters.contentRange; + this.delimiter = parameters.delimiter ?? " "; this.scopeType = parameters.scopeType; this.position = parameters.position; - this.delimiter = parameters.delimiter; - this.contentRange = parameters.contentRange; this.removalRange = parameters.removalRange; this.interiorRange = parameters.interiorRange; this.boundary = parameters.boundary; @@ -48,13 +49,11 @@ export default class BaseTarget implements Target { /** Possibly add delimiter for positions before/after */ maybeAddDelimiter(text: string): string { - if (this.delimiter != null) { - if (this.position === "before") { - return text + this.delimiter; - } - if (this.position === "after") { - return this.delimiter + text; - } + if (this.position === "before") { + return text + this.delimiter; + } + if (this.position === "after") { + return this.delimiter + text; } return text; } @@ -122,4 +121,10 @@ export default class BaseTarget implements Target { } return this.getRemovalContentHighlightRange(); } + + getEditNewLineContext(_isBefore: boolean): EditNewLineContext { + return { + delimiter: "\n", + }; + } } diff --git a/src/processTargets/targets/DocumentTarget.ts b/src/processTargets/targets/DocumentTarget.ts index 1faf379074..90f2eb07f4 100644 --- a/src/processTargets/targets/DocumentTarget.ts +++ b/src/processTargets/targets/DocumentTarget.ts @@ -1,4 +1,5 @@ import { Range, TextEditor } from "vscode"; +import { EditNewLineContext, ScopeType } from "../../typings/target.types"; import BaseTarget from "./BaseTarget"; interface DocumentTargetParameters { @@ -8,6 +9,10 @@ interface DocumentTargetParameters { } export default class DocumentTarget extends BaseTarget { + scopeType: ScopeType; + delimiter: string; + isLine: boolean; + constructor(parameters: DocumentTargetParameters) { super(parameters); this.scopeType = "document"; diff --git a/src/processTargets/targets/LineTarget.ts b/src/processTargets/targets/LineTarget.ts index 5bca714565..9e1d244a7f 100644 --- a/src/processTargets/targets/LineTarget.ts +++ b/src/processTargets/targets/LineTarget.ts @@ -1,5 +1,5 @@ import { Range, TextEditor } from "vscode"; -import { RemovalRange } from "../../typings/target.types"; +import { RemovalRange, ScopeType } from "../../typings/target.types"; import { parseRemovalRange } from "../../util/targetUtils"; import BaseTarget from "./BaseTarget"; @@ -12,6 +12,10 @@ interface LineTargetParameters { } export default class LineTarget extends BaseTarget { + scopeType: ScopeType; + delimiter: string; + isLine: boolean; + constructor(parameters: LineTargetParameters) { super(parameters); this.scopeType = "line"; diff --git a/src/processTargets/targets/NotebookCellTarget.ts b/src/processTargets/targets/NotebookCellTarget.ts index bb2820cb64..02ca05cd1e 100644 --- a/src/processTargets/targets/NotebookCellTarget.ts +++ b/src/processTargets/targets/NotebookCellTarget.ts @@ -1,4 +1,6 @@ import { Range, TextEditor } from "vscode"; +import { EditNewLineContext } from "../../typings/target.types"; +import { getNotebookFromCellDocument } from "../../util/notebook"; import BaseTarget from "./BaseTarget"; interface NotebookCellTargetParameters { @@ -13,4 +15,21 @@ export default class NotebookCellTarget extends BaseTarget { this.scopeType = "notebookCell"; this.delimiter = "\n"; } + + getEditNewLineContext(isBefore: boolean): EditNewLineContext { + if (this.isNotebookEditor(this.editor)) { + return { + command: isBefore + ? "notebook.cell.insertCodeCellAbove" + : "notebook.cell.insertCodeCellBelow", + }; + } + return { + command: isBefore ? "jupyter.insertCellAbove" : "jupyter.insertCellBelow", + }; + } + + private isNotebookEditor(editor: TextEditor) { + return getNotebookFromCellDocument(editor.document) != null; + } } diff --git a/src/processTargets/targets/ParagraphTarget.ts b/src/processTargets/targets/ParagraphTarget.ts index a2056204bf..ce30d6455b 100644 --- a/src/processTargets/targets/ParagraphTarget.ts +++ b/src/processTargets/targets/ParagraphTarget.ts @@ -1,5 +1,9 @@ import { Range, TextEditor } from "vscode"; -import { RemovalRange } from "../../typings/target.types"; +import { + EditNewLineContext, + RemovalRange, + ScopeType, +} from "../../typings/target.types"; import { parseRemovalRange } from "../../util/targetUtils"; import BaseTarget from "./BaseTarget"; @@ -12,6 +16,10 @@ interface ParagraphTargetParameters { } export default class ParagraphTarget extends BaseTarget { + scopeType: ScopeType; + delimiter: string; + isLine: boolean; + constructor(parameters: ParagraphTargetParameters) { super(parameters); this.scopeType = "paragraph"; @@ -67,4 +75,10 @@ export default class ParagraphTarget extends BaseTarget { ? removalRange.union(delimiterRange) : removalRange; } + + getEditNewLineContext(_isBefore: boolean): EditNewLineContext { + return { + delimiter: this.delimiter, + }; + } } diff --git a/src/processTargets/targets/ScopeTypeTarget.ts b/src/processTargets/targets/ScopeTypeTarget.ts index a2ca12d127..a5ce853637 100644 --- a/src/processTargets/targets/ScopeTypeTarget.ts +++ b/src/processTargets/targets/ScopeTypeTarget.ts @@ -1,9 +1,12 @@ -import { ScopeType, TargetParameters } from "../../typings/target.types"; +import { + EditNewLineContext, + ScopeType, + TargetParameters, +} from "../../typings/target.types"; import BaseTarget from "./BaseTarget"; export interface ScopeTypeTargetParameters extends TargetParameters { scopeType: ScopeType; - delimiter: string; } export default class ScopeTypeTarget extends BaseTarget { @@ -13,6 +16,31 @@ export default class ScopeTypeTarget extends BaseTarget { constructor(parameters: ScopeTypeTargetParameters) { super(parameters); this.scopeType = parameters.scopeType; - this.delimiter = parameters.delimiter; + this.delimiter = + parameters.delimiter ?? this.getDelimiter(parameters.scopeType); + } + + private getDelimiter(scopeType: ScopeType): string { + switch (scopeType) { + case "namedFunction": + case "anonymousFunction": + case "statement": + case "ifStatement": + return "\n"; + case "class": + return "\n\n"; + default: + return " "; + } + } + + getEditNewLineContext(isBefore: boolean): EditNewLineContext { + // This is the default and should implement the default version whatever that is. + if (this.delimiter === "\n") { + return super.getEditNewLineContext(isBefore); + } + return { + delimiter: this.delimiter, + }; } } diff --git a/src/test/suite/fixtures/recorded/actions/drinkArg.yml b/src/test/suite/fixtures/recorded/actions/drinkArg.yml new file mode 100644 index 0000000000..a8d72e49a1 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/drinkArg.yml @@ -0,0 +1,27 @@ +languageId: typescript +command: + spokenForm: drink arg + version: 2 + action: editNewLineBefore + targets: + - type: primitive + modifiers: + - {type: containingScope, scopeType: argumentOrParameter} + usePrePhraseSnapshot: true +initialState: + documentContents: | + function helloWorld(foo: string, bar: number, baz: string) {} + selections: + - anchor: {line: 0, character: 40} + active: {line: 0, character: 40} + marks: {} +finalState: + documentContents: | + function helloWorld(foo: string, , bar: number, baz: string) {} + selections: + - anchor: {line: 0, character: 33} + active: {line: 0, character: 33} + thatMark: + - anchor: {line: 0, character: 35} + active: {line: 0, character: 46} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: containingScope, scopeType: argumentOrParameter}]}] diff --git a/src/test/suite/fixtures/recorded/actions/drinkBlock.yml b/src/test/suite/fixtures/recorded/actions/drinkBlock.yml new file mode 100644 index 0000000000..bb24a95e80 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/drinkBlock.yml @@ -0,0 +1,29 @@ +languageId: typescript +command: + spokenForm: drink block + version: 2 + action: editNewLineBefore + targets: + - type: primitive + modifiers: + - {type: containingScope, scopeType: paragraph} + usePrePhraseSnapshot: true +initialState: + documentContents: | + function helloWorld(foo: string, bar: number, baz: string) {} + selections: + - anchor: {line: 0, character: 40} + active: {line: 0, character: 40} + marks: {} +finalState: + documentContents: | + + + function helloWorld(foo: string, bar: number, baz: string) {} + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 61} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: containingScope, scopeType: paragraph}]}] diff --git a/src/test/suite/fixtures/recorded/actions/pourArg.yml b/src/test/suite/fixtures/recorded/actions/pourArg.yml new file mode 100644 index 0000000000..bd0bfa6792 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/pourArg.yml @@ -0,0 +1,27 @@ +languageId: typescript +command: + spokenForm: pour arg + version: 2 + action: editNewLineAfter + targets: + - type: primitive + modifiers: + - {type: containingScope, scopeType: argumentOrParameter} + usePrePhraseSnapshot: true +initialState: + documentContents: | + function helloWorld(foo: string, bar: number, baz: string) {} + selections: + - anchor: {line: 0, character: 40} + active: {line: 0, character: 40} + marks: {} +finalState: + documentContents: | + function helloWorld(foo: string, bar: number, , baz: string) {} + selections: + - anchor: {line: 0, character: 46} + active: {line: 0, character: 46} + thatMark: + - anchor: {line: 0, character: 33} + active: {line: 0, character: 44} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: containingScope, scopeType: argumentOrParameter}]}] diff --git a/src/test/suite/fixtures/recorded/actions/pourBlock.yml b/src/test/suite/fixtures/recorded/actions/pourBlock.yml new file mode 100644 index 0000000000..05f2dc3c33 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/pourBlock.yml @@ -0,0 +1,29 @@ +languageId: typescript +command: + spokenForm: pour block + version: 2 + action: editNewLineAfter + targets: + - type: primitive + modifiers: + - {type: containingScope, scopeType: paragraph} + usePrePhraseSnapshot: true +initialState: + documentContents: | + function helloWorld(foo: string, bar: number, baz: string) {} + selections: + - anchor: {line: 0, character: 40} + active: {line: 0, character: 40} + marks: {} +finalState: + documentContents: |+ + function helloWorld(foo: string, bar: number, baz: string) {} + + + selections: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} + thatMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 61} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: containingScope, scopeType: paragraph}]}] diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index e1a7e2a9a2..ae1bb4f283 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -245,6 +245,8 @@ export interface RemovalRange { exclude?: boolean; } +export type EditNewLineContext = { command: string } | { delimiter: string }; + export interface TargetParameters { /** The text editor used for all ranges */ editor: TextEditor; @@ -299,4 +301,5 @@ export interface Target extends TargetParameters { maybeAddDelimiter(text: string): string; getRemovalRange(): Range; getRemovalHighlightRange(): Range | undefined; + getEditNewLineContext(isBefore: boolean): EditNewLineContext; } diff --git a/src/util/targetUtils.ts b/src/util/targetUtils.ts index fb47a1403a..71aa9ec4b7 100644 --- a/src/util/targetUtils.ts +++ b/src/util/targetUtils.ts @@ -1,11 +1,7 @@ import { zip } from "lodash"; import { Range, Selection, TextEditor } from "vscode"; import { getTokenDelimiters } from "../processTargets/modifiers/scopeTypeStages/TokenStage"; -import { - RemovalRange, - Target, - TargetParameters, -} from "../typings/target.types"; +import { RemovalRange, Target } from "../typings/target.types"; import { SelectionContext, SelectionWithEditor, @@ -131,7 +127,7 @@ export function parseRemovalRange( export function selectionWithEditorWithContextToTarget( selection: SelectionWithEditorWithContext -): TargetParameters { +) { // TODO Only use giving context in the future when all the containing scopes have proper delimiters. // For now fall back on token context const { context } = selection; @@ -170,7 +166,7 @@ export function selectionWithEditorWithContextToTarget( interiorRange, removalRange, boundary, - delimiter: tokenContext?.delimiter ?? containingListDelimiter ?? "\n", + delimiter: containingListDelimiter, leadingDelimiter, trailingDelimiter, }; From a48f9ac9cfb55e41f5a212b32d76adfbc8042938 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Sat, 21 May 2022 16:33:36 +0100 Subject: [PATCH 141/314] Run yarn --- third-party-licenses.csv | 12 ++++++++++-- yarn.lock | 37 ++++++++++++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/third-party-licenses.csv b/third-party-licenses.csv index 07edceab1e..2a445576df 100644 --- a/third-party-licenses.csv +++ b/third-party-licenses.csv @@ -1,4 +1,12 @@ "module name","licenses","repository","licenseUrl","parents" -"@types/lodash@4.14.168","MIT","https://github.com/DefinitelyTyped/DefinitelyTyped","https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE","cursorless" +"@docusaurus/core@2.0.0-beta.17","MIT","https://github.com/facebook/docusaurus","https://github.com/facebook/docusaurus/raw/master/LICENSE","website" +"@docusaurus/preset-classic@2.0.0-beta.17","MIT","https://github.com/facebook/docusaurus","https://github.com/facebook/docusaurus/raw/master/LICENSE","website" +"@mdx-js/react@1.6.22","MIT","https://github.com/mdx-js/mdx","https://github.com/mdx-js/mdx/raw/master/license","website" +"@types/lodash@4.14.181","MIT","https://github.com/DefinitelyTyped/DefinitelyTyped","https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE","cursorless" +"clsx@1.1.1","MIT","https://github.com/lukeed/clsx","https://github.com/lukeed/clsx/raw/master/license","website" "immutability-helper@3.1.1","MIT","https://github.com/kolodny/immutability-helper","https://github.com/kolodny/immutability-helper/raw/master/LICENSE","cursorless" -"lodash@4.17.21","MIT","https://github.com/lodash/lodash","https://github.com/lodash/lodash/raw/master/LICENSE","cursorless" +"mdast-util-find-and-replace@2.1.0","MIT","https://github.com/syntax-tree/mdast-util-find-and-replace","https://github.com/syntax-tree/mdast-util-find-and-replace/raw/master/license","website" +"prism-react-renderer@1.3.1","MIT","https://github.com/FormidableLabs/prism-react-renderer","https://github.com/FormidableLabs/prism-react-renderer/raw/master/LICENSE","website" +"react-dom@17.0.2","MIT","https://github.com/facebook/react","https://github.com/facebook/react/raw/master/LICENSE","website" +"react@17.0.2","MIT","https://github.com/facebook/react","https://github.com/facebook/react/raw/master/LICENSE","website" +"unist-util-visit@4.1.0","MIT","https://github.com/syntax-tree/unist-util-visit","https://github.com/syntax-tree/unist-util-visit/raw/master/license","website" diff --git a/yarn.lock b/yarn.lock index ad493155b4..5c81a2053a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -110,6 +110,11 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== + "@types/lodash@^4.14.168": version "4.14.181" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.181.tgz#d1d3740c379fda17ab175165ba04e2d03389385d" @@ -1093,6 +1098,13 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== + dependencies: + minimist "^1.2.0" + just-extend@^4.0.2: version "4.2.1" resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.2.1.tgz#ef5e589afb61e5d66b24eca749409a8939a8c744" @@ -1184,7 +1196,7 @@ minimatch@3.0.4: dependencies: brace-expansion "^1.1.7" -minimist@^1.2.6: +minimist@^1.2.0, minimist@^1.2.6: version "1.2.6" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== @@ -1634,6 +1646,11 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + strip-json-comments@3.1.1, strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" @@ -1692,6 +1709,24 @@ treeify@^1.0.1, treeify@^1.1.0: resolved "https://registry.yarnpkg.com/treeify/-/treeify-1.1.0.tgz#4e31c6a463accd0943879f30667c4fdaff411bb8" integrity sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A== +ts-unused-exports@8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/ts-unused-exports/-/ts-unused-exports-8.0.0.tgz#6dd15ff26286e0b7e5663cda3b98c77ea6f3ffe7" + integrity sha512-gylHFyJqC80PSb4zy35KTckykEW1vmKjnOHjBeX9iKBo4b/SzqQIcXXbYSuif4YMgNm6ewFF62VM1C9z0bGZPw== + dependencies: + chalk "^4.0.0" + tsconfig-paths "^3.9.0" + +tsconfig-paths@^3.9.0: + version "3.14.1" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a" + integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.1" + minimist "^1.2.6" + strip-bom "^3.0.0" + tslib@^1.8.1: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" From 0de07989dc408aedba56995d20c3043fa034f81a Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Sat, 21 May 2022 20:02:14 +0100 Subject: [PATCH 142/314] Attempt to fix raw delimiter --- src/processTargets/targets/BaseTarget.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index 501e527c6f..8841e8baf0 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -13,7 +13,7 @@ export default class BaseTarget implements Target { editor: TextEditor; isReversed: boolean; contentRange: Range; - delimiter: string; + delimiter?: string; scopeType?: ScopeType; position?: Position; removalRange?: Range; @@ -27,7 +27,7 @@ export default class BaseTarget implements Target { this.editor = parameters.editor; this.isReversed = parameters.isReversed; this.contentRange = parameters.contentRange; - this.delimiter = parameters.delimiter ?? " "; + this.delimiter = parameters.delimiter; this.scopeType = parameters.scopeType; this.position = parameters.position; this.removalRange = parameters.removalRange; From a035390f78cba4b9a88b51722d347277293dda9c Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Sat, 21 May 2022 20:40:55 +0100 Subject: [PATCH 143/314] Fixed delimiter --- src/processTargets/targets/BaseTarget.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index 8841e8baf0..dd5c213149 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -49,13 +49,13 @@ export default class BaseTarget implements Target { /** Possibly add delimiter for positions before/after */ maybeAddDelimiter(text: string): string { - if (this.position === "before") { - return text + this.delimiter; - } - if (this.position === "after") { - return this.delimiter + text; - } - return text; + return this.delimiter == null + ? text + : this.position === "before" + ? text + this.delimiter + : this.position === "after" + ? this.delimiter + text + : text; } protected getRemovalContentRange(): Range { From 84f4f4bcac7bcc81a5a1c9fe9e23a170f71eb1ae Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Sat, 21 May 2022 21:48:49 +0100 Subject: [PATCH 144/314] Revert "Attempt to fix raw delimiter" This reverts commit 0de07989dc408aedba56995d20c3043fa034f81a. --- src/processTargets/targets/BaseTarget.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index dd5c213149..4aee76211a 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -13,7 +13,7 @@ export default class BaseTarget implements Target { editor: TextEditor; isReversed: boolean; contentRange: Range; - delimiter?: string; + delimiter: string; scopeType?: ScopeType; position?: Position; removalRange?: Range; @@ -27,7 +27,7 @@ export default class BaseTarget implements Target { this.editor = parameters.editor; this.isReversed = parameters.isReversed; this.contentRange = parameters.contentRange; - this.delimiter = parameters.delimiter; + this.delimiter = parameters.delimiter ?? " "; this.scopeType = parameters.scopeType; this.position = parameters.position; this.removalRange = parameters.removalRange; From c8aee08178756cdcac2b12a8034f3f2e3bc67b3b Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Sat, 21 May 2022 21:52:33 +0100 Subject: [PATCH 145/314] Revert "Fixed delimiter" This reverts commit a035390f78cba4b9a88b51722d347277293dda9c. --- src/processTargets/targets/BaseTarget.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index 4aee76211a..501e527c6f 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -49,13 +49,13 @@ export default class BaseTarget implements Target { /** Possibly add delimiter for positions before/after */ maybeAddDelimiter(text: string): string { - return this.delimiter == null - ? text - : this.position === "before" - ? text + this.delimiter - : this.position === "after" - ? this.delimiter + text - : text; + if (this.position === "before") { + return text + this.delimiter; + } + if (this.position === "after") { + return this.delimiter + text; + } + return text; } protected getRemovalContentRange(): Range { From 77126f1804aab4a4f7696f0febcbb7b6c2ccc0b0 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 22 May 2022 16:19:48 +0200 Subject: [PATCH 146/314] Use low dash unique with --- src/processTargets/processTargets.ts | 5 ++--- src/util/filterDuplicates.ts | 8 -------- 2 files changed, 2 insertions(+), 11 deletions(-) delete mode 100644 src/util/filterDuplicates.ts diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index b2dbe1e137..5a2ce86b99 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -1,4 +1,4 @@ -import { zip } from "lodash"; +import { isEqual, uniqWith, zip } from "lodash"; import { Position, Range } from "vscode"; import { PrimitiveTargetDescriptor, @@ -7,7 +7,6 @@ import { TargetDescriptor, } from "../typings/target.types"; import { ProcessedTargetsContext } from "../typings/Types"; -import { filterDuplicates } from "../util/filterDuplicates"; import { ensureSingleEditor } from "../util/targetUtils"; import getMarkStage from "./getMarkStage"; import getModifierStage from "./getModifierStage"; @@ -32,7 +31,7 @@ export default function ( targets: TargetDescriptor[] ): Target[][] { return targets.map((target) => - filterDuplicates(processTarget(context, target)) + uniqWith(processTarget(context, target), isEqual) ); } diff --git a/src/util/filterDuplicates.ts b/src/util/filterDuplicates.ts deleted file mode 100644 index d04c222d59..0000000000 --- a/src/util/filterDuplicates.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { isEqual } from "lodash"; - -export function filterDuplicates(elements: T[]) { - return elements.filter( - (element, index, elements) => - elements.findIndex((e) => isEqual(e, element)) === index - ); -} From b1044ffcff2906ed6e8739933da84dd367b1537e Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 22 May 2022 18:28:27 +0200 Subject: [PATCH 147/314] Made base target abstract --- src/actions/CutCopyPaste.ts | 6 +-- src/processTargets/getModifierStage.ts | 5 +- src/processTargets/marks/CursorStage.ts | 4 +- .../marks/DecoratedSymbolStage.ts | 5 +- src/processTargets/marks/SourceStage.ts | 4 +- src/processTargets/marks/ThatStage.ts | 4 +- src/processTargets/modifiers/HeadTailStage.ts | 4 +- src/processTargets/modifiers/InteriorStage.ts | 6 +-- .../modifiers/RawSelectionStage.ts | 4 +- src/processTargets/modifiers/SubPieceStage.ts | 5 +- .../modifiers/scopeTypeStages/TokenStage.ts | 14 +++--- src/processTargets/processTargets.ts | 49 +++++++++---------- src/processTargets/targets/BaseTarget.ts | 20 ++++---- src/processTargets/targets/DocumentTarget.ts | 3 +- src/processTargets/targets/LineTarget.ts | 1 - src/processTargets/targets/ParagraphTarget.ts | 1 - .../targets/RawSelectionTarget.ts | 15 ++++++ .../targets/SurroundingPairTarget.ts | 1 + src/processTargets/targets/TokenTarget.ts | 19 +++++++ src/processTargets/targets/WeakTarget.ts | 25 ++++++++++ src/typings/target.types.ts | 3 +- src/util/unifyRanges.ts | 17 +------ 22 files changed, 129 insertions(+), 86 deletions(-) create mode 100644 src/processTargets/targets/RawSelectionTarget.ts create mode 100644 src/processTargets/targets/SurroundingPairTarget.ts create mode 100644 src/processTargets/targets/TokenTarget.ts create mode 100644 src/processTargets/targets/WeakTarget.ts diff --git a/src/actions/CutCopyPaste.ts b/src/actions/CutCopyPaste.ts index 59c7182967..e24fb88099 100644 --- a/src/actions/CutCopyPaste.ts +++ b/src/actions/CutCopyPaste.ts @@ -1,4 +1,4 @@ -import BaseTarget from "../processTargets/targets/BaseTarget"; +import RawSelectionTarget from "../processTargets/targets/RawSelectionTarget"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; import displayPendingEditDecorations from "../util/editDisplayUtils"; @@ -19,9 +19,9 @@ export class Cut implements Action { } return getOutsideOverflow(target.editor, target.contentRange, range).map( (overflow): Target => - new BaseTarget({ + // TODO Instead of creating a new target display decorations by range + new RawSelectionTarget({ editor: target.editor, - scopeType: target.scopeType, contentRange: overflow, isReversed: false, }) diff --git a/src/processTargets/getModifierStage.ts b/src/processTargets/getModifierStage.ts index de8822c0e7..25db9faea8 100644 --- a/src/processTargets/getModifierStage.ts +++ b/src/processTargets/getModifierStage.ts @@ -38,7 +38,7 @@ export default (modifier: Modifier): ModifierStage => { return new SubPieceStage(modifier); case "surroundingPair": return new SurroundingPairStage(modifier); - case "interiorOnly": + case "ContainingScopeModifier(interiorOnly)": return new InteriorOnlyStage(modifier); case "excludeInterior": return new ExcludeInteriorStage(modifier); @@ -66,6 +66,9 @@ const getContainingScopeStage = ( return new NonWhitespaceSequenceStage(modifier); case "url": return new UrlStage(modifier); + case "word": + case "character": + throw new Error(`Unsupported scope type ${modifier.scopeType}`); default: // Default to containing syntax scope using tree sitter return new ContainingSyntaxScopeStage(modifier); diff --git a/src/processTargets/marks/CursorStage.ts b/src/processTargets/marks/CursorStage.ts index 5f3512382e..a782595070 100644 --- a/src/processTargets/marks/CursorStage.ts +++ b/src/processTargets/marks/CursorStage.ts @@ -3,14 +3,14 @@ import { ProcessedTargetsContext } from "../../typings/Types"; import { isReversed } from "../../util/selectionUtils"; import { getTokenDelimiters } from "../modifiers/scopeTypeStages/TokenStage"; import { MarkStage } from "../PipelineStages.types"; -import BaseTarget from "../targets/BaseTarget"; +import WeakTarget from "../targets/WeakTarget"; export default class implements MarkStage { constructor(private modifier: CursorMark) {} run(context: ProcessedTargetsContext): Target[] { return context.currentSelections.map((selection) => { - return new BaseTarget({ + return new WeakTarget({ ...getTokenDelimiters(selection.editor, selection.selection), editor: selection.editor, isReversed: isReversed(selection.selection), diff --git a/src/processTargets/marks/DecoratedSymbolStage.ts b/src/processTargets/marks/DecoratedSymbolStage.ts index 108480ba55..5e95167735 100644 --- a/src/processTargets/marks/DecoratedSymbolStage.ts +++ b/src/processTargets/marks/DecoratedSymbolStage.ts @@ -1,8 +1,8 @@ import { DecoratedSymbolMark, Target } from "../../typings/target.types"; -import BaseTarget from "../targets/BaseTarget"; import { ProcessedTargetsContext } from "../../typings/Types"; import { getTokenDelimiters } from "../modifiers/scopeTypeStages/TokenStage"; import { MarkStage } from "../PipelineStages.types"; +import WeakTarget from "../targets/WeakTarget"; export default class implements MarkStage { constructor(private modifier: DecoratedSymbolMark) {} @@ -18,9 +18,8 @@ export default class implements MarkStage { ); } return [ - new BaseTarget({ + new WeakTarget({ ...getTokenDelimiters(token.editor, token.range), - scopeType: "token", editor: token.editor, contentRange: token.range, isReversed: false, diff --git a/src/processTargets/marks/SourceStage.ts b/src/processTargets/marks/SourceStage.ts index 6c5c8573ce..11585875c2 100644 --- a/src/processTargets/marks/SourceStage.ts +++ b/src/processTargets/marks/SourceStage.ts @@ -1,16 +1,16 @@ import { SourceMark, Target } from "../../typings/target.types"; -import BaseTarget from "../targets/BaseTarget"; import { ProcessedTargetsContext } from "../../typings/Types"; import { isReversed } from "../../util/selectionUtils"; import { getTokenDelimiters } from "../modifiers/scopeTypeStages/TokenStage"; import { MarkStage } from "../PipelineStages.types"; +import WeakTarget from "../targets/WeakTarget"; export default class implements MarkStage { constructor(private modifier: SourceMark) {} run(context: ProcessedTargetsContext): Target[] { return context.sourceMark.map((selection) => { - return new BaseTarget({ + return new WeakTarget({ ...getTokenDelimiters(selection.editor, selection.selection), editor: selection.editor, isReversed: isReversed(selection.selection), diff --git a/src/processTargets/marks/ThatStage.ts b/src/processTargets/marks/ThatStage.ts index d84b8e872d..2f193bfd31 100644 --- a/src/processTargets/marks/ThatStage.ts +++ b/src/processTargets/marks/ThatStage.ts @@ -1,16 +1,16 @@ import { Target, ThatMark } from "../../typings/target.types"; -import BaseTarget from "../targets/BaseTarget"; import { ProcessedTargetsContext } from "../../typings/Types"; import { isReversed } from "../../util/selectionUtils"; import { getTokenDelimiters } from "../modifiers/scopeTypeStages/TokenStage"; import { MarkStage } from "../PipelineStages.types"; +import WeakTarget from "../targets/WeakTarget"; export default class implements MarkStage { constructor(private modifier: ThatMark) {} run(context: ProcessedTargetsContext): Target[] { return context.thatMark.map((selection) => { - return new BaseTarget({ + return new WeakTarget({ ...getTokenDelimiters(selection.editor, selection.selection), editor: selection.editor, isReversed: isReversed(selection.selection), diff --git a/src/processTargets/modifiers/HeadTailStage.ts b/src/processTargets/modifiers/HeadTailStage.ts index 2eca24e4d8..fcd4eaa1d7 100644 --- a/src/processTargets/modifiers/HeadTailStage.ts +++ b/src/processTargets/modifiers/HeadTailStage.ts @@ -1,8 +1,8 @@ import { Position, Range, TextEditor } from "vscode"; import { HeadModifier, TailModifier, Target } from "../../typings/target.types"; -import BaseTarget from "../targets/BaseTarget"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; +import TokenTarget from "../targets/TokenTarget"; abstract class HeadTailStage implements ModifierStage { abstract update(editor: TextEditor, range: Range): Range; @@ -12,7 +12,7 @@ abstract class HeadTailStage implements ModifierStage { run(context: ProcessedTargetsContext, target: Target): Target[] { const contentRange = this.update(target.editor, target.contentRange); return [ - new BaseTarget({ + new TokenTarget({ editor: target.editor, isReversed: this.isReversed, contentRange, diff --git a/src/processTargets/modifiers/InteriorStage.ts b/src/processTargets/modifiers/InteriorStage.ts index 68b478002c..256b060402 100644 --- a/src/processTargets/modifiers/InteriorStage.ts +++ b/src/processTargets/modifiers/InteriorStage.ts @@ -3,9 +3,9 @@ import { InteriorOnlyModifier, Target, } from "../../typings/target.types"; -import BaseTarget from "../targets/BaseTarget"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; +import WeakTarget from "../targets/WeakTarget"; import { processedSurroundingPairTarget } from "./SurroundingPairStage"; abstract class InteriorStage implements ModifierStage { @@ -44,7 +44,7 @@ export class InteriorOnlyStage extends InteriorStage { } const contentRange = target.interiorRange; return [ - new BaseTarget({ + new WeakTarget({ editor: target.editor, isReversed: target.isReversed, contentRange, @@ -68,7 +68,7 @@ export class ExcludeInteriorStage extends InteriorStage { } return target.boundary.map( (contentRange) => - new BaseTarget({ + new WeakTarget({ editor: target.editor, isReversed: target.isReversed, contentRange, diff --git a/src/processTargets/modifiers/RawSelectionStage.ts b/src/processTargets/modifiers/RawSelectionStage.ts index 3f0c48e408..c95a0fdded 100644 --- a/src/processTargets/modifiers/RawSelectionStage.ts +++ b/src/processTargets/modifiers/RawSelectionStage.ts @@ -1,14 +1,14 @@ import { RawSelectionModifier, Target } from "../../typings/target.types"; -import BaseTarget from "../targets/BaseTarget"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; +import RawSelectionTarget from "../targets/RawSelectionTarget"; export default class implements ModifierStage { constructor(private modifier: RawSelectionModifier) {} run(context: ProcessedTargetsContext, target: Target): Target[] { return [ - new BaseTarget({ + new RawSelectionTarget({ editor: target.editor, contentRange: target.contentRange, isReversed: target.isReversed, diff --git a/src/processTargets/modifiers/SubPieceStage.ts b/src/processTargets/modifiers/SubPieceStage.ts index 885387a938..a307cf84a0 100644 --- a/src/processTargets/modifiers/SubPieceStage.ts +++ b/src/processTargets/modifiers/SubPieceStage.ts @@ -2,9 +2,9 @@ import { range } from "lodash"; import { Range } from "vscode"; import { SUBWORD_MATCHER } from "../../core/constants"; import { SubTokenModifier, Target } from "../../typings/target.types"; -import BaseTarget from "../targets/BaseTarget"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; +import ScopeTypeTarget from "../targets/ScopeTypeTarget"; import { getTokenRangeForSelection } from "./scopeTypeStages/TokenStage"; export default class implements ModifierStage { @@ -101,10 +101,11 @@ export default class implements ModifierStage { : undefined; return [ - new BaseTarget({ + new ScopeTypeTarget({ editor: target.editor, isReversed, contentRange, + scopeType: this.modifier.pieceType, delimiter: containingListDelimiter, leadingDelimiter: leadingDelimiterRange != null diff --git a/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts index 8fefe36b8a..516bef261e 100644 --- a/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts @@ -4,15 +4,15 @@ import { EveryScopeModifier, Target, } from "../../../typings/target.types"; -import ScopeTypeTarget from "../../targets/ScopeTypeTarget"; import { ProcessedTargetsContext } from "../../../typings/Types"; import { getTokensInRange, PartialToken } from "../../../util/getTokensInRange"; import { ModifierStage } from "../../PipelineStages.types"; +import TokenTarget from "../../targets/TokenTarget"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} - run(context: ProcessedTargetsContext, target: Target): ScopeTypeTarget[] { + run(context: ProcessedTargetsContext, target: Target): TokenTarget[] { if (this.modifier.type === "everyScope") { return this.getEveryTarget(context, target); } @@ -22,7 +22,7 @@ export default class implements ModifierStage { getEveryTarget( context: ProcessedTargetsContext, target: Target - ): ScopeTypeTarget[] { + ): TokenTarget[] { const { contentRange, editor } = target; const { isEmpty } = contentRange; const start = isEmpty @@ -44,15 +44,13 @@ export default class implements ModifierStage { return targets; } - getSingleTarget(target: Target): ScopeTypeTarget { + getSingleTarget(target: Target): TokenTarget { return this.getTargetFromRange(target, target.contentRange); } - getTargetFromRange(target: Target, range: Range): ScopeTypeTarget { + getTargetFromRange(target: Target, range: Range): TokenTarget { const contentRange = getTokenRangeForSelection(target.editor, range); - return new ScopeTypeTarget({ - ...getTokenDelimiters(target.editor, contentRange), - scopeType: this.modifier.scopeType, + return new TokenTarget({ editor: target.editor, isReversed: target.isReversed, contentRange, diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index 5a2ce86b99..fc5ca262ab 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -11,6 +11,7 @@ import { ensureSingleEditor } from "../util/targetUtils"; import getMarkStage from "./getMarkStage"; import getModifierStage from "./getModifierStage"; import BaseTarget from "./targets/BaseTarget"; +import WeakTarget from "./targets/WeakTarget"; /** * Converts the abstract target descriptions provided by the user to a concrete @@ -72,12 +73,14 @@ function processRangeTarget( switch (targetDesc.rangeType) { case "continuous": - return processContinuousRangeTarget( - anchorTarget, - activeTarget, - targetDesc.excludeAnchor, - targetDesc.excludeActive - ); + return [ + processContinuousRangeTarget( + anchorTarget, + activeTarget, + targetDesc.excludeAnchor, + targetDesc.excludeActive + ), + ]; case "vertical": return processVerticalRangeTarget( anchorTarget, @@ -95,7 +98,7 @@ function processContinuousRangeTarget( activeTarget: Target, excludeAnchor: boolean, excludeActive: boolean -): Target[] { +): Target { const { document } = ensureSingleEditor([anchorTarget, activeTarget]); const isForward = calcIsForward(anchorTarget, activeTarget); const startTarget = isForward ? anchorTarget : activeTarget; @@ -173,30 +176,23 @@ function processContinuousRangeTarget( const constructor = startConstructor === endConstructor ? startConstructor : BaseTarget; - return [ - new constructor({ - editor: activeTarget.editor, - isReversed: !isForward, - delimiter: anchorTarget.delimiter, - contentRange, - removalRange, - scopeType, - leadingDelimiter, - trailingDelimiter, - }), - ]; + return new constructor({ + editor: activeTarget.editor, + isReversed: !isForward, + delimiter: anchorTarget.delimiter, + contentRange, + removalRange, + scopeType, + leadingDelimiter, + trailingDelimiter, + }); } export function targetsToContinuousTarget( anchorTarget: Target, activeTarget: Target ): Target { - return processContinuousRangeTarget( - anchorTarget, - activeTarget, - false, - false - )[0]; + return processContinuousRangeTarget(anchorTarget, activeTarget, false, false); } function processVerticalRangeTarget( @@ -226,10 +222,9 @@ function processVerticalRangeTarget( anchorTarget.contentRange.end.character ); results.push( - new BaseTarget({ + new WeakTarget({ editor: anchorTarget.editor, isReversed: anchorTarget.isReversed, - delimiter: anchorTarget.delimiter, position: anchorTarget.position, contentRange, }) diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index 501e527c6f..2c376b185b 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -9,11 +9,11 @@ import { EditNewLineContext, } from "../../typings/target.types"; -export default class BaseTarget implements Target { +export default abstract class BaseTarget implements Target { editor: TextEditor; isReversed: boolean; contentRange: Range; - delimiter: string; + delimiter?: string; scopeType?: ScopeType; position?: Position; removalRange?: Range; @@ -21,13 +21,13 @@ export default class BaseTarget implements Target { boundary?: [Range, Range]; leadingDelimiter?: RemovalRange; trailingDelimiter?: RemovalRange; - isLine?: boolean; + isLine: boolean = false; constructor(parameters: TargetParameters) { this.editor = parameters.editor; this.isReversed = parameters.isReversed; this.contentRange = parameters.contentRange; - this.delimiter = parameters.delimiter ?? " "; + this.delimiter = parameters.delimiter; this.scopeType = parameters.scopeType; this.position = parameters.position; this.removalRange = parameters.removalRange; @@ -49,11 +49,13 @@ export default class BaseTarget implements Target { /** Possibly add delimiter for positions before/after */ maybeAddDelimiter(text: string): string { - if (this.position === "before") { - return text + this.delimiter; - } - if (this.position === "after") { - return this.delimiter + text; + if (this.delimiter != null) { + if (this.position === "before") { + return text + this.delimiter; + } + if (this.position === "after") { + return this.delimiter + text; + } } return text; } diff --git a/src/processTargets/targets/DocumentTarget.ts b/src/processTargets/targets/DocumentTarget.ts index 90f2eb07f4..eab8eb30ad 100644 --- a/src/processTargets/targets/DocumentTarget.ts +++ b/src/processTargets/targets/DocumentTarget.ts @@ -1,5 +1,5 @@ import { Range, TextEditor } from "vscode"; -import { EditNewLineContext, ScopeType } from "../../typings/target.types"; +import { ScopeType } from "../../typings/target.types"; import BaseTarget from "./BaseTarget"; interface DocumentTargetParameters { @@ -11,7 +11,6 @@ interface DocumentTargetParameters { export default class DocumentTarget extends BaseTarget { scopeType: ScopeType; delimiter: string; - isLine: boolean; constructor(parameters: DocumentTargetParameters) { super(parameters); diff --git a/src/processTargets/targets/LineTarget.ts b/src/processTargets/targets/LineTarget.ts index 9e1d244a7f..8a9df9b75c 100644 --- a/src/processTargets/targets/LineTarget.ts +++ b/src/processTargets/targets/LineTarget.ts @@ -14,7 +14,6 @@ interface LineTargetParameters { export default class LineTarget extends BaseTarget { scopeType: ScopeType; delimiter: string; - isLine: boolean; constructor(parameters: LineTargetParameters) { super(parameters); diff --git a/src/processTargets/targets/ParagraphTarget.ts b/src/processTargets/targets/ParagraphTarget.ts index ce30d6455b..a67696fe7e 100644 --- a/src/processTargets/targets/ParagraphTarget.ts +++ b/src/processTargets/targets/ParagraphTarget.ts @@ -18,7 +18,6 @@ interface ParagraphTargetParameters { export default class ParagraphTarget extends BaseTarget { scopeType: ScopeType; delimiter: string; - isLine: boolean; constructor(parameters: ParagraphTargetParameters) { super(parameters); diff --git a/src/processTargets/targets/RawSelectionTarget.ts b/src/processTargets/targets/RawSelectionTarget.ts new file mode 100644 index 0000000000..afaa9de23d --- /dev/null +++ b/src/processTargets/targets/RawSelectionTarget.ts @@ -0,0 +1,15 @@ +import { Range, TextEditor } from "vscode"; +import BaseTarget from "./BaseTarget"; + +interface RawSelectionTargetParameters { + editor: TextEditor; + isReversed: boolean; + contentRange: Range; +} + +export default class RawSelectionTarget extends BaseTarget { + constructor(parameters: RawSelectionTargetParameters) { + super(parameters); + this.delimiter = undefined; + } +} diff --git a/src/processTargets/targets/SurroundingPairTarget.ts b/src/processTargets/targets/SurroundingPairTarget.ts new file mode 100644 index 0000000000..838f3ccd2a --- /dev/null +++ b/src/processTargets/targets/SurroundingPairTarget.ts @@ -0,0 +1 @@ +export default class SurroundingPairTarget {} diff --git a/src/processTargets/targets/TokenTarget.ts b/src/processTargets/targets/TokenTarget.ts new file mode 100644 index 0000000000..914ee71e76 --- /dev/null +++ b/src/processTargets/targets/TokenTarget.ts @@ -0,0 +1,19 @@ +import { Range, TextEditor } from "vscode"; +import { getTokenDelimiters } from "../modifiers/scopeTypeStages/TokenStage"; +import BaseTarget from "./BaseTarget"; + +interface TokenTargetParameters { + editor: TextEditor; + isReversed: boolean; + contentRange: Range; +} + +export default class TokenTarget extends BaseTarget { + constructor(parameters: TokenTargetParameters) { + super({ + ...parameters, + ...getTokenDelimiters(parameters.editor, parameters.contentRange), + scopeType: "token", + }); + } +} diff --git a/src/processTargets/targets/WeakTarget.ts b/src/processTargets/targets/WeakTarget.ts new file mode 100644 index 0000000000..b5725d63e9 --- /dev/null +++ b/src/processTargets/targets/WeakTarget.ts @@ -0,0 +1,25 @@ +import { Range, TextEditor } from "vscode"; +import { Position } from "../../typings/target.types"; +import { getTokenDelimiters } from "../modifiers/scopeTypeStages/TokenStage"; +import BaseTarget from "./BaseTarget"; + +interface WeakTargetParameters { + editor: TextEditor; + isReversed: boolean; + contentRange: Range; + position?: Position; +} + +/** + * - Treated as "line" for "pour", "clone", and "breakpoint" + * - Use token delimiters (space) for removal and insertion + * - Expand to nearest containing pair when asked for boundary or interior + */ +export default class WeakTarget extends BaseTarget { + constructor(parameters: WeakTargetParameters) { + super({ + ...parameters, + ...getTokenDelimiters(parameters.editor, parameters.contentRange), + }); + } +} diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index ae1bb4f283..36274c9030 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -101,12 +101,13 @@ export type ScopeType = | "xmlEndTag" | "xmlStartTag" // Text based scopes - // | "character" Not implemented | "token" | "line" | "notebookCell" | "paragraph" | "document" + | "character" + | "word" | "nonWhitespaceSequence" | "url"; diff --git a/src/util/unifyRanges.ts b/src/util/unifyRanges.ts index 8b03f3c840..21e94ee8e5 100644 --- a/src/util/unifyRanges.ts +++ b/src/util/unifyRanges.ts @@ -1,5 +1,5 @@ import { Range } from "vscode"; -import BaseTarget from "../processTargets/targets/BaseTarget"; +import { targetsToContinuousTarget } from "../processTargets/processTargets"; import { Target } from "../typings/target.types"; import { groupTargetsForEachEditor } from "./targetUtils"; @@ -90,20 +90,7 @@ function mergeTargets(targets: Target[]): Target { } const first = targets[0]; const last = targets[targets.length - 1]; - return new BaseTarget({ - editor: first.editor, - isReversed: first.isReversed, - leadingDelimiter: first.leadingDelimiter, - trailingDelimiter: last.trailingDelimiter, - contentRange: new Range(first.contentRange.start, last.contentRange.end), - removalRange: - first.removalRange != null || last.removalRange != null - ? new Range( - first.removalRange?.start ?? first.contentRange.start, - last.removalRange?.end ?? last.contentRange.end - ) - : undefined, - }); + return targetsToContinuousTarget(first, last); } function intersects(targetA: Target, targetB: Target) { From 83bed3730852796d83239e1b4cb9292cdd9f42bb Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 22 May 2022 18:35:09 +0200 Subject: [PATCH 148/314] Updated tests --- .../surroundingPair/parseTreeParity/takePairDouble.yml | 4 ++-- .../surroundingPair/parseTreeParity/takePairRound.yml | 4 ++-- .../surroundingPair/parseTreeParity/takePairRound2.yml | 2 +- .../recorded/surroundingPair/textual/takePairDouble.yml | 4 ++-- .../recorded/surroundingPair/textual/takePairRound.yml | 4 ++-- .../recorded/surroundingPair/textual/takePairRound2.yml | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairDouble.yml b/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairDouble.yml index 7496c0978d..4f1f3520bc 100644 --- a/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairDouble.yml +++ b/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairDouble.yml @@ -1,11 +1,11 @@ languageId: typescript command: version: 1 - spokenForm: clear pair double + spokenForm: clear bounds double action: clearAndSetSelection targets: - type: primitive - modifier: {type: surroundingPair, delimiter: any} + modifier: {type: surroundingPair, delimiter: any, delimiterInclusion: excludeInterior} mark: {type: decoratedSymbol, symbolColor: default, character: '"'} initialState: documentContents: "\"\"" diff --git a/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairRound.yml b/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairRound.yml index b91e95600c..384343be9d 100644 --- a/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairRound.yml +++ b/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairRound.yml @@ -1,11 +1,11 @@ languageId: typescript command: version: 1 - spokenForm: clear pair round + spokenForm: clear bounds round action: clearAndSetSelection targets: - type: primitive - modifier: {type: surroundingPair, delimiter: parentheses} + modifier: {type: surroundingPair, delimiter: parentheses, delimiterInclusion: excludeInterior} initialState: documentContents: () selections: diff --git a/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairRound2.yml b/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairRound2.yml index 41102831e0..f31d48c666 100644 --- a/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairRound2.yml +++ b/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairRound2.yml @@ -1,7 +1,7 @@ languageId: typescript command: version: 1 - spokenForm: clear pair round + spokenForm: clear bounds round action: clearAndSetSelection targets: - type: primitive diff --git a/src/test/suite/fixtures/recorded/surroundingPair/textual/takePairDouble.yml b/src/test/suite/fixtures/recorded/surroundingPair/textual/takePairDouble.yml index 08929808c1..d58ca06205 100644 --- a/src/test/suite/fixtures/recorded/surroundingPair/textual/takePairDouble.yml +++ b/src/test/suite/fixtures/recorded/surroundingPair/textual/takePairDouble.yml @@ -1,11 +1,11 @@ languageId: plaintext command: version: 1 - spokenForm: clear pair double + spokenForm: clear bounds double action: clearAndSetSelection targets: - type: primitive - modifier: {type: surroundingPair, delimiter: any} + modifier: {type: surroundingPair, delimiter: any, delimiterInclusion: excludeInterior} mark: {type: decoratedSymbol, symbolColor: default, character: '"'} initialState: documentContents: "\"\"" diff --git a/src/test/suite/fixtures/recorded/surroundingPair/textual/takePairRound.yml b/src/test/suite/fixtures/recorded/surroundingPair/textual/takePairRound.yml index 8eeb39647b..1226f21476 100644 --- a/src/test/suite/fixtures/recorded/surroundingPair/textual/takePairRound.yml +++ b/src/test/suite/fixtures/recorded/surroundingPair/textual/takePairRound.yml @@ -1,11 +1,11 @@ languageId: plaintext command: version: 1 - spokenForm: clear pair round + spokenForm: clear bounds round action: clearAndSetSelection targets: - type: primitive - modifier: {type: surroundingPair, delimiter: parentheses} + modifier: {type: surroundingPair, delimiter: parentheses, delimiterInclusion: excludeInterior} initialState: documentContents: () selections: diff --git a/src/test/suite/fixtures/recorded/surroundingPair/textual/takePairRound2.yml b/src/test/suite/fixtures/recorded/surroundingPair/textual/takePairRound2.yml index bc2c5d6d41..aefae8a424 100644 --- a/src/test/suite/fixtures/recorded/surroundingPair/textual/takePairRound2.yml +++ b/src/test/suite/fixtures/recorded/surroundingPair/textual/takePairRound2.yml @@ -1,7 +1,7 @@ languageId: plaintext command: version: 1 - spokenForm: clear pair round + spokenForm: clear bounds round action: clearAndSetSelection targets: - type: primitive From 652ef140afdf74df3379addac6a5fb6384301f8d Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 22 May 2022 18:36:49 +0200 Subject: [PATCH 149/314] Added return type --- src/processTargets/modifiers/SurroundingPairStage.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/processTargets/modifiers/SurroundingPairStage.ts b/src/processTargets/modifiers/SurroundingPairStage.ts index 84de77a74d..a057c8626d 100644 --- a/src/processTargets/modifiers/SurroundingPairStage.ts +++ b/src/processTargets/modifiers/SurroundingPairStage.ts @@ -3,6 +3,7 @@ import { ProcessedTargetsContext } from "../../typings/Types"; import { selectionWithEditorWithContextToTarget } from "../../util/targetUtils"; import { ModifierStage } from "../PipelineStages.types"; import BaseTarget from "../targets/BaseTarget"; +import SurroundingPairTarget from "../targets/SurroundingPairTarget"; import { processSurroundingPair } from "./surroundingPair"; /** @@ -29,7 +30,7 @@ export default class implements ModifierStage { export function processedSurroundingPairTarget( modifier: SurroundingPairModifier, context: ProcessedTargetsContext, - target: Target + target: SurroundingPairTarget ) { const pairs = processSurroundingPair( context, @@ -44,7 +45,7 @@ export function processedSurroundingPairTarget( return pairs.map( (pair) => - new BaseTarget({ + new SurroundingPairTarget({ ...selectionWithEditorWithContextToTarget(pair), isReversed: target.isReversed, }) From 44cdd6ad08961692ab5e18577e0707fae94279ad Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 22 May 2022 19:50:20 +0200 Subject: [PATCH 150/314] Fixed compilation errors --- src/actions/Rewrap.ts | 4 ++-- src/processTargets/getModifierStage.ts | 2 +- .../modifiers/SurroundingPairStage.ts | 10 +++++---- .../targets/SurroundingPairTarget.ts | 21 ++++++++++++++++++- 4 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/actions/Rewrap.ts b/src/actions/Rewrap.ts index 7c1129e411..a16ae8df9f 100644 --- a/src/actions/Rewrap.ts +++ b/src/actions/Rewrap.ts @@ -1,7 +1,7 @@ import { flatten, zip } from "lodash"; import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; +import RawSelectionTarget from "../processTargets/targets/RawSelectionTarget"; import { Target } from "../typings/target.types"; -import BaseTarget from "../processTargets/targets/BaseTarget"; import { ActionPreferences, Graph } from "../typings/Types"; import displayPendingEditDecorations from "../util/editDisplayUtils"; import { runForEachEditor } from "../util/targetUtils"; @@ -39,7 +39,7 @@ export default class Rewrap implements Action { editor: target.editor, boundary: boundary.map( (edge) => - new BaseTarget({ + new RawSelectionTarget({ editor: target.editor, contentRange: edge, isReversed: target.isReversed, diff --git a/src/processTargets/getModifierStage.ts b/src/processTargets/getModifierStage.ts index 25db9faea8..6e13e27fe4 100644 --- a/src/processTargets/getModifierStage.ts +++ b/src/processTargets/getModifierStage.ts @@ -38,7 +38,7 @@ export default (modifier: Modifier): ModifierStage => { return new SubPieceStage(modifier); case "surroundingPair": return new SurroundingPairStage(modifier); - case "ContainingScopeModifier(interiorOnly)": + case "interiorOnly": return new InteriorOnlyStage(modifier); case "excludeInterior": return new ExcludeInteriorStage(modifier); diff --git a/src/processTargets/modifiers/SurroundingPairStage.ts b/src/processTargets/modifiers/SurroundingPairStage.ts index a057c8626d..405f6d95b0 100644 --- a/src/processTargets/modifiers/SurroundingPairStage.ts +++ b/src/processTargets/modifiers/SurroundingPairStage.ts @@ -2,7 +2,6 @@ import { SurroundingPairModifier, Target } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { selectionWithEditorWithContextToTarget } from "../../util/targetUtils"; import { ModifierStage } from "../PipelineStages.types"; -import BaseTarget from "../targets/BaseTarget"; import SurroundingPairTarget from "../targets/SurroundingPairTarget"; import { processSurroundingPair } from "./surroundingPair"; @@ -22,7 +21,10 @@ import { processSurroundingPair } from "./surroundingPair"; export default class implements ModifierStage { constructor(private modifier: SurroundingPairModifier) {} - run(context: ProcessedTargetsContext, target: Target): Target[] { + run( + context: ProcessedTargetsContext, + target: Target + ): SurroundingPairTarget[] { return processedSurroundingPairTarget(this.modifier, context, target); } } @@ -30,8 +32,8 @@ export default class implements ModifierStage { export function processedSurroundingPairTarget( modifier: SurroundingPairModifier, context: ProcessedTargetsContext, - target: SurroundingPairTarget -) { + target: Target +): SurroundingPairTarget[] { const pairs = processSurroundingPair( context, target.editor, diff --git a/src/processTargets/targets/SurroundingPairTarget.ts b/src/processTargets/targets/SurroundingPairTarget.ts index 838f3ccd2a..a80d83b078 100644 --- a/src/processTargets/targets/SurroundingPairTarget.ts +++ b/src/processTargets/targets/SurroundingPairTarget.ts @@ -1 +1,20 @@ -export default class SurroundingPairTarget {} +import { Range, TextEditor } from "vscode"; +import { RemovalRange } from "../../typings/target.types"; +import BaseTarget from "./BaseTarget"; + +interface SurroundingPairTargetParameters { + editor: TextEditor; + isReversed: boolean; + contentRange: Range; + delimiter?: string; + interiorRange?: Range; + boundary?: [Range, Range]; + leadingDelimiter?: RemovalRange; + trailingDelimiter?: RemovalRange; +} + +export default class SurroundingPairTarget extends BaseTarget { + constructor(parameters: SurroundingPairTargetParameters) { + super(parameters); + } +} From 682a9306c96e268f4b88c7fb685d16331f746c78 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 22 May 2022 21:58:17 +0200 Subject: [PATCH 151/314] Updated position --- src/processTargets/modifiers/PositionStage.ts | 70 ++++++------------- src/processTargets/targets/BaseTarget.ts | 8 +-- .../targets/RawSelectionTarget.ts | 7 ++ .../fixtures/recorded/actions/drinkVest.yml | 4 +- .../fixtures/recorded/actions/pourVest.yml | 4 +- ...PointToEndOfThisAndEndOfWhaleTakeWhale.yml | 2 +- 6 files changed, 36 insertions(+), 59 deletions(-) diff --git a/src/processTargets/modifiers/PositionStage.ts b/src/processTargets/modifiers/PositionStage.ts index 7523865d18..8e290681c5 100644 --- a/src/processTargets/modifiers/PositionStage.ts +++ b/src/processTargets/modifiers/PositionStage.ts @@ -7,66 +7,36 @@ export default class implements ModifierStage { constructor(private modifier: PositionModifier) {} run(context: ProcessedTargetsContext, target: Target): Target[] { - const { position } = this.modifier; const { start, end } = target.contentRange; - const { - editor, - isReversed, - delimiter, - scopeType, - leadingDelimiter, - trailingDelimiter, - } = target; + const { leadingDelimiter, trailingDelimiter } = target; - const common = { - position: this.modifier.position, - editor, - isReversed, - }; + target.position = this.modifier.position; + target.leadingDelimiter = undefined; + target.trailingDelimiter = undefined; - const constructor = Object.getPrototypeOf(target).constructor; - - switch (position) { + switch (this.modifier.position) { case "before": - return [ - new constructor({ - ...common, - contentRange: new Range(start, start), - delimiter, - scopeType, - leadingDelimiter, - }), - ]; + target.contentRange = new Range(start, start); + target.leadingDelimiter = leadingDelimiter; + break; case "after": - return [ - new constructor({ - ...common, - contentRange: new Range(end, end), - delimiter, - scopeType, - trailingDelimiter, - }), - ]; + target.contentRange = new Range(end, end); + target.trailingDelimiter = trailingDelimiter; + break; case "start": - return [ - new constructor({ - ...common, - contentRange: new Range(start, start), - // This it NOT a raw target. Joining with this should be done on empty delimiter. - delimiter: "", - }), - ]; + target.contentRange = new Range(start, start); + // This it NOT a raw target. Joining with this should be done on empty delimiter. + target.delimiter = ""; + break; case "end": - return [ - new constructor({ - ...common, - contentRange: new Range(end, end), - delimiter: "", - }), - ]; + target.contentRange = new Range(end, end); + target.delimiter = ""; + break; } + + return [target]; } } diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index 2c376b185b..dc2515fcdd 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -1,13 +1,13 @@ import { Range, Selection, TextEditor } from "vscode"; -import { parseRemovalRange } from "../../util/targetUtils"; import { - Target, - ScopeType, + EditNewLineContext, Position, RemovalRange, + ScopeType, + Target, TargetParameters, - EditNewLineContext, } from "../../typings/target.types"; +import { parseRemovalRange } from "../../util/targetUtils"; export default abstract class BaseTarget implements Target { editor: TextEditor; diff --git a/src/processTargets/targets/RawSelectionTarget.ts b/src/processTargets/targets/RawSelectionTarget.ts index afaa9de23d..461dcc5b27 100644 --- a/src/processTargets/targets/RawSelectionTarget.ts +++ b/src/processTargets/targets/RawSelectionTarget.ts @@ -1,4 +1,5 @@ import { Range, TextEditor } from "vscode"; +import { EditNewLineContext } from "../../typings/target.types"; import BaseTarget from "./BaseTarget"; interface RawSelectionTargetParameters { @@ -12,4 +13,10 @@ export default class RawSelectionTarget extends BaseTarget { super(parameters); this.delimiter = undefined; } + + getEditNewLineContext(_isBefore: boolean): EditNewLineContext { + return { + delimiter: "", + }; + } } diff --git a/src/test/suite/fixtures/recorded/actions/drinkVest.yml b/src/test/suite/fixtures/recorded/actions/drinkVest.yml index a1beca3ae8..d722f0ff24 100644 --- a/src/test/suite/fixtures/recorded/actions/drinkVest.yml +++ b/src/test/suite/fixtures/recorded/actions/drinkVest.yml @@ -26,6 +26,6 @@ finalState: - anchor: {line: 1, character: 0} active: {line: 1, character: 0} thatMark: - - anchor: {line: 1, character: 0} - active: {line: 1, character: 0} + - anchor: {line: 2, character: 6} + active: {line: 2, character: 11} fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: v}, selectionType: token, position: contents, modifier: {type: identity}, insideOutsideType: outside}] diff --git a/src/test/suite/fixtures/recorded/actions/pourVest.yml b/src/test/suite/fixtures/recorded/actions/pourVest.yml index 8d7e4594d4..7284f45325 100644 --- a/src/test/suite/fixtures/recorded/actions/pourVest.yml +++ b/src/test/suite/fixtures/recorded/actions/pourVest.yml @@ -26,6 +26,6 @@ finalState: - anchor: {line: 2, character: 0} active: {line: 2, character: 0} thatMark: - - anchor: {line: 2, character: 0} - active: {line: 2, character: 0} + - anchor: {line: 1, character: 6} + active: {line: 1, character: 11} fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: v}, selectionType: token, position: contents, modifier: {type: identity}, insideOutsideType: outside}] diff --git a/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToEndOfThisAndEndOfWhaleTakeWhale.yml b/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToEndOfThisAndEndOfWhaleTakeWhale.yml index ba8dfd6fb6..da4787b80c 100644 --- a/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToEndOfThisAndEndOfWhaleTakeWhale.yml +++ b/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToEndOfThisAndEndOfWhaleTakeWhale.yml @@ -1,7 +1,7 @@ languageId: plaintext command: version: 1 - spokenForm: bring harp and point to end of this and end of whale take whale + spokenForm: bring harp and point to end of this and end of whale action: replaceWithTarget targets: - type: list From 9a35ceab561cc4fb7add2a6d018375c45983d93b Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 22 May 2022 22:07:07 +0200 Subject: [PATCH 152/314] Add empty string as default delimiter for sub tokens --- src/processTargets/modifiers/SubPieceStage.ts | 2 +- .../hatTokenMap/bringPointAfterFirstCarWhaleTakeWhale.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/processTargets/modifiers/SubPieceStage.ts b/src/processTargets/modifiers/SubPieceStage.ts index a307cf84a0..288c31ffeb 100644 --- a/src/processTargets/modifiers/SubPieceStage.ts +++ b/src/processTargets/modifiers/SubPieceStage.ts @@ -106,7 +106,7 @@ export default class implements ModifierStage { isReversed, contentRange, scopeType: this.modifier.pieceType, - delimiter: containingListDelimiter, + delimiter: containingListDelimiter ?? "", leadingDelimiter: leadingDelimiterRange != null ? { range: leadingDelimiterRange } diff --git a/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAfterFirstCarWhaleTakeWhale.yml b/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAfterFirstCarWhaleTakeWhale.yml index a800665a71..48b58aaa6e 100644 --- a/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAfterFirstCarWhaleTakeWhale.yml +++ b/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAfterFirstCarWhaleTakeWhale.yml @@ -1,7 +1,7 @@ languageId: plaintext command: version: 1 - spokenForm: bring point after first car whale take whale + spokenForm: bring point after first car whale action: replaceWithTarget targets: - type: primitive From fb89dfcfedc9ad875eb8fd3ac4928a26da81bc99 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 22 May 2022 23:56:21 +0200 Subject: [PATCH 153/314] Updated bugs --- src/processTargets/modifiers/PositionStage.ts | 10 +++++-- src/processTargets/processTargets.ts | 7 +++-- src/processTargets/targets/WeakTarget.ts | 2 +- src/test/suite/runSingleRecordedTest.ts | 2 +- src/util/targetUtils.ts | 26 ++++++++++--------- src/util/uniqDeep.ts | 5 ++++ 6 files changed, 32 insertions(+), 20 deletions(-) create mode 100644 src/util/uniqDeep.ts diff --git a/src/processTargets/modifiers/PositionStage.ts b/src/processTargets/modifiers/PositionStage.ts index 8e290681c5..844b573d61 100644 --- a/src/processTargets/modifiers/PositionStage.ts +++ b/src/processTargets/modifiers/PositionStage.ts @@ -17,12 +17,18 @@ export default class implements ModifierStage { switch (this.modifier.position) { case "before": target.contentRange = new Range(start, start); - target.leadingDelimiter = leadingDelimiter; + target.leadingDelimiter = + leadingDelimiter != null + ? { ...leadingDelimiter, exclude: false } + : undefined; break; case "after": target.contentRange = new Range(end, end); - target.trailingDelimiter = trailingDelimiter; + target.trailingDelimiter = + trailingDelimiter != null + ? { ...trailingDelimiter, exclude: false } + : undefined; break; case "start": diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index fc5ca262ab..07275c6783 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -1,4 +1,4 @@ -import { isEqual, uniqWith, zip } from "lodash"; +import { zip } from "lodash"; import { Position, Range } from "vscode"; import { PrimitiveTargetDescriptor, @@ -8,6 +8,7 @@ import { } from "../typings/target.types"; import { ProcessedTargetsContext } from "../typings/Types"; import { ensureSingleEditor } from "../util/targetUtils"; +import uniqDeep from "../util/uniqDeep"; import getMarkStage from "./getMarkStage"; import getModifierStage from "./getModifierStage"; import BaseTarget from "./targets/BaseTarget"; @@ -31,9 +32,7 @@ export default function ( context: ProcessedTargetsContext, targets: TargetDescriptor[] ): Target[][] { - return targets.map((target) => - uniqWith(processTarget(context, target), isEqual) - ); + return targets.map((target) => uniqDeep(processTarget(context, target))); } function processTarget( diff --git a/src/processTargets/targets/WeakTarget.ts b/src/processTargets/targets/WeakTarget.ts index b5725d63e9..f0a6dcd278 100644 --- a/src/processTargets/targets/WeakTarget.ts +++ b/src/processTargets/targets/WeakTarget.ts @@ -18,8 +18,8 @@ interface WeakTargetParameters { export default class WeakTarget extends BaseTarget { constructor(parameters: WeakTargetParameters) { super({ - ...parameters, ...getTokenDelimiters(parameters.editor, parameters.contentRange), + ...parameters, }); } } diff --git a/src/test/suite/runSingleRecordedTest.ts b/src/test/suite/runSingleRecordedTest.ts index f9ea62d9df..f13a78ad16 100644 --- a/src/test/suite/runSingleRecordedTest.ts +++ b/src/test/suite/runSingleRecordedTest.ts @@ -5,7 +5,7 @@ // example: // const filenameEnd = "textual/takePairRound.yml"; -const filenameEnd = ""; +const filenameEnd = "drinkCell.yml"; export function runSingleTest() { return !!filenameEnd; diff --git a/src/util/targetUtils.ts b/src/util/targetUtils.ts index 71aa9ec4b7..d8b9d4835e 100644 --- a/src/util/targetUtils.ts +++ b/src/util/targetUtils.ts @@ -9,6 +9,7 @@ import { } from "../typings/Types"; import { groupBy } from "./itertools"; import { isReversed } from "./selectionUtils"; +import uniqDeep from "./uniqDeep"; export function ensureSingleEditor(targets: Target[]) { if (targets.length === 0) { @@ -95,18 +96,19 @@ export function createThatMark( targets: Target[], ranges?: Range[] ): SelectionWithEditor[] { - if (ranges) { - return zip(targets, ranges).map(([target, range]) => ({ - editor: target!.editor, - selection: target?.isReversed - ? new Selection(range!.end, range!.start) - : new Selection(range!.start, range!.end), - })); - } - return targets.map((target) => ({ - editor: target!.editor, - selection: target.getContentSelection(), - })); + const thatMark = + ranges != null + ? zip(targets, ranges).map(([target, range]) => ({ + editor: target!.editor, + selection: target?.isReversed + ? new Selection(range!.end, range!.start) + : new Selection(range!.start, range!.end), + })) + : targets.map((target) => ({ + editor: target!.editor, + selection: target.getContentSelection(), + })); + return uniqDeep(thatMark); } export function getRemovalRange(target: Target) { diff --git a/src/util/uniqDeep.ts b/src/util/uniqDeep.ts new file mode 100644 index 0000000000..182226a01e --- /dev/null +++ b/src/util/uniqDeep.ts @@ -0,0 +1,5 @@ +import { uniqWith, isEqual } from "lodash"; + +export default (array: T[]): T[] => { + return uniqWith(array, isEqual); +}; From 567999a5f84d5a41621f93879d5964f3c83c5e1e Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 23 May 2022 00:10:51 +0200 Subject: [PATCH 154/314] Cleanup --- src/test/suite/runSingleRecordedTest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/suite/runSingleRecordedTest.ts b/src/test/suite/runSingleRecordedTest.ts index f13a78ad16..f9ea62d9df 100644 --- a/src/test/suite/runSingleRecordedTest.ts +++ b/src/test/suite/runSingleRecordedTest.ts @@ -5,7 +5,7 @@ // example: // const filenameEnd = "textual/takePairRound.yml"; -const filenameEnd = "drinkCell.yml"; +const filenameEnd = ""; export function runSingleTest() { return !!filenameEnd; From cdc2384fd0e3562560207dd3afaf9f6ba4be078c Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 23 May 2022 00:18:33 +0200 Subject: [PATCH 155/314] Added tests --- src/processTargets/targets/TokenTarget.ts | 7 +++++ .../recorded/selectionTypes/drinkJustFine.yml | 29 +++++++++++++++++++ .../recorded/selectionTypes/drinkToken.yml | 25 ++++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 src/test/suite/fixtures/recorded/selectionTypes/drinkJustFine.yml create mode 100644 src/test/suite/fixtures/recorded/selectionTypes/drinkToken.yml diff --git a/src/processTargets/targets/TokenTarget.ts b/src/processTargets/targets/TokenTarget.ts index 914ee71e76..72385adc49 100644 --- a/src/processTargets/targets/TokenTarget.ts +++ b/src/processTargets/targets/TokenTarget.ts @@ -1,4 +1,5 @@ import { Range, TextEditor } from "vscode"; +import { EditNewLineContext } from "../../typings/target.types"; import { getTokenDelimiters } from "../modifiers/scopeTypeStages/TokenStage"; import BaseTarget from "./BaseTarget"; @@ -16,4 +17,10 @@ export default class TokenTarget extends BaseTarget { scopeType: "token", }); } + + getEditNewLineContext(_isBefore: boolean): EditNewLineContext { + return { + delimiter: " ", + }; + } } diff --git a/src/test/suite/fixtures/recorded/selectionTypes/drinkJustFine.yml b/src/test/suite/fixtures/recorded/selectionTypes/drinkJustFine.yml new file mode 100644 index 0000000000..b8819a85f1 --- /dev/null +++ b/src/test/suite/fixtures/recorded/selectionTypes/drinkJustFine.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: drink just fine + version: 2 + action: editNewLineBefore + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: f} + modifiers: + - {type: toRawSelection} + usePrePhraseSnapshot: true +initialState: + documentContents: foo + selections: + - anchor: {line: 0, character: 3} + active: {line: 0, character: 3} + marks: + default.f: + start: {line: 0, character: 0} + end: {line: 0, character: 3} +finalState: + documentContents: foo + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 3} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: f}, modifiers: [{type: toRawSelection}]}] diff --git a/src/test/suite/fixtures/recorded/selectionTypes/drinkToken.yml b/src/test/suite/fixtures/recorded/selectionTypes/drinkToken.yml new file mode 100644 index 0000000000..823539a19b --- /dev/null +++ b/src/test/suite/fixtures/recorded/selectionTypes/drinkToken.yml @@ -0,0 +1,25 @@ +languageId: python +command: + spokenForm: drink token + version: 2 + action: editNewLineBefore + targets: + - type: primitive + modifiers: + - {type: containingScope, scopeType: token} + usePrePhraseSnapshot: true +initialState: + documentContents: foo + selections: + - anchor: {line: 0, character: 2} + active: {line: 0, character: 2} + marks: {} +finalState: + documentContents: " foo" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 0, character: 1} + active: {line: 0, character: 4} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: containingScope, scopeType: token}]}] From cfe87bc340829df85444c4667d75ef8bf325b69c Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 23 May 2022 08:22:49 +0200 Subject: [PATCH 156/314] Updated inference of implicit target --- src/core/inferFullTargets.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/core/inferFullTargets.ts b/src/core/inferFullTargets.ts index f5d7e64283..8361689d20 100644 --- a/src/core/inferFullTargets.ts +++ b/src/core/inferFullTargets.ts @@ -1,5 +1,4 @@ import { - Modifier, PartialListTargetDesc, PartialPrimitiveTargetDesc, PartialRangeTargetDesc, @@ -108,6 +107,14 @@ function inferPrimitiveTarget( previousTargets: PartialTargetDesc[], actionPreferences?: ActionPreferences ): PrimitiveTargetDescriptor { + if (target.isImplicit) { + return { + type: "primitive", + mark: { type: "cursor" }, + modifiers: [{ type: "toRawSelection" }], + }; + } + const hasPosition = !!target.modifiers?.find( (modifier) => modifier.type === "position" ); @@ -119,16 +126,9 @@ function inferPrimitiveTarget( }; const previousModifiers = getPreviousModifiers(previousTargets); - const implicitModifiers = target.isImplicit - ? [{ type: "toRawSelection" } as Modifier] - : undefined; const modifiers = - target.modifiers ?? - implicitModifiers ?? - previousModifiers ?? - actionPreferences?.modifiers ?? - []; + target.modifiers ?? previousModifiers ?? actionPreferences?.modifiers ?? []; // "bring line to after this" needs to infer line on second target const modifierTypes = [ From a5c57520f178486c33c6292c8f25847dd4b6dbcf Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 23 May 2022 09:50:31 +0200 Subject: [PATCH 157/314] Updated spoken forms in test --- .../bringHarpAndPointToEndOfThisAndEndOfWhaleTakeWhale.yml | 2 +- .../hatTokenMap/bringPointAfterFirstCarWhaleTakeWhale.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToEndOfThisAndEndOfWhaleTakeWhale.yml b/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToEndOfThisAndEndOfWhaleTakeWhale.yml index da4787b80c..ba8dfd6fb6 100644 --- a/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToEndOfThisAndEndOfWhaleTakeWhale.yml +++ b/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToEndOfThisAndEndOfWhaleTakeWhale.yml @@ -1,7 +1,7 @@ languageId: plaintext command: version: 1 - spokenForm: bring harp and point to end of this and end of whale + spokenForm: bring harp and point to end of this and end of whale take whale action: replaceWithTarget targets: - type: list diff --git a/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAfterFirstCarWhaleTakeWhale.yml b/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAfterFirstCarWhaleTakeWhale.yml index 48b58aaa6e..a800665a71 100644 --- a/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAfterFirstCarWhaleTakeWhale.yml +++ b/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAfterFirstCarWhaleTakeWhale.yml @@ -1,7 +1,7 @@ languageId: plaintext command: version: 1 - spokenForm: bring point after first car whale + spokenForm: bring point after first car whale take whale action: replaceWithTarget targets: - type: primitive From e050a2a42c905295deb8302610f7635096738074 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 23 May 2022 12:17:38 +0200 Subject: [PATCH 158/314] Utilize getters --- src/actions/BringMoveSwap.ts | 21 +-- src/actions/CommandAction.ts | 4 +- src/actions/GetText.ts | 2 +- src/actions/InsertEmptyLines.ts | 2 +- src/actions/Replace.ts | 2 +- src/actions/Rewrap.ts | 2 +- src/actions/SetSelection.ts | 2 +- src/actions/Wrap.ts | 2 +- src/actions/WrapWithSnippet.ts | 4 +- src/processTargets/modifiers/PositionStage.ts | 37 +---- src/processTargets/modifiers/SubPieceStage.ts | 31 ++-- src/processTargets/targets/BaseTarget.ts | 151 ++++++++++++++---- src/processTargets/targets/DocumentTarget.ts | 14 +- src/processTargets/targets/LineTarget.ts | 15 +- .../targets/NotebookCellTarget.ts | 8 +- src/processTargets/targets/ParagraphTarget.ts | 27 +--- .../targets/RawSelectionTarget.ts | 7 +- src/processTargets/targets/ScopeTypeTarget.ts | 53 +++--- .../targets/SurroundingPairTarget.ts | 5 +- src/typings/target.types.ts | 60 +------ src/util/targetUtils.ts | 2 +- 21 files changed, 226 insertions(+), 225 deletions(-) diff --git a/src/actions/BringMoveSwap.ts b/src/actions/BringMoveSwap.ts index bb7a13e785..dcca5a1299 100644 --- a/src/actions/BringMoveSwap.ts +++ b/src/actions/BringMoveSwap.ts @@ -100,7 +100,7 @@ class BringMoveSwap implements Action { if (zipSources) { text = sources .map((source, i) => { - const text = source.getContentText(); + const text = source.contentText; const containingListDelimiter = destination.delimiter ?? source.delimiter; return i > 0 && containingListDelimiter @@ -134,7 +134,7 @@ class BringMoveSwap implements Action { if (this.type !== "move") { results.push({ range: source.contentRange, - text: destination.getContentText(), + text: destination.contentText, editor: source.editor, originalTarget: source, isSource: true, @@ -178,7 +178,7 @@ class BringMoveSwap implements Action { const editSelectionInfos = edits.map(({ originalTarget }) => getSelectionInfo( editor.document, - originalTarget.getContentSelection(), + originalTarget.contentSelection, DecorationRangeBehavior.OpenOpen ) ); @@ -207,10 +207,7 @@ class BringMoveSwap implements Action { editor, selection, isSource: edit!.isSource, - target: { - ...edit!.originalTarget, - contentRange: selection, - }, + target: edit!.originalTarget, }; }); } @@ -220,16 +217,20 @@ class BringMoveSwap implements Action { private async decorateThatMark(thatMark: MarkEntry[]) { const decorationContext = this.getDecorationContext(); + const getRange = (target: Target) => + thatMark.find((t) => t.target === target)!.selection; return Promise.all([ displayPendingEditDecorations( thatMark.filter(({ isSource }) => isSource).map(({ target }) => target), - decorationContext.sourceStyle + decorationContext.sourceStyle, + getRange ), displayPendingEditDecorations( thatMark .filter(({ isSource }) => !isSource) .map(({ target }) => target), - decorationContext.destinationStyle + decorationContext.destinationStyle, + getRange ), ]); } @@ -290,6 +291,6 @@ export class Swap extends BringMoveSwap { /** Get text from selection. Possibly add delimiter for positions before/after */ function getTextWithPossibleDelimiter(source: Target, destination: Target) { - const sourceText = source.getContentText(); + const sourceText = source.contentText; return destination.maybeAddDelimiter(sourceText); } diff --git a/src/actions/CommandAction.ts b/src/actions/CommandAction.ts index 730406afb4..9386c6c3fe 100644 --- a/src/actions/CommandAction.ts +++ b/src/actions/CommandAction.ts @@ -42,8 +42,8 @@ export default class CommandAction implements Action { await runOnTargetsForEachEditor(targets, async (editor, targets) => { const originalSelections = editor.selections; - const targetSelections = targets.map((target) => - target.getContentSelection() + const targetSelections = targets.map( + (target) => target.contentSelection ); // For command to the work we have to have the correct editor focused diff --git a/src/actions/GetText.ts b/src/actions/GetText.ts index e9dabf0173..65f845c092 100644 --- a/src/actions/GetText.ts +++ b/src/actions/GetText.ts @@ -28,7 +28,7 @@ export default class GetText implements Action { } return { - returnValue: targets.map((target) => target.getContentText()), + returnValue: targets.map((target) => target.contentText), thatMark: createThatMark(targets), }; } diff --git a/src/actions/InsertEmptyLines.ts b/src/actions/InsertEmptyLines.ts index d8a5052f00..e6c5ad5782 100644 --- a/src/actions/InsertEmptyLines.ts +++ b/src/actions/InsertEmptyLines.ts @@ -52,7 +52,7 @@ class InsertEmptyLines implements Action { editor, edits, [ - targets.map((target) => target.getContentSelection()), + targets.map((target) => target.contentSelection), ranges.map((range) => new Selection(range.start, range.end)), editor.selections, ] diff --git a/src/actions/Replace.ts b/src/actions/Replace.ts index 3762a59b16..be51d5413a 100644 --- a/src/actions/Replace.ts +++ b/src/actions/Replace.ts @@ -61,7 +61,7 @@ export default class implements Action { this.graph.rangeUpdater, editor, edits, - [targets.map((target) => target.getContentSelection())] + [targets.map((target) => target.contentSelection)] ); return updatedSelections.map((selection) => ({ diff --git a/src/actions/Rewrap.ts b/src/actions/Rewrap.ts index a16ae8df9f..e7bfabab64 100644 --- a/src/actions/Rewrap.ts +++ b/src/actions/Rewrap.ts @@ -45,7 +45,7 @@ export default class Rewrap implements Action { isReversed: target.isReversed, }) ), - targetSelection: target.getContentSelection(), + targetSelection: target.contentSelection, }; }); diff --git a/src/actions/SetSelection.ts b/src/actions/SetSelection.ts index 8ad32e2938..ef796b8c85 100644 --- a/src/actions/SetSelection.ts +++ b/src/actions/SetSelection.ts @@ -11,7 +11,7 @@ export class SetSelection implements Action { } protected getSelection(target: Target) { - return target.getContentSelection(); + return target.contentSelection; } async run([targets]: [Target[]]): Promise { diff --git a/src/actions/Wrap.ts b/src/actions/Wrap.ts index 5f7fbb20e6..630747b363 100644 --- a/src/actions/Wrap.ts +++ b/src/actions/Wrap.ts @@ -76,7 +76,7 @@ export default class Wrap implements Action { const thatMarkSelectionInfos = targets.map((target) => getSelectionInfo( document, - target.getContentSelection(), + target.contentSelection, DecorationRangeBehavior.OpenOpen ) ); diff --git a/src/actions/WrapWithSnippet.ts b/src/actions/WrapWithSnippet.ts index 85362ce258..c7f117addf 100644 --- a/src/actions/WrapWithSnippet.ts +++ b/src/actions/WrapWithSnippet.ts @@ -86,9 +86,7 @@ export default class WrapWithSnippet implements Action { this.graph.editStyles.pendingModification0 ); - const targetSelections = targets.map((target) => - target.getContentSelection() - ); + const targetSelections = targets.map((target) => target.contentSelection); await this.graph.actions.setSelection.run([targets]); diff --git a/src/processTargets/modifiers/PositionStage.ts b/src/processTargets/modifiers/PositionStage.ts index 844b573d61..d1cbd2b7f7 100644 --- a/src/processTargets/modifiers/PositionStage.ts +++ b/src/processTargets/modifiers/PositionStage.ts @@ -1,4 +1,3 @@ -import { Range } from "vscode"; import { PositionModifier, Target } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; @@ -7,41 +6,7 @@ export default class implements ModifierStage { constructor(private modifier: PositionModifier) {} run(context: ProcessedTargetsContext, target: Target): Target[] { - const { start, end } = target.contentRange; - const { leadingDelimiter, trailingDelimiter } = target; - - target.position = this.modifier.position; - target.leadingDelimiter = undefined; - target.trailingDelimiter = undefined; - - switch (this.modifier.position) { - case "before": - target.contentRange = new Range(start, start); - target.leadingDelimiter = - leadingDelimiter != null - ? { ...leadingDelimiter, exclude: false } - : undefined; - break; - - case "after": - target.contentRange = new Range(end, end); - target.trailingDelimiter = - trailingDelimiter != null - ? { ...trailingDelimiter, exclude: false } - : undefined; - break; - - case "start": - target.contentRange = new Range(start, start); - // This it NOT a raw target. Joining with this should be done on empty delimiter. - target.delimiter = ""; - break; - - case "end": - target.contentRange = new Range(end, end); - target.delimiter = ""; - break; - } + target.setPosition(this.modifier.position); return [target]; } diff --git a/src/processTargets/modifiers/SubPieceStage.ts b/src/processTargets/modifiers/SubPieceStage.ts index 288c31ffeb..8cc42a3b91 100644 --- a/src/processTargets/modifiers/SubPieceStage.ts +++ b/src/processTargets/modifiers/SubPieceStage.ts @@ -11,14 +11,12 @@ export default class implements ModifierStage { constructor(private modifier: SubTokenModifier) {} run(context: ProcessedTargetsContext, target: Target): Target[] { - if (target.contentRange.isEmpty) { - target.contentRange = getTokenRangeForSelection( - target.editor, - target.contentRange - ); - } + const { editor } = target; + const contentRange = target.contentRange.isEmpty + ? getTokenRangeForSelection(target.editor, target.contentRange) + : target.contentRange; - const token = target.getContentText(); + const token = editor.document.getText(contentRange); let pieces: { start: number; end: number }[] = []; if (this.modifier.excludeActive || this.modifier.excludeAnchor) { @@ -57,25 +55,24 @@ export default class implements ModifierStage { const isReversed = activeIndex < anchorIndex; - const anchor = target.contentRange.start.translate( + const anchor = contentRange.start.translate( undefined, isReversed ? pieces[anchorIndex].end : pieces[anchorIndex].start ); - const active = target.contentRange.start.translate( + const active = contentRange.start.translate( undefined, isReversed ? pieces[activeIndex].start : pieces[activeIndex].end ); - const contentRange = new Range(anchor, active); const startIndex = Math.min(anchorIndex, activeIndex); const endIndex = Math.max(anchorIndex, activeIndex); const leadingDelimiterRange = startIndex > 0 && pieces[startIndex - 1].end < pieces[startIndex].start ? new Range( - target.contentRange.start.translate({ + contentRange.start.translate({ characterDelta: pieces[startIndex - 1].end, }), - target.contentRange.start.translate({ + contentRange.start.translate({ characterDelta: pieces[startIndex].start, }) ) @@ -84,10 +81,10 @@ export default class implements ModifierStage { endIndex + 1 < pieces.length && pieces[endIndex].end < pieces[endIndex + 1].start ? new Range( - target.contentRange.start.translate({ + contentRange.start.translate({ characterDelta: pieces[endIndex].end, }), - target.contentRange.start.translate({ + contentRange.start.translate({ characterDelta: pieces[endIndex + 1].start, }) ) @@ -95,16 +92,16 @@ export default class implements ModifierStage { const isInDelimitedList = leadingDelimiterRange != null || trailingDelimiterRange != null; const containingListDelimiter = isInDelimitedList - ? target.editor.document.getText( + ? editor.document.getText( (leadingDelimiterRange ?? trailingDelimiterRange)! ) : undefined; return [ new ScopeTypeTarget({ - editor: target.editor, + editor, isReversed, - contentRange, + contentRange: new Range(anchor, active), scopeType: this.modifier.pieceType, delimiter: containingListDelimiter ?? "", leadingDelimiter: diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index dc2515fcdd..1c7fb606e6 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -5,46 +5,135 @@ import { RemovalRange, ScopeType, Target, - TargetParameters, } from "../../typings/target.types"; import { parseRemovalRange } from "../../util/targetUtils"; -export default abstract class BaseTarget implements Target { +export interface BaseTargetParameters { editor: TextEditor; isReversed: boolean; - contentRange: Range; - delimiter?: string; scopeType?: ScopeType; - position?: Position; + delimiter: string; + contentRange: Range; removalRange?: Range; interiorRange?: Range; boundary?: [Range, Range]; leadingDelimiter?: RemovalRange; trailingDelimiter?: RemovalRange; - isLine: boolean = false; + isLine?: boolean; +} + +export default abstract class BaseTarget implements Target { + /** The text editor used for all ranges */ + readonly editor: TextEditor; + + /** If true active is before anchor */ + readonly isReversed: boolean; + + /** The range of the content */ + private readonly _contentRange: Range; - constructor(parameters: TargetParameters) { + /** If this selection has a delimiter. For example, new line for a line or paragraph and comma for a list or argument */ + private readonly _delimiter: string; + + /** Is this a scope type other raw selection? */ + readonly scopeType?: ScopeType; + + /** The range to remove the content */ + readonly removalRange?: Range; + + /** + * Represents the interior range of this selection. For example, for a + * surrounding pair this would exclude the opening and closing delimiter. For an if + * statement this would be the statements in the body. + */ + readonly interiorRange?: Range; + + /** + * Represents the boundary ranges of this selection. For example, for a + * surrounding pair this would be the opening and closing delimiter. For an if + * statement this would be the line of the guard as well as the closing brace. + */ + readonly boundary?: [Range, Range]; + + /** The range of the delimiter before the content selection */ + readonly _leadingDelimiter?: RemovalRange; + + /** The range of the delimiter after the content selection */ + readonly _trailingDelimiter?: RemovalRange; + + /** If true this target should be treated as a line in regards to continuous range */ + readonly isLine: boolean; + + /** The current position */ + position?: Position; + + constructor(parameters: BaseTargetParameters) { this.editor = parameters.editor; this.isReversed = parameters.isReversed; - this.contentRange = parameters.contentRange; - this.delimiter = parameters.delimiter; + this._contentRange = parameters.contentRange; + this._delimiter = parameters.delimiter; this.scopeType = parameters.scopeType; - this.position = parameters.position; this.removalRange = parameters.removalRange; this.interiorRange = parameters.interiorRange; this.boundary = parameters.boundary; - this.leadingDelimiter = parameters.leadingDelimiter; - this.trailingDelimiter = parameters.trailingDelimiter; + this._leadingDelimiter = parameters.leadingDelimiter; + this._trailingDelimiter = parameters.trailingDelimiter; + this.isLine = parameters.isLine ?? false; } - getContentText(): string { + get contentRange(): Range { + switch (this.position) { + case undefined: + return this._contentRange; + case "start": + case "before": + return new Range(this._contentRange.start, this._contentRange.start); + case "end": + case "after": + return new Range(this._contentRange.end, this._contentRange.end); + } + } + + get contentText(): string { return this.editor.document.getText(this.contentRange); } - getContentSelection(): Selection { + get contentSelection(): Selection { + const { start, end } = this.contentRange; return this.isReversed - ? new Selection(this.contentRange.end, this.contentRange.start) - : new Selection(this.contentRange.start, this.contentRange.end); + ? new Selection(end, start) + : new Selection(start, end); + } + + get delimiter(): string | undefined { + switch (this.position) { + // This it NOT a raw target. Joining with this should be done on empty delimiter. + case "start": + case "end": + return ""; + default: + return this._delimiter; + } + } + + get leadingDelimiter() { + switch (this.position) { + case undefined: + case "before": + return this._leadingDelimiter; + default: + return undefined; + } + } + + get trailingDelimiter() { + switch (this.position) { + case undefined: + case "after": + return this._trailingDelimiter; + default: + return undefined; + } } /** Possibly add delimiter for positions before/after */ @@ -105,23 +194,25 @@ export default abstract class BaseTarget implements Target { } getRemovalRange(): Range { - if (this.position === "before") { - return this.getRemovalBeforeRange(); + switch (this.position) { + case "before": + return this.getRemovalBeforeRange(); + case "after": + return this.getRemovalAfterRange(); + default: + return this.getRemovalContentRange(); } - if (this.position === "after") { - return this.getRemovalAfterRange(); - } - return this.getRemovalContentRange(); } getRemovalHighlightRange(): Range | undefined { - if (this.position === "before") { - return this.getRemovalBeforeHighlightRange(); - } - if (this.position === "after") { - return this.getRemovalAfterHighlightRange(); + switch (this.position) { + case "before": + return this.getRemovalBeforeHighlightRange(); + case "after": + return this.getRemovalAfterHighlightRange(); + default: + return this.getRemovalContentHighlightRange(); } - return this.getRemovalContentHighlightRange(); } getEditNewLineContext(_isBefore: boolean): EditNewLineContext { @@ -129,4 +220,8 @@ export default abstract class BaseTarget implements Target { delimiter: "\n", }; } + + setPosition(position: Position): void { + this.position = position; + } } diff --git a/src/processTargets/targets/DocumentTarget.ts b/src/processTargets/targets/DocumentTarget.ts index eab8eb30ad..998fd4842c 100644 --- a/src/processTargets/targets/DocumentTarget.ts +++ b/src/processTargets/targets/DocumentTarget.ts @@ -1,5 +1,4 @@ import { Range, TextEditor } from "vscode"; -import { ScopeType } from "../../typings/target.types"; import BaseTarget from "./BaseTarget"; interface DocumentTargetParameters { @@ -9,14 +8,13 @@ interface DocumentTargetParameters { } export default class DocumentTarget extends BaseTarget { - scopeType: ScopeType; - delimiter: string; - constructor(parameters: DocumentTargetParameters) { - super(parameters); - this.scopeType = "document"; - this.delimiter = "\n"; - this.isLine = true; + super({ + ...parameters, + isLine: true, + scopeType: "document", + delimiter: "\n", + }); } protected getRemovalContentRange(): Range { diff --git a/src/processTargets/targets/LineTarget.ts b/src/processTargets/targets/LineTarget.ts index 8a9df9b75c..3a7c8c38ee 100644 --- a/src/processTargets/targets/LineTarget.ts +++ b/src/processTargets/targets/LineTarget.ts @@ -1,5 +1,5 @@ import { Range, TextEditor } from "vscode"; -import { RemovalRange, ScopeType } from "../../typings/target.types"; +import { RemovalRange } from "../../typings/target.types"; import { parseRemovalRange } from "../../util/targetUtils"; import BaseTarget from "./BaseTarget"; @@ -12,14 +12,13 @@ interface LineTargetParameters { } export default class LineTarget extends BaseTarget { - scopeType: ScopeType; - delimiter: string; - constructor(parameters: LineTargetParameters) { - super(parameters); - this.scopeType = "line"; - this.delimiter = "\n"; - this.isLine = true; + super({ + ...parameters, + isLine: true, + scopeType: "line", + delimiter: "\n", + }); } protected getRemovalContentRange(): Range { diff --git a/src/processTargets/targets/NotebookCellTarget.ts b/src/processTargets/targets/NotebookCellTarget.ts index 02ca05cd1e..a24c28afb4 100644 --- a/src/processTargets/targets/NotebookCellTarget.ts +++ b/src/processTargets/targets/NotebookCellTarget.ts @@ -11,9 +11,11 @@ interface NotebookCellTargetParameters { export default class NotebookCellTarget extends BaseTarget { constructor(parameters: NotebookCellTargetParameters) { - super(parameters); - this.scopeType = "notebookCell"; - this.delimiter = "\n"; + super({ + ...parameters, + scopeType: "notebookCell", + delimiter: "\n", + }); } getEditNewLineContext(isBefore: boolean): EditNewLineContext { diff --git a/src/processTargets/targets/ParagraphTarget.ts b/src/processTargets/targets/ParagraphTarget.ts index a67696fe7e..ad0c75df4b 100644 --- a/src/processTargets/targets/ParagraphTarget.ts +++ b/src/processTargets/targets/ParagraphTarget.ts @@ -1,9 +1,5 @@ import { Range, TextEditor } from "vscode"; -import { - EditNewLineContext, - RemovalRange, - ScopeType, -} from "../../typings/target.types"; +import { EditNewLineContext, RemovalRange } from "../../typings/target.types"; import { parseRemovalRange } from "../../util/targetUtils"; import BaseTarget from "./BaseTarget"; @@ -16,14 +12,13 @@ interface ParagraphTargetParameters { } export default class ParagraphTarget extends BaseTarget { - scopeType: ScopeType; - delimiter: string; - constructor(parameters: ParagraphTargetParameters) { - super(parameters); - this.scopeType = "paragraph"; - this.delimiter = "\n\n"; - this.isLine = true; + super({ + ...parameters, + isLine: true, + scopeType: "paragraph", + delimiter: "\n\n", + }); } protected getRemovalBeforeRange(): Range { @@ -37,12 +32,6 @@ export default class ParagraphTarget extends BaseTarget { : this.contentRange; } - protected getRemovalAfterRange(): Range { - return this.trailingDelimiter != null - ? this.trailingDelimiter.range - : this.contentRange; - } - getRemovalContentRange(): Range { const removalRange = new Range( this.editor.document.lineAt(this.contentRange.start).range.start, @@ -77,7 +66,7 @@ export default class ParagraphTarget extends BaseTarget { getEditNewLineContext(_isBefore: boolean): EditNewLineContext { return { - delimiter: this.delimiter, + delimiter: this.delimiter!, }; } } diff --git a/src/processTargets/targets/RawSelectionTarget.ts b/src/processTargets/targets/RawSelectionTarget.ts index 461dcc5b27..1046e2ccdb 100644 --- a/src/processTargets/targets/RawSelectionTarget.ts +++ b/src/processTargets/targets/RawSelectionTarget.ts @@ -10,8 +10,11 @@ interface RawSelectionTargetParameters { export default class RawSelectionTarget extends BaseTarget { constructor(parameters: RawSelectionTargetParameters) { - super(parameters); - this.delimiter = undefined; + super({ ...parameters, delimiter: "" }); + } + + get delimiter() { + return undefined; } getEditNewLineContext(_isBefore: boolean): EditNewLineContext { diff --git a/src/processTargets/targets/ScopeTypeTarget.ts b/src/processTargets/targets/ScopeTypeTarget.ts index a5ce853637..6277d3b5f1 100644 --- a/src/processTargets/targets/ScopeTypeTarget.ts +++ b/src/processTargets/targets/ScopeTypeTarget.ts @@ -1,37 +1,28 @@ +import { Range, TextEditor } from "vscode"; import { EditNewLineContext, + RemovalRange, ScopeType, - TargetParameters, } from "../../typings/target.types"; import BaseTarget from "./BaseTarget"; -export interface ScopeTypeTargetParameters extends TargetParameters { +export interface ScopeTypeTargetParameters { + editor: TextEditor; + isReversed: boolean; scopeType: ScopeType; + delimiter?: string; + contentRange: Range; + removalRange?: Range; + leadingDelimiter?: RemovalRange; + trailingDelimiter?: RemovalRange; } export default class ScopeTypeTarget extends BaseTarget { - scopeType: ScopeType; - delimiter: string; - constructor(parameters: ScopeTypeTargetParameters) { - super(parameters); - this.scopeType = parameters.scopeType; - this.delimiter = - parameters.delimiter ?? this.getDelimiter(parameters.scopeType); - } - - private getDelimiter(scopeType: ScopeType): string { - switch (scopeType) { - case "namedFunction": - case "anonymousFunction": - case "statement": - case "ifStatement": - return "\n"; - case "class": - return "\n\n"; - default: - return " "; - } + super({ + ...parameters, + delimiter: parameters.delimiter ?? getDelimiter(parameters.scopeType), + }); } getEditNewLineContext(isBefore: boolean): EditNewLineContext { @@ -40,7 +31,21 @@ export default class ScopeTypeTarget extends BaseTarget { return super.getEditNewLineContext(isBefore); } return { - delimiter: this.delimiter, + delimiter: this.delimiter!, }; } } + +function getDelimiter(scopeType: ScopeType): string { + switch (scopeType) { + case "namedFunction": + case "anonymousFunction": + case "statement": + case "ifStatement": + return "\n"; + case "class": + return "\n\n"; + default: + return " "; + } +} diff --git a/src/processTargets/targets/SurroundingPairTarget.ts b/src/processTargets/targets/SurroundingPairTarget.ts index a80d83b078..0ed0b801e9 100644 --- a/src/processTargets/targets/SurroundingPairTarget.ts +++ b/src/processTargets/targets/SurroundingPairTarget.ts @@ -15,6 +15,9 @@ interface SurroundingPairTargetParameters { export default class SurroundingPairTarget extends BaseTarget { constructor(parameters: SurroundingPairTargetParameters) { - super(parameters); + super({ + ...parameters, + delimiter: parameters.delimiter ?? " ", + }); } } diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 36274c9030..6f33ef4d51 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -1,5 +1,6 @@ -import { Range, Selection, TextEditor } from "vscode"; +import { Range } from "vscode"; import { HatStyleName } from "../core/constants"; +import BaseTarget from "../processTargets/targets/BaseTarget"; export interface CursorMark { type: "cursor"; @@ -248,59 +249,4 @@ export interface RemovalRange { export type EditNewLineContext = { command: string } | { delimiter: string }; -export interface TargetParameters { - /** The text editor used for all ranges */ - editor: TextEditor; - - /** If true active is before anchor */ - isReversed: boolean; - - /** Is this a scope type other raw selection? */ - scopeType?: ScopeType; - - /** The current position */ - position?: Position; - - /** - * If this selection has a delimiter. For example, new line for a line or paragraph and comma for a list or argument - */ - delimiter?: string; - - /** The range of the content */ - contentRange: Range; - - /** The range to remove the content */ - removalRange?: Range; - - /** - * Represents the interior range of this selection. For example, for a - * surrounding pair this would exclude the opening and closing delimiter. For an if - * statement this would be the statements in the body. - */ - interiorRange?: Range; - - /** - * Represents the boundary ranges of this selection. For example, for a - * surrounding pair this would be the opening and closing delimiter. For an if - * statement this would be the line of the guard as well as the closing brace. - */ - boundary?: [Range, Range]; - - /** The range of the delimiter before the content selection */ - leadingDelimiter?: RemovalRange; - - /** The range of the delimiter after the content selection */ - trailingDelimiter?: RemovalRange; -} - -export interface Target extends TargetParameters { - /** If true this target should be treated as a line in regards to continuous range */ - isLine?: boolean; - - getContentSelection(): Selection; - getContentText(): string; - maybeAddDelimiter(text: string): string; - getRemovalRange(): Range; - getRemovalHighlightRange(): Range | undefined; - getEditNewLineContext(isBefore: boolean): EditNewLineContext; -} +export type Target = BaseTarget; diff --git a/src/util/targetUtils.ts b/src/util/targetUtils.ts index d8b9d4835e..1b58914277 100644 --- a/src/util/targetUtils.ts +++ b/src/util/targetUtils.ts @@ -106,7 +106,7 @@ export function createThatMark( })) : targets.map((target) => ({ editor: target!.editor, - selection: target.getContentSelection(), + selection: target.contentSelection, })); return uniqDeep(thatMark); } From f645dcdc24067beff3680edc1983dc9e63cd6996 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 23 May 2022 16:38:26 +0200 Subject: [PATCH 159/314] Refactored getters and setters for targets --- src/processTargets/modifiers/InteriorStage.ts | 73 ++------- src/processTargets/modifiers/PositionStage.ts | 4 +- .../modifiers/SurroundingPairStage.ts | 2 +- src/processTargets/targets/BaseTarget.ts | 143 ++++++++++++++---- src/processTargets/targets/DocumentTarget.ts | 26 ++-- src/processTargets/targets/LineTarget.ts | 23 ++- .../targets/NotebookCellTarget.ts | 16 +- src/processTargets/targets/ParagraphTarget.ts | 23 ++- .../targets/RawSelectionTarget.ts | 20 +-- src/processTargets/targets/ScopeTypeTarget.ts | 16 +- .../targets/SurroundingPairTarget.ts | 18 ++- src/processTargets/targets/TokenTarget.ts | 20 +-- src/processTargets/targets/WeakTarget.ts | 49 ++++-- 13 files changed, 257 insertions(+), 176 deletions(-) diff --git a/src/processTargets/modifiers/InteriorStage.ts b/src/processTargets/modifiers/InteriorStage.ts index 256b060402..0482fbc810 100644 --- a/src/processTargets/modifiers/InteriorStage.ts +++ b/src/processTargets/modifiers/InteriorStage.ts @@ -5,78 +5,27 @@ import { } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; -import WeakTarget from "../targets/WeakTarget"; -import { processedSurroundingPairTarget } from "./SurroundingPairStage"; -abstract class InteriorStage implements ModifierStage { - abstract getTargets(target: Target): Target[]; - abstract hasData(target: Target): boolean; +export class InteriorOnlyStage implements ModifierStage { + constructor(private modifier: InteriorOnlyModifier) {} run(context: ProcessedTargetsContext, target: Target): Target[] { - if (this.hasData(target)) { - return this.getTargets(target); - } - return this.processSurroundingPair(context, target).flatMap((target) => - this.getTargets(target) - ); - } - - processSurroundingPair( - context: ProcessedTargetsContext, - target: Target - ): Target[] { - return processedSurroundingPairTarget( - { type: "surroundingPair", delimiter: "any" }, - context, - target - ); - } -} - -export class InteriorOnlyStage extends InteriorStage { - constructor(private modifier: InteriorOnlyModifier) { - super(); - } - - getTargets(target: Target): Target[] { - if (target.interiorRange == null) { + const interiorTargets = target.getInterior(context); + if (interiorTargets == null) { throw Error("No available interior"); } - const contentRange = target.interiorRange; - return [ - new WeakTarget({ - editor: target.editor, - isReversed: target.isReversed, - contentRange, - }), - ]; - } - - hasData(target: Target): boolean { - return target.interiorRange != null; + return interiorTargets; } } -export class ExcludeInteriorStage extends InteriorStage { - constructor(private modifier: ExcludeInteriorModifier) { - super(); - } +export class ExcludeInteriorStage implements ModifierStage { + constructor(private modifier: ExcludeInteriorModifier) {} - getTargets(target: Target): Target[] { - if (target.boundary == null) { + run(context: ProcessedTargetsContext, target: Target): Target[] { + const boundaryTargets = target.getBoundary(context); + if (boundaryTargets == null) { throw Error("No available boundaries"); } - return target.boundary.map( - (contentRange) => - new WeakTarget({ - editor: target.editor, - isReversed: target.isReversed, - contentRange, - }) - ); - } - - hasData(target: Target): boolean { - return target.boundary != null; + return boundaryTargets; } } diff --git a/src/processTargets/modifiers/PositionStage.ts b/src/processTargets/modifiers/PositionStage.ts index d1cbd2b7f7..b9e6be6d73 100644 --- a/src/processTargets/modifiers/PositionStage.ts +++ b/src/processTargets/modifiers/PositionStage.ts @@ -6,8 +6,6 @@ export default class implements ModifierStage { constructor(private modifier: PositionModifier) {} run(context: ProcessedTargetsContext, target: Target): Target[] { - target.setPosition(this.modifier.position); - - return [target]; + return [target.withPosition(this.modifier.position)]; } } diff --git a/src/processTargets/modifiers/SurroundingPairStage.ts b/src/processTargets/modifiers/SurroundingPairStage.ts index 405f6d95b0..ad14e0be82 100644 --- a/src/processTargets/modifiers/SurroundingPairStage.ts +++ b/src/processTargets/modifiers/SurroundingPairStage.ts @@ -29,7 +29,7 @@ export default class implements ModifierStage { } } -export function processedSurroundingPairTarget( +function processedSurroundingPairTarget( modifier: SurroundingPairModifier, context: ProcessedTargetsContext, target: Target diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index 1c7fb606e6..61ae2a36e7 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -6,14 +6,30 @@ import { ScopeType, Target, } from "../../typings/target.types"; +import { ProcessedTargetsContext } from "../../typings/Types"; import { parseRemovalRange } from "../../util/targetUtils"; +import WeakTarget from "./WeakTarget"; -export interface BaseTargetParameters { +export function extractCommonParameters(parameters: CommonTargetParameters) { + return { + editor: parameters.editor, + isReversed: parameters.isReversed, + contentRange: parameters.contentRange, + position: parameters.position, + }; +} + +/** Parameters supported by all target classes */ +export interface CommonTargetParameters { editor: TextEditor; isReversed: boolean; + contentRange: Range; + position?: Position; +} + +export interface BaseTargetParameters extends CommonTargetParameters { scopeType?: ScopeType; delimiter: string; - contentRange: Range; removalRange?: Range; interiorRange?: Range; boundary?: [Range, Range]; @@ -22,7 +38,7 @@ export interface BaseTargetParameters { isLine?: boolean; } -export default abstract class BaseTarget implements Target { +interface BaseTargetState { /** The text editor used for all ranges */ readonly editor: TextEditor; @@ -30,10 +46,10 @@ export default abstract class BaseTarget implements Target { readonly isReversed: boolean; /** The range of the content */ - private readonly _contentRange: Range; + readonly contentRange: Range; /** If this selection has a delimiter. For example, new line for a line or paragraph and comma for a list or argument */ - private readonly _delimiter: string; + readonly delimiter: string; /** Is this a scope type other raw selection? */ readonly scopeType?: ScopeType; @@ -56,41 +72,106 @@ export default abstract class BaseTarget implements Target { readonly boundary?: [Range, Range]; /** The range of the delimiter before the content selection */ - readonly _leadingDelimiter?: RemovalRange; + readonly leadingDelimiter?: RemovalRange; /** The range of the delimiter after the content selection */ - readonly _trailingDelimiter?: RemovalRange; - - /** If true this target should be treated as a line in regards to continuous range */ - readonly isLine: boolean; + readonly trailingDelimiter?: RemovalRange; /** The current position */ position?: Position; +} + +export default abstract class BaseTarget implements Target { + protected readonly state: BaseTargetState; constructor(parameters: BaseTargetParameters) { - this.editor = parameters.editor; - this.isReversed = parameters.isReversed; - this._contentRange = parameters.contentRange; - this._delimiter = parameters.delimiter; - this.scopeType = parameters.scopeType; - this.removalRange = parameters.removalRange; - this.interiorRange = parameters.interiorRange; - this.boundary = parameters.boundary; - this._leadingDelimiter = parameters.leadingDelimiter; - this._trailingDelimiter = parameters.trailingDelimiter; - this.isLine = parameters.isLine ?? false; + this.state = { + editor: parameters.editor, + isReversed: parameters.isReversed, + contentRange: parameters.contentRange, + delimiter: parameters.delimiter, + scopeType: parameters.scopeType, + removalRange: parameters.removalRange, + interiorRange: parameters.interiorRange, + boundary: parameters.boundary, + leadingDelimiter: parameters.leadingDelimiter, + trailingDelimiter: parameters.trailingDelimiter, + position: parameters.position, + }; + } + + get position() { + return this.state.position; + } + + get editor() { + return this.state.editor; + } + + get isReversed() { + return this.state.isReversed; + } + + get removalRange() { + return this.state.removalRange; + } + + get scopeType() { + return this.state.scopeType; + } + + /** If true this target should be treated as a line in regards to continuous range */ + get isLine() { + return false; + } + + getInterior(_context: ProcessedTargetsContext): Target[] | undefined { + if (this.position != null) { + return undefined; + } + return this.state.interiorRange != null + ? [ + new WeakTarget({ + editor: this.editor, + isReversed: this.isReversed, + contentRange: this.state.interiorRange, + }), + ] + : undefined; + } + + getBoundary(_context: ProcessedTargetsContext): Target[] | undefined { + if (this.position != null) { + return undefined; + } + return this.state.boundary != null + ? this.state.boundary.map( + (contentRange) => + new WeakTarget({ + editor: this.editor, + isReversed: this.isReversed, + contentRange, + }) + ) + : undefined; } get contentRange(): Range { switch (this.position) { case undefined: - return this._contentRange; + return this.state.contentRange; case "start": case "before": - return new Range(this._contentRange.start, this._contentRange.start); + return new Range( + this.state.contentRange.start, + this.state.contentRange.start + ); case "end": case "after": - return new Range(this._contentRange.end, this._contentRange.end); + return new Range( + this.state.contentRange.end, + this.state.contentRange.end + ); } } @@ -112,7 +193,7 @@ export default abstract class BaseTarget implements Target { case "end": return ""; default: - return this._delimiter; + return this.state.delimiter; } } @@ -120,7 +201,7 @@ export default abstract class BaseTarget implements Target { switch (this.position) { case undefined: case "before": - return this._leadingDelimiter; + return this.state.leadingDelimiter; default: return undefined; } @@ -130,7 +211,7 @@ export default abstract class BaseTarget implements Target { switch (this.position) { case undefined: case "after": - return this._trailingDelimiter; + return this.state.trailingDelimiter; default: return undefined; } @@ -221,7 +302,11 @@ export default abstract class BaseTarget implements Target { }; } - setPosition(position: Position): void { - this.position = position; + abstract clone(): Target; + + withPosition(position: Position): Target { + const target = this.clone(); + target.state.position = position; + return target; } } diff --git a/src/processTargets/targets/DocumentTarget.ts b/src/processTargets/targets/DocumentTarget.ts index 998fd4842c..e5bbc6db11 100644 --- a/src/processTargets/targets/DocumentTarget.ts +++ b/src/processTargets/targets/DocumentTarget.ts @@ -1,17 +1,13 @@ -import { Range, TextEditor } from "vscode"; -import BaseTarget from "./BaseTarget"; - -interface DocumentTargetParameters { - editor: TextEditor; - isReversed: boolean; - contentRange: Range; -} +import { Range } from "vscode"; +import BaseTarget, { + CommonTargetParameters, + extractCommonParameters, +} from "./BaseTarget"; export default class DocumentTarget extends BaseTarget { - constructor(parameters: DocumentTargetParameters) { + constructor(parameters: CommonTargetParameters) { super({ - ...parameters, - isLine: true, + ...extractCommonParameters(parameters), scopeType: "document", delimiter: "\n", }); @@ -27,10 +23,18 @@ export default class DocumentTarget extends BaseTarget { ); } + get isLine() { + return true; + } + getRemovalHighlightRange(): Range | undefined { if (this.position != null) { return undefined; } return this.contentRange; } + + clone(): DocumentTarget { + return new DocumentTarget(this.state); + } } diff --git a/src/processTargets/targets/LineTarget.ts b/src/processTargets/targets/LineTarget.ts index 3a7c8c38ee..18b894708e 100644 --- a/src/processTargets/targets/LineTarget.ts +++ b/src/processTargets/targets/LineTarget.ts @@ -1,12 +1,12 @@ -import { Range, TextEditor } from "vscode"; +import { Range } from "vscode"; import { RemovalRange } from "../../typings/target.types"; import { parseRemovalRange } from "../../util/targetUtils"; -import BaseTarget from "./BaseTarget"; +import BaseTarget, { + CommonTargetParameters, + extractCommonParameters, +} from "./BaseTarget"; -interface LineTargetParameters { - editor: TextEditor; - isReversed: boolean; - contentRange: Range; +interface LineTargetParameters extends CommonTargetParameters { leadingDelimiter?: RemovalRange; trailingDelimiter?: RemovalRange; } @@ -14,13 +14,16 @@ interface LineTargetParameters { export default class LineTarget extends BaseTarget { constructor(parameters: LineTargetParameters) { super({ - ...parameters, - isLine: true, + ...extractCommonParameters(parameters), scopeType: "line", delimiter: "\n", }); } + get isLine() { + return true; + } + protected getRemovalContentRange(): Range { if (this.position != null) { return this.contentRange; @@ -43,4 +46,8 @@ export default class LineTarget extends BaseTarget { } return this.contentRange; } + + clone(): LineTarget { + return new LineTarget(this.state); + } } diff --git a/src/processTargets/targets/NotebookCellTarget.ts b/src/processTargets/targets/NotebookCellTarget.ts index a24c28afb4..2693f7ca03 100644 --- a/src/processTargets/targets/NotebookCellTarget.ts +++ b/src/processTargets/targets/NotebookCellTarget.ts @@ -1,16 +1,10 @@ -import { Range, TextEditor } from "vscode"; +import { TextEditor } from "vscode"; import { EditNewLineContext } from "../../typings/target.types"; import { getNotebookFromCellDocument } from "../../util/notebook"; -import BaseTarget from "./BaseTarget"; - -interface NotebookCellTargetParameters { - editor: TextEditor; - isReversed: boolean; - contentRange: Range; -} +import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; export default class NotebookCellTarget extends BaseTarget { - constructor(parameters: NotebookCellTargetParameters) { + constructor(parameters: CommonTargetParameters) { super({ ...parameters, scopeType: "notebookCell", @@ -34,4 +28,8 @@ export default class NotebookCellTarget extends BaseTarget { private isNotebookEditor(editor: TextEditor) { return getNotebookFromCellDocument(editor.document) != null; } + + clone(): NotebookCellTarget { + return new NotebookCellTarget(this.state); + } } diff --git a/src/processTargets/targets/ParagraphTarget.ts b/src/processTargets/targets/ParagraphTarget.ts index ad0c75df4b..fa6b8abc44 100644 --- a/src/processTargets/targets/ParagraphTarget.ts +++ b/src/processTargets/targets/ParagraphTarget.ts @@ -1,12 +1,12 @@ -import { Range, TextEditor } from "vscode"; +import { Range } from "vscode"; import { EditNewLineContext, RemovalRange } from "../../typings/target.types"; import { parseRemovalRange } from "../../util/targetUtils"; -import BaseTarget from "./BaseTarget"; +import BaseTarget, { + CommonTargetParameters, + extractCommonParameters, +} from "./BaseTarget"; -interface ParagraphTargetParameters { - editor: TextEditor; - isReversed: boolean; - contentRange: Range; +interface ParagraphTargetParameters extends CommonTargetParameters { leadingDelimiter?: RemovalRange; trailingDelimiter?: RemovalRange; } @@ -14,13 +14,16 @@ interface ParagraphTargetParameters { export default class ParagraphTarget extends BaseTarget { constructor(parameters: ParagraphTargetParameters) { super({ - ...parameters, - isLine: true, + ...extractCommonParameters(parameters), scopeType: "paragraph", delimiter: "\n\n", }); } + get isLine() { + return true; + } + protected getRemovalBeforeRange(): Range { return this.leadingDelimiter != null ? new Range( @@ -69,4 +72,8 @@ export default class ParagraphTarget extends BaseTarget { delimiter: this.delimiter!, }; } + + clone(): ParagraphTarget { + return new ParagraphTarget(this.state); + } } diff --git a/src/processTargets/targets/RawSelectionTarget.ts b/src/processTargets/targets/RawSelectionTarget.ts index 1046e2ccdb..adf86cee0f 100644 --- a/src/processTargets/targets/RawSelectionTarget.ts +++ b/src/processTargets/targets/RawSelectionTarget.ts @@ -1,16 +1,12 @@ -import { Range, TextEditor } from "vscode"; import { EditNewLineContext } from "../../typings/target.types"; -import BaseTarget from "./BaseTarget"; - -interface RawSelectionTargetParameters { - editor: TextEditor; - isReversed: boolean; - contentRange: Range; -} +import BaseTarget, { + CommonTargetParameters, + extractCommonParameters, +} from "./BaseTarget"; export default class RawSelectionTarget extends BaseTarget { - constructor(parameters: RawSelectionTargetParameters) { - super({ ...parameters, delimiter: "" }); + constructor(parameters: CommonTargetParameters) { + super({ ...extractCommonParameters(parameters), delimiter: "" }); } get delimiter() { @@ -22,4 +18,8 @@ export default class RawSelectionTarget extends BaseTarget { delimiter: "", }; } + + clone(): RawSelectionTarget { + return new RawSelectionTarget(this.state); + } } diff --git a/src/processTargets/targets/ScopeTypeTarget.ts b/src/processTargets/targets/ScopeTypeTarget.ts index 6277d3b5f1..860e46c429 100644 --- a/src/processTargets/targets/ScopeTypeTarget.ts +++ b/src/processTargets/targets/ScopeTypeTarget.ts @@ -4,14 +4,14 @@ import { RemovalRange, ScopeType, } from "../../typings/target.types"; -import BaseTarget from "./BaseTarget"; +import BaseTarget, { + CommonTargetParameters, + extractCommonParameters, +} from "./BaseTarget"; -export interface ScopeTypeTargetParameters { - editor: TextEditor; - isReversed: boolean; +export interface ScopeTypeTargetParameters extends CommonTargetParameters { scopeType: ScopeType; delimiter?: string; - contentRange: Range; removalRange?: Range; leadingDelimiter?: RemovalRange; trailingDelimiter?: RemovalRange; @@ -20,7 +20,7 @@ export interface ScopeTypeTargetParameters { export default class ScopeTypeTarget extends BaseTarget { constructor(parameters: ScopeTypeTargetParameters) { super({ - ...parameters, + ...extractCommonParameters(parameters), delimiter: parameters.delimiter ?? getDelimiter(parameters.scopeType), }); } @@ -34,6 +34,10 @@ export default class ScopeTypeTarget extends BaseTarget { delimiter: this.delimiter!, }; } + + clone(): ScopeTypeTarget { + return new ScopeTypeTarget(this.state); + } } function getDelimiter(scopeType: ScopeType): string { diff --git a/src/processTargets/targets/SurroundingPairTarget.ts b/src/processTargets/targets/SurroundingPairTarget.ts index 0ed0b801e9..8f50414e22 100644 --- a/src/processTargets/targets/SurroundingPairTarget.ts +++ b/src/processTargets/targets/SurroundingPairTarget.ts @@ -1,11 +1,11 @@ -import { Range, TextEditor } from "vscode"; +import { Range } from "vscode"; import { RemovalRange } from "../../typings/target.types"; -import BaseTarget from "./BaseTarget"; +import BaseTarget, { + CommonTargetParameters, + extractCommonParameters, +} from "./BaseTarget"; -interface SurroundingPairTargetParameters { - editor: TextEditor; - isReversed: boolean; - contentRange: Range; +interface SurroundingPairTargetParameters extends CommonTargetParameters { delimiter?: string; interiorRange?: Range; boundary?: [Range, Range]; @@ -16,8 +16,12 @@ interface SurroundingPairTargetParameters { export default class SurroundingPairTarget extends BaseTarget { constructor(parameters: SurroundingPairTargetParameters) { super({ - ...parameters, + ...extractCommonParameters(parameters), delimiter: parameters.delimiter ?? " ", }); } + + clone(): SurroundingPairTarget { + return new SurroundingPairTarget(this.state); + } } diff --git a/src/processTargets/targets/TokenTarget.ts b/src/processTargets/targets/TokenTarget.ts index 72385adc49..3778b25b59 100644 --- a/src/processTargets/targets/TokenTarget.ts +++ b/src/processTargets/targets/TokenTarget.ts @@ -1,18 +1,14 @@ -import { Range, TextEditor } from "vscode"; import { EditNewLineContext } from "../../typings/target.types"; import { getTokenDelimiters } from "../modifiers/scopeTypeStages/TokenStage"; -import BaseTarget from "./BaseTarget"; - -interface TokenTargetParameters { - editor: TextEditor; - isReversed: boolean; - contentRange: Range; -} +import BaseTarget, { + CommonTargetParameters, + extractCommonParameters, +} from "./BaseTarget"; export default class TokenTarget extends BaseTarget { - constructor(parameters: TokenTargetParameters) { + constructor(parameters: CommonTargetParameters) { super({ - ...parameters, + ...extractCommonParameters(parameters), ...getTokenDelimiters(parameters.editor, parameters.contentRange), scopeType: "token", }); @@ -23,4 +19,8 @@ export default class TokenTarget extends BaseTarget { delimiter: " ", }; } + + clone(): TokenTarget { + return new TokenTarget(this.state); + } } diff --git a/src/processTargets/targets/WeakTarget.ts b/src/processTargets/targets/WeakTarget.ts index f0a6dcd278..be69e8d932 100644 --- a/src/processTargets/targets/WeakTarget.ts +++ b/src/processTargets/targets/WeakTarget.ts @@ -1,14 +1,13 @@ -import { Range, TextEditor } from "vscode"; -import { Position } from "../../typings/target.types"; +import _ = require("lodash"); +import { Target } from "../../typings/target.types"; +import { ProcessedTargetsContext } from "../../typings/Types"; import { getTokenDelimiters } from "../modifiers/scopeTypeStages/TokenStage"; -import BaseTarget from "./BaseTarget"; - -interface WeakTargetParameters { - editor: TextEditor; - isReversed: boolean; - contentRange: Range; - position?: Position; -} +import SurroundingPairStage from "../modifiers/SurroundingPairStage"; +import BaseTarget, { + CommonTargetParameters, + extractCommonParameters, +} from "./BaseTarget"; +import SurroundingPairTarget from "./SurroundingPairTarget"; /** * - Treated as "line" for "pour", "clone", and "breakpoint" @@ -16,10 +15,36 @@ interface WeakTargetParameters { * - Expand to nearest containing pair when asked for boundary or interior */ export default class WeakTarget extends BaseTarget { - constructor(parameters: WeakTargetParameters) { + constructor(parameters: CommonTargetParameters) { super({ + ...extractCommonParameters(parameters), ...getTokenDelimiters(parameters.editor, parameters.contentRange), - ...parameters, }); } + + getInterior(context: ProcessedTargetsContext): Target[] { + return this.processSurroundingPair(context).flatMap( + (surroundingPairTarget) => surroundingPairTarget.getInterior(context)! + ); + } + + getBoundary(context: ProcessedTargetsContext): Target[] { + return this.processSurroundingPair(context).flatMap( + (surroundingPairTarget) => surroundingPairTarget.getBoundary(context)! + ); + } + + clone(): WeakTarget { + return new WeakTarget(this.state); + } + + private processSurroundingPair( + context: ProcessedTargetsContext + ): SurroundingPairTarget[] { + const surroundingPairStage = new SurroundingPairStage({ + type: "surroundingPair", + delimiter: "any", + }); + return surroundingPairStage.run(context, this); + } } From 848364ff72321fd148392e6f60421ea5f616fcea Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 23 May 2022 18:04:00 +0200 Subject: [PATCH 160/314] Implemented get final stages --- src/actions/Rewrap.ts | 90 +- src/actions/ToggleBreakpoint.ts | 10 +- src/actions/WrapWithSnippet.ts | 17 +- src/actions/actions.types.ts | 7 +- src/core/commandRunner/CommandRunner.ts | 14 +- src/core/inferFullTargets.ts | 52 +- src/processTargets/modifiers/InteriorStage.ts | 12 +- .../modifiers/WeakContainingScopeStage.ts | 16 + src/processTargets/targets/BaseTarget.ts | 51 +- src/processTargets/targets/WeakTarget.ts | 4 + .../fixtures/inferFullTargets.fixture.ts | 2617 ----------------- src/test/suite/inferFullTargets.test.ts | 18 - src/typings/Types.ts | 5 - 13 files changed, 122 insertions(+), 2791 deletions(-) create mode 100644 src/processTargets/modifiers/WeakContainingScopeStage.ts delete mode 100644 src/test/suite/fixtures/inferFullTargets.fixture.ts delete mode 100644 src/test/suite/inferFullTargets.test.ts diff --git a/src/actions/Rewrap.ts b/src/actions/Rewrap.ts index e7bfabab64..b63d424dcf 100644 --- a/src/actions/Rewrap.ts +++ b/src/actions/Rewrap.ts @@ -1,21 +1,17 @@ -import { flatten, zip } from "lodash"; -import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; -import RawSelectionTarget from "../processTargets/targets/RawSelectionTarget"; +import { flatten } from "lodash"; +import { performEditsAndUpdateRanges } from "../core/updateSelections/updateSelections"; import { Target } from "../typings/target.types"; -import { ActionPreferences, Graph } from "../typings/Types"; +import { Graph, ProcessedTargetsContext } from "../typings/Types"; import displayPendingEditDecorations from "../util/editDisplayUtils"; -import { runForEachEditor } from "../util/targetUtils"; +import { createThatMark, runOnTargetsForEachEditor } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; export default class Rewrap implements Action { - getTargetPreferences: () => ActionPreferences[] = () => [ + getFinalStages = () => [ { - modifiers: [ - { - type: "surroundingPair", - delimiter: "any", - }, - ], + run(context: ProcessedTargetsContext, target: Target): Target[] { + return target.getBoundary(context); + }, }, ]; @@ -28,59 +24,41 @@ export default class Rewrap implements Action { left: string, right: string ): Promise { - const targetInfos = targets.flatMap((target) => { - const boundary = target.boundary; - - if (boundary == null || boundary.length !== 2) { - throw Error("Target must have an opening and closing delimiter"); - } - - return { - editor: target.editor, - boundary: boundary.map( - (edge) => - new RawSelectionTarget({ - editor: target.editor, - contentRange: edge, - isReversed: target.isReversed, - }) - ), - targetSelection: target.contentSelection, - }; - }); + if (targets.length % 2 !== 0) { + throw Error("Target must have an opening and closing delimiter"); + } await displayPendingEditDecorations( - targetInfos.flatMap(({ boundary }) => boundary), + targets, this.graph.editStyles.pendingModification0 ); const thatMark = flatten( - await runForEachEditor( - targetInfos, - (targetInfo) => targetInfo.editor, - async (editor, targetInfos) => { - const edits = targetInfos.flatMap((targetInfo) => - zip(targetInfo.boundary, [left, right]).map(([target, text]) => ({ - editor, - range: target!.contentRange, - text: text!, - })) + await runOnTargetsForEachEditor(targets, async (editor, targets) => { + const edits = targets.map((target, i) => ({ + editor, + range: target.contentRange, + text: i % 2 === 0 ? left : right, + })); + + const thatRanges = []; + const thatTargets = []; + for (let i = 0; i < targets.length; i += 2) { + thatTargets.push(targets[i]); + thatRanges.push( + targets[i].contentRange.union(targets[i + 1].contentRange) ); + } - const [updatedTargetSelections] = - await performEditsAndUpdateSelections( - this.graph.rangeUpdater, - editor, - edits, - [targetInfos.map((targetInfo) => targetInfo.targetSelection)] - ); + const [updatedThatRanges] = await performEditsAndUpdateRanges( + this.graph.rangeUpdater, + editor, + edits, + [thatRanges] + ); - return updatedTargetSelections.map((selection) => ({ - editor, - selection, - })); - } - ) + return createThatMark(thatTargets, updatedThatRanges); + }) ); return { thatMark }; diff --git a/src/actions/ToggleBreakpoint.ts b/src/actions/ToggleBreakpoint.ts index d11766c0d6..fbbec9265c 100644 --- a/src/actions/ToggleBreakpoint.ts +++ b/src/actions/ToggleBreakpoint.ts @@ -6,8 +6,9 @@ import { SourceBreakpoint, Uri, } from "vscode"; +import WeakContainingScopeStage from "../processTargets/modifiers/WeakContainingScopeStage"; import { Target } from "../typings/target.types"; -import { ActionPreferences, Graph } from "../typings/Types"; +import { Graph } from "../typings/Types"; import displayPendingEditDecorations from "../util/editDisplayUtils"; import { createThatMark } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; @@ -22,8 +23,11 @@ function getBreakpoints(uri: Uri, range: Range) { } export default class ToggleBreakpoint implements Action { - getTargetPreferences: () => ActionPreferences[] = () => [ - { modifiers: [{ type: "containingScope", scopeType: "line" }] }, + getFinalStages = () => [ + new WeakContainingScopeStage({ + type: "containingScope", + scopeType: "line", + }), ]; constructor(private graph: Graph) { diff --git a/src/actions/WrapWithSnippet.ts b/src/actions/WrapWithSnippet.ts index c7f117addf..8c5fd613ff 100644 --- a/src/actions/WrapWithSnippet.ts +++ b/src/actions/WrapWithSnippet.ts @@ -1,8 +1,9 @@ import { commands } from "vscode"; import { callFunctionAndUpdateSelections } from "../core/updateSelections/updateSelections"; +import WeakContainingScopeStage from "../processTargets/modifiers/WeakContainingScopeStage"; import { SnippetDefinition } from "../typings/snippet"; import { Target } from "../typings/target.types"; -import { ActionPreferences, Graph } from "../typings/Types"; +import { Graph } from "../typings/Types"; import displayPendingEditDecorations from "../util/editDisplayUtils"; import { ensureSingleEditor } from "../util/targetUtils"; import { @@ -17,7 +18,7 @@ import { Action, ActionReturnValue } from "./actions.types"; export default class WrapWithSnippet implements Action { private snippetParser = new SnippetParser(); - getTargetPreferences(snippetLocation: string): ActionPreferences[] { + getFinalStages(snippetLocation: string) { const [snippetName, placeholderName] = parseSnippetLocation(snippetLocation); @@ -35,14 +36,10 @@ export default class WrapWithSnippet implements Action { } return [ - { - modifiers: [ - { - type: "containingScope", - scopeType: defaultScopeType, - }, - ], - }, + new WeakContainingScopeStage({ + type: "containingScope", + scopeType: defaultScopeType, + }), ]; } diff --git a/src/actions/actions.types.ts b/src/actions/actions.types.ts index 18b2f663db..5c081147b4 100644 --- a/src/actions/actions.types.ts +++ b/src/actions/actions.types.ts @@ -1,5 +1,6 @@ +import { ModifierStage } from "../processTargets/PipelineStages.types"; import { Target } from "../typings/target.types"; -import { ActionPreferences, SelectionWithEditor } from "../typings/Types"; +import { SelectionWithEditor } from "../typings/Types"; export type ActionType = | "callAsFunction" @@ -55,10 +56,10 @@ export interface Action { run(targets: Target[][], ...args: any[]): Promise; /** - * Used to define default values for parts of target during inference. + * Used to define final stages that should be run at the end of the pipeline before the action * @param args Extra args to command */ - getTargetPreferences?(...args: any[]): ActionPreferences[]; + getFinalStages?(...args: any[]): ModifierStage[]; } export type ActionRecord = Record; diff --git a/src/core/commandRunner/CommandRunner.ts b/src/core/commandRunner/CommandRunner.ts index 5314c018e0..18d711c911 100644 --- a/src/core/commandRunner/CommandRunner.ts +++ b/src/core/commandRunner/CommandRunner.ts @@ -39,7 +39,7 @@ export default class CommandRunner { * {@link canonicalizeAndValidateCommand}, primarily for the purpose of * backwards compatibility * 2. Perform inference on targets to fill in details left out using things - * like previous targets and action preferences. For example we would + * like previous targets. For example we would * automatically infer that `"take funk air and bat"` is equivalent to * `"take funk air and funk bat"`. See {@link inferFullTargets} for details * of how this is done. @@ -81,12 +81,7 @@ export default class CommandRunner { throw new Error(`Unknown action ${actionName}`); } - const targetDescriptors = inferFullTargets( - partialTargetDescriptors, - action.getTargetPreferences - ? action.getTargetPreferences(...extraArgs) - : undefined - ); + const targetDescriptors = inferFullTargets(partialTargetDescriptors); if (this.graph.debug.active) { this.graph.debug.log("Full targets:"); @@ -111,6 +106,11 @@ export default class CommandRunner { targetDescriptors ); + const finalStages = + action.getFinalStages != null + ? action.getFinalStages(...extraArgs) + : []; + if (this.graph.testCaseRecorder.isActive()) { const context = { targets: targetDescriptors, diff --git a/src/core/inferFullTargets.ts b/src/core/inferFullTargets.ts index 8361689d20..cf7b8933ef 100644 --- a/src/core/inferFullTargets.ts +++ b/src/core/inferFullTargets.ts @@ -7,7 +7,6 @@ import { RangeTargetDescriptor, TargetDescriptor, } from "../typings/target.types"; -import { ActionPreferences } from "../typings/Types"; /** * Performs inference on the partial targets provided by the user, using @@ -16,51 +15,39 @@ import { ActionPreferences } from "../typings/Types"; * For example, we would automatically infer that `"take funk air and bat"` is * equivalent to `"take funk air and funk bat"`. * @param targets The partial targets which need to be completed by inference. - * @param actionPreferences The preferences provided by the action, so that different actions can provide their own defaults * @returns Target objects fully filled out and ready to be processed by {@link processTargets}. */ export default function inferFullTargets( - targets: PartialTargetDesc[], - actionPreferences?: ActionPreferences[] + targets: PartialTargetDesc[] ): TargetDescriptor[] { - if ( - actionPreferences != null && - targets.length !== actionPreferences.length - ) { - throw new Error("Target length is not equal to action preference length"); - } - return targets.map((target, index) => - inferTarget(target, targets.slice(0, index), actionPreferences?.at(index)) + inferTarget(target, targets.slice(0, index)) ); } function inferTarget( target: PartialTargetDesc, - previousTargets: PartialTargetDesc[], - actionPreferences?: ActionPreferences + previousTargets: PartialTargetDesc[] ): TargetDescriptor { switch (target.type) { case "list": - return inferListTarget(target, previousTargets, actionPreferences); + return inferListTarget(target, previousTargets); case "range": case "primitive": - return inferNonListTarget(target, previousTargets, actionPreferences); + return inferNonListTarget(target, previousTargets); } } function inferListTarget( target: PartialListTargetDesc, - previousTargets: PartialTargetDesc[], - actionPreferences?: ActionPreferences + previousTargets: PartialTargetDesc[] ): TargetDescriptor { return { ...target, elements: target.elements.map((element, index) => inferNonListTarget( element, - previousTargets.concat(target.elements.slice(0, index)), - actionPreferences + previousTargets.concat(target.elements.slice(0, index)) ) ), }; @@ -68,44 +55,36 @@ function inferListTarget( function inferNonListTarget( target: PartialPrimitiveTargetDesc | PartialRangeTargetDesc, - previousTargets: PartialTargetDesc[], - actionPreferences?: ActionPreferences + previousTargets: PartialTargetDesc[] ): PrimitiveTargetDescriptor | RangeTargetDescriptor { switch (target.type) { case "primitive": - return inferPrimitiveTarget(target, previousTargets, actionPreferences); + return inferPrimitiveTarget(target, previousTargets); case "range": - return inferRangeTarget(target, previousTargets, actionPreferences); + return inferRangeTarget(target, previousTargets); } } function inferRangeTarget( target: PartialRangeTargetDesc, - previousTargets: PartialTargetDesc[], - actionPreferences?: ActionPreferences + previousTargets: PartialTargetDesc[] ): RangeTargetDescriptor { return { type: "range", excludeAnchor: target.excludeStart ?? false, excludeActive: target.excludeEnd ?? false, rangeType: target.rangeType ?? "continuous", - anchor: inferPrimitiveTarget( - target.anchor, - previousTargets, - actionPreferences - ), + anchor: inferPrimitiveTarget(target.anchor, previousTargets), active: inferPrimitiveTarget( target.active, - previousTargets.concat(target.anchor), - actionPreferences + previousTargets.concat(target.anchor) ), }; } function inferPrimitiveTarget( target: PartialPrimitiveTargetDesc, - previousTargets: PartialTargetDesc[], - actionPreferences?: ActionPreferences + previousTargets: PartialTargetDesc[] ): PrimitiveTargetDescriptor { if (target.isImplicit) { return { @@ -127,8 +106,7 @@ function inferPrimitiveTarget( const previousModifiers = getPreviousModifiers(previousTargets); - const modifiers = - target.modifiers ?? previousModifiers ?? actionPreferences?.modifiers ?? []; + const modifiers = target.modifiers ?? previousModifiers ?? []; // "bring line to after this" needs to infer line on second target const modifierTypes = [ diff --git a/src/processTargets/modifiers/InteriorStage.ts b/src/processTargets/modifiers/InteriorStage.ts index 0482fbc810..7081d39e31 100644 --- a/src/processTargets/modifiers/InteriorStage.ts +++ b/src/processTargets/modifiers/InteriorStage.ts @@ -10,11 +10,7 @@ export class InteriorOnlyStage implements ModifierStage { constructor(private modifier: InteriorOnlyModifier) {} run(context: ProcessedTargetsContext, target: Target): Target[] { - const interiorTargets = target.getInterior(context); - if (interiorTargets == null) { - throw Error("No available interior"); - } - return interiorTargets; + return target.getInterior(context); } } @@ -22,10 +18,6 @@ export class ExcludeInteriorStage implements ModifierStage { constructor(private modifier: ExcludeInteriorModifier) {} run(context: ProcessedTargetsContext, target: Target): Target[] { - const boundaryTargets = target.getBoundary(context); - if (boundaryTargets == null) { - throw Error("No available boundaries"); - } - return boundaryTargets; + return target.getBoundary(context); } } diff --git a/src/processTargets/modifiers/WeakContainingScopeStage.ts b/src/processTargets/modifiers/WeakContainingScopeStage.ts new file mode 100644 index 0000000000..52dc0c420c --- /dev/null +++ b/src/processTargets/modifiers/WeakContainingScopeStage.ts @@ -0,0 +1,16 @@ +import { ContainingScopeModifier, Target } from "../../typings/target.types"; +import { ProcessedTargetsContext } from "../../typings/Types"; +import getModifierStage from "../getModifierStage"; +import { ModifierStage } from "../PipelineStages.types"; + +export default class implements ModifierStage { + constructor(private nestedModifier: ContainingScopeModifier) {} + + run(context: ProcessedTargetsContext, target: Target): Target[] { + if (target.isWeak) { + const stage = getModifierStage(this.nestedModifier); + return stage.run(context, target); + } + return [target]; + } +} diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index 61ae2a36e7..811a589ee9 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -125,35 +125,36 @@ export default abstract class BaseTarget implements Target { return false; } - getInterior(_context: ProcessedTargetsContext): Target[] | undefined { - if (this.position != null) { - return undefined; + /** If true this target is of weak type and should use inference/upgrade when needed. See {@link WeakTarget} for more info */ + get isWeak() { + return false; + } + + getInterior(_context: ProcessedTargetsContext): Target[] { + if (this.state.interiorRange == null || this.position != null) { + throw Error("No available interior"); } - return this.state.interiorRange != null - ? [ - new WeakTarget({ - editor: this.editor, - isReversed: this.isReversed, - contentRange: this.state.interiorRange, - }), - ] - : undefined; + return [ + new WeakTarget({ + editor: this.editor, + isReversed: this.isReversed, + contentRange: this.state.interiorRange, + }), + ]; } - getBoundary(_context: ProcessedTargetsContext): Target[] | undefined { - if (this.position != null) { - return undefined; + getBoundary(_context: ProcessedTargetsContext): Target[] { + if (this.state.boundary == null || this.position != null) { + throw Error("No available boundaries"); } - return this.state.boundary != null - ? this.state.boundary.map( - (contentRange) => - new WeakTarget({ - editor: this.editor, - isReversed: this.isReversed, - contentRange, - }) - ) - : undefined; + return this.state.boundary.map( + (contentRange) => + new WeakTarget({ + editor: this.editor, + isReversed: this.isReversed, + contentRange, + }) + ); } get contentRange(): Range { diff --git a/src/processTargets/targets/WeakTarget.ts b/src/processTargets/targets/WeakTarget.ts index be69e8d932..2066aa3eb8 100644 --- a/src/processTargets/targets/WeakTarget.ts +++ b/src/processTargets/targets/WeakTarget.ts @@ -22,6 +22,10 @@ export default class WeakTarget extends BaseTarget { }); } + get isWeak() { + return true; + } + getInterior(context: ProcessedTargetsContext): Target[] { return this.processSurroundingPair(context).flatMap( (surroundingPairTarget) => surroundingPairTarget.getInterior(context)! diff --git a/src/test/suite/fixtures/inferFullTargets.fixture.ts b/src/test/suite/fixtures/inferFullTargets.fixture.ts deleted file mode 100644 index 16e9d91fba..0000000000 --- a/src/test/suite/fixtures/inferFullTargets.fixture.ts +++ /dev/null @@ -1,2617 +0,0 @@ -// @ts-nocheck -import { ActionPreferences, InferenceContext } from "../../../typings/Types"; -import { - PartialTargetDesc, - TargetDescriptor, -} from "../../../typings/target.types"; - -interface FixtureInput { - context: InferenceContext; - partialTargets: PartialTargetDesc[]; - actionPreferences: ActionPreferences[]; -} - -interface Fixture { - input: FixtureInput; - expectedOutput: TargetDescriptor[]; -} - -const fixture: Fixture[] = [ - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "f", - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "f", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "identity", - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "primitive", - mark: { - type: "cursor", - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "identity", - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "primitive", - modifier: { - type: "containingScope", - scopeType: "namedFunction", - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "containingScope", - scopeType: "namedFunction", - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "primitive", - selectionType: "line", - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "line", - position: "contents", - modifier: { - type: "identity", - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "range", - anchor: { - type: "primitive", - }, - active: { - type: "primitive", - position: "end", - modifier: { - type: "containingScope", - scopeType: "namedFunction", - }, - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "range", - anchor: { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "identity", - }, - }, - active: { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "token", - position: "end", - modifier: { - type: "containingScope", - scopeType: "namedFunction", - }, - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "range", - anchor: { - type: "primitive", - selectionType: "line", - }, - active: { - type: "primitive", - position: "end", - modifier: { - type: "containingScope", - scopeType: "namedFunction", - }, - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "range", - anchor: { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "line", - position: "contents", - modifier: { - type: "identity", - }, - }, - active: { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "line", - position: "end", - modifier: { - type: "containingScope", - scopeType: "namedFunction", - }, - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "range", - anchor: { - type: "primitive", - modifier: { - type: "containingScope", - scopeType: "namedFunction", - }, - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "g", - }, - }, - active: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "h", - }, - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "range", - anchor: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "g", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "containingScope", - scopeType: "namedFunction", - }, - }, - active: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "h", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "containingScope", - scopeType: "namedFunction", - }, - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "range", - anchor: { - type: "primitive", - }, - active: { - type: "primitive", - selectionType: "paragraph", - mark: { - type: "decoratedSymbol", - symbolColor: "red", - character: "h", - }, - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "range", - anchor: { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "paragraph", - position: "contents", - modifier: { - type: "identity", - }, - }, - active: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "red", - character: "h", - }, - selectionType: "paragraph", - position: "contents", - modifier: { - type: "identity", - }, - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "primitive", - selectionType: "line", - modifier: { - type: "containingScope", - scopeType: "class", - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "line", - position: "contents", - modifier: { - type: "containingScope", - scopeType: "class", - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "primitive", - selectionType: "line", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "i", - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "i", - }, - selectionType: "line", - position: "contents", - modifier: { - type: "identity", - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "primitive", - selectionType: "line", - modifier: { - type: "surroundingPair", - delimiter: "parentheses", - includePairDelimiter: false, - }, - mark: { - type: "cursor", - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "line", - position: "contents", - modifier: { - type: "surroundingPair", - delimiter: "parentheses", - includePairDelimiter: false, - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "primitive", - selectionType: "line", - modifier: { - type: "surroundingPair", - delimiter: "parentheses", - includePairDelimiter: false, - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "line", - position: "contents", - modifier: { - type: "surroundingPair", - delimiter: "parentheses", - includePairDelimiter: false, - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: true, - clipboardContents: "hello", - }, - partialTargets: [ - { - type: "primitive", - mark: { - type: "cursor", - }, - }, - ], - actionPreferences: [{ position: "after" }], - }, - expectedOutput: [ - { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "token", - position: "after", - modifier: { - type: "identity", - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: true, - clipboardContents: "hello", - }, - partialTargets: [ - { - type: "primitive", - position: "before", - selectionType: "line", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "f", - }, - }, - ], - actionPreferences: [{ position: "after" }], - }, - expectedOutput: [ - { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "f", - }, - selectionType: "line", - position: "before", - modifier: { - type: "identity", - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: true, - clipboardContents: "hello", - }, - partialTargets: [ - { - type: "primitive", - modifier: { - type: "surroundingPair", - delimiter: "parentheses", - includePairDelimiter: false, - }, - }, - ], - actionPreferences: [{ position: "after" }], - }, - expectedOutput: [ - { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "surroundingPair", - delimiter: "parentheses", - includePairDelimiter: false, - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: true, - clipboardContents: "hello", - }, - partialTargets: [ - { - type: "primitive", - modifier: { - type: "surroundingPair", - delimiter: "parentheses", - includePairDelimiter: false, - }, - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "f", - }, - }, - ], - actionPreferences: [{ position: "after" }], - }, - expectedOutput: [ - { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "f", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "surroundingPair", - delimiter: "parentheses", - includePairDelimiter: false, - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: true, - clipboardContents: "hello", - }, - partialTargets: [ - { - type: "primitive", - selectionType: "line", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "h", - }, - }, - ], - actionPreferences: [{ position: "after" }], - }, - expectedOutput: [ - { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "h", - }, - selectionType: "line", - position: "after", - modifier: { - type: "identity", - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: true, - clipboardContents: "hello", - }, - partialTargets: [ - { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "h", - }, - }, - ], - actionPreferences: [{ position: "after" }], - }, - expectedOutput: [ - { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "h", - }, - selectionType: "token", - position: "after", - modifier: { - type: "identity", - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: true, - clipboardContents: "hello\n", - }, - partialTargets: [ - { - type: "primitive", - mark: { - type: "cursor", - }, - }, - ], - actionPreferences: [{ position: "after" }], - }, - expectedOutput: [ - { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "line", - position: "after", - modifier: { - type: "identity", - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: true, - clipboardContents: "\nhello\n", - }, - partialTargets: [ - { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "f", - }, - }, - ], - actionPreferences: [{ position: "after" }], - }, - expectedOutput: [ - { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "f", - }, - selectionType: "paragraph", - position: "after", - modifier: { - type: "identity", - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: true, - clipboardContents: "\nhello\n", - }, - partialTargets: [ - { - type: "primitive", - mark: { - type: "cursor", - }, - }, - ], - actionPreferences: [{ position: "after" }], - }, - expectedOutput: [ - { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "paragraph", - position: "after", - modifier: { - type: "identity", - }, - }, - ], - }, - { - input: { - context: { - selectionContents: ["hello"], - isPaste: true, - clipboardContents: "\nhello\n", - }, - partialTargets: [ - { - type: "primitive", - mark: { - type: "cursor", - }, - }, - ], - actionPreferences: [{ position: "after" }], - }, - expectedOutput: [ - { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "paragraph", - position: "contents", - modifier: { - type: "identity", - }, - }, - ], - }, - { - input: { - context: { - selectionContents: ["hello\n"], - isPaste: false, - }, - partialTargets: [ - { - type: "primitive", - mark: { - type: "cursor", - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "line", - position: "contents", - modifier: { - type: "identity", - }, - }, - ], - }, - { - input: { - context: { - selectionContents: ["\nhello\n"], - isPaste: false, - }, - partialTargets: [ - { - type: "primitive", - mark: { - type: "cursor", - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "paragraph", - position: "contents", - modifier: { - type: "identity", - }, - }, - ], - }, - { - input: { - context: { - selectionContents: ["hello"], - isPaste: false, - }, - partialTargets: [ - { - type: "primitive", - mark: { - type: "cursor", - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "identity", - }, - }, - ], - }, - { - input: { - context: { - selectionContents: ["hello"], - isPaste: false, - }, - partialTargets: [ - { - type: "list", - elements: [ - { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "f", - }, - }, - { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "g", - }, - }, - ], - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "list", - elements: [ - { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "f", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "identity", - }, - }, - { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "g", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "identity", - }, - }, - ], - }, - ], - }, - { - input: { - context: { - selectionContents: ["hello"], - isPaste: false, - }, - partialTargets: [ - { - type: "list", - elements: [ - { - type: "primitive", - selectionType: "line", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "f", - }, - }, - { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "g", - }, - }, - ], - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "list", - elements: [ - { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "f", - }, - selectionType: "line", - position: "contents", - modifier: { - type: "identity", - }, - }, - { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "g", - }, - selectionType: "line", - position: "contents", - modifier: { - type: "identity", - }, - }, - ], - }, - ], - }, - { - input: { - context: { - selectionContents: ["hello"], - isPaste: false, - }, - partialTargets: [ - { - type: "range", - anchor: { - type: "primitive", - selectionType: "line", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "f", - }, - }, - active: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "g", - }, - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "range", - anchor: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "f", - }, - selectionType: "line", - position: "contents", - modifier: { - type: "identity", - }, - }, - active: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "g", - }, - selectionType: "line", - position: "contents", - modifier: { - type: "identity", - }, - }, - }, - ], - }, - { - input: { - context: { - selectionContents: ["hello"], - isPaste: false, - }, - partialTargets: [ - { - type: "list", - elements: [ - { - type: "primitive", - modifier: { - type: "containingScope", - scopeType: "namedFunction", - }, - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "g", - }, - }, - { - type: "range", - anchor: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "h", - }, - }, - active: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "e", - }, - }, - }, - ], - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "list", - elements: [ - { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "g", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "containingScope", - scopeType: "namedFunction", - }, - }, - { - type: "range", - anchor: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "h", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "containingScope", - scopeType: "namedFunction", - }, - }, - active: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "e", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "containingScope", - scopeType: "namedFunction", - }, - }, - }, - ], - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "primitive", - modifier: { - type: "subpiece", - pieceType: "subtoken", - startIndex: 3, - endIndex: 4, - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "subpiece", - pieceType: "subtoken", - startIndex: 3, - endIndex: 4, - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "primitive", - modifier: { - type: "subpiece", - pieceType: "subtoken", - startIndex: 1, - endIndex: 3, - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "subpiece", - pieceType: "subtoken", - startIndex: 1, - endIndex: 3, - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "primitive", - modifier: { - type: "subpiece", - pieceType: "subtoken", - startIndex: 1, - endIndex: 2, - }, - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "f", - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "f", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "subpiece", - pieceType: "subtoken", - startIndex: 1, - endIndex: 2, - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "g", - }, - modifier: { - type: "subpiece", - pieceType: "subtoken", - startIndex: 2, - endIndex: 3, - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "g", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "subpiece", - pieceType: "subtoken", - startIndex: 2, - endIndex: 3, - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "primitive", - modifier: { - type: "subpiece", - pieceType: "character", - startIndex: 2, - endIndex: 6, - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "subpiece", - pieceType: "character", - startIndex: 2, - endIndex: 6, - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: true, - clipboardContents: "hello", - }, - partialTargets: [ - { - type: "primitive", - position: "after", - modifier: { - type: "subpiece", - pieceType: "subtoken", - startIndex: 2, - endIndex: 3, - }, - }, - ], - actionPreferences: [{ position: "after" }], - }, - expectedOutput: [ - { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "token", - position: "after", - modifier: { - type: "subpiece", - pieceType: "subtoken", - startIndex: 2, - endIndex: 3, - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "primitive", - modifier: { - type: "subpiece", - pieceType: "character", - startIndex: 3, - endIndex: 4, - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "subpiece", - pieceType: "character", - startIndex: 3, - endIndex: 4, - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "f", - }, - modifier: { - type: "subpiece", - pieceType: "character", - startIndex: 3, - endIndex: 4, - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "f", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "subpiece", - pieceType: "character", - startIndex: 3, - endIndex: 4, - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "list", - elements: [ - { - type: "primitive", - selectionType: "line", - modifier: { - type: "containingScope", - scopeType: "namedFunction", - }, - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "h", - }, - }, - { - type: "range", - anchor: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "g", - }, - }, - active: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "f", - }, - }, - }, - ], - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "list", - elements: [ - { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "h", - }, - selectionType: "line", - position: "contents", - modifier: { - type: "containingScope", - scopeType: "namedFunction", - }, - }, - { - type: "range", - anchor: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "g", - }, - selectionType: "line", - position: "contents", - modifier: { - type: "containingScope", - scopeType: "namedFunction", - }, - }, - active: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "f", - }, - selectionType: "line", - position: "contents", - modifier: { - type: "containingScope", - scopeType: "namedFunction", - }, - }, - }, - ], - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "list", - elements: [ - { - type: "range", - anchor: { - type: "primitive", - selectionType: "line", - modifier: { - type: "containingScope", - scopeType: "namedFunction", - }, - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "g", - }, - }, - active: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "h", - }, - }, - }, - { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "e", - }, - }, - ], - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "list", - elements: [ - { - type: "range", - anchor: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "g", - }, - selectionType: "line", - position: "contents", - modifier: { - type: "containingScope", - scopeType: "namedFunction", - }, - }, - active: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "h", - }, - selectionType: "line", - position: "contents", - modifier: { - type: "containingScope", - scopeType: "namedFunction", - }, - }, - }, - { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "e", - }, - selectionType: "line", - position: "contents", - modifier: { - type: "containingScope", - scopeType: "namedFunction", - }, - }, - ], - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "range", - anchor: { - type: "primitive", - }, - active: { - type: "primitive", - position: "end", - selectionType: "line", - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "range", - anchor: { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "identity", - }, - }, - active: { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "line", - position: "end", - modifier: { - type: "identity", - }, - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "range", - anchor: { - type: "primitive", - selectionType: "line", - }, - active: { - type: "primitive", - position: "end", - selectionType: "paragraph", - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "range", - anchor: { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "line", - position: "contents", - modifier: { - type: "identity", - }, - }, - active: { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "paragraph", - position: "end", - modifier: { - type: "identity", - }, - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "range", - anchor: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "f", - }, - }, - active: { - type: "primitive", - position: "end", - selectionType: "line", - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "range", - anchor: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "f", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "identity", - }, - }, - active: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "f", - }, - selectionType: "line", - position: "end", - modifier: { - type: "identity", - }, - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "range", - anchor: { - type: "primitive", - selectionType: "line", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "g", - }, - }, - active: { - type: "primitive", - position: "end", - modifier: { - type: "containingScope", - scopeType: "namedFunction", - }, - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "range", - anchor: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "g", - }, - selectionType: "line", - position: "contents", - modifier: { - type: "identity", - }, - }, - active: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "g", - }, - selectionType: "line", - position: "end", - modifier: { - type: "containingScope", - scopeType: "namedFunction", - }, - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "range", - anchor: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "g", - }, - }, - active: { - type: "primitive", - modifier: { - type: "surroundingPair", - delimiter: "doubleQuotes", - includePairDelimiter: true, - }, - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "h", - }, - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "range", - anchor: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "g", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "identity", - }, - }, - active: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "h", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "surroundingPair", - delimiter: "doubleQuotes", - includePairDelimiter: true, - }, - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "range", - anchor: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "g", - }, - }, - active: { - type: "primitive", - modifier: { - type: "containingScope", - scopeType: "namedFunction", - }, - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "f", - }, - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "range", - anchor: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "g", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "identity", - }, - }, - active: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "f", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "containingScope", - scopeType: "namedFunction", - }, - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "range", - anchor: { - type: "primitive", - }, - active: { - type: "primitive", - modifier: { - type: "containingScope", - scopeType: "namedFunction", - }, - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "f", - }, - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "range", - anchor: { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "containingScope", - scopeType: "namedFunction", - }, - }, - active: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "f", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "containingScope", - scopeType: "namedFunction", - }, - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "range", - anchor: { - type: "primitive", - }, - active: { - type: "primitive", - modifier: { - type: "surroundingPair", - delimiter: "doubleQuotes", - includePairDelimiter: true, - }, - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "f", - }, - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "range", - anchor: { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "identity", - }, - }, - active: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "f", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "surroundingPair", - delimiter: "doubleQuotes", - includePairDelimiter: true, - }, - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "range", - anchor: { - type: "primitive", - modifier: { - type: "surroundingPair", - delimiter: "doubleQuotes", - includePairDelimiter: false, - }, - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "f", - }, - }, - active: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "g", - }, - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "range", - anchor: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "f", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "surroundingPair", - delimiter: "doubleQuotes", - includePairDelimiter: false, - }, - }, - active: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "g", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "identity", - }, - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "range", - anchor: { - type: "primitive", - modifier: { - type: "surroundingPair", - delimiter: "singleQuotes", - includePairDelimiter: false, - }, - }, - active: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "h", - }, - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "range", - anchor: { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "surroundingPair", - delimiter: "singleQuotes", - includePairDelimiter: false, - }, - }, - active: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "h", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "identity", - }, - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "range", - anchor: { - type: "primitive", - selectionType: "line", - modifier: { - type: "surroundingPair", - delimiter: "parentheses", - includePairDelimiter: false, - }, - }, - active: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "g", - }, - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "range", - anchor: { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "line", - position: "contents", - modifier: { - type: "surroundingPair", - delimiter: "parentheses", - includePairDelimiter: false, - }, - }, - active: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "g", - }, - selectionType: "line", - position: "contents", - modifier: { - type: "identity", - }, - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "range", - anchor: { - type: "primitive", - selectionType: "line", - modifier: { - type: "containingScope", - scopeType: "namedFunction", - }, - }, - active: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "g", - }, - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "range", - anchor: { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "line", - position: "contents", - modifier: { - type: "containingScope", - scopeType: "namedFunction", - }, - }, - active: { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "g", - }, - selectionType: "line", - position: "contents", - modifier: { - type: "containingScope", - scopeType: "namedFunction", - }, - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "primitive", - selectionType: "line", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "g", - }, - modifier: { - type: "matchingPairSymbol", - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "g", - }, - selectionType: "line", - position: "contents", - modifier: { - type: "matchingPairSymbol", - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "primitive", - modifier: { - type: "matchingPairSymbol", - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "matchingPairSymbol", - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: false, - }, - partialTargets: [ - { - type: "primitive", - selectionType: "line", - modifier: { - type: "matchingPairSymbol", - }, - }, - ], - actionPreferences: [{}], - }, - expectedOutput: [ - { - type: "primitive", - mark: { - type: "cursor", - }, - selectionType: "line", - position: "contents", - modifier: { - type: "matchingPairSymbol", - }, - }, - ], - }, - { - input: { - context: { - selectionContents: [""], - isPaste: true, - clipboardContents: "hello", - }, - partialTargets: [ - { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "(", - }, - modifier: { - type: "matchingPairSymbol", - }, - }, - ], - actionPreferences: [{ position: "after" }], - }, - expectedOutput: [ - { - type: "primitive", - mark: { - type: "decoratedSymbol", - symbolColor: "default", - character: "(", - }, - selectionType: "token", - position: "contents", - modifier: { - type: "matchingPairSymbol", - }, - }, - ], - }, -]; - -export default fixture; diff --git a/src/test/suite/inferFullTargets.test.ts b/src/test/suite/inferFullTargets.test.ts deleted file mode 100644 index 052237e6e8..0000000000 --- a/src/test/suite/inferFullTargets.test.ts +++ /dev/null @@ -1,18 +0,0 @@ -import * as assert from "assert"; - -import inferFullTargets from "../../core/inferFullTargets"; -import fixture from "./fixtures/inferFullTargets.fixture"; - -/* - * FIXME: These tests are outdated and thus disabled for now - */ -suite.skip("inferFullTargets", () => { - fixture.forEach(({ input, expectedOutput }, index) => { - test(`inferFullTargets ${index}`, () => { - assert.deepStrictEqual( - inferFullTargets(input.partialTargets, input.actionPreferences), - expectedOutput - ); - }); - }); -}); diff --git a/src/typings/Types.ts b/src/typings/Types.ts index c291f13e96..9fbf726970 100644 --- a/src/typings/Types.ts +++ b/src/typings/Types.ts @@ -12,7 +12,6 @@ import { Snippets } from "../core/Snippets"; import { RangeUpdater } from "../core/updateSelections/RangeUpdater"; import { TestCaseRecorder } from "../testUtil/TestCaseRecorder"; import { CommandServerApi } from "../util/getExtensionApi"; -import { Modifier } from "./target.types"; import { FullRangeInfo } from "./updateSelections"; /** @@ -75,10 +74,6 @@ export interface SelectionContext { interiorRange?: vscode.Range; } -export interface ActionPreferences { - modifiers: Modifier[]; -} - export type SelectionWithEditorWithContext = { selection: SelectionWithEditor; context: SelectionContext; From f68edd8871647937348fa65a7ccf4f44fb8a766d Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 23 May 2022 18:39:36 +0200 Subject: [PATCH 161/314] Added final stages to process targets --- src/core/commandRunner/CommandRunner.ts | 11 ++++++----- src/processTargets/processTargets.ts | 11 +++++++---- src/typings/Types.ts | 2 ++ 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/core/commandRunner/CommandRunner.ts b/src/core/commandRunner/CommandRunner.ts index 18d711c911..7bb8bf5846 100644 --- a/src/core/commandRunner/CommandRunner.ts +++ b/src/core/commandRunner/CommandRunner.ts @@ -88,7 +88,13 @@ export default class CommandRunner { this.graph.debug.log(JSON.stringify(targetDescriptors, null, 3)); } + const finalStages = + action.getFinalStages != null + ? action.getFinalStages(...extraArgs) + : []; + const processedTargetsContext: ProcessedTargetsContext = { + finalStages, currentSelections: vscode.window.activeTextEditor?.selections.map((selection) => ({ selection, @@ -106,11 +112,6 @@ export default class CommandRunner { targetDescriptors ); - const finalStages = - action.getFinalStages != null - ? action.getFinalStages(...extraArgs) - : []; - if (this.graph.testCaseRecorder.isActive()) { const context = { targets: targetDescriptors, diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index 07275c6783..02f4972dcc 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -241,15 +241,18 @@ function processPrimitiveTarget( const markStage = getMarkStage(target.mark); let targets = markStage.run(context); - for (let i = target.modifiers.length - 1; i > -1; --i) { - const modifier = target.modifiers[i]; - const stage = getModifierStage(modifier); + const modifierStages = [ + ...target.modifiers.reverse().map(getModifierStage), + ...context.finalStages, + ]; + + modifierStages.forEach((stage) => { const stageTargets: Target[] = []; for (const target of targets) { stageTargets.push(...stage.run(context, target)); } targets = stageTargets; - } + }); return targets; } diff --git a/src/typings/Types.ts b/src/typings/Types.ts index 9fbf726970..2065e994dc 100644 --- a/src/typings/Types.ts +++ b/src/typings/Types.ts @@ -10,6 +10,7 @@ import HatTokenMap from "../core/HatTokenMap"; import { ReadOnlyHatMap } from "../core/IndividualHatMap"; import { Snippets } from "../core/Snippets"; import { RangeUpdater } from "../core/updateSelections/RangeUpdater"; +import { ModifierStage } from "../processTargets/PipelineStages.types"; import { TestCaseRecorder } from "../testUtil/TestCaseRecorder"; import { CommandServerApi } from "../util/getExtensionApi"; import { FullRangeInfo } from "./updateSelections"; @@ -23,6 +24,7 @@ export interface Token extends FullRangeInfo { } export interface ProcessedTargetsContext { + finalStages: ModifierStage[]; currentSelections: SelectionWithEditor[]; currentEditor: vscode.TextEditor | undefined; hatTokenMap: ReadOnlyHatMap; From f73e669e28a3462cf78924c01a69463d7d6ce83a Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 23 May 2022 18:57:18 +0200 Subject: [PATCH 162/314] Cleanup --- src/processTargets/targets/ScopeTypeTarget.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/processTargets/targets/ScopeTypeTarget.ts b/src/processTargets/targets/ScopeTypeTarget.ts index 860e46c429..c5c3c77b39 100644 --- a/src/processTargets/targets/ScopeTypeTarget.ts +++ b/src/processTargets/targets/ScopeTypeTarget.ts @@ -1,4 +1,4 @@ -import { Range, TextEditor } from "vscode"; +import { Range } from "vscode"; import { EditNewLineContext, RemovalRange, From b46392f55102d0405e7cbc977d40b07f02f1f2f3 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Mon, 23 May 2022 19:27:16 +0200 Subject: [PATCH 163/314] Converted command action into object with associated arguments --- cursorless-talon/src/command.py | 6 +++-- src/core/commandRunner/CommandRunner.ts | 7 +++--- src/core/commandRunner/command.types.ts | 24 +++++++++++-------- .../canonicalizeAndValidateCommand.ts | 11 +++++---- .../upgradeV1ToV2/upgradeV1ToV2.ts | 6 +++-- src/testUtil/TestCase.ts | 4 ++-- src/testUtil/cleanUpTestCaseCommand.ts | 13 +++++----- 7 files changed, 39 insertions(+), 32 deletions(-) diff --git a/cursorless-talon/src/command.py b/cursorless-talon/src/command.py index 757c78a7a4..f596fa8006 100644 --- a/cursorless-talon/src/command.py +++ b/cursorless-talon/src/command.py @@ -129,9 +129,11 @@ def construct_cursorless_command_argument( return { "version": 2, "spokenForm": get_spoken_form(), - "action": action, + "action": { + "name": action, + "args": args, + }, "targets": targets, - "extraArgs": args, "usePrePhraseSnapshot": use_pre_phrase_snapshot, } diff --git a/src/core/commandRunner/CommandRunner.ts b/src/core/commandRunner/CommandRunner.ts index 7bb8bf5846..96da4a40e2 100644 --- a/src/core/commandRunner/CommandRunner.ts +++ b/src/core/commandRunner/CommandRunner.ts @@ -65,9 +65,8 @@ export default class CommandRunner { const commandComplete = canonicalizeAndValidateCommand(command); const { spokenForm, - action: actionName, + action: { name: actionName, args: actionArgs }, targets: partialTargetDescriptors, - extraArgs, usePrePhraseSnapshot, } = commandComplete; @@ -90,7 +89,7 @@ export default class CommandRunner { const finalStages = action.getFinalStages != null - ? action.getFinalStages(...extraArgs) + ? action.getFinalStages(...actionArgs) : []; const processedTargetsContext: ProcessedTargetsContext = { @@ -130,7 +129,7 @@ export default class CommandRunner { returnValue, thatMark: newThatMark, sourceMark: newSourceMark, - } = await action.run(targets, ...extraArgs); + } = await action.run(targets, ...actionArgs); this.thatMark.set(newThatMark); this.sourceMark.set(newSourceMark); diff --git a/src/core/commandRunner/command.types.ts b/src/core/commandRunner/command.types.ts index fdceaffd6b..f4767b24e4 100644 --- a/src/core/commandRunner/command.types.ts +++ b/src/core/commandRunner/command.types.ts @@ -6,7 +6,7 @@ import { } from "../commandVersionUpgrades/upgradeV1ToV2/commandV1.types"; export type CommandComplete = Required> & - Pick; + Pick & { action: Required }; export const LATEST_VERSION = 2 as const; @@ -16,6 +16,18 @@ export type CommandLatest = Command & { export type Command = CommandV0 | CommandV1 | CommandV2; +interface ActionCommand { + /** + * The action to run + */ + name: ActionType; + + /** + * A list of arguments expected by the given action. + */ + args?: unknown[]; +} + export interface CommandV2 { /** * The version number of the command API @@ -35,19 +47,11 @@ export interface CommandV2 { */ usePrePhraseSnapshot: boolean; - /** - * The action to run - */ - action: ActionType; + action: ActionCommand; /** * A list of targets expected by the action. Inference will be run on the * targets */ targets: PartialTargetDesc[]; - - /** - * A list of extra arguments expected by the given action. - */ - extraArgs?: unknown[]; } diff --git a/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts b/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts index 815114d1ab..f246e3e709 100644 --- a/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts +++ b/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts @@ -30,15 +30,14 @@ export function canonicalizeAndValidateCommand( ): CommandComplete { const commandUpgraded = upgradeCommand(command); const { - action: inputActionName, + action, targets: inputPartialTargets, - extraArgs: inputExtraArgs = [], usePrePhraseSnapshot = false, version, ...rest } = commandUpgraded; - const actionName = canonicalizeActionName(inputActionName); + const actionName = canonicalizeActionName(action.name); const partialTargets = canonicalizeTargets(inputPartialTargets); validateCommand(actionName, partialTargets); @@ -46,9 +45,11 @@ export function canonicalizeAndValidateCommand( return { ...rest, version: LATEST_VERSION, - action: actionName, + action: { + name: actionName, + args: action.args ?? [], + }, targets: partialTargets, - extraArgs: inputExtraArgs, usePrePhraseSnapshot, }; } diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts index 7ace71b1d8..800ad7cbef 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts @@ -20,9 +20,11 @@ import { upgradeStrictHere } from "./upgradeStrictHere"; export function upgradeV1ToV2(command: CommandV1): CommandV2 { return { spokenForm: command.spokenForm, - action: command.action as ActionType, + action: { + name: command.action as ActionType, + args: command.extraArgs, + }, targets: upgradeTargets(command.targets), - extraArgs: command.extraArgs, usePrePhraseSnapshot: command.usePrePhraseSnapshot ?? false, version: 2, }; diff --git a/src/testUtil/TestCase.ts b/src/testUtil/TestCase.ts index d4f4ee09cd..28868b0dc5 100644 --- a/src/testUtil/TestCase.ts +++ b/src/testUtil/TestCase.ts @@ -107,7 +107,7 @@ export class TestCase { private getExcludedFields(context?: { initialSnapshot?: boolean }) { const excludableFields = { - clipboard: !["copy", "paste"].includes(this.command.action), + clipboard: !["copy", "paste"].includes(this.command.action.name), thatMark: context?.initialSnapshot && !this.fullTargets.some((target) => @@ -124,7 +124,7 @@ export class TestCase { "scrollToBottom", "scrollToCenter", "scrollToTop", - ].includes(this.command.action), + ].includes(this.command.action.name), }; return Object.keys(excludableFields).filter( diff --git a/src/testUtil/cleanUpTestCaseCommand.ts b/src/testUtil/cleanUpTestCaseCommand.ts index f61acd841d..63edfa6083 100644 --- a/src/testUtil/cleanUpTestCaseCommand.ts +++ b/src/testUtil/cleanUpTestCaseCommand.ts @@ -3,15 +3,14 @@ import { TestCaseCommand } from "./TestCase"; export function cleanUpTestCaseCommand( command: TestCaseCommand ): TestCaseCommand { - const { extraArgs, ...rest } = command; + const { action, ...rest } = command; + const { args } = action; return { ...rest, - extraArgs: - extraArgs == null - ? undefined - : extraArgs.length === 0 - ? undefined - : extraArgs, + action: { + ...action, + args: args == null ? undefined : args.length === 0 ? undefined : args, + }, }; } From 2c125e632642048eb4c802445d7e77f6a23dbefe Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Mon, 23 May 2022 21:39:31 +0100 Subject: [PATCH 164/314] Switch to complex scope types --- .../src/modifiers/containing_scope.py | 4 +- cursorless-talon/src/modifiers/sub_token.py | 6 +- .../src/modifiers/surrounding_pair.py | 18 +++-- src/actions/CopyLines.ts | 2 +- src/actions/Rewrap.ts | 65 +++++++++---------- src/actions/ToggleBreakpoint.ts | 9 +-- src/actions/WrapWithSnippet.ts | 4 +- .../canonicalizeAndValidateCommand.ts | 6 +- .../canonicalizeTargets.ts | 9 +-- .../upgradeV1ToV2/upgradeV1ToV2.ts | 37 +++++++++-- src/languages/clojure.ts | 4 +- src/languages/cpp.ts | 4 +- src/languages/csharp.ts | 4 +- src/languages/getNodeMatcher.ts | 8 +-- src/languages/go.ts | 4 +- src/languages/html.ts | 4 +- src/languages/java.ts | 4 +- src/languages/json.ts | 4 +- src/languages/markdown.ts | 4 +- src/languages/php.ts | 4 +- src/languages/python.ts | 4 +- src/languages/ruby.ts | 4 +- src/languages/scala.ts | 4 +- src/languages/scss.ts | 4 +- src/languages/typescript.ts | 4 +- src/processTargets/getModifierStage.ts | 45 +++++++++---- src/processTargets/modifiers/InteriorStage.ts | 9 ++- ...eStage.ts => OrdinalRangeSubTokenStage.ts} | 22 +++++-- .../modifiers/SurroundingPairStage.ts | 11 ++-- .../commonWeakContainingScopeStages.ts | 11 ++++ .../ContainingSyntaxScopeStage.ts | 17 ++++- .../modifiers/scopeTypeStages/RegexStage.ts | 21 ++++-- .../modifiers/surroundingPair/index.ts | 4 +- src/processTargets/processTargets.ts | 4 +- src/processTargets/targets/BaseTarget.ts | 17 +++-- src/processTargets/targets/DocumentTarget.ts | 2 +- src/processTargets/targets/LineTarget.ts | 2 +- .../targets/NotebookCellTarget.ts | 2 +- src/processTargets/targets/ParagraphTarget.ts | 2 +- src/processTargets/targets/ScopeTypeTarget.ts | 8 +-- src/processTargets/targets/TokenTarget.ts | 2 +- src/processTargets/targets/WeakTarget.ts | 27 -------- src/typings/snippet.ts | 4 +- src/typings/target.types.ts | 24 ++++--- src/util/nodeMatchers.ts | 10 +-- 45 files changed, 275 insertions(+), 193 deletions(-) rename src/processTargets/modifiers/{SubPieceStage.ts => OrdinalRangeSubTokenStage.ts} (87%) create mode 100644 src/processTargets/modifiers/commonWeakContainingScopeStages.ts diff --git a/cursorless-talon/src/modifiers/containing_scope.py b/cursorless-talon/src/modifiers/containing_scope.py index da1829103c..e8525be1a6 100644 --- a/cursorless-talon/src/modifiers/containing_scope.py +++ b/cursorless-talon/src/modifiers/containing_scope.py @@ -62,7 +62,9 @@ def cursorless_containing_scope(m) -> dict[str, Any]: """Expand to containing scope""" return { "type": "everyScope" if m[0] == "every" else "containingScope", - "scopeType": m.cursorless_scope_type, + "scopeType": { + "type": m.cursorless_scope_type, + }, } diff --git a/cursorless-talon/src/modifiers/sub_token.py b/cursorless-talon/src/modifiers/sub_token.py index 88e5627b5d..419d2a75a1 100644 --- a/cursorless-talon/src/modifiers/sub_token.py +++ b/cursorless-talon/src/modifiers/sub_token.py @@ -60,7 +60,9 @@ def cursorless_subtoken_scope(m) -> dict[str, Any]: except AttributeError: range = m.cursorless_first_last_range return { - "type": "subpiece", - "pieceType": m.cursorless_subtoken_scope_type, + "type": "ordinalRange", + "scopeType": { + "type": m.cursorless_subtoken_scope_type, + }, **range, } diff --git a/cursorless-talon/src/modifiers/surrounding_pair.py b/cursorless-talon/src/modifiers/surrounding_pair.py index 24c866869e..7dbd359263 100644 --- a/cursorless-talon/src/modifiers/surrounding_pair.py +++ b/cursorless-talon/src/modifiers/surrounding_pair.py @@ -23,6 +23,9 @@ ) +import contextlib + + @mod.capture( rule=( " |" @@ -43,20 +46,21 @@ def cursorless_surrounding_pair_scope_type(m) -> str: rule="[{user.cursorless_delimiter_force_direction}] " ) def cursorless_surrounding_pair(m) -> dict[str, Any]: - """Surrounding pair modifier""" + """Expand to containing surrounding pair""" try: surrounding_pair_scope_type = m.cursorless_surrounding_pair_scope_type except AttributeError: surrounding_pair_scope_type = "any" - modifier = { + scope_type = { "type": "surroundingPair", "delimiter": surrounding_pair_scope_type, } - try: - modifier["forceDirection"] = m.cursorless_delimiter_force_direction - except AttributeError: - pass + with contextlib.suppress(AttributeError): + scope_type["forceDirection"] = m.cursorless_delimiter_force_direction - return modifier + return { + "type": "containingScope", + "scopeType": scope_type, + } diff --git a/src/actions/CopyLines.ts b/src/actions/CopyLines.ts index 082c6afb1c..c0ce0d58cb 100644 --- a/src/actions/CopyLines.ts +++ b/src/actions/CopyLines.ts @@ -15,7 +15,7 @@ class CopyLines implements Action { private getRanges(editor: TextEditor, targets: Target[]) { const paragraphTargets = targets.filter( - (target) => target.scopeType === "paragraph" + (target) => target.scopeTypeType === "paragraph" ); const ranges = targets.map((target) => expandToContainingLine(editor, target.contentRange) diff --git a/src/actions/Rewrap.ts b/src/actions/Rewrap.ts index b63d424dcf..9f7f857862 100644 --- a/src/actions/Rewrap.ts +++ b/src/actions/Rewrap.ts @@ -1,19 +1,14 @@ import { flatten } from "lodash"; import { performEditsAndUpdateRanges } from "../core/updateSelections/updateSelections"; +import { weakContainingSurroundingPairStage } from "../processTargets/modifiers/commonWeakContainingScopeStages"; import { Target } from "../typings/target.types"; -import { Graph, ProcessedTargetsContext } from "../typings/Types"; +import { Graph } from "../typings/Types"; import displayPendingEditDecorations from "../util/editDisplayUtils"; import { createThatMark, runOnTargetsForEachEditor } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; export default class Rewrap implements Action { - getFinalStages = () => [ - { - run(context: ProcessedTargetsContext, target: Target): Target[] { - return target.getBoundary(context); - }, - }, - ]; + getFinalStages = () => [weakContainingSurroundingPairStage]; constructor(private graph: Graph) { this.run = this.run.bind(this); @@ -24,41 +19,41 @@ export default class Rewrap implements Action { left: string, right: string ): Promise { - if (targets.length % 2 !== 0) { - throw Error("Target must have an opening and closing delimiter"); - } + const boundaryTargets = targets.flatMap((target) => { + const boundary = target.boundary; + + if (boundary.length !== 2) { + throw Error("Target must have an opening and closing delimiter"); + } + + return boundary; + }); await displayPendingEditDecorations( - targets, + boundaryTargets, this.graph.editStyles.pendingModification0 ); const thatMark = flatten( - await runOnTargetsForEachEditor(targets, async (editor, targets) => { - const edits = targets.map((target, i) => ({ - editor, - range: target.contentRange, - text: i % 2 === 0 ? left : right, - })); - - const thatRanges = []; - const thatTargets = []; - for (let i = 0; i < targets.length; i += 2) { - thatTargets.push(targets[i]); - thatRanges.push( - targets[i].contentRange.union(targets[i + 1].contentRange) + await runOnTargetsForEachEditor( + boundaryTargets, + async (editor, boundaryTargets) => { + const edits = boundaryTargets.map((target, i) => ({ + editor, + range: target.contentRange, + text: i % 2 === 0 ? left : right, + })); + + const [updatedThatRanges] = await performEditsAndUpdateRanges( + this.graph.rangeUpdater, + editor, + edits, + [targets.map((target) => target.contentRange)] ); - } - - const [updatedThatRanges] = await performEditsAndUpdateRanges( - this.graph.rangeUpdater, - editor, - edits, - [thatRanges] - ); - return createThatMark(thatTargets, updatedThatRanges); - }) + return createThatMark(targets, updatedThatRanges); + } + ) ); return { thatMark }; diff --git a/src/actions/ToggleBreakpoint.ts b/src/actions/ToggleBreakpoint.ts index fbbec9265c..5a9b65bc47 100644 --- a/src/actions/ToggleBreakpoint.ts +++ b/src/actions/ToggleBreakpoint.ts @@ -6,7 +6,7 @@ import { SourceBreakpoint, Uri, } from "vscode"; -import WeakContainingScopeStage from "../processTargets/modifiers/WeakContainingScopeStage"; +import { weakContainingLineStage } from "../processTargets/modifiers/commonWeakContainingScopeStages"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; import displayPendingEditDecorations from "../util/editDisplayUtils"; @@ -23,12 +23,7 @@ function getBreakpoints(uri: Uri, range: Range) { } export default class ToggleBreakpoint implements Action { - getFinalStages = () => [ - new WeakContainingScopeStage({ - type: "containingScope", - scopeType: "line", - }), - ]; + getFinalStages = () => [weakContainingLineStage]; constructor(private graph: Graph) { this.run = this.run.bind(this); diff --git a/src/actions/WrapWithSnippet.ts b/src/actions/WrapWithSnippet.ts index 8c5fd613ff..c5b5c98f1c 100644 --- a/src/actions/WrapWithSnippet.ts +++ b/src/actions/WrapWithSnippet.ts @@ -38,7 +38,9 @@ export default class WrapWithSnippet implements Action { return [ new WeakContainingScopeStage({ type: "containingScope", - scopeType: defaultScopeType, + scopeType: { + type: defaultScopeType, + }, }), ]; } diff --git a/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts b/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts index f246e3e709..20e5756f2b 100644 --- a/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts +++ b/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts @@ -3,7 +3,7 @@ import { ActionableError } from "../../errors"; import { Modifier, PartialTargetDesc, - ScopeType, + SimpleScopeTypeType, } from "../../typings/target.types"; import { ActionType } from "../../actions/actions.types"; import { getPartialPrimitiveTargets } from "../../util/getPrimitiveTargets"; @@ -107,14 +107,14 @@ export function validateCommand( } function usesScopeType( - scopeType: ScopeType, + scopeTypeType: SimpleScopeTypeType, partialTargets: PartialTargetDesc[] ) { return getPartialPrimitiveTargets(partialTargets).some((partialTarget) => partialTarget.modifiers?.find( (mod: Modifier) => (mod.type === "containingScope" || mod.type === "everyScope") && - mod.scopeType === scopeType + mod.scopeType.type === scopeTypeType ) ); } diff --git a/src/core/commandVersionUpgrades/canonicalizeTargets.ts b/src/core/commandVersionUpgrades/canonicalizeTargets.ts index 5dca959849..8c36e615bd 100644 --- a/src/core/commandVersionUpgrades/canonicalizeTargets.ts +++ b/src/core/commandVersionUpgrades/canonicalizeTargets.ts @@ -3,12 +3,12 @@ import { flow } from "lodash"; import { PartialPrimitiveTargetDesc, PartialTargetDesc, - ScopeType, + SimpleScopeTypeType, } from "../../typings/target.types"; import { transformPartialPrimitiveTargets } from "../../util/getPrimitiveTargets"; import { HatStyleName } from "../constants"; -const SCOPE_TYPE_CANONICALIZATION_MAPPING: Record = { +const SCOPE_TYPE_CANONICALIZATION_MAPPING: Record = { arrowFunction: "anonymousFunction", dictionary: "map", regex: "regularExpression", @@ -23,8 +23,9 @@ const canonicalizeScopeTypes = ( ): PartialPrimitiveTargetDesc => { target.modifiers?.forEach((mod) => { if (mod.type === "containingScope" || mod.type === "everyScope") { - mod.scopeType = - SCOPE_TYPE_CANONICALIZATION_MAPPING[mod.scopeType] ?? mod.scopeType; + mod.scopeType.type = + SCOPE_TYPE_CANONICALIZATION_MAPPING[mod.scopeType.type] ?? + mod.scopeType; } }); return target; diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts index 800ad7cbef..24dcb834ed 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts @@ -4,7 +4,7 @@ import { PartialPrimitiveTargetDesc, PartialRangeTargetDesc, PartialTargetDesc, - ScopeType, + SimpleScopeTypeType, } from "../../../typings/target.types"; import { ActionType } from "../../../actions/actions.types"; import { transformPartialPrimitiveTargets } from "../../../util/getPrimitiveTargets"; @@ -37,10 +37,13 @@ function upgradeModifier(modifier: ModifierV0V1): Modifier[] { case "containingScope": { const { includeSiblings, scopeType, type, ...rest } = modifier; + return [ { type: includeSiblings ? "everyScope" : "containingScope", - scopeType: scopeType as ScopeType, + scopeType: { + type: scopeType as SimpleScopeTypeType, + }, ...rest, }, ]; @@ -48,13 +51,32 @@ function upgradeModifier(modifier: ModifierV0V1): Modifier[] { case "surroundingPair": { const { delimiterInclusion, ...rest } = modifier; + const surroundingPairModifier = { + type: "containingScope", + scopeType: rest, + } as const; + if (delimiterInclusion === "interiorOnly") { - return [{ type: "interiorOnly" }, rest]; + return [{ type: "interiorOnly" }, surroundingPairModifier]; } + if (delimiterInclusion === "excludeInterior") { - return [{ type: "excludeInterior" }, rest]; + return [{ type: "excludeInterior" }, surroundingPairModifier]; } - return [rest]; + + return [surroundingPairModifier]; + } + + case "subpiece": { + const { type, pieceType, ...rest } = modifier; + + return [ + { + type: "containingScope", + scopeType: { type: pieceType }, + ...rest, + }, + ]; } default: @@ -102,7 +124,10 @@ function upgradePrimitiveTarget( break; } default: - modifiers.push({ type: "containingScope", scopeType: selectionType }); + modifiers.push({ + type: "containingScope", + scopeType: { type: selectionType }, + }); } } diff --git a/src/languages/clojure.ts b/src/languages/clojure.ts index a07ff970b2..d968192725 100644 --- a/src/languages/clojure.ts +++ b/src/languages/clojure.ts @@ -6,7 +6,7 @@ import { patternMatcher, } from "../util/nodeMatchers"; import { NodeMatcherAlternative, NodeFinder } from "../typings/Types"; -import { ScopeType } from "../typings/target.types"; +import { SimpleScopeTypeType } from "../typings/target.types"; import { SyntaxNode } from "web-tree-sitter"; import { delimitedSelector } from "../util/nodeSelectors"; import { identity } from "lodash"; @@ -130,7 +130,7 @@ const ifStatementFinder = functionNameBasedFinder( const ifStatementMatcher = matcher(ifStatementFinder); -const nodeMatchers: Partial> = { +const nodeMatchers: Partial> = { comment: "comment", map: "map_lit", diff --git a/src/languages/cpp.ts b/src/languages/cpp.ts index 8741e72bf3..c0616c7fc8 100644 --- a/src/languages/cpp.ts +++ b/src/languages/cpp.ts @@ -5,7 +5,7 @@ import { trailingMatcher, } from "../util/nodeMatchers"; import { NodeMatcherAlternative } from "../typings/Types"; -import { ScopeType } from "../typings/target.types"; +import { SimpleScopeTypeType } from "../typings/target.types"; // Generated by the following command: // > curl https://raw.githubusercontent.com/tree-sitter/tree-sitter-cpp/master/src/node-types.json | jq '[.[] | select(.type == "compound_statement") | .children.types[].type] + [.[] | select(.type == "_statement") | .subtypes[].type]' @@ -62,7 +62,7 @@ const TYPE_TYPES = [ "union_specifier", ]; -const nodeMatchers: Partial> = { +const nodeMatchers: Partial> = { statement: STATEMENT_TYPES, class: [ "class_specifier", diff --git a/src/languages/csharp.ts b/src/languages/csharp.ts index c1cd010d75..f122338833 100644 --- a/src/languages/csharp.ts +++ b/src/languages/csharp.ts @@ -9,7 +9,7 @@ import { typeMatcher, } from "../util/nodeMatchers"; import { NodeMatcherAlternative } from "../typings/Types"; -import { ScopeType } from "../typings/target.types"; +import { SimpleScopeTypeType } from "../typings/target.types"; import { nodeFinder, typedNodeFinder } from "../util/nodeFinders"; import { delimitedSelector } from "../util/nodeSelectors"; @@ -214,7 +214,7 @@ const getMapMatchers = { string: typeMatcher("string_literal"), }; -const nodeMatchers: Partial> = { +const nodeMatchers: Partial> = { ...getMapMatchers, ifStatement: "if_statement", class: "class_declaration", diff --git a/src/languages/getNodeMatcher.ts b/src/languages/getNodeMatcher.ts index 226640da43..21bf322bb2 100644 --- a/src/languages/getNodeMatcher.ts +++ b/src/languages/getNodeMatcher.ts @@ -6,7 +6,7 @@ import { NodeMatcherValue, SelectionWithEditor, } from "../typings/Types"; -import { ScopeType } from "../typings/target.types"; +import { SimpleScopeTypeType } from "../typings/target.types"; import cpp from "./cpp"; import clojure from "./clojure"; import csharp from "./csharp"; @@ -26,7 +26,7 @@ import { SupportedLanguageId } from "./constants"; export function getNodeMatcher( languageId: string, - scopeType: ScopeType, + scopeTypeType: SimpleScopeTypeType, includeSiblings: boolean ): NodeMatcher { const matchers = languageMatchers[languageId as SupportedLanguageId]; @@ -35,7 +35,7 @@ export function getNodeMatcher( throw new UnsupportedLanguageError(languageId); } - const matcher = matchers[scopeType]; + const matcher = matchers[scopeTypeType]; if (matcher == null) { return notSupported; @@ -50,7 +50,7 @@ export function getNodeMatcher( const languageMatchers: Record< SupportedLanguageId, - Record + Record > = { c: cpp, cpp, diff --git a/src/languages/go.ts b/src/languages/go.ts index 1bf68458f8..73cff88065 100644 --- a/src/languages/go.ts +++ b/src/languages/go.ts @@ -6,7 +6,7 @@ import { patternMatcher, } from "../util/nodeMatchers"; import { NodeMatcherAlternative } from "../typings/Types"; -import { ScopeType } from "../typings/target.types"; +import { SimpleScopeTypeType } from "../typings/target.types"; // Generated by the following command: // `curl https://raw.githubusercontent.com/tree-sitter/tree-sitter-go/master/src/node-types.json | jq '[.[] | select(.type == "_statement" or .type == "_simple_statement") | .subtypes[].type]'` @@ -37,7 +37,7 @@ const STATEMENT_TYPES = [ "var_declaration", ]; -const nodeMatchers: Partial> = { +const nodeMatchers: Partial> = { map: "composite_literal", list: ["composite_literal", "slice_type", "array_type"], statement: STATEMENT_TYPES, diff --git a/src/languages/html.ts b/src/languages/html.ts index 808803d4d0..39772e9667 100644 --- a/src/languages/html.ts +++ b/src/languages/html.ts @@ -4,7 +4,7 @@ import { patternMatcher, } from "../util/nodeMatchers"; import { NodeMatcherAlternative, SelectionWithEditor } from "../typings/Types"; -import { ScopeType } from "../typings/target.types"; +import { SimpleScopeTypeType } from "../typings/target.types"; import { SyntaxNode } from "web-tree-sitter"; import { getNodeRange } from "../util/nodeSelectors"; @@ -18,7 +18,7 @@ const getTags = (selection: SelectionWithEditor, node: SyntaxNode) => { const endTag = getEndTag(selection, node); return startTag != null && endTag != null ? startTag.concat(endTag) : null; }; -const nodeMatchers: Partial> = { +const nodeMatchers: Partial> = { xmlElement: ["element", "script_element", "style_element"], xmlBothTags: getTags, xmlStartTag: getStartTag, diff --git a/src/languages/java.ts b/src/languages/java.ts index 597d52e4ab..8c7083675d 100644 --- a/src/languages/java.ts +++ b/src/languages/java.ts @@ -6,7 +6,7 @@ import { trailingMatcher, } from "../util/nodeMatchers"; import { NodeMatcherAlternative } from "../typings/Types"; -import { ScopeType } from "../typings/target.types"; +import { SimpleScopeTypeType } from "../typings/target.types"; // Generated by the following command: // > curl https://raw.githubusercontent.com/tree-sitter/tree-sitter-java/master/src/node-types.json | jq '[.[] | select(.type == "statement" or .type == "declaration") | .subtypes[].type]' @@ -44,7 +44,7 @@ const STATEMENT_TYPES = [ "switch_statement", ]; -const nodeMatchers: Partial> = { +const nodeMatchers: Partial> = { statement: STATEMENT_TYPES, class: "class_declaration", className: "class_declaration[name]", diff --git a/src/languages/json.ts b/src/languages/json.ts index 394a552bf4..d45bd8775e 100644 --- a/src/languages/json.ts +++ b/src/languages/json.ts @@ -5,11 +5,11 @@ import { trailingMatcher, } from "../util/nodeMatchers"; import { NodeMatcherAlternative, SelectionWithEditor } from "../typings/Types"; -import { ScopeType } from "../typings/target.types"; +import { SimpleScopeTypeType } from "../typings/target.types"; import { SyntaxNode } from "web-tree-sitter"; import { getNodeRange } from "../util/nodeSelectors"; -const nodeMatchers: Partial> = { +const nodeMatchers: Partial> = { map: "object", list: "array", string: "string", diff --git a/src/languages/markdown.ts b/src/languages/markdown.ts index 913bc00638..8d8dc681a0 100644 --- a/src/languages/markdown.ts +++ b/src/languages/markdown.ts @@ -5,7 +5,7 @@ import { NodeMatcherAlternative, SelectionWithContext, } from "../typings/Types"; -import { ScopeType } from "../typings/target.types"; +import { SimpleScopeTypeType } from "../typings/target.types"; import { leadingSiblingNodeFinder, patternFinder } from "../util/nodeFinders"; import { createPatternMatchers, @@ -89,7 +89,7 @@ function sectionMatcher(...patterns: string[]) { return matcher(leadingSiblingNodeFinder(finder), sectionExtractor); } -const nodeMatchers: Partial> = { +const nodeMatchers: Partial> = { list: ["loose_list", "tight_list"], comment: "html_block", name: matcher( diff --git a/src/languages/php.ts b/src/languages/php.ts index 9098e536c7..5aab14d7e5 100644 --- a/src/languages/php.ts +++ b/src/languages/php.ts @@ -5,7 +5,7 @@ import { SelectionWithContext, SelectionWithEditor, } from "../typings/Types"; -import { ScopeType } from "../typings/target.types"; +import { SimpleScopeTypeType } from "../typings/target.types"; import { patternFinder } from "../util/nodeFinders"; import { argumentMatcher, @@ -98,7 +98,7 @@ function castTypeExtractor( }; } -const nodeMatchers: Partial> = { +const nodeMatchers: Partial> = { statement: STATEMENT_TYPES, ifStatement: "if_statement", class: "class_declaration", diff --git a/src/languages/python.ts b/src/languages/python.ts index f5eca5cdc7..6cda01ef65 100644 --- a/src/languages/python.ts +++ b/src/languages/python.ts @@ -11,7 +11,7 @@ import { } from "../util/nodeMatchers"; import { patternFinder } from "../util/nodeFinders"; import { NodeMatcherAlternative } from "../typings/Types"; -import { ScopeType } from "../typings/target.types"; +import { SimpleScopeTypeType } from "../typings/target.types"; import { childRangeSelector } from "../util/nodeSelectors"; // Generated by the following command: @@ -49,7 +49,7 @@ export const getTypeNode = (node: SyntaxNode) => const dictionaryTypes = ["dictionary", "dictionary_comprehension"]; const listTypes = ["list", "list_comprehension", "set"]; -const nodeMatchers: Partial> = { +const nodeMatchers: Partial> = { map: dictionaryTypes, list: listTypes, statement: STATEMENT_TYPES, diff --git a/src/languages/ruby.ts b/src/languages/ruby.ts index c98c79fcc1..8cf1669fc7 100644 --- a/src/languages/ruby.ts +++ b/src/languages/ruby.ts @@ -10,7 +10,7 @@ import { trailingMatcher, } from "../util/nodeMatchers"; import { NodeMatcherAlternative, SelectionWithEditor } from "../typings/Types"; -import { ScopeType } from "../typings/target.types"; +import { SimpleScopeTypeType } from "../typings/target.types"; import { SyntaxNode } from "web-tree-sitter"; import { getNodeRange } from "../util/nodeSelectors"; import { patternFinder } from "../util/nodeFinders"; @@ -148,7 +148,7 @@ function blockFinder(node: SyntaxNode) { return block; } -const nodeMatchers: Partial> = { +const nodeMatchers: Partial> = { map: mapTypes, list: listTypes, statement: cascadingMatcher( diff --git a/src/languages/scala.ts b/src/languages/scala.ts index 7bf7806369..b6d4fdc564 100644 --- a/src/languages/scala.ts +++ b/src/languages/scala.ts @@ -5,9 +5,9 @@ import { conditionMatcher, } from "../util/nodeMatchers"; import { NodeMatcherAlternative } from "../typings/Types"; -import { ScopeType } from "../typings/target.types"; +import { SimpleScopeTypeType } from "../typings/target.types"; -const nodeMatchers: Partial> = { +const nodeMatchers: Partial> = { // treating classes = classlike class: ["class_definition", "object_definition", "trait_definition"], className: [ diff --git a/src/languages/scss.ts b/src/languages/scss.ts index b4412911c8..c05adef4c3 100644 --- a/src/languages/scss.ts +++ b/src/languages/scss.ts @@ -1,6 +1,6 @@ import { SyntaxNode } from "web-tree-sitter"; import { NodeMatcherAlternative, SelectionWithEditor } from "../typings/Types"; -import { ScopeType } from "../typings/target.types"; +import { SimpleScopeTypeType } from "../typings/target.types"; import { patternFinder } from "../util/nodeFinders"; import { cascadingMatcher, @@ -87,7 +87,7 @@ function findAdjacentArgValues( }; } -const nodeMatchers: Partial> = { +const nodeMatchers: Partial> = { ifStatement: "if_statement", condition: conditionMatcher("condition"), statement: cascadingMatcher( diff --git a/src/languages/typescript.ts b/src/languages/typescript.ts index d7836d97b3..93fc8e7aa3 100644 --- a/src/languages/typescript.ts +++ b/src/languages/typescript.ts @@ -13,7 +13,7 @@ import { NodeMatcherAlternative, SelectionWithEditor, } from "../typings/Types"; -import { ScopeType } from "../typings/target.types"; +import { SimpleScopeTypeType } from "../typings/target.types"; import { getNodeInternalRange, getNodeRange, @@ -158,7 +158,7 @@ function valueMatcher() { const mapTypes = ["object", "object_pattern"]; const listTypes = ["array", "array_pattern"]; -const nodeMatchers: Partial> = { +const nodeMatchers: Partial> = { map: mapTypes, list: listTypes, string: ["string", "template_string"], diff --git a/src/processTargets/getModifierStage.ts b/src/processTargets/getModifierStage.ts index 6e13e27fe4..d903f96618 100644 --- a/src/processTargets/getModifierStage.ts +++ b/src/processTargets/getModifierStage.ts @@ -1,26 +1,33 @@ import { ContainingScopeModifier, + ContainingSurroundingPairModifier, EveryScopeModifier, Modifier, } from "../typings/target.types"; import { HeadStage, TailStage } from "./modifiers/HeadTailStage"; import { - InteriorOnlyStage, ExcludeInteriorStage, + InteriorOnlyStage, } from "./modifiers/InteriorStage"; +import OrdinalRangeSubTokenStage, { + OrdinalRangeSubTokenModifier, +} from "./modifiers/OrdinalRangeSubTokenStage"; import PositionStage from "./modifiers/PositionStage"; import RawSelectionStage from "./modifiers/RawSelectionStage"; -import ContainingSyntaxScopeStage from "./modifiers/scopeTypeStages/ContainingSyntaxScopeStage"; +import ContainingSyntaxScopeStage, { + SimpleContainingScopeModifier, +} from "./modifiers/scopeTypeStages/ContainingSyntaxScopeStage"; import DocumentStage from "./modifiers/scopeTypeStages/DocumentStage"; import LineStage from "./modifiers/scopeTypeStages/LineStage"; import NotebookCellStage from "./modifiers/scopeTypeStages/NotebookCellStage"; import ParagraphStage from "./modifiers/scopeTypeStages/ParagraphStage"; import { + NonWhitespaceSequenceModifier, NonWhitespaceSequenceStage, + UrlModifier, UrlStage, } from "./modifiers/scopeTypeStages/RegexStage"; import TokenStage from "./modifiers/scopeTypeStages/TokenStage"; -import SubPieceStage from "./modifiers/SubPieceStage"; import SurroundingPairStage from "./modifiers/SurroundingPairStage"; import { ModifierStage } from "./PipelineStages.types"; @@ -34,10 +41,16 @@ export default (modifier: Modifier): ModifierStage => { return new TailStage(modifier); case "toRawSelection": return new RawSelectionStage(modifier); - case "subpiece": - return new SubPieceStage(modifier); - case "surroundingPair": - return new SurroundingPairStage(modifier); + case "ordinalRange": + if (!["word", "character"].includes(modifier.scopeType.type)) { + throw Error( + `Unsupported ordinal scope type ${modifier.scopeType.type}` + ); + } + + return new OrdinalRangeSubTokenStage( + modifier as OrdinalRangeSubTokenModifier + ); case "interiorOnly": return new InteriorOnlyStage(modifier); case "excludeInterior": @@ -51,7 +64,7 @@ export default (modifier: Modifier): ModifierStage => { const getContainingScopeStage = ( modifier: ContainingScopeModifier | EveryScopeModifier ): ModifierStage => { - switch (modifier.scopeType) { + switch (modifier.scopeType.type) { case "token": return new TokenStage(modifier); case "notebookCell": @@ -63,14 +76,22 @@ const getContainingScopeStage = ( case "paragraph": return new ParagraphStage(modifier); case "nonWhitespaceSequence": - return new NonWhitespaceSequenceStage(modifier); + return new NonWhitespaceSequenceStage( + modifier as NonWhitespaceSequenceModifier + ); case "url": - return new UrlStage(modifier); + return new UrlStage(modifier as UrlModifier); + case "surroundingPair": + return new SurroundingPairStage( + modifier as ContainingSurroundingPairModifier + ); case "word": case "character": - throw new Error(`Unsupported scope type ${modifier.scopeType}`); + throw new Error(`Unsupported scope type ${modifier.scopeType.type}`); default: // Default to containing syntax scope using tree sitter - return new ContainingSyntaxScopeStage(modifier); + return new ContainingSyntaxScopeStage( + modifier as SimpleContainingScopeModifier + ); } }; diff --git a/src/processTargets/modifiers/InteriorStage.ts b/src/processTargets/modifiers/InteriorStage.ts index 7081d39e31..b359d33896 100644 --- a/src/processTargets/modifiers/InteriorStage.ts +++ b/src/processTargets/modifiers/InteriorStage.ts @@ -5,12 +5,15 @@ import { } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; +import { weakContainingSurroundingPairStage } from "./commonWeakContainingScopeStages"; export class InteriorOnlyStage implements ModifierStage { constructor(private modifier: InteriorOnlyModifier) {} run(context: ProcessedTargetsContext, target: Target): Target[] { - return target.getInterior(context); + return weakContainingSurroundingPairStage + .run(context, target) + .flatMap((target) => target.interior); } } @@ -18,6 +21,8 @@ export class ExcludeInteriorStage implements ModifierStage { constructor(private modifier: ExcludeInteriorModifier) {} run(context: ProcessedTargetsContext, target: Target): Target[] { - return target.getBoundary(context); + return weakContainingSurroundingPairStage + .run(context, target) + .flatMap((target) => target.boundary); } } diff --git a/src/processTargets/modifiers/SubPieceStage.ts b/src/processTargets/modifiers/OrdinalRangeSubTokenStage.ts similarity index 87% rename from src/processTargets/modifiers/SubPieceStage.ts rename to src/processTargets/modifiers/OrdinalRangeSubTokenStage.ts index 8cc42a3b91..38bd2a8aaa 100644 --- a/src/processTargets/modifiers/SubPieceStage.ts +++ b/src/processTargets/modifiers/OrdinalRangeSubTokenStage.ts @@ -1,14 +1,26 @@ import { range } from "lodash"; import { Range } from "vscode"; import { SUBWORD_MATCHER } from "../../core/constants"; -import { SubTokenModifier, Target } from "../../typings/target.types"; +import { + OrdinalRangeModifier, + SimpleScopeType, + Target, +} from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; import ScopeTypeTarget from "../targets/ScopeTypeTarget"; import { getTokenRangeForSelection } from "./scopeTypeStages/TokenStage"; +interface OrdinalScopeType extends SimpleScopeType { + type: "character" | "word"; +} + +export interface OrdinalRangeSubTokenModifier extends OrdinalRangeModifier { + scopeType: OrdinalScopeType; +} + export default class implements ModifierStage { - constructor(private modifier: SubTokenModifier) {} + constructor(private modifier: OrdinalRangeSubTokenModifier) {} run(context: ProcessedTargetsContext, target: Target): Target[] { const { editor } = target; @@ -23,12 +35,12 @@ export default class implements ModifierStage { throw new Error("Subtoken exclusions unsupported"); } - if (this.modifier.pieceType === "word") { + if (this.modifier.scopeType.type === "word") { pieces = [...token.matchAll(SUBWORD_MATCHER)].map((match) => ({ start: match.index!, end: match.index! + match[0].length, })); - } else if (this.modifier.pieceType === "character") { + } else if (this.modifier.scopeType.type === "character") { pieces = range(token.length).map((index) => ({ start: index, end: index + 1, @@ -102,7 +114,7 @@ export default class implements ModifierStage { editor, isReversed, contentRange: new Range(anchor, active), - scopeType: this.modifier.pieceType, + scopeTypeType: this.modifier.scopeType.type, delimiter: containingListDelimiter ?? "", leadingDelimiter: leadingDelimiterRange != null diff --git a/src/processTargets/modifiers/SurroundingPairStage.ts b/src/processTargets/modifiers/SurroundingPairStage.ts index ad14e0be82..9e00876859 100644 --- a/src/processTargets/modifiers/SurroundingPairStage.ts +++ b/src/processTargets/modifiers/SurroundingPairStage.ts @@ -1,4 +1,7 @@ -import { SurroundingPairModifier, Target } from "../../typings/target.types"; +import { + ContainingSurroundingPairModifier, + Target, +} from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { selectionWithEditorWithContextToTarget } from "../../util/targetUtils"; import { ModifierStage } from "../PipelineStages.types"; @@ -19,7 +22,7 @@ import { processSurroundingPair } from "./surroundingPair"; * `null` if none was found */ export default class implements ModifierStage { - constructor(private modifier: SurroundingPairModifier) {} + constructor(private modifier: ContainingSurroundingPairModifier) {} run( context: ProcessedTargetsContext, @@ -30,7 +33,7 @@ export default class implements ModifierStage { } function processedSurroundingPairTarget( - modifier: SurroundingPairModifier, + modifier: ContainingSurroundingPairModifier, context: ProcessedTargetsContext, target: Target ): SurroundingPairTarget[] { @@ -38,7 +41,7 @@ function processedSurroundingPairTarget( context, target.editor, target.contentRange, - modifier + modifier.scopeType ); if (pairs == null) { diff --git a/src/processTargets/modifiers/commonWeakContainingScopeStages.ts b/src/processTargets/modifiers/commonWeakContainingScopeStages.ts new file mode 100644 index 0000000000..3f4aee6271 --- /dev/null +++ b/src/processTargets/modifiers/commonWeakContainingScopeStages.ts @@ -0,0 +1,11 @@ +import WeakContainingScopeStage from "./WeakContainingScopeStage"; + +export const weakContainingSurroundingPairStage = new WeakContainingScopeStage({ + type: "containingScope", + scopeType: { type: "surroundingPair", delimiter: "any" }, +}); + +export const weakContainingLineStage = new WeakContainingScopeStage({ + type: "containingScope", + scopeType: { type: "line" }, +}); diff --git a/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts b/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts index 7453fc1fbf..48aa47b568 100644 --- a/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts @@ -4,6 +4,7 @@ import { getNodeMatcher } from "../../../languages/getNodeMatcher"; import { ContainingScopeModifier, EveryScopeModifier, + SimpleScopeType, Target, } from "../../../typings/target.types"; import ScopeTypeTarget from "../../targets/ScopeTypeTarget"; @@ -17,13 +18,23 @@ import { selectionWithEditorFromRange } from "../../../util/selectionUtils"; import { selectionWithEditorWithContextToTarget } from "../../../util/targetUtils"; import { ModifierStage } from "../../PipelineStages.types"; +export interface SimpleContainingScopeModifier extends ContainingScopeModifier { + scopeType: SimpleScopeType; +} + +export interface SimpleEveryScopeModifier extends EveryScopeModifier { + scopeType: SimpleScopeType; +} + export default class implements ModifierStage { - constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} + constructor( + private modifier: SimpleContainingScopeModifier | SimpleEveryScopeModifier + ) {} run(context: ProcessedTargetsContext, target: Target): ScopeTypeTarget[] { const nodeMatcher = getNodeMatcher( target.editor.document.languageId, - this.modifier.scopeType, + this.modifier.scopeType.type, this.modifier.type === "everyScope" ); @@ -47,7 +58,7 @@ export default class implements ModifierStage { (scope) => new ScopeTypeTarget({ ...selectionWithEditorWithContextToTarget(scope), - scopeType: this.modifier.scopeType, + scopeTypeType: this.modifier.scopeType.type, isReversed: target.isReversed, }) ); diff --git a/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts b/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts index f88590ee79..892aa2d9ab 100644 --- a/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts @@ -9,9 +9,11 @@ import { ProcessedTargetsContext } from "../../../typings/Types"; import { ModifierStage } from "../../PipelineStages.types"; import { getTokenDelimiters } from "./TokenStage"; +type RegexModifier = NonWhitespaceSequenceModifier | UrlModifier; + class RegexStage implements ModifierStage { constructor( - private modifier: ContainingScopeModifier | EveryScopeModifier, + private modifier: RegexModifier, private regex: RegExp, private name?: string ) {} @@ -63,7 +65,7 @@ class RegexStage implements ModifierStage { getTargetFromRange(target: Target, range: Range): ScopeTypeTarget { return new ScopeTypeTarget({ ...getTokenDelimiters(target.editor, range), - scopeType: this.modifier.scopeType, + scopeTypeType: this.modifier.scopeType.type, editor: target.editor, isReversed: target.isReversed, contentRange: range, @@ -106,8 +108,15 @@ class RegexStage implements ModifierStage { } } +export type NonWhitespaceSequenceModifier = ( + | ContainingScopeModifier + | EveryScopeModifier +) & { + scopeType: { type: "nonWhitespaceSequence" }; +}; + export class NonWhitespaceSequenceStage extends RegexStage { - constructor(modifier: ContainingScopeModifier | EveryScopeModifier) { + constructor(modifier: NonWhitespaceSequenceModifier) { super(modifier, /\S+/g, "Non whitespace sequence"); } } @@ -116,8 +125,12 @@ export class NonWhitespaceSequenceStage extends RegexStage { const URL_REGEX = /(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/g; +export type UrlModifier = (ContainingScopeModifier | EveryScopeModifier) & { + scopeType: { type: "url" }; +}; + export class UrlStage extends RegexStage { - constructor(modifier: ContainingScopeModifier | EveryScopeModifier) { + constructor(modifier: UrlModifier) { super(modifier, URL_REGEX, "URL"); } } diff --git a/src/processTargets/modifiers/surroundingPair/index.ts b/src/processTargets/modifiers/surroundingPair/index.ts index e2e45145ed..4b2e90a940 100644 --- a/src/processTargets/modifiers/surroundingPair/index.ts +++ b/src/processTargets/modifiers/surroundingPair/index.ts @@ -5,7 +5,7 @@ import getTextFragmentExtractor, { } from "../../../languages/getTextFragmentExtractor"; import { ComplexSurroundingPairName, - SurroundingPairModifier, + SurroundingPairScopeType, } from "../../../typings/target.types"; import { ProcessedTargetsContext, @@ -32,7 +32,7 @@ export function processSurroundingPair( context: ProcessedTargetsContext, editor: TextEditor, range: Range, - modifier: SurroundingPairModifier + modifier: SurroundingPairScopeType ): SelectionWithEditorWithContext[] | null { const document = editor.document; const delimiters = complexDelimiterMap[ diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index 02f4972dcc..43f74abe8d 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -165,8 +165,8 @@ function processContinuousRangeTarget( })(); const scopeType = - startTarget.scopeType === endTarget.scopeType - ? startTarget.scopeType + startTarget.scopeTypeType === endTarget.scopeTypeType + ? startTarget.scopeTypeType : undefined; // If both objects are of the same type create a new object of the same diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index 811a589ee9..402f6ec903 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -3,10 +3,9 @@ import { EditNewLineContext, Position, RemovalRange, - ScopeType, + SimpleScopeTypeType, Target, } from "../../typings/target.types"; -import { ProcessedTargetsContext } from "../../typings/Types"; import { parseRemovalRange } from "../../util/targetUtils"; import WeakTarget from "./WeakTarget"; @@ -28,7 +27,7 @@ export interface CommonTargetParameters { } export interface BaseTargetParameters extends CommonTargetParameters { - scopeType?: ScopeType; + scopeTypeType?: SimpleScopeTypeType; delimiter: string; removalRange?: Range; interiorRange?: Range; @@ -52,7 +51,7 @@ interface BaseTargetState { readonly delimiter: string; /** Is this a scope type other raw selection? */ - readonly scopeType?: ScopeType; + readonly scopeTypeType?: SimpleScopeTypeType; /** The range to remove the content */ readonly removalRange?: Range; @@ -90,7 +89,7 @@ export default abstract class BaseTarget implements Target { isReversed: parameters.isReversed, contentRange: parameters.contentRange, delimiter: parameters.delimiter, - scopeType: parameters.scopeType, + scopeTypeType: parameters.scopeTypeType, removalRange: parameters.removalRange, interiorRange: parameters.interiorRange, boundary: parameters.boundary, @@ -116,8 +115,8 @@ export default abstract class BaseTarget implements Target { return this.state.removalRange; } - get scopeType() { - return this.state.scopeType; + get scopeTypeType() { + return this.state.scopeTypeType; } /** If true this target should be treated as a line in regards to continuous range */ @@ -130,7 +129,7 @@ export default abstract class BaseTarget implements Target { return false; } - getInterior(_context: ProcessedTargetsContext): Target[] { + get interior(): Target[] { if (this.state.interiorRange == null || this.position != null) { throw Error("No available interior"); } @@ -143,7 +142,7 @@ export default abstract class BaseTarget implements Target { ]; } - getBoundary(_context: ProcessedTargetsContext): Target[] { + get boundary(): Target[] { if (this.state.boundary == null || this.position != null) { throw Error("No available boundaries"); } diff --git a/src/processTargets/targets/DocumentTarget.ts b/src/processTargets/targets/DocumentTarget.ts index e5bbc6db11..62e94cb9a5 100644 --- a/src/processTargets/targets/DocumentTarget.ts +++ b/src/processTargets/targets/DocumentTarget.ts @@ -8,7 +8,7 @@ export default class DocumentTarget extends BaseTarget { constructor(parameters: CommonTargetParameters) { super({ ...extractCommonParameters(parameters), - scopeType: "document", + scopeTypeType: "document", delimiter: "\n", }); } diff --git a/src/processTargets/targets/LineTarget.ts b/src/processTargets/targets/LineTarget.ts index 18b894708e..3121cab9fb 100644 --- a/src/processTargets/targets/LineTarget.ts +++ b/src/processTargets/targets/LineTarget.ts @@ -15,7 +15,7 @@ export default class LineTarget extends BaseTarget { constructor(parameters: LineTargetParameters) { super({ ...extractCommonParameters(parameters), - scopeType: "line", + scopeTypeType: "line", delimiter: "\n", }); } diff --git a/src/processTargets/targets/NotebookCellTarget.ts b/src/processTargets/targets/NotebookCellTarget.ts index 2693f7ca03..b94ae94565 100644 --- a/src/processTargets/targets/NotebookCellTarget.ts +++ b/src/processTargets/targets/NotebookCellTarget.ts @@ -7,7 +7,7 @@ export default class NotebookCellTarget extends BaseTarget { constructor(parameters: CommonTargetParameters) { super({ ...parameters, - scopeType: "notebookCell", + scopeTypeType: "notebookCell", delimiter: "\n", }); } diff --git a/src/processTargets/targets/ParagraphTarget.ts b/src/processTargets/targets/ParagraphTarget.ts index fa6b8abc44..d6792ff64f 100644 --- a/src/processTargets/targets/ParagraphTarget.ts +++ b/src/processTargets/targets/ParagraphTarget.ts @@ -15,7 +15,7 @@ export default class ParagraphTarget extends BaseTarget { constructor(parameters: ParagraphTargetParameters) { super({ ...extractCommonParameters(parameters), - scopeType: "paragraph", + scopeTypeType: "paragraph", delimiter: "\n\n", }); } diff --git a/src/processTargets/targets/ScopeTypeTarget.ts b/src/processTargets/targets/ScopeTypeTarget.ts index c5c3c77b39..aaca02272a 100644 --- a/src/processTargets/targets/ScopeTypeTarget.ts +++ b/src/processTargets/targets/ScopeTypeTarget.ts @@ -2,7 +2,7 @@ import { Range } from "vscode"; import { EditNewLineContext, RemovalRange, - ScopeType, + SimpleScopeTypeType, } from "../../typings/target.types"; import BaseTarget, { CommonTargetParameters, @@ -10,7 +10,7 @@ import BaseTarget, { } from "./BaseTarget"; export interface ScopeTypeTargetParameters extends CommonTargetParameters { - scopeType: ScopeType; + scopeTypeType: SimpleScopeTypeType; delimiter?: string; removalRange?: Range; leadingDelimiter?: RemovalRange; @@ -21,7 +21,7 @@ export default class ScopeTypeTarget extends BaseTarget { constructor(parameters: ScopeTypeTargetParameters) { super({ ...extractCommonParameters(parameters), - delimiter: parameters.delimiter ?? getDelimiter(parameters.scopeType), + delimiter: parameters.delimiter ?? getDelimiter(parameters.scopeTypeType), }); } @@ -40,7 +40,7 @@ export default class ScopeTypeTarget extends BaseTarget { } } -function getDelimiter(scopeType: ScopeType): string { +function getDelimiter(scopeType: SimpleScopeTypeType): string { switch (scopeType) { case "namedFunction": case "anonymousFunction": diff --git a/src/processTargets/targets/TokenTarget.ts b/src/processTargets/targets/TokenTarget.ts index 3778b25b59..2f00fd0cb6 100644 --- a/src/processTargets/targets/TokenTarget.ts +++ b/src/processTargets/targets/TokenTarget.ts @@ -10,7 +10,7 @@ export default class TokenTarget extends BaseTarget { super({ ...extractCommonParameters(parameters), ...getTokenDelimiters(parameters.editor, parameters.contentRange), - scopeType: "token", + scopeTypeType: "token", }); } diff --git a/src/processTargets/targets/WeakTarget.ts b/src/processTargets/targets/WeakTarget.ts index 2066aa3eb8..38f6f2c4ab 100644 --- a/src/processTargets/targets/WeakTarget.ts +++ b/src/processTargets/targets/WeakTarget.ts @@ -1,13 +1,8 @@ -import _ = require("lodash"); -import { Target } from "../../typings/target.types"; -import { ProcessedTargetsContext } from "../../typings/Types"; import { getTokenDelimiters } from "../modifiers/scopeTypeStages/TokenStage"; -import SurroundingPairStage from "../modifiers/SurroundingPairStage"; import BaseTarget, { CommonTargetParameters, extractCommonParameters, } from "./BaseTarget"; -import SurroundingPairTarget from "./SurroundingPairTarget"; /** * - Treated as "line" for "pour", "clone", and "breakpoint" @@ -26,29 +21,7 @@ export default class WeakTarget extends BaseTarget { return true; } - getInterior(context: ProcessedTargetsContext): Target[] { - return this.processSurroundingPair(context).flatMap( - (surroundingPairTarget) => surroundingPairTarget.getInterior(context)! - ); - } - - getBoundary(context: ProcessedTargetsContext): Target[] { - return this.processSurroundingPair(context).flatMap( - (surroundingPairTarget) => surroundingPairTarget.getBoundary(context)! - ); - } - clone(): WeakTarget { return new WeakTarget(this.state); } - - private processSurroundingPair( - context: ProcessedTargetsContext - ): SurroundingPairTarget[] { - const surroundingPairStage = new SurroundingPairStage({ - type: "surroundingPair", - delimiter: "any", - }); - return surroundingPairStage.run(context, this); - } } diff --git a/src/typings/snippet.ts b/src/typings/snippet.ts index 7dd6053146..e96872f663 100644 --- a/src/typings/snippet.ts +++ b/src/typings/snippet.ts @@ -1,4 +1,4 @@ -import { ScopeType } from "./target.types"; +import { ScopeType, SimpleScopeTypeType } from "./target.types"; export interface SnippetScope { langIds?: string[]; @@ -21,7 +21,7 @@ export interface SnippetVariable { * Default to this scope type when wrapping a target without scope type * specified. */ - wrapperScopeType?: ScopeType; + wrapperScopeType?: SimpleScopeTypeType; /** * Description of the snippet variable diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 6f33ef4d51..75e2b1f92c 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -67,7 +67,7 @@ export type SurroundingPairName = | SimpleSurroundingPairName | ComplexSurroundingPairName; -export type ScopeType = +export type SimpleScopeTypeType = | "argumentOrParameter" | "anonymousFunction" | "attribute" @@ -112,15 +112,24 @@ export type ScopeType = | "nonWhitespaceSequence" | "url"; -export type SubTokenType = "word" | "character"; +export interface SimpleScopeType { + type: SimpleScopeTypeType; +} export type SurroundingPairDirection = "left" | "right"; -export interface SurroundingPairModifier { +export interface SurroundingPairScopeType { type: "surroundingPair"; delimiter: SurroundingPairName; forceDirection?: SurroundingPairDirection; } +export type ScopeType = SimpleScopeType | SurroundingPairScopeType; + +export interface ContainingSurroundingPairModifier + extends ContainingScopeModifier { + scopeType: SurroundingPairScopeType; +} + export interface InteriorOnlyModifier { type: "interiorOnly"; } @@ -139,9 +148,9 @@ export interface EveryScopeModifier { scopeType: ScopeType; } -export interface SubTokenModifier { - type: "subpiece"; - pieceType: SubTokenType; +export interface OrdinalRangeModifier { + type: "ordinalRange"; + scopeType: ScopeType; anchor: number; active: number; excludeAnchor?: boolean; @@ -181,12 +190,11 @@ export interface PartialPrimitiveTargetDesc { export type Modifier = | PositionModifier - | SurroundingPairModifier | InteriorOnlyModifier | ExcludeInteriorModifier | ContainingScopeModifier | EveryScopeModifier - | SubTokenModifier + | OrdinalRangeModifier | HeadModifier | TailModifier | RawSelectionModifier; diff --git a/src/util/nodeMatchers.ts b/src/util/nodeMatchers.ts index ed1fa29fe1..6a47f7c2d3 100644 --- a/src/util/nodeMatchers.ts +++ b/src/util/nodeMatchers.ts @@ -6,7 +6,7 @@ import { NodeMatcherAlternative, SelectionWithEditor, } from "../typings/Types"; -import { ScopeType } from "../typings/target.types"; +import { SimpleScopeTypeType } from "../typings/target.types"; import { simpleSelectionExtractor, argumentSelectionExtractor, @@ -176,9 +176,9 @@ export const notSupported: NodeMatcher = ( }; export function createPatternMatchers( - nodeMatchers: Partial> -): Record { - Object.keys(nodeMatchers).forEach((scopeType: ScopeType) => { + nodeMatchers: Partial> +): Record { + Object.keys(nodeMatchers).forEach((scopeType: SimpleScopeTypeType) => { let matcher = nodeMatchers[scopeType]; if (Array.isArray(matcher)) { nodeMatchers[scopeType] = patternMatcher(...matcher); @@ -186,5 +186,5 @@ export function createPatternMatchers( nodeMatchers[scopeType] = patternMatcher(matcher); } }); - return nodeMatchers as Record; + return nodeMatchers as Record; } From 6a758dad004a9d07ad39e69b6d5e1624e78aa4f1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 23 May 2022 20:42:23 +0000 Subject: [PATCH 165/314] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../commandVersionUpgrades/canonicalizeTargets.ts | 11 ++++++----- src/languages/clojure.ts | 4 +++- src/languages/cpp.ts | 4 +++- src/languages/csharp.ts | 4 +++- src/languages/go.ts | 4 +++- src/languages/html.ts | 4 +++- src/languages/java.ts | 4 +++- src/languages/json.ts | 4 +++- src/languages/markdown.ts | 4 +++- src/languages/php.ts | 4 +++- src/languages/python.ts | 4 +++- src/languages/ruby.ts | 4 +++- src/languages/scala.ts | 4 +++- src/languages/scss.ts | 4 +++- src/languages/typescript.ts | 4 +++- 15 files changed, 48 insertions(+), 19 deletions(-) diff --git a/src/core/commandVersionUpgrades/canonicalizeTargets.ts b/src/core/commandVersionUpgrades/canonicalizeTargets.ts index 8c36e615bd..ddd3df7697 100644 --- a/src/core/commandVersionUpgrades/canonicalizeTargets.ts +++ b/src/core/commandVersionUpgrades/canonicalizeTargets.ts @@ -8,11 +8,12 @@ import { import { transformPartialPrimitiveTargets } from "../../util/getPrimitiveTargets"; import { HatStyleName } from "../constants"; -const SCOPE_TYPE_CANONICALIZATION_MAPPING: Record = { - arrowFunction: "anonymousFunction", - dictionary: "map", - regex: "regularExpression", -}; +const SCOPE_TYPE_CANONICALIZATION_MAPPING: Record = + { + arrowFunction: "anonymousFunction", + dictionary: "map", + regex: "regularExpression", + }; const COLOR_CANONICALIZATION_MAPPING: Record = { purple: "pink", diff --git a/src/languages/clojure.ts b/src/languages/clojure.ts index d968192725..f1dffd8a24 100644 --- a/src/languages/clojure.ts +++ b/src/languages/clojure.ts @@ -130,7 +130,9 @@ const ifStatementFinder = functionNameBasedFinder( const ifStatementMatcher = matcher(ifStatementFinder); -const nodeMatchers: Partial> = { +const nodeMatchers: Partial< + Record +> = { comment: "comment", map: "map_lit", diff --git a/src/languages/cpp.ts b/src/languages/cpp.ts index c0616c7fc8..bf8355cea1 100644 --- a/src/languages/cpp.ts +++ b/src/languages/cpp.ts @@ -62,7 +62,9 @@ const TYPE_TYPES = [ "union_specifier", ]; -const nodeMatchers: Partial> = { +const nodeMatchers: Partial< + Record +> = { statement: STATEMENT_TYPES, class: [ "class_specifier", diff --git a/src/languages/csharp.ts b/src/languages/csharp.ts index f122338833..be2ad92776 100644 --- a/src/languages/csharp.ts +++ b/src/languages/csharp.ts @@ -214,7 +214,9 @@ const getMapMatchers = { string: typeMatcher("string_literal"), }; -const nodeMatchers: Partial> = { +const nodeMatchers: Partial< + Record +> = { ...getMapMatchers, ifStatement: "if_statement", class: "class_declaration", diff --git a/src/languages/go.ts b/src/languages/go.ts index 73cff88065..c372308e62 100644 --- a/src/languages/go.ts +++ b/src/languages/go.ts @@ -37,7 +37,9 @@ const STATEMENT_TYPES = [ "var_declaration", ]; -const nodeMatchers: Partial> = { +const nodeMatchers: Partial< + Record +> = { map: "composite_literal", list: ["composite_literal", "slice_type", "array_type"], statement: STATEMENT_TYPES, diff --git a/src/languages/html.ts b/src/languages/html.ts index 39772e9667..f9b393ba83 100644 --- a/src/languages/html.ts +++ b/src/languages/html.ts @@ -18,7 +18,9 @@ const getTags = (selection: SelectionWithEditor, node: SyntaxNode) => { const endTag = getEndTag(selection, node); return startTag != null && endTag != null ? startTag.concat(endTag) : null; }; -const nodeMatchers: Partial> = { +const nodeMatchers: Partial< + Record +> = { xmlElement: ["element", "script_element", "style_element"], xmlBothTags: getTags, xmlStartTag: getStartTag, diff --git a/src/languages/java.ts b/src/languages/java.ts index 8c7083675d..19247fd768 100644 --- a/src/languages/java.ts +++ b/src/languages/java.ts @@ -44,7 +44,9 @@ const STATEMENT_TYPES = [ "switch_statement", ]; -const nodeMatchers: Partial> = { +const nodeMatchers: Partial< + Record +> = { statement: STATEMENT_TYPES, class: "class_declaration", className: "class_declaration[name]", diff --git a/src/languages/json.ts b/src/languages/json.ts index d45bd8775e..cf4f619a7e 100644 --- a/src/languages/json.ts +++ b/src/languages/json.ts @@ -9,7 +9,9 @@ import { SimpleScopeTypeType } from "../typings/target.types"; import { SyntaxNode } from "web-tree-sitter"; import { getNodeRange } from "../util/nodeSelectors"; -const nodeMatchers: Partial> = { +const nodeMatchers: Partial< + Record +> = { map: "object", list: "array", string: "string", diff --git a/src/languages/markdown.ts b/src/languages/markdown.ts index 8d8dc681a0..d82c657b99 100644 --- a/src/languages/markdown.ts +++ b/src/languages/markdown.ts @@ -89,7 +89,9 @@ function sectionMatcher(...patterns: string[]) { return matcher(leadingSiblingNodeFinder(finder), sectionExtractor); } -const nodeMatchers: Partial> = { +const nodeMatchers: Partial< + Record +> = { list: ["loose_list", "tight_list"], comment: "html_block", name: matcher( diff --git a/src/languages/php.ts b/src/languages/php.ts index 5aab14d7e5..404118945b 100644 --- a/src/languages/php.ts +++ b/src/languages/php.ts @@ -98,7 +98,9 @@ function castTypeExtractor( }; } -const nodeMatchers: Partial> = { +const nodeMatchers: Partial< + Record +> = { statement: STATEMENT_TYPES, ifStatement: "if_statement", class: "class_declaration", diff --git a/src/languages/python.ts b/src/languages/python.ts index 6cda01ef65..25e908874a 100644 --- a/src/languages/python.ts +++ b/src/languages/python.ts @@ -49,7 +49,9 @@ export const getTypeNode = (node: SyntaxNode) => const dictionaryTypes = ["dictionary", "dictionary_comprehension"]; const listTypes = ["list", "list_comprehension", "set"]; -const nodeMatchers: Partial> = { +const nodeMatchers: Partial< + Record +> = { map: dictionaryTypes, list: listTypes, statement: STATEMENT_TYPES, diff --git a/src/languages/ruby.ts b/src/languages/ruby.ts index 8cf1669fc7..15930e6de4 100644 --- a/src/languages/ruby.ts +++ b/src/languages/ruby.ts @@ -148,7 +148,9 @@ function blockFinder(node: SyntaxNode) { return block; } -const nodeMatchers: Partial> = { +const nodeMatchers: Partial< + Record +> = { map: mapTypes, list: listTypes, statement: cascadingMatcher( diff --git a/src/languages/scala.ts b/src/languages/scala.ts index b6d4fdc564..94d3be74db 100644 --- a/src/languages/scala.ts +++ b/src/languages/scala.ts @@ -7,7 +7,9 @@ import { import { NodeMatcherAlternative } from "../typings/Types"; import { SimpleScopeTypeType } from "../typings/target.types"; -const nodeMatchers: Partial> = { +const nodeMatchers: Partial< + Record +> = { // treating classes = classlike class: ["class_definition", "object_definition", "trait_definition"], className: [ diff --git a/src/languages/scss.ts b/src/languages/scss.ts index c05adef4c3..a162e11cf5 100644 --- a/src/languages/scss.ts +++ b/src/languages/scss.ts @@ -87,7 +87,9 @@ function findAdjacentArgValues( }; } -const nodeMatchers: Partial> = { +const nodeMatchers: Partial< + Record +> = { ifStatement: "if_statement", condition: conditionMatcher("condition"), statement: cascadingMatcher( diff --git a/src/languages/typescript.ts b/src/languages/typescript.ts index 93fc8e7aa3..067283d584 100644 --- a/src/languages/typescript.ts +++ b/src/languages/typescript.ts @@ -158,7 +158,9 @@ function valueMatcher() { const mapTypes = ["object", "object_pattern"]; const listTypes = ["array", "array_pattern"]; -const nodeMatchers: Partial> = { +const nodeMatchers: Partial< + Record +> = { map: mapTypes, list: listTypes, string: ["string", "template_string"], From 713ac87569b9dda2c3eaa1d9edfce1ee6ff9658f Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Mon, 23 May 2022 22:50:41 +0100 Subject: [PATCH 166/314] Remove scope type type from base target --- src/actions/CopyLines.ts | 4 +- src/actions/Rewrap.ts | 2 +- .../canonicalizeTargets.ts | 2 +- src/processTargets/modifiers/InteriorStage.ts | 4 +- .../modifiers/SurroundingPairStage.ts | 19 +++--- ...ractSelectionFromSurroundingPairOffsets.ts | 35 ++++++----- .../findSurroundingPairParseTreeBased.ts | 5 +- .../findSurroundingPairTextBased.ts | 5 +- .../modifiers/surroundingPair/index.ts | 10 +-- src/processTargets/processTargets.ts | 6 -- src/processTargets/targets/BaseTarget.ts | 63 +++---------------- src/processTargets/targets/DocumentTarget.ts | 1 - src/processTargets/targets/LineTarget.ts | 1 - .../targets/NotebookCellTarget.ts | 1 - src/processTargets/targets/ParagraphTarget.ts | 5 +- .../targets/SurroundingPairTarget.ts | 63 ++++++++++++++++--- src/processTargets/targets/TokenTarget.ts | 1 - 17 files changed, 108 insertions(+), 119 deletions(-) diff --git a/src/actions/CopyLines.ts b/src/actions/CopyLines.ts index c0ce0d58cb..f8bb55e54e 100644 --- a/src/actions/CopyLines.ts +++ b/src/actions/CopyLines.ts @@ -14,9 +14,7 @@ class CopyLines implements Action { } private getRanges(editor: TextEditor, targets: Target[]) { - const paragraphTargets = targets.filter( - (target) => target.scopeTypeType === "paragraph" - ); + const paragraphTargets = targets.filter((target) => target.isParagraph); const ranges = targets.map((target) => expandToContainingLine(editor, target.contentRange) ); diff --git a/src/actions/Rewrap.ts b/src/actions/Rewrap.ts index 9f7f857862..ff93afc27c 100644 --- a/src/actions/Rewrap.ts +++ b/src/actions/Rewrap.ts @@ -20,7 +20,7 @@ export default class Rewrap implements Action { right: string ): Promise { const boundaryTargets = targets.flatMap((target) => { - const boundary = target.boundary; + const boundary = target.getBoundaryStrict(); if (boundary.length !== 2) { throw Error("Target must have an opening and closing delimiter"); diff --git a/src/core/commandVersionUpgrades/canonicalizeTargets.ts b/src/core/commandVersionUpgrades/canonicalizeTargets.ts index ddd3df7697..0198d06a92 100644 --- a/src/core/commandVersionUpgrades/canonicalizeTargets.ts +++ b/src/core/commandVersionUpgrades/canonicalizeTargets.ts @@ -26,7 +26,7 @@ const canonicalizeScopeTypes = ( if (mod.type === "containingScope" || mod.type === "everyScope") { mod.scopeType.type = SCOPE_TYPE_CANONICALIZATION_MAPPING[mod.scopeType.type] ?? - mod.scopeType; + mod.scopeType.type; } }); return target; diff --git a/src/processTargets/modifiers/InteriorStage.ts b/src/processTargets/modifiers/InteriorStage.ts index b359d33896..fc46dbda49 100644 --- a/src/processTargets/modifiers/InteriorStage.ts +++ b/src/processTargets/modifiers/InteriorStage.ts @@ -13,7 +13,7 @@ export class InteriorOnlyStage implements ModifierStage { run(context: ProcessedTargetsContext, target: Target): Target[] { return weakContainingSurroundingPairStage .run(context, target) - .flatMap((target) => target.interior); + .flatMap((target) => target.getInteriorStrict()); } } @@ -23,6 +23,6 @@ export class ExcludeInteriorStage implements ModifierStage { run(context: ProcessedTargetsContext, target: Target): Target[] { return weakContainingSurroundingPairStage .run(context, target) - .flatMap((target) => target.boundary); + .flatMap((target) => target.getBoundaryStrict()); } } diff --git a/src/processTargets/modifiers/SurroundingPairStage.ts b/src/processTargets/modifiers/SurroundingPairStage.ts index 9e00876859..0e12d6f64d 100644 --- a/src/processTargets/modifiers/SurroundingPairStage.ts +++ b/src/processTargets/modifiers/SurroundingPairStage.ts @@ -3,7 +3,6 @@ import { Target, } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; -import { selectionWithEditorWithContextToTarget } from "../../util/targetUtils"; import { ModifierStage } from "../PipelineStages.types"; import SurroundingPairTarget from "../targets/SurroundingPairTarget"; import { processSurroundingPair } from "./surroundingPair"; @@ -37,22 +36,22 @@ function processedSurroundingPairTarget( context: ProcessedTargetsContext, target: Target ): SurroundingPairTarget[] { - const pairs = processSurroundingPair( + const pairInfo = processSurroundingPair( context, target.editor, target.contentRange, modifier.scopeType ); - if (pairs == null) { + if (pairInfo == null) { throw new Error("Couldn't find containing pair"); } - return pairs.map( - (pair) => - new SurroundingPairTarget({ - ...selectionWithEditorWithContextToTarget(pair), - isReversed: target.isReversed, - }) - ); + return [ + new SurroundingPairTarget({ + ...pairInfo, + editor: target.editor, + isReversed: target.isReversed, + }), + ]; } diff --git a/src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts b/src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts index 14b290b0b2..a3e51fc510 100644 --- a/src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts +++ b/src/processTargets/modifiers/surroundingPair/extractSelectionFromSurroundingPairOffsets.ts @@ -1,7 +1,12 @@ import { Range, Selection, TextDocument } from "vscode"; -import { SelectionWithContext } from "../../../typings/Types"; import { SurroundingPairOffsets } from "./types"; +export interface SurroundingPairInfo { + contentRange: Selection; + boundary: [Range, Range]; + interiorRange: Range; +} + /** * Given offsets describing a surrounding pair, returns a selection * @@ -15,7 +20,7 @@ export function extractSelectionFromSurroundingPairOffsets( document: TextDocument, baseOffset: number, surroundingPairOffsets: SurroundingPairOffsets -): SelectionWithContext[] { +): SurroundingPairInfo { const interior = new Range( document.positionAt(baseOffset + surroundingPairOffsets.leftDelimiter.end), document.positionAt( @@ -39,20 +44,16 @@ export function extractSelectionFromSurroundingPairOffsets( ), ]; - return [ - { - selection: new Selection( - document.positionAt( - baseOffset + surroundingPairOffsets.leftDelimiter.start - ), - document.positionAt( - baseOffset + surroundingPairOffsets.rightDelimiter.end - ) + return { + contentRange: new Selection( + document.positionAt( + baseOffset + surroundingPairOffsets.leftDelimiter.start ), - context: { - boundary, - interiorRange: interior, - }, - }, - ]; + document.positionAt( + baseOffset + surroundingPairOffsets.rightDelimiter.end + ) + ), + boundary, + interiorRange: interior, + }; } diff --git a/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts b/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts index a96c3a7bf4..a3626d9992 100644 --- a/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts +++ b/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts @@ -116,10 +116,7 @@ export function findSurroundingPairParseTreeBased( document, 0, pairOffsets - ).map(({ selection, context }) => ({ - selection: { selection, editor }, - context, - })); + ); } } diff --git a/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts b/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts index ee626f37c3..3eae43f80c 100644 --- a/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts +++ b/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts @@ -166,10 +166,7 @@ export function findSurroundingPairTextBased( document, currentRangeOffsets.start, pairOffsets - ).map(({ selection, context }) => ({ - selection: { selection, editor }, - context, - })); + ); } // If the current range is greater than are equal to the full range then we diff --git a/src/processTargets/modifiers/surroundingPair/index.ts b/src/processTargets/modifiers/surroundingPair/index.ts index 4b2e90a940..dcb015bff9 100644 --- a/src/processTargets/modifiers/surroundingPair/index.ts +++ b/src/processTargets/modifiers/surroundingPair/index.ts @@ -1,17 +1,17 @@ import { Location, Range, Selection, TextEditor } from "vscode"; import { SyntaxNode } from "web-tree-sitter"; import getTextFragmentExtractor, { - TextFragmentExtractor, + TextFragmentExtractor } from "../../../languages/getTextFragmentExtractor"; import { ComplexSurroundingPairName, - SurroundingPairScopeType, + SurroundingPairScopeType } from "../../../typings/target.types"; import { - ProcessedTargetsContext, - SelectionWithEditorWithContext, + ProcessedTargetsContext } from "../../../typings/Types"; import { complexDelimiterMap } from "./delimiterMaps"; +import { SurroundingPairInfo } from "./extractSelectionFromSurroundingPairOffsets"; import { findSurroundingPairParseTreeBased } from "./findSurroundingPairParseTreeBased"; import { findSurroundingPairTextBased } from "./findSurroundingPairTextBased"; @@ -33,7 +33,7 @@ export function processSurroundingPair( editor: TextEditor, range: Range, modifier: SurroundingPairScopeType -): SelectionWithEditorWithContext[] | null { +): SurroundingPairInfo | null { const document = editor.document; const delimiters = complexDelimiterMap[ modifier.delimiter as ComplexSurroundingPairName diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index 43f74abe8d..b424fdd2fe 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -164,11 +164,6 @@ function processContinuousRangeTarget( return endTarget.trailingDelimiter; })(); - const scopeType = - startTarget.scopeTypeType === endTarget.scopeTypeType - ? startTarget.scopeTypeType - : undefined; - // If both objects are of the same type create a new object of the same const startConstructor = Object.getPrototypeOf(startTarget).constructor; const endConstructor = Object.getPrototypeOf(endTarget).constructor; @@ -181,7 +176,6 @@ function processContinuousRangeTarget( delimiter: anchorTarget.delimiter, contentRange, removalRange, - scopeType, leadingDelimiter, trailingDelimiter, }); diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index 402f6ec903..7ea206087e 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -3,11 +3,9 @@ import { EditNewLineContext, Position, RemovalRange, - SimpleScopeTypeType, Target, } from "../../typings/target.types"; import { parseRemovalRange } from "../../util/targetUtils"; -import WeakTarget from "./WeakTarget"; export function extractCommonParameters(parameters: CommonTargetParameters) { return { @@ -27,11 +25,8 @@ export interface CommonTargetParameters { } export interface BaseTargetParameters extends CommonTargetParameters { - scopeTypeType?: SimpleScopeTypeType; delimiter: string; removalRange?: Range; - interiorRange?: Range; - boundary?: [Range, Range]; leadingDelimiter?: RemovalRange; trailingDelimiter?: RemovalRange; isLine?: boolean; @@ -50,26 +45,9 @@ interface BaseTargetState { /** If this selection has a delimiter. For example, new line for a line or paragraph and comma for a list or argument */ readonly delimiter: string; - /** Is this a scope type other raw selection? */ - readonly scopeTypeType?: SimpleScopeTypeType; - /** The range to remove the content */ readonly removalRange?: Range; - /** - * Represents the interior range of this selection. For example, for a - * surrounding pair this would exclude the opening and closing delimiter. For an if - * statement this would be the statements in the body. - */ - readonly interiorRange?: Range; - - /** - * Represents the boundary ranges of this selection. For example, for a - * surrounding pair this would be the opening and closing delimiter. For an if - * statement this would be the line of the guard as well as the closing brace. - */ - readonly boundary?: [Range, Range]; - /** The range of the delimiter before the content selection */ readonly leadingDelimiter?: RemovalRange; @@ -80,7 +58,7 @@ interface BaseTargetState { position?: Position; } -export default abstract class BaseTarget implements Target { +export default abstract class BaseTarget { protected readonly state: BaseTargetState; constructor(parameters: BaseTargetParameters) { @@ -89,10 +67,7 @@ export default abstract class BaseTarget implements Target { isReversed: parameters.isReversed, contentRange: parameters.contentRange, delimiter: parameters.delimiter, - scopeTypeType: parameters.scopeTypeType, removalRange: parameters.removalRange, - interiorRange: parameters.interiorRange, - boundary: parameters.boundary, leadingDelimiter: parameters.leadingDelimiter, trailingDelimiter: parameters.trailingDelimiter, position: parameters.position, @@ -115,12 +90,13 @@ export default abstract class BaseTarget implements Target { return this.state.removalRange; } - get scopeTypeType() { - return this.state.scopeTypeType; + /** If true this target should be treated as a line */ + get isLine() { + return false; } - /** If true this target should be treated as a line in regards to continuous range */ - get isLine() { + /** If true this target should be treated as a paragraph */ + get isParagraph() { return false; } @@ -129,31 +105,12 @@ export default abstract class BaseTarget implements Target { return false; } - get interior(): Target[] { - if (this.state.interiorRange == null || this.position != null) { - throw Error("No available interior"); - } - return [ - new WeakTarget({ - editor: this.editor, - isReversed: this.isReversed, - contentRange: this.state.interiorRange, - }), - ]; + getInteriorStrict(): Target[] { + throw Error("No available interior"); } - get boundary(): Target[] { - if (this.state.boundary == null || this.position != null) { - throw Error("No available boundaries"); - } - return this.state.boundary.map( - (contentRange) => - new WeakTarget({ - editor: this.editor, - isReversed: this.isReversed, - contentRange, - }) - ); + getBoundaryStrict(): Target[] { + throw Error("No available boundaries"); } get contentRange(): Range { diff --git a/src/processTargets/targets/DocumentTarget.ts b/src/processTargets/targets/DocumentTarget.ts index 62e94cb9a5..6e9eea78c0 100644 --- a/src/processTargets/targets/DocumentTarget.ts +++ b/src/processTargets/targets/DocumentTarget.ts @@ -8,7 +8,6 @@ export default class DocumentTarget extends BaseTarget { constructor(parameters: CommonTargetParameters) { super({ ...extractCommonParameters(parameters), - scopeTypeType: "document", delimiter: "\n", }); } diff --git a/src/processTargets/targets/LineTarget.ts b/src/processTargets/targets/LineTarget.ts index 3121cab9fb..0e96383951 100644 --- a/src/processTargets/targets/LineTarget.ts +++ b/src/processTargets/targets/LineTarget.ts @@ -15,7 +15,6 @@ export default class LineTarget extends BaseTarget { constructor(parameters: LineTargetParameters) { super({ ...extractCommonParameters(parameters), - scopeTypeType: "line", delimiter: "\n", }); } diff --git a/src/processTargets/targets/NotebookCellTarget.ts b/src/processTargets/targets/NotebookCellTarget.ts index b94ae94565..f5c414e94c 100644 --- a/src/processTargets/targets/NotebookCellTarget.ts +++ b/src/processTargets/targets/NotebookCellTarget.ts @@ -7,7 +7,6 @@ export default class NotebookCellTarget extends BaseTarget { constructor(parameters: CommonTargetParameters) { super({ ...parameters, - scopeTypeType: "notebookCell", delimiter: "\n", }); } diff --git a/src/processTargets/targets/ParagraphTarget.ts b/src/processTargets/targets/ParagraphTarget.ts index d6792ff64f..01039baf76 100644 --- a/src/processTargets/targets/ParagraphTarget.ts +++ b/src/processTargets/targets/ParagraphTarget.ts @@ -15,7 +15,6 @@ export default class ParagraphTarget extends BaseTarget { constructor(parameters: ParagraphTargetParameters) { super({ ...extractCommonParameters(parameters), - scopeTypeType: "paragraph", delimiter: "\n\n", }); } @@ -24,6 +23,10 @@ export default class ParagraphTarget extends BaseTarget { return true; } + get isParagraph() { + return true; + } + protected getRemovalBeforeRange(): Range { return this.leadingDelimiter != null ? new Range( diff --git a/src/processTargets/targets/SurroundingPairTarget.ts b/src/processTargets/targets/SurroundingPairTarget.ts index 8f50414e22..6691666b7e 100644 --- a/src/processTargets/targets/SurroundingPairTarget.ts +++ b/src/processTargets/targets/SurroundingPairTarget.ts @@ -1,27 +1,74 @@ import { Range } from "vscode"; -import { RemovalRange } from "../../typings/target.types"; +import { RemovalRange, Target } from "../../typings/target.types"; +import { getTokenDelimiters } from "../modifiers/scopeTypeStages/TokenStage"; import BaseTarget, { CommonTargetParameters, extractCommonParameters, } from "./BaseTarget"; +import WeakTarget from "./WeakTarget"; interface SurroundingPairTargetParameters extends CommonTargetParameters { - delimiter?: string; - interiorRange?: Range; - boundary?: [Range, Range]; - leadingDelimiter?: RemovalRange; - trailingDelimiter?: RemovalRange; + /** + * Represents the interior range of this selection. For example, for a + * surrounding pair this would exclude the opening and closing delimiter. For an if + * statement this would be the statements in the body. + */ + readonly interiorRange: Range; + + /** + * Represents the boundary ranges of this selection. For example, for a + * surrounding pair this would be the opening and closing delimiter. For an if + * statement this would be the line of the guard as well as the closing brace. + */ + readonly boundary: [Range, Range]; } export default class SurroundingPairTarget extends BaseTarget { + private interiorRange_: Range; + private boundary_: [Range, Range]; + constructor(parameters: SurroundingPairTargetParameters) { super({ ...extractCommonParameters(parameters), - delimiter: parameters.delimiter ?? " ", + ...getTokenDelimiters(parameters.editor, parameters.contentRange), }); + + this.boundary_ = parameters.boundary; + this.interiorRange_ = parameters.interiorRange; } clone(): SurroundingPairTarget { - return new SurroundingPairTarget(this.state); + return new SurroundingPairTarget({ + ...this.state, + interiorRange: this.interiorRange_, + boundary: this.boundary_, + }); + } + + getInteriorStrict(): Target[] { + if (this.interiorRange_ == null || this.position != null) { + throw Error("No available interior"); + } + return [ + new WeakTarget({ + editor: this.editor, + isReversed: this.isReversed, + contentRange: this.interiorRange_, + }), + ]; + } + + getBoundaryStrict(): Target[] { + if (this.boundary_ == null || this.position != null) { + throw Error("No available boundaries"); + } + return this.boundary_.map( + (contentRange) => + new WeakTarget({ + editor: this.editor, + isReversed: this.isReversed, + contentRange, + }) + ); } } diff --git a/src/processTargets/targets/TokenTarget.ts b/src/processTargets/targets/TokenTarget.ts index 2f00fd0cb6..0fb9ceb9e5 100644 --- a/src/processTargets/targets/TokenTarget.ts +++ b/src/processTargets/targets/TokenTarget.ts @@ -10,7 +10,6 @@ export default class TokenTarget extends BaseTarget { super({ ...extractCommonParameters(parameters), ...getTokenDelimiters(parameters.editor, parameters.contentRange), - scopeTypeType: "token", }); } From 9642209f692f77862e2f3281f089a8158fe3aef1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 23 May 2022 21:53:50 +0000 Subject: [PATCH 167/314] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/processTargets/modifiers/surroundingPair/index.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/processTargets/modifiers/surroundingPair/index.ts b/src/processTargets/modifiers/surroundingPair/index.ts index dcb015bff9..c73a21e12a 100644 --- a/src/processTargets/modifiers/surroundingPair/index.ts +++ b/src/processTargets/modifiers/surroundingPair/index.ts @@ -1,15 +1,13 @@ import { Location, Range, Selection, TextEditor } from "vscode"; import { SyntaxNode } from "web-tree-sitter"; import getTextFragmentExtractor, { - TextFragmentExtractor + TextFragmentExtractor, } from "../../../languages/getTextFragmentExtractor"; import { ComplexSurroundingPairName, - SurroundingPairScopeType + SurroundingPairScopeType, } from "../../../typings/target.types"; -import { - ProcessedTargetsContext -} from "../../../typings/Types"; +import { ProcessedTargetsContext } from "../../../typings/Types"; import { complexDelimiterMap } from "./delimiterMaps"; import { SurroundingPairInfo } from "./extractSelectionFromSurroundingPairOffsets"; import { findSurroundingPairParseTreeBased } from "./findSurroundingPairParseTreeBased"; From 0aa8149b36389441ffcb83b5d74e732453ab14fe Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 24 May 2022 09:52:11 +0200 Subject: [PATCH 168/314] Updated to edit new context --- src/actions/Actions.ts | 6 +++--- src/actions/{EditNewLine.ts => EditNew.ts} | 10 +++++----- src/processTargets/targets/BaseTarget.ts | 6 +++--- src/processTargets/targets/NotebookCellTarget.ts | 4 ++-- src/processTargets/targets/ParagraphTarget.ts | 8 +------- src/processTargets/targets/RawSelectionTarget.ts | 7 ------- src/processTargets/targets/ScopeTypeTarget.ts | 16 +--------------- src/processTargets/targets/TokenTarget.ts | 7 ------- src/processTargets/targets/WeakTarget.ts | 7 +++++++ src/typings/target.types.ts | 2 +- 10 files changed, 23 insertions(+), 50 deletions(-) rename src/actions/{EditNewLine.ts => EditNew.ts} (94%) diff --git a/src/actions/Actions.ts b/src/actions/Actions.ts index c9cde79265..811281ae02 100644 --- a/src/actions/Actions.ts +++ b/src/actions/Actions.ts @@ -7,7 +7,7 @@ import { CommentLines } from "./Comment"; import { CopyLinesDown, CopyLinesUp } from "./CopyLines"; import { Copy, Cut, Paste } from "./CutCopyPaste"; import Deselect from "./Deselect"; -import { EditNewLineAbove, EditNewLineBelow } from "./EditNewLine"; +import { EditNewBefore, EditNewAfter } from "./EditNew"; import ExecuteCommand from "./ExecuteCommand"; import ExtractVariable from "./ExtractVariable"; import { FindInFiles } from "./Find"; @@ -43,8 +43,8 @@ class Actions implements ActionRecord { copyToClipboard = new Copy(this.graph); cutToClipboard = new Cut(this.graph); deselect = new Deselect(this.graph); - editNewLineAfter = new EditNewLineBelow(this.graph); - editNewLineBefore = new EditNewLineAbove(this.graph); + editNewLineAfter = new EditNewAfter(this.graph); + editNewLineBefore = new EditNewBefore(this.graph); executeCommand = new ExecuteCommand(this.graph); extractVariable = new ExtractVariable(this.graph); findInWorkspace = new FindInFiles(this.graph); diff --git a/src/actions/EditNewLine.ts b/src/actions/EditNew.ts similarity index 94% rename from src/actions/EditNewLine.ts rename to src/actions/EditNew.ts index de025ec46c..172322ae24 100644 --- a/src/actions/EditNewLine.ts +++ b/src/actions/EditNew.ts @@ -10,7 +10,7 @@ import { Graph } from "../typings/Types"; import { createThatMark, ensureSingleEditor } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; -class EditNewLine implements Action { +class EditNew implements Action { constructor(private graph: Graph, private isBefore: boolean) { this.run = this.run.bind(this); } @@ -20,7 +20,7 @@ class EditNewLine implements Action { const targetsWithContext = targets.map((target) => ({ target, - context: target.getEditNewLineContext(this.isBefore), + context: target.getEditNewContext(this.isBefore), })); const commandTargets = targetsWithContext.filter( ({ context }) => !!(context).command @@ -50,7 +50,7 @@ class EditNewLine implements Action { async runDelimiter(targets: Target[], editor: TextEditor) { const edits = targets.map((target) => { const { contentRange } = target; - const context = target.getEditNewLineContext(this.isBefore); + const context = target.getEditNewContext(this.isBefore); const delimiter = (context).delimiter as string; // Delimiter is one or more new lines. Handle as lines. @@ -137,13 +137,13 @@ class EditNewLine implements Action { } } -export class EditNewLineAbove extends EditNewLine { +export class EditNewBefore extends EditNew { constructor(graph: Graph) { super(graph, true); } } -export class EditNewLineBelow extends EditNewLine { +export class EditNewAfter extends EditNew { constructor(graph: Graph) { super(graph, false); } diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index 7ea206087e..cc270a0a2c 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -1,6 +1,6 @@ import { Range, Selection, TextEditor } from "vscode"; import { - EditNewLineContext, + EditNewContext as EditNewContext, Position, RemovalRange, Target, @@ -253,9 +253,9 @@ export default abstract class BaseTarget { } } - getEditNewLineContext(_isBefore: boolean): EditNewLineContext { + getEditNewContext(_isBefore: boolean): EditNewContext { return { - delimiter: "\n", + delimiter: this.delimiter ?? "", }; } diff --git a/src/processTargets/targets/NotebookCellTarget.ts b/src/processTargets/targets/NotebookCellTarget.ts index f5c414e94c..47e7da61f5 100644 --- a/src/processTargets/targets/NotebookCellTarget.ts +++ b/src/processTargets/targets/NotebookCellTarget.ts @@ -1,5 +1,5 @@ import { TextEditor } from "vscode"; -import { EditNewLineContext } from "../../typings/target.types"; +import { EditNewContext } from "../../typings/target.types"; import { getNotebookFromCellDocument } from "../../util/notebook"; import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; @@ -11,7 +11,7 @@ export default class NotebookCellTarget extends BaseTarget { }); } - getEditNewLineContext(isBefore: boolean): EditNewLineContext { + getEditNewContext(isBefore: boolean): EditNewContext { if (this.isNotebookEditor(this.editor)) { return { command: isBefore diff --git a/src/processTargets/targets/ParagraphTarget.ts b/src/processTargets/targets/ParagraphTarget.ts index 01039baf76..50aeb5a9b4 100644 --- a/src/processTargets/targets/ParagraphTarget.ts +++ b/src/processTargets/targets/ParagraphTarget.ts @@ -1,5 +1,5 @@ import { Range } from "vscode"; -import { EditNewLineContext, RemovalRange } from "../../typings/target.types"; +import { RemovalRange } from "../../typings/target.types"; import { parseRemovalRange } from "../../util/targetUtils"; import BaseTarget, { CommonTargetParameters, @@ -70,12 +70,6 @@ export default class ParagraphTarget extends BaseTarget { : removalRange; } - getEditNewLineContext(_isBefore: boolean): EditNewLineContext { - return { - delimiter: this.delimiter!, - }; - } - clone(): ParagraphTarget { return new ParagraphTarget(this.state); } diff --git a/src/processTargets/targets/RawSelectionTarget.ts b/src/processTargets/targets/RawSelectionTarget.ts index adf86cee0f..9e3e184e6a 100644 --- a/src/processTargets/targets/RawSelectionTarget.ts +++ b/src/processTargets/targets/RawSelectionTarget.ts @@ -1,4 +1,3 @@ -import { EditNewLineContext } from "../../typings/target.types"; import BaseTarget, { CommonTargetParameters, extractCommonParameters, @@ -13,12 +12,6 @@ export default class RawSelectionTarget extends BaseTarget { return undefined; } - getEditNewLineContext(_isBefore: boolean): EditNewLineContext { - return { - delimiter: "", - }; - } - clone(): RawSelectionTarget { return new RawSelectionTarget(this.state); } diff --git a/src/processTargets/targets/ScopeTypeTarget.ts b/src/processTargets/targets/ScopeTypeTarget.ts index aaca02272a..6269f2f222 100644 --- a/src/processTargets/targets/ScopeTypeTarget.ts +++ b/src/processTargets/targets/ScopeTypeTarget.ts @@ -1,9 +1,5 @@ import { Range } from "vscode"; -import { - EditNewLineContext, - RemovalRange, - SimpleScopeTypeType, -} from "../../typings/target.types"; +import { RemovalRange, SimpleScopeTypeType } from "../../typings/target.types"; import BaseTarget, { CommonTargetParameters, extractCommonParameters, @@ -25,16 +21,6 @@ export default class ScopeTypeTarget extends BaseTarget { }); } - getEditNewLineContext(isBefore: boolean): EditNewLineContext { - // This is the default and should implement the default version whatever that is. - if (this.delimiter === "\n") { - return super.getEditNewLineContext(isBefore); - } - return { - delimiter: this.delimiter!, - }; - } - clone(): ScopeTypeTarget { return new ScopeTypeTarget(this.state); } diff --git a/src/processTargets/targets/TokenTarget.ts b/src/processTargets/targets/TokenTarget.ts index 0fb9ceb9e5..4335fece8f 100644 --- a/src/processTargets/targets/TokenTarget.ts +++ b/src/processTargets/targets/TokenTarget.ts @@ -1,4 +1,3 @@ -import { EditNewLineContext } from "../../typings/target.types"; import { getTokenDelimiters } from "../modifiers/scopeTypeStages/TokenStage"; import BaseTarget, { CommonTargetParameters, @@ -13,12 +12,6 @@ export default class TokenTarget extends BaseTarget { }); } - getEditNewLineContext(_isBefore: boolean): EditNewLineContext { - return { - delimiter: " ", - }; - } - clone(): TokenTarget { return new TokenTarget(this.state); } diff --git a/src/processTargets/targets/WeakTarget.ts b/src/processTargets/targets/WeakTarget.ts index 38f6f2c4ab..9c6314d8a8 100644 --- a/src/processTargets/targets/WeakTarget.ts +++ b/src/processTargets/targets/WeakTarget.ts @@ -1,3 +1,4 @@ +import { EditNewContext } from "../../typings/target.types"; import { getTokenDelimiters } from "../modifiers/scopeTypeStages/TokenStage"; import BaseTarget, { CommonTargetParameters, @@ -21,6 +22,12 @@ export default class WeakTarget extends BaseTarget { return true; } + getEditNewContext(_isBefore: boolean): EditNewContext { + return { + delimiter: "\n", + }; + } + clone(): WeakTarget { return new WeakTarget(this.state); } diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 75e2b1f92c..bb55a15956 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -255,6 +255,6 @@ export interface RemovalRange { exclude?: boolean; } -export type EditNewLineContext = { command: string } | { delimiter: string }; +export type EditNewContext = { command: string } | { delimiter: string }; export type Target = BaseTarget; From 0239d07c03aad92795e548aa601b1fd43587d50d Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 24 May 2022 15:44:23 +0200 Subject: [PATCH 169/314] Added bring statement test --- .../positions/bringStateFineToAfterBatt.yml | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 src/test/suite/fixtures/recorded/positions/bringStateFineToAfterBatt.yml diff --git a/src/test/suite/fixtures/recorded/positions/bringStateFineToAfterBatt.yml b/src/test/suite/fixtures/recorded/positions/bringStateFineToAfterBatt.yml new file mode 100644 index 0000000000..ce4633ab56 --- /dev/null +++ b/src/test/suite/fixtures/recorded/positions/bringStateFineToAfterBatt.yml @@ -0,0 +1,47 @@ +languageId: typescript +command: + spokenForm: bring state fine to after batt + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: f} + modifiers: + - type: containingScope + scopeType: {type: statement} + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: b} + modifiers: + - type: containingScope + scopeType: {type: statement} + - {type: position, position: after} + usePrePhraseSnapshot: true + action: {name: replaceWithTarget} +initialState: + documentContents: | + let foo; + let bar; + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: + default.f: + start: {line: 0, character: 4} + end: {line: 0, character: 7} + default.b: + start: {line: 1, character: 4} + end: {line: 1, character: 7} +finalState: + documentContents: | + let foo; + let bar; + let foo; + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 1, character: 8} + active: {line: 2, character: 8} + sourceMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 8} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: f}, modifiers: [&ref_0 {type: containingScope, scopeType: {type: statement}}]}, {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: b}, modifiers: [*ref_0, {type: position, position: after}]}] From 05d3f465d0bf8979bb69f57fa55367f9873ca699 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 24 May 2022 16:03:56 +0200 Subject: [PATCH 170/314] Change behavior of pour line --- src/processTargets/targets/BaseTarget.ts | 5 ++- src/processTargets/targets/WeakTarget.ts | 8 ++--- .../fixtures/recorded/actions/drinkLine.yml | 33 +++++++++++++++++++ .../fixtures/recorded/actions/pourLine.yml | 33 +++++++++++++++++++ 4 files changed, 74 insertions(+), 5 deletions(-) create mode 100644 src/test/suite/fixtures/recorded/actions/drinkLine.yml create mode 100644 src/test/suite/fixtures/recorded/actions/pourLine.yml diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index cc270a0a2c..301129c887 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -253,7 +253,10 @@ export default abstract class BaseTarget { } } - getEditNewContext(_isBefore: boolean): EditNewContext { + getEditNewContext(isBefore: boolean): EditNewContext { + if (this.delimiter === "\n" && !isBefore) { + return { command: "editor.action.insertLineAfter" }; + } return { delimiter: this.delimiter ?? "", }; diff --git a/src/processTargets/targets/WeakTarget.ts b/src/processTargets/targets/WeakTarget.ts index 9c6314d8a8..86156272e0 100644 --- a/src/processTargets/targets/WeakTarget.ts +++ b/src/processTargets/targets/WeakTarget.ts @@ -22,10 +22,10 @@ export default class WeakTarget extends BaseTarget { return true; } - getEditNewContext(_isBefore: boolean): EditNewContext { - return { - delimiter: "\n", - }; + getEditNewContext(isBefore: boolean): EditNewContext { + return isBefore + ? { delimiter: "\n" } + : { command: "editor.action.insertLineAfter" }; } clone(): WeakTarget { diff --git a/src/test/suite/fixtures/recorded/actions/drinkLine.yml b/src/test/suite/fixtures/recorded/actions/drinkLine.yml new file mode 100644 index 0000000000..4f025ce87e --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/drinkLine.yml @@ -0,0 +1,33 @@ +languageId: python +command: + spokenForm: drink line + version: 2 + targets: + - type: primitive + modifiers: + - type: containingScope + scopeType: {type: line} + usePrePhraseSnapshot: true + action: {name: editNewLineBefore} +initialState: + documentContents: | + class MyClass: + def my_funk(): + pass + selections: + - anchor: {line: 1, character: 11} + active: {line: 1, character: 11} + marks: {} +finalState: + documentContents: | + class MyClass: + + def my_funk(): + pass + selections: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} + thatMark: + - anchor: {line: 2, character: 4} + active: {line: 2, character: 18} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: containingScope, scopeType: {type: line}}]}] diff --git a/src/test/suite/fixtures/recorded/actions/pourLine.yml b/src/test/suite/fixtures/recorded/actions/pourLine.yml new file mode 100644 index 0000000000..200974a6d2 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/pourLine.yml @@ -0,0 +1,33 @@ +languageId: python +command: + spokenForm: pour line + version: 2 + targets: + - type: primitive + modifiers: + - type: containingScope + scopeType: {type: line} + usePrePhraseSnapshot: true + action: {name: editNewLineAfter} +initialState: + documentContents: | + class MyClass: + def my_funk(): + pass + selections: + - anchor: {line: 1, character: 9} + active: {line: 1, character: 9} + marks: {} +finalState: + documentContents: | + class MyClass: + def my_funk(): + + pass + selections: + - anchor: {line: 2, character: 8} + active: {line: 2, character: 8} + thatMark: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 18} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: containingScope, scopeType: {type: line}}]}] From 55f761f0e768b5c64585f265a941af02066c6760 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 24 May 2022 16:08:07 +0200 Subject: [PATCH 171/314] Use weak containing line stage for edit new --- src/actions/EditNew.ts | 3 +++ src/processTargets/targets/WeakTarget.ts | 7 ------- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/actions/EditNew.ts b/src/actions/EditNew.ts index 172322ae24..d376584ec7 100644 --- a/src/actions/EditNew.ts +++ b/src/actions/EditNew.ts @@ -5,12 +5,15 @@ import { Selection, TextEditor, } from "vscode"; +import { weakContainingLineStage } from "../processTargets/modifiers/commonWeakContainingScopeStages"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; import { createThatMark, ensureSingleEditor } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; class EditNew implements Action { + getFinalStages = () => [weakContainingLineStage]; + constructor(private graph: Graph, private isBefore: boolean) { this.run = this.run.bind(this); } diff --git a/src/processTargets/targets/WeakTarget.ts b/src/processTargets/targets/WeakTarget.ts index 86156272e0..38f6f2c4ab 100644 --- a/src/processTargets/targets/WeakTarget.ts +++ b/src/processTargets/targets/WeakTarget.ts @@ -1,4 +1,3 @@ -import { EditNewContext } from "../../typings/target.types"; import { getTokenDelimiters } from "../modifiers/scopeTypeStages/TokenStage"; import BaseTarget, { CommonTargetParameters, @@ -22,12 +21,6 @@ export default class WeakTarget extends BaseTarget { return true; } - getEditNewContext(isBefore: boolean): EditNewContext { - return isBefore - ? { delimiter: "\n" } - : { command: "editor.action.insertLineAfter" }; - } - clone(): WeakTarget { return new WeakTarget(this.state); } From 8dc708ef5b262bd1fc5cc53248772764a9b4af35 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 24 May 2022 20:09:35 +0200 Subject: [PATCH 172/314] Updated edit new --- src/actions/EditNew.ts | 302 ++++++++++++------ src/core/updateSelections/updateSelections.ts | 4 +- src/processTargets/targets/BaseTarget.ts | 3 +- .../targets/NotebookCellTarget.ts | 2 + src/typings/target.types.ts | 11 +- 5 files changed, 221 insertions(+), 101 deletions(-) diff --git a/src/actions/EditNew.ts b/src/actions/EditNew.ts index d376584ec7..efa80b8be0 100644 --- a/src/actions/EditNew.ts +++ b/src/actions/EditNew.ts @@ -1,12 +1,22 @@ +import { zip } from "lodash"; import { + commands, commands as vscommands, Position, Range, Selection, TextEditor, } from "vscode"; +import { + callFunctionAndUpdateSelections, + performEditsAndUpdateSelections, +} from "../core/updateSelections/updateSelections"; import { weakContainingLineStage } from "../processTargets/modifiers/commonWeakContainingScopeStages"; -import { Target } from "../typings/target.types"; +import { + EditNewCommandContext, + EditNewDelimiterContext, + Target, +} from "../typings/target.types"; import { Graph } from "../typings/Types"; import { createThatMark, ensureSingleEditor } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; @@ -20,124 +30,188 @@ class EditNew implements Action { async run([targets]: [Target[]]): Promise { const editor = ensureSingleEditor(targets); - - const targetsWithContext = targets.map((target) => ({ - target, - context: target.getEditNewContext(this.isBefore), - })); - const commandTargets = targetsWithContext.filter( - ({ context }) => !!(context).command - ); - const delimiterTargets = targetsWithContext.filter( - ({ context }) => !!(context).delimiter + const { commandTargets, delimiterTargets } = groupTargets( + targets, + this.isBefore ); - if (commandTargets.length > 0 && delimiterTargets.length > 0) { - throw new Error("Can't insert edit using command and delimiter at once"); - } + const { + updatedCommandTargetSelections, + updatedDelimiterTargetSelections, + commandSelections, + } = await this.runCommandTargets(editor, commandTargets, delimiterTargets); - if (commandTargets.length > 0) { - const commands = commandTargets.map( - ({ context }) => (context).command - ); + if (updatedDelimiterTargetSelections.length < 1) { return { - thatMark: await this.runCommand(targets, commands), + thatMark: updatedCommandTargetSelections.map((selection) => ({ + editor, + selection, + })), }; } - return { - thatMark: await this.runDelimiter(targets, editor), - }; - } - - async runDelimiter(targets: Target[], editor: TextEditor) { - const edits = targets.map((target) => { - const { contentRange } = target; - const context = target.getEditNewContext(this.isBefore); - const delimiter = (context).delimiter as string; - - // Delimiter is one or more new lines. Handle as lines. - if (delimiter.includes("\n")) { - const lineNumber = this.isBefore - ? contentRange.start.line - : contentRange.end.line; - const line = editor.document.lineAt(lineNumber); - const characterIndex = line.isEmptyOrWhitespace - ? contentRange.start.character - : line.firstNonWhitespaceCharacterIndex; - const padding = line.text.slice(0, characterIndex); - const positionSelection = new Position( - this.isBefore ? lineNumber : lineNumber + delimiter.length, - characterIndex - ); + const edits = zip(delimiterTargets, updatedDelimiterTargetSelections).map( + ([target, selection]) => { + const position = this.isBefore ? selection!.start : selection!.end; return { - contentRange, - text: this.isBefore ? padding + delimiter : delimiter + padding, - insertPosition: this.isBefore ? line.range.start : line.range.end, - selection: new Selection(positionSelection, positionSelection), - thatMarkRange: this.isBefore - ? new Range( - contentRange.start.translate({ - lineDelta: delimiter.length, - }), - contentRange.end.translate({ - lineDelta: delimiter.length, - }) - ) - : contentRange, + text: target!.context.delimiter, + range: new Range(position, position), + isReplace: !this.isBefore, }; } - // Delimiter is something else. Handle as inline. - else { - const positionSelection = this.isBefore - ? contentRange.start - : contentRange.end.translate({ - characterDelta: delimiter.length, - }); - return { - contentRange, - text: delimiter, - insertPosition: this.isBefore ? contentRange.start : contentRange.end, - selection: new Selection(positionSelection, positionSelection), - thatMarkRange: this.isBefore - ? new Range( - contentRange.start.translate({ - characterDelta: delimiter.length, - }), - contentRange.end.translate({ - characterDelta: delimiter.length, - }) - ) - : contentRange, - }; - } - }); - - await editor.edit((editBuilder) => { - edits.forEach((edit) => { - editBuilder.replace(edit.insertPosition, edit.text); - }); - }); + ); - editor.selections = edits.map((edit) => edit.selection); + const originalThatSelections = [ + ...updatedCommandTargetSelections, + ...updatedDelimiterTargetSelections, + ]; - const thatMarkRanges = edits.map((edit) => edit.thatMarkRange); + const [updatedCommandSelections] = await performEditsAndUpdateSelections( + this.graph.rangeUpdater, + editor, + edits, + [originalThatSelections] + ); - return createThatMark(targets, thatMarkRanges); + return { + thatMark: updatedCommandSelections.map((selection) => ({ + editor, + selection, + })), + }; } - async runCommand(targets: Target[], commands: string[]) { - if (new Set(commands).size > 1) { - throw new Error("Can't run multiple different commands at once"); + async runCommandTargets( + editor: TextEditor, + commandTargets: CommandTarget[], + delimiterTargets: DelimiterTarget[] + ) { + const originalDelimiterTargetSelections = delimiterTargets.map( + (target) => target.target.contentSelection + ); + if (commandTargets.length === 0) { + return { + updatedCommandTargetSelections: [], + updatedDelimiterTargetSelections: originalDelimiterTargetSelections, + commandSelections: [], + }; } + + const originalCommandTargetSelections = commandTargets.map( + (target) => target.target.contentSelection + ); + + const command = ensureSingleCommand(commandTargets); + const targets = commandTargets.map((target) => target.target); if (this.isBefore) { await this.graph.actions.setSelectionBefore.run([targets]); } else { await this.graph.actions.setSelectionAfter.run([targets]); } - await vscommands.executeCommand(commands[0]); - return createThatMark(targets); + + const [updatedCommandTargetSelections, updatedDelimiterTargetSelections] = + await callFunctionAndUpdateSelections( + this.graph.rangeUpdater, + () => vscommands.executeCommand(command), + editor.document, + [originalCommandTargetSelections, originalDelimiterTargetSelections] + ); + + return { + updatedCommandTargetSelections, + updatedDelimiterTargetSelections, + commandSelections: editor.selections, + }; } + + // async runDelimiter(targets: Target[], editor: TextEditor) { + // const edits = targets.map((target) => { + // const { contentRange } = target; + // const context = target.getEditNewContext(this.isBefore); + // const delimiter = (context).delimiter as string; + + // // Delimiter is one or more new lines. Handle as lines. + // if (delimiter.includes("\n")) { + // const lineNumber = this.isBefore + // ? contentRange.start.line + // : contentRange.end.line; + // const line = editor.document.lineAt(lineNumber); + // const characterIndex = line.isEmptyOrWhitespace + // ? contentRange.start.character + // : line.firstNonWhitespaceCharacterIndex; + // const padding = line.text.slice(0, characterIndex); + // const positionSelection = new Position( + // this.isBefore ? lineNumber : lineNumber + delimiter.length, + // characterIndex + // ); + // return { + // contentRange, + // text: this.isBefore ? padding + delimiter : delimiter + padding, + // insertPosition: this.isBefore ? line.range.start : line.range.end, + // selection: new Selection(positionSelection, positionSelection), + // thatMarkRange: this.isBefore + // ? new Range( + // contentRange.start.translate({ + // lineDelta: delimiter.length, + // }), + // contentRange.end.translate({ + // lineDelta: delimiter.length, + // }) + // ) + // : contentRange, + // }; + // } + // // Delimiter is something else. Handle as inline. + // else { + // const positionSelection = this.isBefore + // ? contentRange.start + // : contentRange.end.translate({ + // characterDelta: delimiter.length, + // }); + // return { + // contentRange, + // text: delimiter, + // insertPosition: this.isBefore ? contentRange.start : contentRange.end, + // selection: new Selection(positionSelection, positionSelection), + // thatMarkRange: this.isBefore + // ? new Range( + // contentRange.start.translate({ + // characterDelta: delimiter.length, + // }), + // contentRange.end.translate({ + // characterDelta: delimiter.length, + // }) + // ) + // : contentRange, + // }; + // } + // }); + + // await editor.edit((editBuilder) => { + // edits.forEach((edit) => { + // editBuilder.replace(edit.insertPosition, edit.text); + // }); + // }); + + // editor.selections = edits.map((edit) => edit.selection); + + // const thatMarkRanges = edits.map((edit) => edit.thatMarkRange); + + // return createThatMark(targets, thatMarkRanges); + // } + + // async runCommand(targets: Target[], commands: string[]) { + // if (new Set(commands).size > 1) { + // throw new Error("Can't run multiple different commands at once"); + // } + // if (this.isBefore) { + // await this.graph.actions.setSelectionBefore.run([targets]); + // } else { + // await this.graph.actions.setSelectionAfter.run([targets]); + // } + // await vscommands.executeCommand(commands[0]); + // return createThatMark(targets); + // } } export class EditNewBefore extends EditNew { @@ -151,3 +225,37 @@ export class EditNewAfter extends EditNew { super(graph, false); } } + +interface CommandTarget { + target: Target; + context: EditNewCommandContext; +} +interface DelimiterTarget { + target: Target; + context: EditNewDelimiterContext; +} + +function groupTargets(targets: Target[], isBefore: boolean) { + const commandTargets: CommandTarget[] = []; + const delimiterTargets: DelimiterTarget[] = []; + targets.forEach((target) => { + const context = target.getEditNewContext(isBefore); + switch (context.type) { + case "command": + commandTargets.push({ target, context }); + break; + case "delimiter": + delimiterTargets.push({ target, context }); + break; + } + }); + return { commandTargets, delimiterTargets }; +} + +function ensureSingleCommand(targets: CommandTarget[]) { + const commands = targets.map((target) => target.context.command); + if (new Set(commands).size > 1) { + throw new Error("Can't run multiple different commands at once"); + } + return commands[0]; +} diff --git a/src/core/updateSelections/updateSelections.ts b/src/core/updateSelections/updateSelections.ts index d4890d10f9..6508ccbf02 100644 --- a/src/core/updateSelections/updateSelections.ts +++ b/src/core/updateSelections/updateSelections.ts @@ -142,7 +142,7 @@ function selectionInfosToSelections( */ export async function callFunctionAndUpdateSelections( rangeUpdater: RangeUpdater, - func: () => Thenable, + func: () => Thenable, document: TextDocument, selectionMatrix: (readonly Selection[])[] ): Promise { @@ -170,7 +170,7 @@ export async function callFunctionAndUpdateSelections( */ async function callFunctionAndUpdateSelectionInfos( rangeUpdater: RangeUpdater, - func: () => Thenable, + func: () => Thenable, document: TextDocument, selectionInfoMatrix: FullSelectionInfo[][] ) { diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index 301129c887..d6739f59de 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -255,9 +255,10 @@ export default abstract class BaseTarget { getEditNewContext(isBefore: boolean): EditNewContext { if (this.delimiter === "\n" && !isBefore) { - return { command: "editor.action.insertLineAfter" }; + return { type: "command", command: "editor.action.insertLineAfter" }; } return { + type: "delimiter", delimiter: this.delimiter ?? "", }; } diff --git a/src/processTargets/targets/NotebookCellTarget.ts b/src/processTargets/targets/NotebookCellTarget.ts index 47e7da61f5..40b23572a2 100644 --- a/src/processTargets/targets/NotebookCellTarget.ts +++ b/src/processTargets/targets/NotebookCellTarget.ts @@ -14,12 +14,14 @@ export default class NotebookCellTarget extends BaseTarget { getEditNewContext(isBefore: boolean): EditNewContext { if (this.isNotebookEditor(this.editor)) { return { + type: "command", command: isBefore ? "notebook.cell.insertCodeCellAbove" : "notebook.cell.insertCodeCellBelow", }; } return { + type: "command", command: isBefore ? "jupyter.insertCellAbove" : "jupyter.insertCellBelow", }; } diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index bb55a15956..252b653ee3 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -255,6 +255,15 @@ export interface RemovalRange { exclude?: boolean; } -export type EditNewContext = { command: string } | { delimiter: string }; +export interface EditNewCommandContext { + type: "command"; + command: string; +} +export interface EditNewDelimiterContext { + type: "delimiter"; + delimiter: string; +} + +export type EditNewContext = EditNewCommandContext | EditNewDelimiterContext; export type Target = BaseTarget; From ab45cc675782c11f10ce8864905c4ccccf2e5f91 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 24 May 2022 20:50:36 +0200 Subject: [PATCH 173/314] Get targets in correct order --- src/actions/EditNew.ts | 132 ++++++++++++++++++++--------------------- 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/src/actions/EditNew.ts b/src/actions/EditNew.ts index efa80b8be0..9ddb99db64 100644 --- a/src/actions/EditNew.ts +++ b/src/actions/EditNew.ts @@ -1,12 +1,5 @@ import { zip } from "lodash"; -import { - commands, - commands as vscommands, - Position, - Range, - Selection, - TextEditor, -} from "vscode"; +import { commands, Range, Selection, TextEditor } from "vscode"; import { callFunctionAndUpdateSelections, performEditsAndUpdateSelections, @@ -35,91 +28,94 @@ class EditNew implements Action { this.isBefore ); - const { - updatedCommandTargetSelections, - updatedDelimiterTargetSelections, - commandSelections, - } = await this.runCommandTargets(editor, commandTargets, delimiterTargets); + const { targetsWithSelection, commandSelections } = + await this.runCommandTargets(editor, targets, commandTargets); - if (updatedDelimiterTargetSelections.length < 1) { - return { - thatMark: updatedCommandTargetSelections.map((selection) => ({ - editor, - selection, - })), - }; - } + const { updatedCommandSelections, updatedTargetSelections } = + await this.runDelimiterTargets( + editor, + targetsWithSelection, + commandSelections, + delimiterTargets + ); - const edits = zip(delimiterTargets, updatedDelimiterTargetSelections).map( - ([target, selection]) => { - const position = this.isBefore ? selection!.start : selection!.end; - return { - text: target!.context.delimiter, - range: new Range(position, position), - isReplace: !this.isBefore, - }; - } + return { + thatMark: createThatMark(targets, updatedTargetSelections), + }; + } + + async runDelimiterTargets( + editor: TextEditor, + targetsWithSelection: TargetWithSelection[], + commandSelections: readonly Selection[], + delimiterTargets: DelimiterTarget[] + ) { + const originalTargetSelections = targetsWithSelection.map( + (selection) => selection.selection ); - const originalThatSelections = [ - ...updatedCommandTargetSelections, - ...updatedDelimiterTargetSelections, - ]; + if (delimiterTargets.length < 1) { + return { + updatedTargetSelections: originalTargetSelections, + }; + } - const [updatedCommandSelections] = await performEditsAndUpdateSelections( - this.graph.rangeUpdater, - editor, - edits, - [originalThatSelections] - ); + const edits = delimiterTargets.map((target) => { + const selection = targetsWithSelection.find( + (selection) => selection.target === target.target + )!.selection; + const position = this.isBefore ? selection.start : selection.end; + return { + text: target!.context.delimiter, + range: new Range(position, position), + isReplace: !this.isBefore, + }; + }); - return { - thatMark: updatedCommandSelections.map((selection) => ({ + const [updatedCommandSelections, updatedTargetSelections] = + await performEditsAndUpdateSelections( + this.graph.rangeUpdater, editor, - selection, - })), - }; + edits, + [commandSelections, originalTargetSelections] + ); + + return { updatedCommandSelections, updatedTargetSelections }; } async runCommandTargets( editor: TextEditor, - commandTargets: CommandTarget[], - delimiterTargets: DelimiterTarget[] + targets: Target[], + commandTargets: CommandTarget[] ) { - const originalDelimiterTargetSelections = delimiterTargets.map( - (target) => target.target.contentSelection - ); if (commandTargets.length === 0) { return { - updatedCommandTargetSelections: [], - updatedDelimiterTargetSelections: originalDelimiterTargetSelections, + targetsWithSelection: targets.map((target) => ({ + target: target, + selection: target.contentSelection, + })), commandSelections: [], }; } - const originalCommandTargetSelections = commandTargets.map( - (target) => target.target.contentSelection - ); - const command = ensureSingleCommand(commandTargets); - const targets = commandTargets.map((target) => target.target); if (this.isBefore) { await this.graph.actions.setSelectionBefore.run([targets]); } else { await this.graph.actions.setSelectionAfter.run([targets]); } - const [updatedCommandTargetSelections, updatedDelimiterTargetSelections] = - await callFunctionAndUpdateSelections( - this.graph.rangeUpdater, - () => vscommands.executeCommand(command), - editor.document, - [originalCommandTargetSelections, originalDelimiterTargetSelections] - ); + const [updatedTargetSelections] = await callFunctionAndUpdateSelections( + this.graph.rangeUpdater, + () => commands.executeCommand(command), + editor.document, + [targets.map((target) => target.contentSelection)] + ); return { - updatedCommandTargetSelections, - updatedDelimiterTargetSelections, + targetsWithSelection: zip(targets, updatedTargetSelections).map( + ([target, selection]) => ({ target: target!, selection: selection! }) + ), commandSelections: editor.selections, }; } @@ -234,6 +230,10 @@ interface DelimiterTarget { target: Target; context: EditNewDelimiterContext; } +interface TargetWithSelection { + target: Target; + selection: Selection; +} function groupTargets(targets: Target[], isBefore: boolean) { const commandTargets: CommandTarget[] = []; From fa73fa525b8333c1e56355a45c39a44a5b5763a8 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 24 May 2022 21:16:33 +0200 Subject: [PATCH 174/314] Updated selection for editor --- src/actions/EditNew.ts | 46 +++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/src/actions/EditNew.ts b/src/actions/EditNew.ts index 9ddb99db64..433e0cd408 100644 --- a/src/actions/EditNew.ts +++ b/src/actions/EditNew.ts @@ -31,13 +31,12 @@ class EditNew implements Action { const { targetsWithSelection, commandSelections } = await this.runCommandTargets(editor, targets, commandTargets); - const { updatedCommandSelections, updatedTargetSelections } = - await this.runDelimiterTargets( - editor, - targetsWithSelection, - commandSelections, - delimiterTargets - ); + const { updatedTargetSelections } = await this.runDelimiterTargets( + editor, + targetsWithSelection, + commandSelections, + delimiterTargets + ); return { thatMark: createThatMark(targets, updatedTargetSelections), @@ -80,7 +79,30 @@ class EditNew implements Action { [commandSelections, originalTargetSelections] ); - return { updatedCommandSelections, updatedTargetSelections }; + targetsWithSelection.forEach((target, i) => { + target.selection = updatedTargetSelections[i]; + }); + + const newSelections = [ + ...updatedCommandSelections, + ...delimiterTargets.map((target) => { + const selection = targetsWithSelection.find( + (selection) => selection.target === target.target + )!.selection; + const delimiter = target.context.delimiter; + const isLine = delimiter.includes("\n"); + const delta = delimiter.length; + const position = this.isBefore ? selection.start : selection.end; + const updatedPosition = isLine + ? position.translate({ lineDelta: -delta }) + : position.translate({ characterDelta: -delta }); + return new Selection(updatedPosition, updatedPosition); + }), + ]; + + editor.selections = newSelections; + + return { updatedTargetSelections }; } async runCommandTargets( @@ -100,9 +122,13 @@ class EditNew implements Action { const command = ensureSingleCommand(commandTargets); if (this.isBefore) { - await this.graph.actions.setSelectionBefore.run([targets]); + await this.graph.actions.setSelectionBefore.run([ + commandTargets.map((target) => target.target), + ]); } else { - await this.graph.actions.setSelectionAfter.run([targets]); + await this.graph.actions.setSelectionAfter.run([ + commandTargets.map((target) => target.target), + ]); } const [updatedTargetSelections] = await callFunctionAndUpdateSelections( From 74370d7ed653ede79b728c1fcc6cdec6bbf9e1b4 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 24 May 2022 21:17:40 +0200 Subject: [PATCH 175/314] Cleanup --- src/actions/EditNew.ts | 89 ------------------------------------------ 1 file changed, 89 deletions(-) diff --git a/src/actions/EditNew.ts b/src/actions/EditNew.ts index 433e0cd408..cb8f73f654 100644 --- a/src/actions/EditNew.ts +++ b/src/actions/EditNew.ts @@ -145,95 +145,6 @@ class EditNew implements Action { commandSelections: editor.selections, }; } - - // async runDelimiter(targets: Target[], editor: TextEditor) { - // const edits = targets.map((target) => { - // const { contentRange } = target; - // const context = target.getEditNewContext(this.isBefore); - // const delimiter = (context).delimiter as string; - - // // Delimiter is one or more new lines. Handle as lines. - // if (delimiter.includes("\n")) { - // const lineNumber = this.isBefore - // ? contentRange.start.line - // : contentRange.end.line; - // const line = editor.document.lineAt(lineNumber); - // const characterIndex = line.isEmptyOrWhitespace - // ? contentRange.start.character - // : line.firstNonWhitespaceCharacterIndex; - // const padding = line.text.slice(0, characterIndex); - // const positionSelection = new Position( - // this.isBefore ? lineNumber : lineNumber + delimiter.length, - // characterIndex - // ); - // return { - // contentRange, - // text: this.isBefore ? padding + delimiter : delimiter + padding, - // insertPosition: this.isBefore ? line.range.start : line.range.end, - // selection: new Selection(positionSelection, positionSelection), - // thatMarkRange: this.isBefore - // ? new Range( - // contentRange.start.translate({ - // lineDelta: delimiter.length, - // }), - // contentRange.end.translate({ - // lineDelta: delimiter.length, - // }) - // ) - // : contentRange, - // }; - // } - // // Delimiter is something else. Handle as inline. - // else { - // const positionSelection = this.isBefore - // ? contentRange.start - // : contentRange.end.translate({ - // characterDelta: delimiter.length, - // }); - // return { - // contentRange, - // text: delimiter, - // insertPosition: this.isBefore ? contentRange.start : contentRange.end, - // selection: new Selection(positionSelection, positionSelection), - // thatMarkRange: this.isBefore - // ? new Range( - // contentRange.start.translate({ - // characterDelta: delimiter.length, - // }), - // contentRange.end.translate({ - // characterDelta: delimiter.length, - // }) - // ) - // : contentRange, - // }; - // } - // }); - - // await editor.edit((editBuilder) => { - // edits.forEach((edit) => { - // editBuilder.replace(edit.insertPosition, edit.text); - // }); - // }); - - // editor.selections = edits.map((edit) => edit.selection); - - // const thatMarkRanges = edits.map((edit) => edit.thatMarkRange); - - // return createThatMark(targets, thatMarkRanges); - // } - - // async runCommand(targets: Target[], commands: string[]) { - // if (new Set(commands).size > 1) { - // throw new Error("Can't run multiple different commands at once"); - // } - // if (this.isBefore) { - // await this.graph.actions.setSelectionBefore.run([targets]); - // } else { - // await this.graph.actions.setSelectionAfter.run([targets]); - // } - // await vscommands.executeCommand(commands[0]); - // return createThatMark(targets); - // } } export class EditNewBefore extends EditNew { From 5f82b78284279eea61abb717a48bfb41b1241163 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Tue, 24 May 2022 23:02:19 +0100 Subject: [PATCH 176/314] New attempt at EditNew --- src/actions/EditNew.ts | 138 +++++++++++++++++++++++++++-------------- 1 file changed, 93 insertions(+), 45 deletions(-) diff --git a/src/actions/EditNew.ts b/src/actions/EditNew.ts index cb8f73f654..999f4f045b 100644 --- a/src/actions/EditNew.ts +++ b/src/actions/EditNew.ts @@ -31,13 +31,25 @@ class EditNew implements Action { const { targetsWithSelection, commandSelections } = await this.runCommandTargets(editor, targets, commandTargets); - const { updatedTargetSelections } = await this.runDelimiterTargets( + const { + updatedTargetSelections, + updatedCommandSelections, + updatedDelimiterSelections, + } = await this.runDelimiterTargets( editor, targetsWithSelection, commandSelections, delimiterTargets ); + editor.selections = zip([ + ...updatedCommandSelections, + ...updatedDelimiterSelections, + ], [ + ...commandTargets, + ...delimiterTargets, + ]).map(([updatedSelection, target]) => ()); + return { thatMark: createThatMark(targets, updatedTargetSelections), }; @@ -55,54 +67,88 @@ class EditNew implements Action { if (delimiterTargets.length < 1) { return { + updatedCommandSelections: commandSelections, + updatedDelimiterSelections: [], updatedTargetSelections: originalTargetSelections, }; } - const edits = delimiterTargets.map((target) => { - const selection = targetsWithSelection.find( - (selection) => selection.target === target.target - )!.selection; - const position = this.isBefore ? selection.start : selection.end; - return { - text: target!.context.delimiter, - range: new Range(position, position), - isReplace: !this.isBefore, - }; - }); + const delimiterTargetInfos = delimiterTargets.map( + ({ target, context: { delimiter }, index }) => { + const targetSelection = targetsWithSelection[index].selection; + + const position = this.isBefore + ? targetSelection.start + : targetSelection.end; + + return { + targetSelection, + insertionSelection: new Selection(position, position), + target, + delimiter, + }; + } + ); - const [updatedCommandSelections, updatedTargetSelections] = - await performEditsAndUpdateSelections( - this.graph.rangeUpdater, - editor, - edits, - [commandSelections, originalTargetSelections] - ); + const edits = delimiterTargetInfos.flatMap( + ({ delimiter, targetSelection, insertionSelection }) => { + const [before, after] = delimiter.includes("\n") + ? this.getLineEditTexts(editor, targetSelection, delimiter) + : this.isBefore + ? ["", delimiter] + : [delimiter, ""]; + + return [ + { + text: before, + range: insertionSelection, + isReplace: false, + }, + { + text: after, + range: insertionSelection, + isReplace: true, + }, + ].filter(({ text }) => !!text); + } + ); - targetsWithSelection.forEach((target, i) => { - target.selection = updatedTargetSelections[i]; - }); + const originalDelimiterSelections = delimiterTargetInfos.map( + ({ insertionSelection }) => insertionSelection + ); - const newSelections = [ - ...updatedCommandSelections, - ...delimiterTargets.map((target) => { - const selection = targetsWithSelection.find( - (selection) => selection.target === target.target - )!.selection; - const delimiter = target.context.delimiter; - const isLine = delimiter.includes("\n"); - const delta = delimiter.length; - const position = this.isBefore ? selection.start : selection.end; - const updatedPosition = isLine - ? position.translate({ lineDelta: -delta }) - : position.translate({ characterDelta: -delta }); - return new Selection(updatedPosition, updatedPosition); - }), - ]; - - editor.selections = newSelections; - - return { updatedTargetSelections }; + const [ + updatedCommandSelections, + updatedDelimiterSelections, + updatedTargetSelections, + ] = await performEditsAndUpdateSelections( + this.graph.rangeUpdater, + editor, + edits, + [commandSelections, originalDelimiterSelections, originalTargetSelections] + ); + + return { + updatedTargetSelections, + updatedCommandSelections, + updatedDelimiterSelections, + }; + } + + private getLineEditTexts( + editor: TextEditor, + selection: Selection, + delimiter: string + ) { + const lineNumber = this.isBefore + ? selection.start.line + : selection.end.line; + const line = editor.document.lineAt(lineNumber); + const characterIndex = line.isEmptyOrWhitespace + ? selection.start.character + : line.firstNonWhitespaceCharacterIndex; + const padding = line.text.slice(0, characterIndex); + return this.isBefore ? [padding, delimiter] : [delimiter, padding]; } async runCommandTargets( @@ -161,10 +207,12 @@ export class EditNewAfter extends EditNew { interface CommandTarget { target: Target; + index: number; context: EditNewCommandContext; } interface DelimiterTarget { target: Target; + index: number; context: EditNewDelimiterContext; } interface TargetWithSelection { @@ -175,14 +223,14 @@ interface TargetWithSelection { function groupTargets(targets: Target[], isBefore: boolean) { const commandTargets: CommandTarget[] = []; const delimiterTargets: DelimiterTarget[] = []; - targets.forEach((target) => { + targets.forEach((target, index) => { const context = target.getEditNewContext(isBefore); switch (context.type) { case "command": - commandTargets.push({ target, context }); + commandTargets.push({ target, index, context }); break; case "delimiter": - delimiterTargets.push({ target, context }); + delimiterTargets.push({ target, index, context }); break; } }); From 83b2741bf20141ae2c5fe4d8365163301005b43a Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 25 May 2022 09:30:41 +0200 Subject: [PATCH 177/314] Added rich targets --- src/actions/EditNew.ts | 317 ++++++++---------- src/core/updateSelections/updateSelections.ts | 16 + src/processTargets/targets/BaseTarget.ts | 8 +- src/util/selectionUtils.ts | 5 + 4 files changed, 165 insertions(+), 181 deletions(-) diff --git a/src/actions/EditNew.ts b/src/actions/EditNew.ts index 999f4f045b..09bf022738 100644 --- a/src/actions/EditNew.ts +++ b/src/actions/EditNew.ts @@ -1,16 +1,13 @@ import { zip } from "lodash"; -import { commands, Range, Selection, TextEditor } from "vscode"; +import { commands, Range, TextEditor } from "vscode"; import { - callFunctionAndUpdateSelections, - performEditsAndUpdateSelections, + callFunctionAndUpdateRanges, + performEditsAndUpdateRanges, } from "../core/updateSelections/updateSelections"; import { weakContainingLineStage } from "../processTargets/modifiers/commonWeakContainingScopeStages"; -import { - EditNewCommandContext, - EditNewDelimiterContext, - Target, -} from "../typings/target.types"; +import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; +import { selectionFromRange } from "../util/selectionUtils"; import { createThatMark, ensureSingleEditor } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; @@ -23,173 +20,130 @@ class EditNew implements Action { async run([targets]: [Target[]]): Promise { const editor = ensureSingleEditor(targets); - const { commandTargets, delimiterTargets } = groupTargets( - targets, - this.isBefore - ); - const { targetsWithSelection, commandSelections } = - await this.runCommandTargets(editor, targets, commandTargets); - - const { - updatedTargetSelections, - updatedCommandSelections, - updatedDelimiterSelections, - } = await this.runDelimiterTargets( - editor, - targetsWithSelection, - commandSelections, - delimiterTargets - ); + const richTargets: RichTarget[] = targets.map((target, index) => { + const context = target.getEditNewContext(this.isBefore); + const position = this.isBefore + ? target.contentRange.start + : target.contentRange.end; + const common = { + target, + index, + targetRange: target.contentRange, + cursorRange: new Range(position, position), + }; + switch (context.type) { + case "command": + return { + ...common, + type: "command", + command: context.command, + }; + case "delimiter": + return { + ...common, + type: "delimiter", + delimiter: context.delimiter, + }; + } + }); - editor.selections = zip([ - ...updatedCommandSelections, - ...updatedDelimiterSelections, - ], [ - ...commandTargets, - ...delimiterTargets, - ]).map(([updatedSelection, target]) => ()); + await this.runCommandTargets(editor, richTargets); + await this.runDelimiterTargets(editor, richTargets); + + editor.selections = richTargets.map((target) => + selectionFromRange(target.target.isReversed, target.cursorRange) + ); + const targetRanges = richTargets.map((target) => target.targetRange); return { - thatMark: createThatMark(targets, updatedTargetSelections), + thatMark: createThatMark(targets, targetRanges), }; } - async runDelimiterTargets( - editor: TextEditor, - targetsWithSelection: TargetWithSelection[], - commandSelections: readonly Selection[], - delimiterTargets: DelimiterTarget[] - ) { - const originalTargetSelections = targetsWithSelection.map( - (selection) => selection.selection + async runDelimiterTargets(editor: TextEditor, targets: RichTarget[]) { + const delimiterTargets: DelimiterTarget[] = targets.filter( + (target): target is DelimiterTarget => target.type === "delimiter" ); - if (delimiterTargets.length < 1) { - return { - updatedCommandSelections: commandSelections, - updatedDelimiterSelections: [], - updatedTargetSelections: originalTargetSelections, - }; + if (delimiterTargets.length === 0) { + return; } - const delimiterTargetInfos = delimiterTargets.map( - ({ target, context: { delimiter }, index }) => { - const targetSelection = targetsWithSelection[index].selection; - - const position = this.isBefore - ? targetSelection.start - : targetSelection.end; - - return { - targetSelection, - insertionSelection: new Selection(position, position), - target, - delimiter, - }; - } - ); - - const edits = delimiterTargetInfos.flatMap( - ({ delimiter, targetSelection, insertionSelection }) => { - const [before, after] = delimiter.includes("\n") - ? this.getLineEditTexts(editor, targetSelection, delimiter) - : this.isBefore - ? ["", delimiter] - : [delimiter, ""]; - - return [ - { - text: before, - range: insertionSelection, - isReplace: false, - }, - { - text: after, - range: insertionSelection, - isReplace: true, - }, - ].filter(({ text }) => !!text); - } - ); - - const originalDelimiterSelections = delimiterTargetInfos.map( - ({ insertionSelection }) => insertionSelection - ); - - const [ - updatedCommandSelections, - updatedDelimiterSelections, - updatedTargetSelections, - ] = await performEditsAndUpdateSelections( - this.graph.rangeUpdater, - editor, - edits, - [commandSelections, originalDelimiterSelections, originalTargetSelections] - ); - - return { - updatedTargetSelections, - updatedCommandSelections, - updatedDelimiterSelections, - }; + const edits = delimiterTargets.flatMap(({ delimiter, cursorRange }) => { + const [before, after] = delimiter.includes("\n") + ? getLineEditTexts(editor, cursorRange, delimiter, this.isBefore) + : this.isBefore + ? ["", delimiter] + : [delimiter, ""]; + + return [ + { + text: before, + range: cursorRange, + isReplace: false, + }, + { + text: after, + range: cursorRange, + isReplace: true, + }, + ].filter(({ text }) => !!text); + }); + + const [updatedTargetRanges, updatedCursorRanges] = + await performEditsAndUpdateRanges( + this.graph.rangeUpdater, + editor, + edits, + [ + targets.map(({ targetRange }) => targetRange), + targets.map(({ cursorRange }) => cursorRange), + ] + ); + + updateTargets(targets, updatedTargetRanges, updatedCursorRanges); } - private getLineEditTexts( - editor: TextEditor, - selection: Selection, - delimiter: string - ) { - const lineNumber = this.isBefore - ? selection.start.line - : selection.end.line; - const line = editor.document.lineAt(lineNumber); - const characterIndex = line.isEmptyOrWhitespace - ? selection.start.character - : line.firstNonWhitespaceCharacterIndex; - const padding = line.text.slice(0, characterIndex); - return this.isBefore ? [padding, delimiter] : [delimiter, padding]; - } + async runCommandTargets(editor: TextEditor, targets: RichTarget[]) { + const commandTargets: CommandTarget[] = targets.filter( + (target): target is CommandTarget => target.type === "command" + ); - async runCommandTargets( - editor: TextEditor, - targets: Target[], - commandTargets: CommandTarget[] - ) { if (commandTargets.length === 0) { - return { - targetsWithSelection: targets.map((target) => ({ - target: target, - selection: target.contentSelection, - })), - commandSelections: [], - }; + return; } const command = ensureSingleCommand(commandTargets); + if (this.isBefore) { await this.graph.actions.setSelectionBefore.run([ - commandTargets.map((target) => target.target), + commandTargets.map(({ target }) => target), ]); } else { await this.graph.actions.setSelectionAfter.run([ - commandTargets.map((target) => target.target), + commandTargets.map(({ target }) => target), ]); } - const [updatedTargetSelections] = await callFunctionAndUpdateSelections( - this.graph.rangeUpdater, - () => commands.executeCommand(command), - editor.document, - [targets.map((target) => target.contentSelection)] + const [updatedTargetRanges, updatedCursorRanges] = + await callFunctionAndUpdateRanges( + this.graph.rangeUpdater, + () => commands.executeCommand(command), + editor.document, + [ + targets.map(({ targetRange }) => targetRange), + targets.map(({ cursorRange }) => cursorRange), + ] + ); + + updateTargets(targets, updatedTargetRanges, updatedCursorRanges); + + zip(commandTargets, editor.selections).forEach( + ([commandTarget, cursorSelection]) => { + commandTarget!.cursorRange = cursorSelection!; + } ); - - return { - targetsWithSelection: zip(targets, updatedTargetSelections).map( - ([target, selection]) => ({ target: target!, selection: selection! }) - ), - commandSelections: editor.selections, - }; } } @@ -205,42 +159,53 @@ export class EditNewAfter extends EditNew { } } -interface CommandTarget { +interface CommonTarget { target: Target; - index: number; - context: EditNewCommandContext; + targetRange: Range; + cursorRange: Range; } -interface DelimiterTarget { - target: Target; - index: number; - context: EditNewDelimiterContext; -} -interface TargetWithSelection { - target: Target; - selection: Selection; +interface CommandTarget extends CommonTarget { + type: "command"; + command: string; } - -function groupTargets(targets: Target[], isBefore: boolean) { - const commandTargets: CommandTarget[] = []; - const delimiterTargets: DelimiterTarget[] = []; - targets.forEach((target, index) => { - const context = target.getEditNewContext(isBefore); - switch (context.type) { - case "command": - commandTargets.push({ target, index, context }); - break; - case "delimiter": - delimiterTargets.push({ target, index, context }); - break; - } - }); - return { commandTargets, delimiterTargets }; +interface DelimiterTarget extends CommonTarget { + type: "delimiter"; + delimiter: string; } +type RichTarget = CommandTarget | DelimiterTarget; function ensureSingleCommand(targets: CommandTarget[]) { - const commands = targets.map((target) => target.context.command); + const commands = targets.map((target) => target.command); if (new Set(commands).size > 1) { throw new Error("Can't run multiple different commands at once"); } return commands[0]; } + +function getLineEditTexts( + editor: TextEditor, + range: Range, + delimiter: string, + isBefore: boolean +) { + const lineNumber = isBefore ? range.start.line : range.end.line; + const line = editor.document.lineAt(lineNumber); + const characterIndex = line.isEmptyOrWhitespace + ? range.start.character + : line.firstNonWhitespaceCharacterIndex; + const padding = line.text.slice(0, characterIndex); + return isBefore ? [padding, delimiter] : [delimiter, padding]; +} + +function updateTargets( + targets: RichTarget[], + updatedTargetRanges: Range[], + updatedCursorRanges: Range[] +) { + zip(targets, updatedTargetRanges, updatedCursorRanges).forEach( + ([target, updatedTargetRange, updatedCursorRange]) => { + target!.targetRange = updatedTargetRange!; + target!.cursorRange = updatedCursorRange!; + } + ); +} diff --git a/src/core/updateSelections/updateSelections.ts b/src/core/updateSelections/updateSelections.ts index 6508ccbf02..d5a4467c1b 100644 --- a/src/core/updateSelections/updateSelections.ts +++ b/src/core/updateSelections/updateSelections.ts @@ -159,6 +159,22 @@ export async function callFunctionAndUpdateSelections( ); } +export async function callFunctionAndUpdateRanges( + rangeUpdater: RangeUpdater, + func: () => Thenable, + document: TextDocument, + rangeMatrix: (readonly Range[])[] +): Promise { + const selectionInfoMatrix = rangesToSelectionInfos(document, rangeMatrix); + + return await callFunctionAndUpdateSelectionInfos( + rangeUpdater, + func, + document, + selectionInfoMatrix + ); +} + /** * Calls the given function and updates the given selections based on the * changes that occurred as a result of calling function. diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index d6739f59de..4151a3188f 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -1,10 +1,11 @@ import { Range, Selection, TextEditor } from "vscode"; import { - EditNewContext as EditNewContext, + EditNewContext, Position, RemovalRange, Target, } from "../../typings/target.types"; +import { selectionFromRange } from "../../util/selectionUtils"; import { parseRemovalRange } from "../../util/targetUtils"; export function extractCommonParameters(parameters: CommonTargetParameters) { @@ -137,10 +138,7 @@ export default abstract class BaseTarget { } get contentSelection(): Selection { - const { start, end } = this.contentRange; - return this.isReversed - ? new Selection(end, start) - : new Selection(start, end); + return selectionFromRange(this.isReversed, this.contentRange); } get delimiter(): string | undefined { diff --git a/src/util/selectionUtils.ts b/src/util/selectionUtils.ts index 254775ceee..8e443b0ef4 100644 --- a/src/util/selectionUtils.ts +++ b/src/util/selectionUtils.ts @@ -37,3 +37,8 @@ function selectionFromPositions( ? new Selection(start, end) : new Selection(end, start); } + +export function selectionFromRange(isReversed: boolean, range: Range) { + const { start, end } = range; + return isReversed ? new Selection(end, start) : new Selection(start, end); +} From b50c7d5916efcef5b698691e9569c522a1011b2d Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 25 May 2022 10:18:33 +0200 Subject: [PATCH 178/314] Updated edit new with proper line handling --- src/actions/EditNew.ts | 78 +++++++++++++++++++++++++++--------------- 1 file changed, 51 insertions(+), 27 deletions(-) diff --git a/src/actions/EditNew.ts b/src/actions/EditNew.ts index 09bf022738..bbbf62e42e 100644 --- a/src/actions/EditNew.ts +++ b/src/actions/EditNew.ts @@ -23,14 +23,10 @@ class EditNew implements Action { const richTargets: RichTarget[] = targets.map((target, index) => { const context = target.getEditNewContext(this.isBefore); - const position = this.isBefore - ? target.contentRange.start - : target.contentRange.end; const common = { target, index, targetRange: target.contentRange, - cursorRange: new Range(position, position), }; switch (context.type) { case "command": @@ -38,12 +34,26 @@ class EditNew implements Action { ...common, type: "command", command: context.command, + cursorRange: getEditRange( + editor, + target.contentRange, + false, + this.isBefore + ), }; case "delimiter": + const isLine = context.delimiter.includes("\n"); return { ...common, type: "delimiter", delimiter: context.delimiter, + isLine, + cursorRange: getEditRange( + editor, + target.contentRange, + isLine, + this.isBefore + ), }; } }); @@ -70,26 +80,27 @@ class EditNew implements Action { return; } - const edits = delimiterTargets.flatMap(({ delimiter, cursorRange }) => { - const [before, after] = delimiter.includes("\n") - ? getLineEditTexts(editor, cursorRange, delimiter, this.isBefore) - : this.isBefore - ? ["", delimiter] - : [delimiter, ""]; - - return [ - { - text: before, - range: cursorRange, - isReplace: false, - }, - { - text: after, - range: cursorRange, - isReplace: true, - }, - ].filter(({ text }) => !!text); - }); + const edits = delimiterTargets.flatMap( + ({ delimiter, isLine, cursorRange }) => { + const [before, after] = isLine + ? getLineEditTexts(editor, cursorRange, delimiter, this.isBefore) + : this.isBefore + ? ["", delimiter] + : [delimiter, ""]; + return [ + { + text: before, + range: cursorRange, + isReplace: false, + }, + { + text: after, + range: cursorRange, + isReplace: true, + }, + ].filter(({ text }) => !!text); + } + ); const [updatedTargetRanges, updatedCursorRanges] = await performEditsAndUpdateRanges( @@ -171,6 +182,7 @@ interface CommandTarget extends CommonTarget { interface DelimiterTarget extends CommonTarget { type: "delimiter"; delimiter: string; + isLine: boolean; } type RichTarget = CommandTarget | DelimiterTarget; @@ -188,13 +200,25 @@ function getLineEditTexts( delimiter: string, isBefore: boolean ) { - const lineNumber = isBefore ? range.start.line : range.end.line; - const line = editor.document.lineAt(lineNumber); + const line = editor.document.lineAt(isBefore ? range.start : range.end); const characterIndex = line.isEmptyOrWhitespace ? range.start.character : line.firstNonWhitespaceCharacterIndex; const padding = line.text.slice(0, characterIndex); - return isBefore ? [padding, delimiter] : [delimiter, padding]; + return isBefore ? [padding, delimiter] : [delimiter + padding, ""]; +} + +function getEditRange( + editor: TextEditor, + range: Range, + isLine: boolean, + isBefore: boolean +) { + const editRange = isLine + ? editor.document.lineAt(isBefore ? range.start : range.end).range + : range; + const position = isBefore ? editRange.start : editRange.end; + return new Range(position, position); } function updateTargets( From 2a079803a7a216f92696a8945f082f23c9c8c37d Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 25 May 2022 10:59:44 +0200 Subject: [PATCH 179/314] Only used single edit --- src/actions/EditNew.ts | 52 ++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 32 deletions(-) diff --git a/src/actions/EditNew.ts b/src/actions/EditNew.ts index bbbf62e42e..0e6f14d92a 100644 --- a/src/actions/EditNew.ts +++ b/src/actions/EditNew.ts @@ -23,10 +23,17 @@ class EditNew implements Action { const richTargets: RichTarget[] = targets.map((target, index) => { const context = target.getEditNewContext(this.isBefore); + const common = { target, index, targetRange: target.contentRange, + cursorRange: getEditRange( + editor, + target.contentRange, + false, + this.isBefore + ), }; switch (context.type) { case "command": @@ -34,12 +41,6 @@ class EditNew implements Action { ...common, type: "command", command: context.command, - cursorRange: getEditRange( - editor, - target.contentRange, - false, - this.isBefore - ), }; case "delimiter": const isLine = context.delimiter.includes("\n"); @@ -80,27 +81,15 @@ class EditNew implements Action { return; } - const edits = delimiterTargets.flatMap( - ({ delimiter, isLine, cursorRange }) => { - const [before, after] = isLine - ? getLineEditTexts(editor, cursorRange, delimiter, this.isBefore) - : this.isBefore - ? ["", delimiter] - : [delimiter, ""]; - return [ - { - text: before, - range: cursorRange, - isReplace: false, - }, - { - text: after, - range: cursorRange, - isReplace: true, - }, - ].filter(({ text }) => !!text); - } - ); + const edits = delimiterTargets.map(({ delimiter, isLine, cursorRange }) => { + return { + text: isLine + ? getLineEditText(editor, cursorRange, delimiter, this.isBefore) + : delimiter, + range: cursorRange, + isReplace: this.isBefore, + }; + }); const [updatedTargetRanges, updatedCursorRanges] = await performEditsAndUpdateRanges( @@ -194,7 +183,7 @@ function ensureSingleCommand(targets: CommandTarget[]) { return commands[0]; } -function getLineEditTexts( +function getLineEditText( editor: TextEditor, range: Range, delimiter: string, @@ -205,7 +194,7 @@ function getLineEditTexts( ? range.start.character : line.firstNonWhitespaceCharacterIndex; const padding = line.text.slice(0, characterIndex); - return isBefore ? [padding, delimiter] : [delimiter + padding, ""]; + return delimiter + padding; } function getEditRange( @@ -214,9 +203,8 @@ function getEditRange( isLine: boolean, isBefore: boolean ) { - const editRange = isLine - ? editor.document.lineAt(isBefore ? range.start : range.end).range - : range; + const editRange = + isLine && !isBefore ? editor.document.lineAt(range.end).range : range; const position = isBefore ? editRange.start : editRange.end; return new Range(position, position); } From d5e265155ff4a9acaeb492697622bb00338f89d7 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 25 May 2022 11:05:06 +0200 Subject: [PATCH 180/314] Added comment --- src/actions/EditNew.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/actions/EditNew.ts b/src/actions/EditNew.ts index 0e6f14d92a..8d0e4f3b7d 100644 --- a/src/actions/EditNew.ts +++ b/src/actions/EditNew.ts @@ -189,6 +189,7 @@ function getLineEditText( delimiter: string, isBefore: boolean ) { + // In case of trialing whitespaces we need to go to the end of the line(not content) const line = editor.document.lineAt(isBefore ? range.start : range.end); const characterIndex = line.isEmptyOrWhitespace ? range.start.character From c52571dd2341e7b32a58da88143a6b4a6d944a7d Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 25 May 2022 11:05:40 +0200 Subject: [PATCH 181/314] Added comment --- src/actions/EditNew.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/actions/EditNew.ts b/src/actions/EditNew.ts index 8d0e4f3b7d..3d14aaaf95 100644 --- a/src/actions/EditNew.ts +++ b/src/actions/EditNew.ts @@ -189,7 +189,6 @@ function getLineEditText( delimiter: string, isBefore: boolean ) { - // In case of trialing whitespaces we need to go to the end of the line(not content) const line = editor.document.lineAt(isBefore ? range.start : range.end); const characterIndex = line.isEmptyOrWhitespace ? range.start.character @@ -204,6 +203,7 @@ function getEditRange( isLine: boolean, isBefore: boolean ) { + // In case of trialing whitespaces we need to go to the end of the line(not content) const editRange = isLine && !isBefore ? editor.document.lineAt(range.end).range : range; const position = isBefore ? editRange.start : editRange.end; From abfd3984531924079f53b18370d50df7e064f8e4 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 25 May 2022 12:08:52 +0200 Subject: [PATCH 182/314] Cleanup --- src/processTargets/targets/BaseTarget.ts | 30 ++---------- src/processTargets/targets/DocumentTarget.ts | 25 +++++----- src/processTargets/targets/LineTarget.ts | 20 ++++---- .../targets/NotebookCellTarget.ts | 10 ++-- src/processTargets/targets/ParagraphTarget.ts | 24 ++++----- .../targets/RawSelectionTarget.ts | 5 +- src/processTargets/targets/ScopeTypeTarget.ts | 16 ++++-- .../targets/SurroundingPairTarget.ts | 20 ++++---- src/processTargets/targets/TokenTarget.ts | 5 +- src/processTargets/targets/WeakTarget.ts | 5 +- src/typings/target.types.ts | 49 +++++++++++++++++-- 11 files changed, 121 insertions(+), 88 deletions(-) diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index 4151a3188f..f24d89dad8 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -34,32 +34,17 @@ export interface BaseTargetParameters extends CommonTargetParameters { } interface BaseTargetState { - /** The text editor used for all ranges */ readonly editor: TextEditor; - - /** If true active is before anchor */ readonly isReversed: boolean; - - /** The range of the content */ readonly contentRange: Range; - - /** If this selection has a delimiter. For example, new line for a line or paragraph and comma for a list or argument */ readonly delimiter: string; - - /** The range to remove the content */ readonly removalRange?: Range; - - /** The range of the delimiter before the content selection */ readonly leadingDelimiter?: RemovalRange; - - /** The range of the delimiter after the content selection */ readonly trailingDelimiter?: RemovalRange; - - /** The current position */ position?: Position; } -export default abstract class BaseTarget { +export default abstract class BaseTarget implements Target { protected readonly state: BaseTargetState; constructor(parameters: BaseTargetParameters) { @@ -67,11 +52,11 @@ export default abstract class BaseTarget { editor: parameters.editor, isReversed: parameters.isReversed, contentRange: parameters.contentRange, + position: parameters.position, delimiter: parameters.delimiter, removalRange: parameters.removalRange, leadingDelimiter: parameters.leadingDelimiter, trailingDelimiter: parameters.trailingDelimiter, - position: parameters.position, }; } @@ -91,17 +76,14 @@ export default abstract class BaseTarget { return this.state.removalRange; } - /** If true this target should be treated as a line */ get isLine() { return false; } - /** If true this target should be treated as a paragraph */ get isParagraph() { return false; } - /** If true this target is of weak type and should use inference/upgrade when needed. See {@link WeakTarget} for more info */ get isWeak() { return false; } @@ -261,11 +243,5 @@ export default abstract class BaseTarget { }; } - abstract clone(): Target; - - withPosition(position: Position): Target { - const target = this.clone(); - target.state.position = position; - return target; - } + abstract withPosition(position: Position): Target; } diff --git a/src/processTargets/targets/DocumentTarget.ts b/src/processTargets/targets/DocumentTarget.ts index 6e9eea78c0..fd5b429c00 100644 --- a/src/processTargets/targets/DocumentTarget.ts +++ b/src/processTargets/targets/DocumentTarget.ts @@ -1,4 +1,5 @@ import { Range } from "vscode"; +import { Position } from "../../typings/target.types"; import BaseTarget, { CommonTargetParameters, extractCommonParameters, @@ -12,16 +13,6 @@ export default class DocumentTarget extends BaseTarget { }); } - protected getRemovalContentRange(): Range { - if (this.position != null) { - return this.contentRange; - } - return new Range( - this.editor.document.lineAt(0).range.start, - this.editor.document.lineAt(this.editor.document.lineCount - 1).range.end - ); - } - get isLine() { return true; } @@ -33,7 +24,17 @@ export default class DocumentTarget extends BaseTarget { return this.contentRange; } - clone(): DocumentTarget { - return new DocumentTarget(this.state); + protected getRemovalContentRange(): Range { + if (this.position != null) { + return this.contentRange; + } + return new Range( + this.editor.document.lineAt(0).range.start, + this.editor.document.lineAt(this.editor.document.lineCount - 1).range.end + ); + } + + withPosition(position: Position): DocumentTarget { + return new DocumentTarget({ ...this.state, position }); } } diff --git a/src/processTargets/targets/LineTarget.ts b/src/processTargets/targets/LineTarget.ts index 0e96383951..5e90da079c 100644 --- a/src/processTargets/targets/LineTarget.ts +++ b/src/processTargets/targets/LineTarget.ts @@ -1,5 +1,5 @@ import { Range } from "vscode"; -import { RemovalRange } from "../../typings/target.types"; +import { Position, RemovalRange } from "../../typings/target.types"; import { parseRemovalRange } from "../../util/targetUtils"; import BaseTarget, { CommonTargetParameters, @@ -23,6 +23,13 @@ export default class LineTarget extends BaseTarget { return true; } + getRemovalHighlightRange(): Range | undefined { + if (this.position != null) { + return undefined; + } + return this.contentRange; + } + protected getRemovalContentRange(): Range { if (this.position != null) { return this.contentRange; @@ -39,14 +46,7 @@ export default class LineTarget extends BaseTarget { : removalRange; } - getRemovalHighlightRange(): Range | undefined { - if (this.position != null) { - return undefined; - } - return this.contentRange; - } - - clone(): LineTarget { - return new LineTarget(this.state); + withPosition(position: Position): LineTarget { + return new LineTarget({ ...this.state, position }); } } diff --git a/src/processTargets/targets/NotebookCellTarget.ts b/src/processTargets/targets/NotebookCellTarget.ts index 40b23572a2..bd34c24cc0 100644 --- a/src/processTargets/targets/NotebookCellTarget.ts +++ b/src/processTargets/targets/NotebookCellTarget.ts @@ -1,5 +1,5 @@ import { TextEditor } from "vscode"; -import { EditNewContext } from "../../typings/target.types"; +import { EditNewContext, Position } from "../../typings/target.types"; import { getNotebookFromCellDocument } from "../../util/notebook"; import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; @@ -26,11 +26,11 @@ export default class NotebookCellTarget extends BaseTarget { }; } - private isNotebookEditor(editor: TextEditor) { - return getNotebookFromCellDocument(editor.document) != null; + withPosition(position: Position): NotebookCellTarget { + return new NotebookCellTarget({ ...this.state, position }); } - clone(): NotebookCellTarget { - return new NotebookCellTarget(this.state); + private isNotebookEditor(editor: TextEditor) { + return getNotebookFromCellDocument(editor.document) != null; } } diff --git a/src/processTargets/targets/ParagraphTarget.ts b/src/processTargets/targets/ParagraphTarget.ts index 50aeb5a9b4..0810e42d20 100644 --- a/src/processTargets/targets/ParagraphTarget.ts +++ b/src/processTargets/targets/ParagraphTarget.ts @@ -1,5 +1,5 @@ import { Range } from "vscode"; -import { RemovalRange } from "../../typings/target.types"; +import { Position, RemovalRange } from "../../typings/target.types"; import { parseRemovalRange } from "../../util/targetUtils"; import BaseTarget, { CommonTargetParameters, @@ -27,15 +27,8 @@ export default class ParagraphTarget extends BaseTarget { return true; } - protected getRemovalBeforeRange(): Range { - return this.leadingDelimiter != null - ? new Range( - this.leadingDelimiter.range.start, - this.editor.document.lineAt( - this.contentRange.start.line - 1 - ).range.start - ) - : this.contentRange; + withPosition(position: Position): ParagraphTarget { + return new ParagraphTarget({ ...this.state, position }); } getRemovalContentRange(): Range { @@ -70,7 +63,14 @@ export default class ParagraphTarget extends BaseTarget { : removalRange; } - clone(): ParagraphTarget { - return new ParagraphTarget(this.state); + protected getRemovalBeforeRange(): Range { + return this.leadingDelimiter != null + ? new Range( + this.leadingDelimiter.range.start, + this.editor.document.lineAt( + this.contentRange.start.line - 1 + ).range.start + ) + : this.contentRange; } } diff --git a/src/processTargets/targets/RawSelectionTarget.ts b/src/processTargets/targets/RawSelectionTarget.ts index 9e3e184e6a..7e6d1d8358 100644 --- a/src/processTargets/targets/RawSelectionTarget.ts +++ b/src/processTargets/targets/RawSelectionTarget.ts @@ -1,3 +1,4 @@ +import { Position } from "../../typings/target.types"; import BaseTarget, { CommonTargetParameters, extractCommonParameters, @@ -12,7 +13,7 @@ export default class RawSelectionTarget extends BaseTarget { return undefined; } - clone(): RawSelectionTarget { - return new RawSelectionTarget(this.state); + withPosition(position: Position): RawSelectionTarget { + return new RawSelectionTarget({ ...this.state, position }); } } diff --git a/src/processTargets/targets/ScopeTypeTarget.ts b/src/processTargets/targets/ScopeTypeTarget.ts index 6269f2f222..274dc91fcf 100644 --- a/src/processTargets/targets/ScopeTypeTarget.ts +++ b/src/processTargets/targets/ScopeTypeTarget.ts @@ -1,5 +1,9 @@ import { Range } from "vscode"; -import { RemovalRange, SimpleScopeTypeType } from "../../typings/target.types"; +import { + Position, + RemovalRange, + SimpleScopeTypeType, +} from "../../typings/target.types"; import BaseTarget, { CommonTargetParameters, extractCommonParameters, @@ -18,11 +22,17 @@ export default class ScopeTypeTarget extends BaseTarget { super({ ...extractCommonParameters(parameters), delimiter: parameters.delimiter ?? getDelimiter(parameters.scopeTypeType), + leadingDelimiter: parameters.leadingDelimiter, + trailingDelimiter: parameters.trailingDelimiter, + removalRange: parameters.removalRange, }); } - clone(): ScopeTypeTarget { - return new ScopeTypeTarget(this.state); + withPosition(position: Position): ScopeTypeTarget { + return new ScopeTypeTarget({ + ...(this.state), + position, + }); } } diff --git a/src/processTargets/targets/SurroundingPairTarget.ts b/src/processTargets/targets/SurroundingPairTarget.ts index 6691666b7e..3123493001 100644 --- a/src/processTargets/targets/SurroundingPairTarget.ts +++ b/src/processTargets/targets/SurroundingPairTarget.ts @@ -1,5 +1,5 @@ import { Range } from "vscode"; -import { RemovalRange, Target } from "../../typings/target.types"; +import { Position, RemovalRange, Target } from "../../typings/target.types"; import { getTokenDelimiters } from "../modifiers/scopeTypeStages/TokenStage"; import BaseTarget, { CommonTargetParameters, @@ -32,19 +32,10 @@ export default class SurroundingPairTarget extends BaseTarget { ...extractCommonParameters(parameters), ...getTokenDelimiters(parameters.editor, parameters.contentRange), }); - this.boundary_ = parameters.boundary; this.interiorRange_ = parameters.interiorRange; } - clone(): SurroundingPairTarget { - return new SurroundingPairTarget({ - ...this.state, - interiorRange: this.interiorRange_, - boundary: this.boundary_, - }); - } - getInteriorStrict(): Target[] { if (this.interiorRange_ == null || this.position != null) { throw Error("No available interior"); @@ -71,4 +62,13 @@ export default class SurroundingPairTarget extends BaseTarget { }) ); } + + withPosition(position: Position): SurroundingPairTarget { + return new SurroundingPairTarget({ + ...this.state, + interiorRange: this.interiorRange_, + boundary: this.boundary_, + position, + }); + } } diff --git a/src/processTargets/targets/TokenTarget.ts b/src/processTargets/targets/TokenTarget.ts index 4335fece8f..b4954a153b 100644 --- a/src/processTargets/targets/TokenTarget.ts +++ b/src/processTargets/targets/TokenTarget.ts @@ -1,3 +1,4 @@ +import { Position } from "../../typings/target.types"; import { getTokenDelimiters } from "../modifiers/scopeTypeStages/TokenStage"; import BaseTarget, { CommonTargetParameters, @@ -12,7 +13,7 @@ export default class TokenTarget extends BaseTarget { }); } - clone(): TokenTarget { - return new TokenTarget(this.state); + withPosition(position: Position): TokenTarget { + return new TokenTarget({ ...this.state, position }); } } diff --git a/src/processTargets/targets/WeakTarget.ts b/src/processTargets/targets/WeakTarget.ts index 38f6f2c4ab..4ed125c9c6 100644 --- a/src/processTargets/targets/WeakTarget.ts +++ b/src/processTargets/targets/WeakTarget.ts @@ -1,3 +1,4 @@ +import { Position } from "../../typings/target.types"; import { getTokenDelimiters } from "../modifiers/scopeTypeStages/TokenStage"; import BaseTarget, { CommonTargetParameters, @@ -21,7 +22,7 @@ export default class WeakTarget extends BaseTarget { return true; } - clone(): WeakTarget { - return new WeakTarget(this.state); + withPosition(position: Position): WeakTarget { + return new WeakTarget({ ...this.state, position }); } } diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 252b653ee3..3522f538da 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -1,6 +1,5 @@ -import { Range } from "vscode"; +import { Range, Selection, TextEditor } from "vscode"; import { HatStyleName } from "../core/constants"; -import BaseTarget from "../processTargets/targets/BaseTarget"; export interface CursorMark { type: "cursor"; @@ -266,4 +265,48 @@ export interface EditNewDelimiterContext { export type EditNewContext = EditNewCommandContext | EditNewDelimiterContext; -export type Target = BaseTarget; +export interface Target { + /** The text editor used for all ranges */ + readonly editor: TextEditor; + + /** If true active is before anchor */ + readonly isReversed: boolean; + + /** The range of the content */ + readonly contentRange: Range; + + /** If this selection has a delimiter. For example, new line for a line or paragraph and comma for a list or argument */ + readonly delimiter?: string; + + /** The range to remove the content */ + readonly removalRange?: Range; + + /** The range of the delimiter before the content selection */ + readonly leadingDelimiter?: RemovalRange; + + /** The range of the delimiter after the content selection */ + readonly trailingDelimiter?: RemovalRange; + + /** The current position */ + readonly position?: Position; + + /** If true this target should be treated as a line */ + readonly isLine: boolean; + + /** If true this target should be treated as a paragraph */ + readonly isParagraph: boolean; + + /** If true this target is of weak type and should use inference/upgrade when needed. See {@link WeakTarget} for more info */ + readonly isWeak: boolean; + + readonly contentText: string; + readonly contentSelection: Selection; + + getInteriorStrict(): Target[]; + getBoundaryStrict(): Target[]; + maybeAddDelimiter(text: string): string; + getRemovalRange(): Range; + getRemovalHighlightRange(): Range | undefined; + getEditNewContext(isBefore: boolean): EditNewContext; + withPosition(position: Position): Target; +} From 40a9bd24f916d7590d3af0108517e972abb67630 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 25 May 2022 12:33:33 +0200 Subject: [PATCH 183/314] Added derived target --- src/actions/EditNew.ts | 2 +- src/actions/ToggleBreakpoint.ts | 6 +- .../modifiers/WeakContainingScopeStage.ts | 5 +- src/processTargets/targets/BaseTarget.ts | 4 ++ src/processTargets/targets/DerivedTarget.ts | 71 +++++++++++++++++++ src/typings/target.types.ts | 1 + 6 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 src/processTargets/targets/DerivedTarget.ts diff --git a/src/actions/EditNew.ts b/src/actions/EditNew.ts index 3d14aaaf95..f7a5694632 100644 --- a/src/actions/EditNew.ts +++ b/src/actions/EditNew.ts @@ -27,7 +27,7 @@ class EditNew implements Action { const common = { target, index, - targetRange: target.contentRange, + targetRange: target.getThatTarget().contentRange, cursorRange: getEditRange( editor, target.contentRange, diff --git a/src/actions/ToggleBreakpoint.ts b/src/actions/ToggleBreakpoint.ts index 5a9b65bc47..712ddab0eb 100644 --- a/src/actions/ToggleBreakpoint.ts +++ b/src/actions/ToggleBreakpoint.ts @@ -30,8 +30,10 @@ export default class ToggleBreakpoint implements Action { } async run([targets]: [Target[], Target[]]): Promise { + const thatTargets = targets.map((target) => target.getThatTarget()); + await displayPendingEditDecorations( - targets, + thatTargets, this.graph.editStyles.referenced ); @@ -60,7 +62,7 @@ export default class ToggleBreakpoint implements Action { debug.removeBreakpoints(toRemove); return { - thatMark: createThatMark(targets), + thatMark: createThatMark(thatTargets), }; } } diff --git a/src/processTargets/modifiers/WeakContainingScopeStage.ts b/src/processTargets/modifiers/WeakContainingScopeStage.ts index 52dc0c420c..535f110492 100644 --- a/src/processTargets/modifiers/WeakContainingScopeStage.ts +++ b/src/processTargets/modifiers/WeakContainingScopeStage.ts @@ -2,6 +2,7 @@ import { ContainingScopeModifier, Target } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import getModifierStage from "../getModifierStage"; import { ModifierStage } from "../PipelineStages.types"; +import DerivedTarget from "../targets/DerivedTarget"; export default class implements ModifierStage { constructor(private nestedModifier: ContainingScopeModifier) {} @@ -9,7 +10,9 @@ export default class implements ModifierStage { run(context: ProcessedTargetsContext, target: Target): Target[] { if (target.isWeak) { const stage = getModifierStage(this.nestedModifier); - return stage.run(context, target); + return stage + .run(context, target) + .map((newTarget) => new DerivedTarget(newTarget, target)); } return [target]; } diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index f24d89dad8..3e8ec65f25 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -88,6 +88,10 @@ export default abstract class BaseTarget implements Target { return false; } + getThatTarget() { + return this; + } + getInteriorStrict(): Target[] { throw Error("No available interior"); } diff --git a/src/processTargets/targets/DerivedTarget.ts b/src/processTargets/targets/DerivedTarget.ts new file mode 100644 index 0000000000..7491b326de --- /dev/null +++ b/src/processTargets/targets/DerivedTarget.ts @@ -0,0 +1,71 @@ +import { Range } from "vscode"; +import { EditNewContext, Position, Target } from "../../typings/target.types"; + +export default class DerivedTarget implements Target { + constructor(private target: Target, private weakTarget: Target) {} + + get editor() { + return this.target.editor; + } + get isReversed() { + return this.target.isReversed; + } + get contentRange() { + return this.target.contentRange; + } + get delimiter() { + return this.target.delimiter; + } + get removalRange() { + return this.target.removalRange; + } + get leadingDelimiter() { + return this.target.leadingDelimiter; + } + get trailingDelimiter() { + return this.target.trailingDelimiter; + } + get position() { + return this.target.position; + } + get isLine() { + return this.target.isLine; + } + get isParagraph() { + return this.target.isParagraph; + } + get isWeak() { + return this.target.isWeak; + } + get contentText() { + return this.target.contentText; + } + get contentSelection() { + return this.target.contentSelection; + } + getInteriorStrict(): Target[] { + return this.target.getInteriorStrict(); + } + getBoundaryStrict(): Target[] { + return this.target.getBoundaryStrict(); + } + maybeAddDelimiter(text: string): string { + return this.target.maybeAddDelimiter(text); + } + getRemovalRange(): Range { + return this.target.getRemovalRange(); + } + getRemovalHighlightRange(): Range | undefined { + return this.target.getRemovalHighlightRange(); + } + getEditNewContext(isBefore: boolean): EditNewContext { + return this.target.getEditNewContext(isBefore); + } + withPosition(position: Position): Target { + return this.target.withPosition(position); + } + + getThatTarget() { + return this.weakTarget; + } +} diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 3522f538da..c5d00b1eed 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -309,4 +309,5 @@ export interface Target { getRemovalHighlightRange(): Range | undefined; getEditNewContext(isBefore: boolean): EditNewContext; withPosition(position: Position): Target; + getThatTarget(): Target; } From 25535edcd4919d457d7a2b88430051c943830b4d Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 25 May 2022 13:01:48 +0200 Subject: [PATCH 184/314] Moved weak target into base target class --- src/actions/EditNew.ts | 2 +- src/actions/ToggleBreakpoint.ts | 2 +- .../modifiers/WeakContainingScopeStage.ts | 3 +- src/processTargets/targets/BaseTarget.ts | 25 ++++++- src/processTargets/targets/DerivedTarget.ts | 71 ------------------- src/processTargets/targets/DocumentTarget.ts | 6 +- src/processTargets/targets/LineTarget.ts | 7 +- .../targets/NotebookCellTarget.ts | 11 +-- src/processTargets/targets/ParagraphTarget.ts | 7 +- .../targets/RawSelectionTarget.ts | 6 +- src/processTargets/targets/ScopeTypeTarget.ts | 11 ++- .../targets/SurroundingPairTarget.ts | 7 +- src/processTargets/targets/TokenTarget.ts | 6 +- src/processTargets/targets/WeakTarget.ts | 6 +- src/typings/target.types.ts | 3 +- 15 files changed, 62 insertions(+), 111 deletions(-) delete mode 100644 src/processTargets/targets/DerivedTarget.ts diff --git a/src/actions/EditNew.ts b/src/actions/EditNew.ts index f7a5694632..571a448a4a 100644 --- a/src/actions/EditNew.ts +++ b/src/actions/EditNew.ts @@ -27,7 +27,7 @@ class EditNew implements Action { const common = { target, index, - targetRange: target.getThatTarget().contentRange, + targetRange: target.thatTarget.contentRange, cursorRange: getEditRange( editor, target.contentRange, diff --git a/src/actions/ToggleBreakpoint.ts b/src/actions/ToggleBreakpoint.ts index 712ddab0eb..2a9735a4c5 100644 --- a/src/actions/ToggleBreakpoint.ts +++ b/src/actions/ToggleBreakpoint.ts @@ -30,7 +30,7 @@ export default class ToggleBreakpoint implements Action { } async run([targets]: [Target[], Target[]]): Promise { - const thatTargets = targets.map((target) => target.getThatTarget()); + const thatTargets = targets.map(({ thatTarget }) => thatTarget); await displayPendingEditDecorations( thatTargets, diff --git a/src/processTargets/modifiers/WeakContainingScopeStage.ts b/src/processTargets/modifiers/WeakContainingScopeStage.ts index 535f110492..113519d855 100644 --- a/src/processTargets/modifiers/WeakContainingScopeStage.ts +++ b/src/processTargets/modifiers/WeakContainingScopeStage.ts @@ -2,7 +2,6 @@ import { ContainingScopeModifier, Target } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import getModifierStage from "../getModifierStage"; import { ModifierStage } from "../PipelineStages.types"; -import DerivedTarget from "../targets/DerivedTarget"; export default class implements ModifierStage { constructor(private nestedModifier: ContainingScopeModifier) {} @@ -12,7 +11,7 @@ export default class implements ModifierStage { const stage = getModifierStage(this.nestedModifier); return stage .run(context, target) - .map((newTarget) => new DerivedTarget(newTarget, target)); + .map((newTarget) => newTarget.withWeakTarget(target)); } return [target]; } diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index 3e8ec65f25..51d3c0d2e1 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -14,6 +14,7 @@ export function extractCommonParameters(parameters: CommonTargetParameters) { isReversed: parameters.isReversed, contentRange: parameters.contentRange, position: parameters.position, + weakTarget: parameters.weakTarget, }; } @@ -23,6 +24,12 @@ export interface CommonTargetParameters { isReversed: boolean; contentRange: Range; position?: Position; + weakTarget?: Target; +} + +export interface CloneWithParameters { + position?: Position; + weakTarget?: Target; } export interface BaseTargetParameters extends CommonTargetParameters { @@ -37,6 +44,7 @@ interface BaseTargetState { readonly editor: TextEditor; readonly isReversed: boolean; readonly contentRange: Range; + readonly weakTarget?: Target; readonly delimiter: string; readonly removalRange?: Range; readonly leadingDelimiter?: RemovalRange; @@ -57,6 +65,7 @@ export default abstract class BaseTarget implements Target { removalRange: parameters.removalRange, leadingDelimiter: parameters.leadingDelimiter, trailingDelimiter: parameters.trailingDelimiter, + weakTarget: parameters.weakTarget, }; } @@ -88,8 +97,10 @@ export default abstract class BaseTarget implements Target { return false; } - getThatTarget() { - return this; + get thatTarget(): Target { + return this.state.weakTarget != null + ? this.state.weakTarget.thatTarget + : this; } getInteriorStrict(): Target[] { @@ -247,5 +258,13 @@ export default abstract class BaseTarget implements Target { }; } - abstract withPosition(position: Position): Target; + withPosition(position: Position): Target { + return this.cloneWith({ position }); + } + + withWeakTarget(weakTarget: Target): Target { + return this.cloneWith({ weakTarget }); + } + + abstract cloneWith(parameters: CloneWithParameters): Target; } diff --git a/src/processTargets/targets/DerivedTarget.ts b/src/processTargets/targets/DerivedTarget.ts deleted file mode 100644 index 7491b326de..0000000000 --- a/src/processTargets/targets/DerivedTarget.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { Range } from "vscode"; -import { EditNewContext, Position, Target } from "../../typings/target.types"; - -export default class DerivedTarget implements Target { - constructor(private target: Target, private weakTarget: Target) {} - - get editor() { - return this.target.editor; - } - get isReversed() { - return this.target.isReversed; - } - get contentRange() { - return this.target.contentRange; - } - get delimiter() { - return this.target.delimiter; - } - get removalRange() { - return this.target.removalRange; - } - get leadingDelimiter() { - return this.target.leadingDelimiter; - } - get trailingDelimiter() { - return this.target.trailingDelimiter; - } - get position() { - return this.target.position; - } - get isLine() { - return this.target.isLine; - } - get isParagraph() { - return this.target.isParagraph; - } - get isWeak() { - return this.target.isWeak; - } - get contentText() { - return this.target.contentText; - } - get contentSelection() { - return this.target.contentSelection; - } - getInteriorStrict(): Target[] { - return this.target.getInteriorStrict(); - } - getBoundaryStrict(): Target[] { - return this.target.getBoundaryStrict(); - } - maybeAddDelimiter(text: string): string { - return this.target.maybeAddDelimiter(text); - } - getRemovalRange(): Range { - return this.target.getRemovalRange(); - } - getRemovalHighlightRange(): Range | undefined { - return this.target.getRemovalHighlightRange(); - } - getEditNewContext(isBefore: boolean): EditNewContext { - return this.target.getEditNewContext(isBefore); - } - withPosition(position: Position): Target { - return this.target.withPosition(position); - } - - getThatTarget() { - return this.weakTarget; - } -} diff --git a/src/processTargets/targets/DocumentTarget.ts b/src/processTargets/targets/DocumentTarget.ts index fd5b429c00..3a0b2836ef 100644 --- a/src/processTargets/targets/DocumentTarget.ts +++ b/src/processTargets/targets/DocumentTarget.ts @@ -1,6 +1,6 @@ import { Range } from "vscode"; -import { Position } from "../../typings/target.types"; import BaseTarget, { + CloneWithParameters, CommonTargetParameters, extractCommonParameters, } from "./BaseTarget"; @@ -34,7 +34,7 @@ export default class DocumentTarget extends BaseTarget { ); } - withPosition(position: Position): DocumentTarget { - return new DocumentTarget({ ...this.state, position }); + cloneWith(parameters: CloneWithParameters): DocumentTarget { + return new DocumentTarget({ ...this.state, ...parameters }); } } diff --git a/src/processTargets/targets/LineTarget.ts b/src/processTargets/targets/LineTarget.ts index 5e90da079c..4ae4738ff1 100644 --- a/src/processTargets/targets/LineTarget.ts +++ b/src/processTargets/targets/LineTarget.ts @@ -1,7 +1,8 @@ import { Range } from "vscode"; -import { Position, RemovalRange } from "../../typings/target.types"; +import { RemovalRange } from "../../typings/target.types"; import { parseRemovalRange } from "../../util/targetUtils"; import BaseTarget, { + CloneWithParameters, CommonTargetParameters, extractCommonParameters, } from "./BaseTarget"; @@ -46,7 +47,7 @@ export default class LineTarget extends BaseTarget { : removalRange; } - withPosition(position: Position): LineTarget { - return new LineTarget({ ...this.state, position }); + cloneWith(parameters: CloneWithParameters): LineTarget { + return new LineTarget({ ...this.state, ...parameters }); } } diff --git a/src/processTargets/targets/NotebookCellTarget.ts b/src/processTargets/targets/NotebookCellTarget.ts index bd34c24cc0..efcc19817c 100644 --- a/src/processTargets/targets/NotebookCellTarget.ts +++ b/src/processTargets/targets/NotebookCellTarget.ts @@ -1,7 +1,10 @@ import { TextEditor } from "vscode"; -import { EditNewContext, Position } from "../../typings/target.types"; +import { EditNewContext } from "../../typings/target.types"; import { getNotebookFromCellDocument } from "../../util/notebook"; -import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; +import BaseTarget, { + CloneWithParameters, + CommonTargetParameters, +} from "./BaseTarget"; export default class NotebookCellTarget extends BaseTarget { constructor(parameters: CommonTargetParameters) { @@ -26,8 +29,8 @@ export default class NotebookCellTarget extends BaseTarget { }; } - withPosition(position: Position): NotebookCellTarget { - return new NotebookCellTarget({ ...this.state, position }); + cloneWith(parameters: CloneWithParameters): NotebookCellTarget { + return new NotebookCellTarget({ ...this.state, ...parameters }); } private isNotebookEditor(editor: TextEditor) { diff --git a/src/processTargets/targets/ParagraphTarget.ts b/src/processTargets/targets/ParagraphTarget.ts index 0810e42d20..7604241718 100644 --- a/src/processTargets/targets/ParagraphTarget.ts +++ b/src/processTargets/targets/ParagraphTarget.ts @@ -1,7 +1,8 @@ import { Range } from "vscode"; -import { Position, RemovalRange } from "../../typings/target.types"; +import { RemovalRange } from "../../typings/target.types"; import { parseRemovalRange } from "../../util/targetUtils"; import BaseTarget, { + CloneWithParameters, CommonTargetParameters, extractCommonParameters, } from "./BaseTarget"; @@ -27,8 +28,8 @@ export default class ParagraphTarget extends BaseTarget { return true; } - withPosition(position: Position): ParagraphTarget { - return new ParagraphTarget({ ...this.state, position }); + cloneWith(parameters: CloneWithParameters): ParagraphTarget { + return new ParagraphTarget({ ...this.state, ...parameters }); } getRemovalContentRange(): Range { diff --git a/src/processTargets/targets/RawSelectionTarget.ts b/src/processTargets/targets/RawSelectionTarget.ts index 7e6d1d8358..77b8b85aa9 100644 --- a/src/processTargets/targets/RawSelectionTarget.ts +++ b/src/processTargets/targets/RawSelectionTarget.ts @@ -1,5 +1,5 @@ -import { Position } from "../../typings/target.types"; import BaseTarget, { + CloneWithParameters, CommonTargetParameters, extractCommonParameters, } from "./BaseTarget"; @@ -13,7 +13,7 @@ export default class RawSelectionTarget extends BaseTarget { return undefined; } - withPosition(position: Position): RawSelectionTarget { - return new RawSelectionTarget({ ...this.state, position }); + cloneWith(parameters: CloneWithParameters): RawSelectionTarget { + return new RawSelectionTarget({ ...this.state, ...parameters }); } } diff --git a/src/processTargets/targets/ScopeTypeTarget.ts b/src/processTargets/targets/ScopeTypeTarget.ts index 274dc91fcf..02d6ae2bde 100644 --- a/src/processTargets/targets/ScopeTypeTarget.ts +++ b/src/processTargets/targets/ScopeTypeTarget.ts @@ -1,10 +1,7 @@ import { Range } from "vscode"; -import { - Position, - RemovalRange, - SimpleScopeTypeType, -} from "../../typings/target.types"; +import { RemovalRange, SimpleScopeTypeType } from "../../typings/target.types"; import BaseTarget, { + CloneWithParameters, CommonTargetParameters, extractCommonParameters, } from "./BaseTarget"; @@ -28,10 +25,10 @@ export default class ScopeTypeTarget extends BaseTarget { }); } - withPosition(position: Position): ScopeTypeTarget { + cloneWith(parameters: CloneWithParameters): ScopeTypeTarget { return new ScopeTypeTarget({ ...(this.state), - position, + ...parameters, }); } } diff --git a/src/processTargets/targets/SurroundingPairTarget.ts b/src/processTargets/targets/SurroundingPairTarget.ts index 3123493001..5a78fe92b9 100644 --- a/src/processTargets/targets/SurroundingPairTarget.ts +++ b/src/processTargets/targets/SurroundingPairTarget.ts @@ -1,7 +1,8 @@ import { Range } from "vscode"; -import { Position, RemovalRange, Target } from "../../typings/target.types"; +import { Target } from "../../typings/target.types"; import { getTokenDelimiters } from "../modifiers/scopeTypeStages/TokenStage"; import BaseTarget, { + CloneWithParameters, CommonTargetParameters, extractCommonParameters, } from "./BaseTarget"; @@ -63,12 +64,12 @@ export default class SurroundingPairTarget extends BaseTarget { ); } - withPosition(position: Position): SurroundingPairTarget { + cloneWith(parameters: CloneWithParameters): SurroundingPairTarget { return new SurroundingPairTarget({ ...this.state, interiorRange: this.interiorRange_, boundary: this.boundary_, - position, + ...parameters, }); } } diff --git a/src/processTargets/targets/TokenTarget.ts b/src/processTargets/targets/TokenTarget.ts index b4954a153b..ffc4dd99d5 100644 --- a/src/processTargets/targets/TokenTarget.ts +++ b/src/processTargets/targets/TokenTarget.ts @@ -1,6 +1,6 @@ -import { Position } from "../../typings/target.types"; import { getTokenDelimiters } from "../modifiers/scopeTypeStages/TokenStage"; import BaseTarget, { + CloneWithParameters, CommonTargetParameters, extractCommonParameters, } from "./BaseTarget"; @@ -13,7 +13,7 @@ export default class TokenTarget extends BaseTarget { }); } - withPosition(position: Position): TokenTarget { - return new TokenTarget({ ...this.state, position }); + cloneWith(parameters: CloneWithParameters): TokenTarget { + return new TokenTarget({ ...this.state, ...parameters }); } } diff --git a/src/processTargets/targets/WeakTarget.ts b/src/processTargets/targets/WeakTarget.ts index 4ed125c9c6..ca8e654d26 100644 --- a/src/processTargets/targets/WeakTarget.ts +++ b/src/processTargets/targets/WeakTarget.ts @@ -1,6 +1,6 @@ -import { Position } from "../../typings/target.types"; import { getTokenDelimiters } from "../modifiers/scopeTypeStages/TokenStage"; import BaseTarget, { + CloneWithParameters, CommonTargetParameters, extractCommonParameters, } from "./BaseTarget"; @@ -22,7 +22,7 @@ export default class WeakTarget extends BaseTarget { return true; } - withPosition(position: Position): WeakTarget { - return new WeakTarget({ ...this.state, position }); + cloneWith(parameters: CloneWithParameters): WeakTarget { + return new WeakTarget({ ...this.state, ...parameters }); } } diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index c5d00b1eed..9ab32559a0 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -301,6 +301,7 @@ export interface Target { readonly contentText: string; readonly contentSelection: Selection; + readonly thatTarget: Target; getInteriorStrict(): Target[]; getBoundaryStrict(): Target[]; @@ -309,5 +310,5 @@ export interface Target { getRemovalHighlightRange(): Range | undefined; getEditNewContext(isBefore: boolean): EditNewContext; withPosition(position: Position): Target; - getThatTarget(): Target; + withWeakTarget(weakTarget: Target): Target; } From 27b2edd3cf16dc974d4d53966779cebe2c0096d4 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 25 May 2022 13:03:02 +0200 Subject: [PATCH 185/314] Cleanup --- src/processTargets/targets/BaseTarget.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index 51d3c0d2e1..8dfe5fd9da 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -49,7 +49,7 @@ interface BaseTargetState { readonly removalRange?: Range; readonly leadingDelimiter?: RemovalRange; readonly trailingDelimiter?: RemovalRange; - position?: Position; + readonly position?: Position; } export default abstract class BaseTarget implements Target { From f566dd1dfafba539f5960b2c8b12be2bfa6f78e9 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 25 May 2022 13:40:06 +0200 Subject: [PATCH 186/314] Updated action form --- src/test/suite/fixtures/recorded/actions/drinkArg.yml | 2 +- src/test/suite/fixtures/recorded/actions/drinkBlock.yml | 2 +- src/test/suite/fixtures/recorded/actions/pourArg.yml | 2 +- src/test/suite/fixtures/recorded/actions/pourBlock.yml | 2 +- .../suite/fixtures/recorded/positions/bringHarpToAfterFile.yml | 2 +- .../fixtures/recorded/positions/bringWhaleToBeforeFile.yml | 2 +- .../fixtures/recorded/selectionTypes/bringHarpToAfterFile.yml | 2 +- .../fixtures/recorded/selectionTypes/bringWhaleToBeforeFile.yml | 2 +- .../recorded/selectionTypes/chuckBlockHarpBetweenFine.yml | 2 +- src/test/suite/fixtures/recorded/selectionTypes/chuckFile2.yml | 2 +- .../recorded/selectionTypes/chuckLineHarpBetweenFine.yml | 2 +- .../suite/fixtures/recorded/selectionTypes/clearLinePair.yml | 2 +- .../suite/fixtures/recorded/selectionTypes/drinkJustFine.yml | 2 +- src/test/suite/fixtures/recorded/selectionTypes/drinkToken.yml | 2 +- .../suite/fixtures/recorded/selectionTypes/takeEveryBlock.yml | 2 +- .../suite/fixtures/recorded/selectionTypes/takeEveryBlock2.yml | 2 +- .../suite/fixtures/recorded/selectionTypes/takeEveryBlock3.yml | 2 +- .../suite/fixtures/recorded/selectionTypes/takeEveryFile.yml | 2 +- .../suite/fixtures/recorded/selectionTypes/takeEveryLine.yml | 2 +- .../suite/fixtures/recorded/selectionTypes/takeEveryLine2.yml | 2 +- .../suite/fixtures/recorded/selectionTypes/takeEveryLine3.yml | 2 +- src/test/suite/fixtures/recorded/selectionTypes/takeFile.yml | 2 +- 22 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/test/suite/fixtures/recorded/actions/drinkArg.yml b/src/test/suite/fixtures/recorded/actions/drinkArg.yml index a8d72e49a1..d717256519 100644 --- a/src/test/suite/fixtures/recorded/actions/drinkArg.yml +++ b/src/test/suite/fixtures/recorded/actions/drinkArg.yml @@ -2,7 +2,7 @@ languageId: typescript command: spokenForm: drink arg version: 2 - action: editNewLineBefore + action: {name: editNewLineBefore} targets: - type: primitive modifiers: diff --git a/src/test/suite/fixtures/recorded/actions/drinkBlock.yml b/src/test/suite/fixtures/recorded/actions/drinkBlock.yml index bb24a95e80..320f20b180 100644 --- a/src/test/suite/fixtures/recorded/actions/drinkBlock.yml +++ b/src/test/suite/fixtures/recorded/actions/drinkBlock.yml @@ -2,7 +2,7 @@ languageId: typescript command: spokenForm: drink block version: 2 - action: editNewLineBefore + action: {name: editNewLineBefore} targets: - type: primitive modifiers: diff --git a/src/test/suite/fixtures/recorded/actions/pourArg.yml b/src/test/suite/fixtures/recorded/actions/pourArg.yml index bd0bfa6792..0de6078fec 100644 --- a/src/test/suite/fixtures/recorded/actions/pourArg.yml +++ b/src/test/suite/fixtures/recorded/actions/pourArg.yml @@ -2,7 +2,7 @@ languageId: typescript command: spokenForm: pour arg version: 2 - action: editNewLineAfter + action: {name: editNewLineAfter} targets: - type: primitive modifiers: diff --git a/src/test/suite/fixtures/recorded/actions/pourBlock.yml b/src/test/suite/fixtures/recorded/actions/pourBlock.yml index 05f2dc3c33..33a3ad4525 100644 --- a/src/test/suite/fixtures/recorded/actions/pourBlock.yml +++ b/src/test/suite/fixtures/recorded/actions/pourBlock.yml @@ -2,7 +2,7 @@ languageId: typescript command: spokenForm: pour block version: 2 - action: editNewLineAfter + action: {name: editNewLineAfter} targets: - type: primitive modifiers: diff --git a/src/test/suite/fixtures/recorded/positions/bringHarpToAfterFile.yml b/src/test/suite/fixtures/recorded/positions/bringHarpToAfterFile.yml index 80c4921c3a..c61c7eb843 100644 --- a/src/test/suite/fixtures/recorded/positions/bringHarpToAfterFile.yml +++ b/src/test/suite/fixtures/recorded/positions/bringHarpToAfterFile.yml @@ -2,7 +2,7 @@ languageId: plaintext command: spokenForm: bring harp to after file version: 2 - action: replaceWithTarget + action: {name: replaceWitrhTarget} targets: - type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: h} diff --git a/src/test/suite/fixtures/recorded/positions/bringWhaleToBeforeFile.yml b/src/test/suite/fixtures/recorded/positions/bringWhaleToBeforeFile.yml index fb66606d55..2b3dde789c 100644 --- a/src/test/suite/fixtures/recorded/positions/bringWhaleToBeforeFile.yml +++ b/src/test/suite/fixtures/recorded/positions/bringWhaleToBeforeFile.yml @@ -2,7 +2,7 @@ languageId: plaintext command: spokenForm: bring whale to before file version: 2 - action: replaceWithTarget + action: {name: replaceWithTarget} targets: - type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: w} diff --git a/src/test/suite/fixtures/recorded/selectionTypes/bringHarpToAfterFile.yml b/src/test/suite/fixtures/recorded/selectionTypes/bringHarpToAfterFile.yml index 9c9098eba4..f0ecb67f2e 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/bringHarpToAfterFile.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/bringHarpToAfterFile.yml @@ -2,7 +2,7 @@ languageId: plaintext command: spokenForm: bring harp to after file version: 2 - action: replaceWithTarget + action: {name: replaceWithTarget} targets: - type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: h} diff --git a/src/test/suite/fixtures/recorded/selectionTypes/bringWhaleToBeforeFile.yml b/src/test/suite/fixtures/recorded/selectionTypes/bringWhaleToBeforeFile.yml index 48596f4294..f787c39633 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/bringWhaleToBeforeFile.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/bringWhaleToBeforeFile.yml @@ -2,7 +2,7 @@ languageId: plaintext command: spokenForm: bring whale to before file version: 2 - action: replaceWithTarget + action: {name: replaceWithTarget} targets: - type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: w} diff --git a/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockHarpBetweenFine.yml b/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockHarpBetweenFine.yml index 0be22b6729..bd5f33b247 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockHarpBetweenFine.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockHarpBetweenFine.yml @@ -2,7 +2,7 @@ languageId: plaintext command: spokenForm: chuck block harp between fine version: 2 - action: remove + action: {name: remove} targets: - type: range start: diff --git a/src/test/suite/fixtures/recorded/selectionTypes/chuckFile2.yml b/src/test/suite/fixtures/recorded/selectionTypes/chuckFile2.yml index 7b919168d7..91e8ff8dd4 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/chuckFile2.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/chuckFile2.yml @@ -2,7 +2,7 @@ languageId: plaintext command: spokenForm: chuck file version: 2 - action: remove + action: {name: remove} targets: - type: primitive modifiers: diff --git a/src/test/suite/fixtures/recorded/selectionTypes/chuckLineHarpBetweenFine.yml b/src/test/suite/fixtures/recorded/selectionTypes/chuckLineHarpBetweenFine.yml index e3cd997de6..9a6a325710 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/chuckLineHarpBetweenFine.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/chuckLineHarpBetweenFine.yml @@ -2,7 +2,7 @@ languageId: plaintext command: spokenForm: chuck line harp between fine version: 2 - action: remove + action: {name: remove} targets: - type: range start: diff --git a/src/test/suite/fixtures/recorded/selectionTypes/clearLinePair.yml b/src/test/suite/fixtures/recorded/selectionTypes/clearLinePair.yml index 22df88e611..f09017bbd3 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/clearLinePair.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/clearLinePair.yml @@ -2,7 +2,7 @@ languageId: plaintext command: spokenForm: clear line pair version: 2 - action: clearAndSetSelection + action: {name: clearAndSetSelection} targets: - type: primitive modifiers: diff --git a/src/test/suite/fixtures/recorded/selectionTypes/drinkJustFine.yml b/src/test/suite/fixtures/recorded/selectionTypes/drinkJustFine.yml index b8819a85f1..6cbc05151c 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/drinkJustFine.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/drinkJustFine.yml @@ -2,7 +2,7 @@ languageId: plaintext command: spokenForm: drink just fine version: 2 - action: editNewLineBefore + action: {name: editNewLineBefore} targets: - type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: f} diff --git a/src/test/suite/fixtures/recorded/selectionTypes/drinkToken.yml b/src/test/suite/fixtures/recorded/selectionTypes/drinkToken.yml index 823539a19b..b7be4f31af 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/drinkToken.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/drinkToken.yml @@ -2,7 +2,7 @@ languageId: python command: spokenForm: drink token version: 2 - action: editNewLineBefore + action: {name: editNewLineBefore} targets: - type: primitive modifiers: diff --git a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock.yml b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock.yml index 46733e12a5..9c48ee581c 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock.yml @@ -2,7 +2,7 @@ languageId: plaintext command: spokenForm: take every block version: 2 - action: setSelection + action: {name: setSelection} targets: - type: primitive modifiers: diff --git a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock2.yml b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock2.yml index 878ea84cf1..e21a53a2fa 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock2.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock2.yml @@ -2,7 +2,7 @@ languageId: plaintext command: spokenForm: take every block version: 2 - action: setSelection + action: {name: setSelection} targets: - type: primitive modifiers: diff --git a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock3.yml b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock3.yml index 7632670f2e..33a04a6e1a 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock3.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock3.yml @@ -2,7 +2,7 @@ languageId: plaintext command: spokenForm: take every block version: 2 - action: setSelection + action: {name: setSelection} targets: - type: primitive modifiers: diff --git a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryFile.yml b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryFile.yml index 00e8975606..cc07b7e48f 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryFile.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryFile.yml @@ -2,7 +2,7 @@ languageId: plaintext command: spokenForm: take every file version: 2 - action: setSelection + action: {name: setSelection} targets: - type: primitive modifiers: diff --git a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine.yml b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine.yml index eaaf7f0b08..62dd0da4e2 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine.yml @@ -2,7 +2,7 @@ languageId: plaintext command: spokenForm: take every line version: 2 - action: setSelection + action: {name: setSelection} targets: - type: primitive modifiers: diff --git a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine2.yml b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine2.yml index 0c5a94e5eb..550b864e66 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine2.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine2.yml @@ -2,7 +2,7 @@ languageId: plaintext command: spokenForm: take every line version: 2 - action: setSelection + action: {name: setSelection} targets: - type: primitive modifiers: diff --git a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine3.yml b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine3.yml index bd926f20d2..b1aa78f006 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine3.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine3.yml @@ -2,7 +2,7 @@ languageId: plaintext command: spokenForm: take every line version: 2 - action: setSelection + action: {name: setSelection} targets: - type: primitive modifiers: diff --git a/src/test/suite/fixtures/recorded/selectionTypes/takeFile.yml b/src/test/suite/fixtures/recorded/selectionTypes/takeFile.yml index 4f843aff48..21d1ec682e 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/takeFile.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/takeFile.yml @@ -2,7 +2,7 @@ languageId: plaintext command: spokenForm: take file version: 2 - action: setSelection + action: {name: setSelection} targets: - type: primitive modifiers: From ca80d974cb815bc8ad1577b829244eb4a5276285 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 25 May 2022 13:57:51 +0200 Subject: [PATCH 187/314] Updated scope type for tests --- src/test/suite/fixtures/recorded/actions/drinkArg.yml | 3 ++- src/test/suite/fixtures/recorded/actions/drinkBlock.yml | 3 ++- src/test/suite/fixtures/recorded/actions/pourArg.yml | 3 ++- src/test/suite/fixtures/recorded/actions/pourBlock.yml | 3 ++- .../fixtures/recorded/positions/bringHarpToAfterFile.yml | 3 ++- .../fixtures/recorded/positions/bringWhaleToBeforeFile.yml | 3 ++- .../recorded/selectionTypes/bringHarpToAfterFile.yml | 3 ++- .../recorded/selectionTypes/bringWhaleToBeforeFile.yml | 3 ++- .../recorded/selectionTypes/chuckBlockHarpBetweenFine.yml | 4 ++-- .../suite/fixtures/recorded/selectionTypes/chuckFile2.yml | 3 ++- .../recorded/selectionTypes/chuckLineHarpBetweenFine.yml | 3 ++- .../fixtures/recorded/selectionTypes/clearLinePair.yml | 6 ++++-- .../suite/fixtures/recorded/selectionTypes/drinkToken.yml | 3 ++- .../fixtures/recorded/selectionTypes/takeEveryBlock.yml | 3 ++- .../fixtures/recorded/selectionTypes/takeEveryBlock2.yml | 3 ++- .../fixtures/recorded/selectionTypes/takeEveryBlock3.yml | 3 ++- .../fixtures/recorded/selectionTypes/takeEveryFile.yml | 3 ++- .../fixtures/recorded/selectionTypes/takeEveryLine.yml | 3 ++- .../fixtures/recorded/selectionTypes/takeEveryLine2.yml | 3 ++- .../fixtures/recorded/selectionTypes/takeEveryLine3.yml | 3 ++- .../suite/fixtures/recorded/selectionTypes/takeFile.yml | 3 ++- 21 files changed, 44 insertions(+), 23 deletions(-) diff --git a/src/test/suite/fixtures/recorded/actions/drinkArg.yml b/src/test/suite/fixtures/recorded/actions/drinkArg.yml index d717256519..292caf4341 100644 --- a/src/test/suite/fixtures/recorded/actions/drinkArg.yml +++ b/src/test/suite/fixtures/recorded/actions/drinkArg.yml @@ -6,7 +6,8 @@ command: targets: - type: primitive modifiers: - - {type: containingScope, scopeType: argumentOrParameter} + - type: containingScope + scopeType: {type: argumentOrParameter} usePrePhraseSnapshot: true initialState: documentContents: | diff --git a/src/test/suite/fixtures/recorded/actions/drinkBlock.yml b/src/test/suite/fixtures/recorded/actions/drinkBlock.yml index 320f20b180..fcff4221d7 100644 --- a/src/test/suite/fixtures/recorded/actions/drinkBlock.yml +++ b/src/test/suite/fixtures/recorded/actions/drinkBlock.yml @@ -6,7 +6,8 @@ command: targets: - type: primitive modifiers: - - {type: containingScope, scopeType: paragraph} + - type: containingScope + scopeType: {type: paragraph} usePrePhraseSnapshot: true initialState: documentContents: | diff --git a/src/test/suite/fixtures/recorded/actions/pourArg.yml b/src/test/suite/fixtures/recorded/actions/pourArg.yml index 0de6078fec..ca4a690830 100644 --- a/src/test/suite/fixtures/recorded/actions/pourArg.yml +++ b/src/test/suite/fixtures/recorded/actions/pourArg.yml @@ -6,7 +6,8 @@ command: targets: - type: primitive modifiers: - - {type: containingScope, scopeType: argumentOrParameter} + - type: containingScope + scopeType: {type: argumentOrParameter} usePrePhraseSnapshot: true initialState: documentContents: | diff --git a/src/test/suite/fixtures/recorded/actions/pourBlock.yml b/src/test/suite/fixtures/recorded/actions/pourBlock.yml index 33a3ad4525..cb640e2ada 100644 --- a/src/test/suite/fixtures/recorded/actions/pourBlock.yml +++ b/src/test/suite/fixtures/recorded/actions/pourBlock.yml @@ -6,7 +6,8 @@ command: targets: - type: primitive modifiers: - - {type: containingScope, scopeType: paragraph} + - type: containingScope + scopeType: {type: paragraph} usePrePhraseSnapshot: true initialState: documentContents: | diff --git a/src/test/suite/fixtures/recorded/positions/bringHarpToAfterFile.yml b/src/test/suite/fixtures/recorded/positions/bringHarpToAfterFile.yml index c61c7eb843..379564a09c 100644 --- a/src/test/suite/fixtures/recorded/positions/bringHarpToAfterFile.yml +++ b/src/test/suite/fixtures/recorded/positions/bringHarpToAfterFile.yml @@ -9,7 +9,8 @@ command: - type: primitive modifiers: - {type: position, position: after} - - {type: containingScope, scopeType: document} + - type: containingScope + scopeType: {type: document} usePrePhraseSnapshot: true initialState: documentContents: hello world diff --git a/src/test/suite/fixtures/recorded/positions/bringWhaleToBeforeFile.yml b/src/test/suite/fixtures/recorded/positions/bringWhaleToBeforeFile.yml index 2b3dde789c..0ffcbf02cf 100644 --- a/src/test/suite/fixtures/recorded/positions/bringWhaleToBeforeFile.yml +++ b/src/test/suite/fixtures/recorded/positions/bringWhaleToBeforeFile.yml @@ -9,7 +9,8 @@ command: - type: primitive modifiers: - {type: position, position: before} - - {type: containingScope, scopeType: document} + - type: containingScope + scopeType: {type: document} usePrePhraseSnapshot: true initialState: documentContents: hello world diff --git a/src/test/suite/fixtures/recorded/selectionTypes/bringHarpToAfterFile.yml b/src/test/suite/fixtures/recorded/selectionTypes/bringHarpToAfterFile.yml index f0ecb67f2e..9f63ae9bfa 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/bringHarpToAfterFile.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/bringHarpToAfterFile.yml @@ -10,7 +10,8 @@ command: - type: primitive modifiers: - {type: position, position: after} - - {type: containingScope, scopeType: document} + - type: containingScope + scopeType: {type: document} usePrePhraseSnapshot: true initialState: documentContents: hello world diff --git a/src/test/suite/fixtures/recorded/selectionTypes/bringWhaleToBeforeFile.yml b/src/test/suite/fixtures/recorded/selectionTypes/bringWhaleToBeforeFile.yml index f787c39633..2ac23a4d52 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/bringWhaleToBeforeFile.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/bringWhaleToBeforeFile.yml @@ -10,7 +10,8 @@ command: - type: primitive modifiers: - {type: position, position: before} - - {type: containingScope, scopeType: document} + - type: containingScope + scopeType: {type: document} usePrePhraseSnapshot: true initialState: documentContents: hello world diff --git a/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockHarpBetweenFine.yml b/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockHarpBetweenFine.yml index bd5f33b247..7c4f6374f0 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockHarpBetweenFine.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockHarpBetweenFine.yml @@ -18,11 +18,11 @@ command: type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: h} modifiers: - - {type: containingScope, scopeType: paragraph} + - type: containingScope + scopeType: {type: paragraph} active: type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: f} - modifiers: [] usePrePhraseSnapshot: true initialState: documentContents: | diff --git a/src/test/suite/fixtures/recorded/selectionTypes/chuckFile2.yml b/src/test/suite/fixtures/recorded/selectionTypes/chuckFile2.yml index 91e8ff8dd4..893e2b7e68 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/chuckFile2.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/chuckFile2.yml @@ -6,7 +6,8 @@ command: targets: - type: primitive modifiers: - - {type: containingScope, scopeType: document} + - type: containingScope + scopeType: {type: document} usePrePhraseSnapshot: true initialState: documentContents: |2+ diff --git a/src/test/suite/fixtures/recorded/selectionTypes/chuckLineHarpBetweenFine.yml b/src/test/suite/fixtures/recorded/selectionTypes/chuckLineHarpBetweenFine.yml index 9a6a325710..467c0fb4e7 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/chuckLineHarpBetweenFine.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/chuckLineHarpBetweenFine.yml @@ -18,7 +18,8 @@ command: type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: h} modifiers: - - {type: containingScope, scopeType: line} + - type: containingScope + scopeType: {type: line} active: type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: f} diff --git a/src/test/suite/fixtures/recorded/selectionTypes/clearLinePair.yml b/src/test/suite/fixtures/recorded/selectionTypes/clearLinePair.yml index f09017bbd3..f2b0820e14 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/clearLinePair.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/clearLinePair.yml @@ -6,8 +6,10 @@ command: targets: - type: primitive modifiers: - - {type: containingScope, scopeType: line} - - {type: surroundingPair, delimiter: any} + - type: containingScope + scopeType: {type: line} + - type: containingScope + scopeType: {type: surroundingPair, delimiter: any} usePrePhraseSnapshot: true initialState: documentContents: foo (bar) baz diff --git a/src/test/suite/fixtures/recorded/selectionTypes/drinkToken.yml b/src/test/suite/fixtures/recorded/selectionTypes/drinkToken.yml index b7be4f31af..269d794b11 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/drinkToken.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/drinkToken.yml @@ -6,7 +6,8 @@ command: targets: - type: primitive modifiers: - - {type: containingScope, scopeType: token} + - type: containingScope + scopeType: {type: token} usePrePhraseSnapshot: true initialState: documentContents: foo diff --git a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock.yml b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock.yml index 9c48ee581c..c909fde190 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock.yml @@ -6,7 +6,8 @@ command: targets: - type: primitive modifiers: - - {type: everyScope, scopeType: paragraph} + - type: everyScope + scopeType: {type: paragraph} usePrePhraseSnapshot: true initialState: documentContents: | diff --git a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock2.yml b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock2.yml index e21a53a2fa..beba4f46e9 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock2.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock2.yml @@ -6,7 +6,8 @@ command: targets: - type: primitive modifiers: - - {type: everyScope, scopeType: paragraph} + - type: everyScope + scopeType: {type: paragraph} usePrePhraseSnapshot: true initialState: documentContents: | diff --git a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock3.yml b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock3.yml index 33a04a6e1a..2f1baaa1ed 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock3.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock3.yml @@ -6,7 +6,8 @@ command: targets: - type: primitive modifiers: - - {type: everyScope, scopeType: paragraph} + - type: everyScope + scopeType: {type: paragraph} usePrePhraseSnapshot: true initialState: documentContents: | diff --git a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryFile.yml b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryFile.yml index cc07b7e48f..4747e078aa 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryFile.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryFile.yml @@ -6,7 +6,8 @@ command: targets: - type: primitive modifiers: - - {type: everyScope, scopeType: document} + - type: everyScope + scopeType: {type: document} usePrePhraseSnapshot: true initialState: documentContents: | diff --git a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine.yml b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine.yml index 62dd0da4e2..cbef2964cc 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine.yml @@ -6,7 +6,8 @@ command: targets: - type: primitive modifiers: - - {type: everyScope, scopeType: line} + - type: everyScope + scopeType: {type: line} usePrePhraseSnapshot: true initialState: documentContents: | diff --git a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine2.yml b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine2.yml index 550b864e66..fcd020adf4 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine2.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine2.yml @@ -6,7 +6,8 @@ command: targets: - type: primitive modifiers: - - {type: everyScope, scopeType: line} + - type: everyScope + scopeType: {type: line} usePrePhraseSnapshot: true initialState: documentContents: | diff --git a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine3.yml b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine3.yml index b1aa78f006..a473f3c06b 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine3.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine3.yml @@ -6,7 +6,8 @@ command: targets: - type: primitive modifiers: - - {type: everyScope, scopeType: line} + - type: everyScope + scopeType: {type: line} usePrePhraseSnapshot: true initialState: documentContents: | diff --git a/src/test/suite/fixtures/recorded/selectionTypes/takeFile.yml b/src/test/suite/fixtures/recorded/selectionTypes/takeFile.yml index 21d1ec682e..461233a6d0 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/takeFile.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/takeFile.yml @@ -6,7 +6,8 @@ command: targets: - type: primitive modifiers: - - {type: containingScope, scopeType: document} + - type: containingScope + scopeType: {type: document} usePrePhraseSnapshot: true initialState: documentContents: |2+ From bc6ccc1e489a03c56e11cf4ab43cffd6dacb7423 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 25 May 2022 14:05:57 +0200 Subject: [PATCH 188/314] Fix upgrade path with ordinal range --- src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts index 24dcb834ed..593aec61ef 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts @@ -72,7 +72,7 @@ function upgradeModifier(modifier: ModifierV0V1): Modifier[] { return [ { - type: "containingScope", + type: "ordinalRange", scopeType: { type: pieceType }, ...rest, }, From 608ea3db8249a9ea0a0fc010cf960862e3aebf21 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 25 May 2022 14:20:22 +0200 Subject: [PATCH 189/314] Pass leading and trailing delimiters to super constructor --- src/processTargets/targets/LineTarget.ts | 2 ++ src/processTargets/targets/ParagraphTarget.ts | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/processTargets/targets/LineTarget.ts b/src/processTargets/targets/LineTarget.ts index 4ae4738ff1..f628ba9a11 100644 --- a/src/processTargets/targets/LineTarget.ts +++ b/src/processTargets/targets/LineTarget.ts @@ -16,6 +16,8 @@ export default class LineTarget extends BaseTarget { constructor(parameters: LineTargetParameters) { super({ ...extractCommonParameters(parameters), + leadingDelimiter: parameters.leadingDelimiter, + trailingDelimiter: parameters.trailingDelimiter, delimiter: "\n", }); } diff --git a/src/processTargets/targets/ParagraphTarget.ts b/src/processTargets/targets/ParagraphTarget.ts index 7604241718..28eba327aa 100644 --- a/src/processTargets/targets/ParagraphTarget.ts +++ b/src/processTargets/targets/ParagraphTarget.ts @@ -16,6 +16,8 @@ export default class ParagraphTarget extends BaseTarget { constructor(parameters: ParagraphTargetParameters) { super({ ...extractCommonParameters(parameters), + leadingDelimiter: parameters.leadingDelimiter, + trailingDelimiter: parameters.trailingDelimiter, delimiter: "\n\n", }); } From cde81f5e455bb5f069be49dbb41316863fe693f2 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 25 May 2022 14:31:59 +0200 Subject: [PATCH 190/314] Learn to spell --- .../suite/fixtures/recorded/positions/bringHarpToAfterFile.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/suite/fixtures/recorded/positions/bringHarpToAfterFile.yml b/src/test/suite/fixtures/recorded/positions/bringHarpToAfterFile.yml index 379564a09c..71d9781961 100644 --- a/src/test/suite/fixtures/recorded/positions/bringHarpToAfterFile.yml +++ b/src/test/suite/fixtures/recorded/positions/bringHarpToAfterFile.yml @@ -2,7 +2,7 @@ languageId: plaintext command: spokenForm: bring harp to after file version: 2 - action: {name: replaceWitrhTarget} + action: {name: replaceWithTarget} targets: - type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: h} From aeeb3ab51704568e9bf5633e9f4774d6f0c63964 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 25 May 2022 14:58:21 +0200 Subject: [PATCH 191/314] Updated more tests --- cursorless-talon/src/compound_targets.py | 4 ++-- src/core/inferFullTargets.ts | 4 ++-- src/processTargets/targets/WeakTarget.ts | 11 ++++++++++- .../recorded/positions/chuckAfterBlockVest.yml | 2 +- .../fixtures/recorded/positions/chuckAfterHarp.yml | 2 +- .../recorded/positions/chuckAfterLineVest.yml | 2 +- .../fixtures/recorded/positions/chuckAfterLook.yml | 2 +- .../fixtures/recorded/positions/chuckAfterVest.yml | 2 +- .../suite/fixtures/recorded/positions/chuckAir.yml | 2 +- .../fixtures/recorded/positions/chuckBeforeAir.yml | 2 +- .../recorded/positions/chuckBeforeBlockAir.yml | 2 +- .../fixtures/recorded/positions/chuckBeforeEach.yml | 2 +- .../fixtures/recorded/positions/chuckBeforeHarp.yml | 2 +- .../recorded/positions/chuckBeforeLineAir.yml | 2 +- .../fixtures/recorded/positions/chuckBeforeVest.yml | 2 +- .../recorded/positions/chuckPastAfterLook.yml | 2 +- .../recorded/positions/chuckPastBeforeTrap.yml | 2 +- .../recorded/positions/chuckPastEndOfLine.yml | 2 +- .../recorded/positions/chuckPastEndOfLook.yml | 2 +- .../recorded/positions/chuckPastStartOfTrap.yml | 2 +- .../positions/replaceAfterVestWithHallo.yml | 2 +- .../positions/replaceBeforeVestWithHello.yml | 2 +- .../positions/replaceEndOfVestWithHello.yml | 2 +- .../positions/replaceStartOfVestWithHello.yml | 2 +- .../selectionTypes/chuckBlockHarpBetweenFine.yml | 13 +++---------- src/test/suite/runSingleRecordedTest.ts | 2 +- src/typings/target.types.ts | 4 ++-- 27 files changed, 41 insertions(+), 39 deletions(-) diff --git a/cursorless-talon/src/compound_targets.py b/cursorless-talon/src/compound_targets.py index ed33648c84..5257c2a1e8 100644 --- a/cursorless-talon/src/compound_targets.py +++ b/cursorless-talon/src/compound_targets.py @@ -55,8 +55,8 @@ def cursorless_range(m) -> str: "type": "range", "anchor": anchor, "active": primitive_targets[-1], - "excludeStart": not is_anchor_included(range_connective), - "excludeEnd": not is_active_included(range_connective), + "excludeAnchor": not is_anchor_included(range_connective), + "excludeActive": not is_active_included(range_connective), } if range_type: diff --git a/src/core/inferFullTargets.ts b/src/core/inferFullTargets.ts index cf7b8933ef..27f45f885a 100644 --- a/src/core/inferFullTargets.ts +++ b/src/core/inferFullTargets.ts @@ -71,8 +71,8 @@ function inferRangeTarget( ): RangeTargetDescriptor { return { type: "range", - excludeAnchor: target.excludeStart ?? false, - excludeActive: target.excludeEnd ?? false, + excludeAnchor: target.excludeAnchor ?? false, + excludeActive: target.excludeActive ?? false, rangeType: target.rangeType ?? "continuous", anchor: inferPrimitiveTarget(target.anchor, previousTargets), active: inferPrimitiveTarget( diff --git a/src/processTargets/targets/WeakTarget.ts b/src/processTargets/targets/WeakTarget.ts index ca8e654d26..33b26b3e8e 100644 --- a/src/processTargets/targets/WeakTarget.ts +++ b/src/processTargets/targets/WeakTarget.ts @@ -1,3 +1,4 @@ +import { RemovalRange } from "../../typings/target.types"; import { getTokenDelimiters } from "../modifiers/scopeTypeStages/TokenStage"; import BaseTarget, { CloneWithParameters, @@ -5,16 +6,24 @@ import BaseTarget, { extractCommonParameters, } from "./BaseTarget"; +interface WeakTargetParameters extends CommonTargetParameters { + // These are needed if constructed from a continuous range + leadingDelimiter?: RemovalRange; + trailingDelimiter?: RemovalRange; +} + /** * - Treated as "line" for "pour", "clone", and "breakpoint" * - Use token delimiters (space) for removal and insertion * - Expand to nearest containing pair when asked for boundary or interior */ export default class WeakTarget extends BaseTarget { - constructor(parameters: CommonTargetParameters) { + constructor(parameters: WeakTargetParameters) { super({ ...extractCommonParameters(parameters), ...getTokenDelimiters(parameters.editor, parameters.contentRange), + leadingDelimiter: parameters.leadingDelimiter, + trailingDelimiter: parameters.trailingDelimiter, }); } diff --git a/src/test/suite/fixtures/recorded/positions/chuckAfterBlockVest.yml b/src/test/suite/fixtures/recorded/positions/chuckAfterBlockVest.yml index cfdd988bfe..b1db52badc 100644 --- a/src/test/suite/fixtures/recorded/positions/chuckAfterBlockVest.yml +++ b/src/test/suite/fixtures/recorded/positions/chuckAfterBlockVest.yml @@ -1,4 +1,4 @@ -languageId: typescript +languageId: plaintext command: version: 1 spokenForm: chuck after block vest diff --git a/src/test/suite/fixtures/recorded/positions/chuckAfterHarp.yml b/src/test/suite/fixtures/recorded/positions/chuckAfterHarp.yml index 56e681336d..812eaa1eba 100644 --- a/src/test/suite/fixtures/recorded/positions/chuckAfterHarp.yml +++ b/src/test/suite/fixtures/recorded/positions/chuckAfterHarp.yml @@ -1,4 +1,4 @@ -languageId: typescript +languageId: plaintext command: version: 1 spokenForm: chuck after harp diff --git a/src/test/suite/fixtures/recorded/positions/chuckAfterLineVest.yml b/src/test/suite/fixtures/recorded/positions/chuckAfterLineVest.yml index 782e48556d..fab54835e3 100644 --- a/src/test/suite/fixtures/recorded/positions/chuckAfterLineVest.yml +++ b/src/test/suite/fixtures/recorded/positions/chuckAfterLineVest.yml @@ -1,4 +1,4 @@ -languageId: typescript +languageId: plaintext command: version: 1 spokenForm: chuck after line vest diff --git a/src/test/suite/fixtures/recorded/positions/chuckAfterLook.yml b/src/test/suite/fixtures/recorded/positions/chuckAfterLook.yml index ca89626b92..9501d5de3d 100644 --- a/src/test/suite/fixtures/recorded/positions/chuckAfterLook.yml +++ b/src/test/suite/fixtures/recorded/positions/chuckAfterLook.yml @@ -1,4 +1,4 @@ -languageId: typescript +languageId: plaintext command: version: 1 spokenForm: chuck after look diff --git a/src/test/suite/fixtures/recorded/positions/chuckAfterVest.yml b/src/test/suite/fixtures/recorded/positions/chuckAfterVest.yml index d199f88cce..c2895ad645 100644 --- a/src/test/suite/fixtures/recorded/positions/chuckAfterVest.yml +++ b/src/test/suite/fixtures/recorded/positions/chuckAfterVest.yml @@ -1,4 +1,4 @@ -languageId: typescript +languageId: plaintext command: version: 1 spokenForm: chuck after vest diff --git a/src/test/suite/fixtures/recorded/positions/chuckAir.yml b/src/test/suite/fixtures/recorded/positions/chuckAir.yml index 4f4c35bc45..65d5d42c05 100644 --- a/src/test/suite/fixtures/recorded/positions/chuckAir.yml +++ b/src/test/suite/fixtures/recorded/positions/chuckAir.yml @@ -1,4 +1,4 @@ -languageId: typescript +languageId: plaintext command: version: 1 spokenForm: chuck air diff --git a/src/test/suite/fixtures/recorded/positions/chuckBeforeAir.yml b/src/test/suite/fixtures/recorded/positions/chuckBeforeAir.yml index 21effed70c..5695ca9c21 100644 --- a/src/test/suite/fixtures/recorded/positions/chuckBeforeAir.yml +++ b/src/test/suite/fixtures/recorded/positions/chuckBeforeAir.yml @@ -1,4 +1,4 @@ -languageId: typescript +languageId: plaintext command: version: 1 spokenForm: chuck before air diff --git a/src/test/suite/fixtures/recorded/positions/chuckBeforeBlockAir.yml b/src/test/suite/fixtures/recorded/positions/chuckBeforeBlockAir.yml index 879a322a89..19d5e41ddd 100644 --- a/src/test/suite/fixtures/recorded/positions/chuckBeforeBlockAir.yml +++ b/src/test/suite/fixtures/recorded/positions/chuckBeforeBlockAir.yml @@ -1,4 +1,4 @@ -languageId: typescript +languageId: plaintext command: version: 1 spokenForm: chuck before block air diff --git a/src/test/suite/fixtures/recorded/positions/chuckBeforeEach.yml b/src/test/suite/fixtures/recorded/positions/chuckBeforeEach.yml index 77483adff0..cbd88701e4 100644 --- a/src/test/suite/fixtures/recorded/positions/chuckBeforeEach.yml +++ b/src/test/suite/fixtures/recorded/positions/chuckBeforeEach.yml @@ -1,4 +1,4 @@ -languageId: typescript +languageId: plaintext command: version: 1 spokenForm: chuck before each diff --git a/src/test/suite/fixtures/recorded/positions/chuckBeforeHarp.yml b/src/test/suite/fixtures/recorded/positions/chuckBeforeHarp.yml index 3b8427314e..169592d160 100644 --- a/src/test/suite/fixtures/recorded/positions/chuckBeforeHarp.yml +++ b/src/test/suite/fixtures/recorded/positions/chuckBeforeHarp.yml @@ -1,4 +1,4 @@ -languageId: typescript +languageId: plaintext command: version: 1 spokenForm: chuck before harp diff --git a/src/test/suite/fixtures/recorded/positions/chuckBeforeLineAir.yml b/src/test/suite/fixtures/recorded/positions/chuckBeforeLineAir.yml index 28d96d84d3..e9281db485 100644 --- a/src/test/suite/fixtures/recorded/positions/chuckBeforeLineAir.yml +++ b/src/test/suite/fixtures/recorded/positions/chuckBeforeLineAir.yml @@ -1,4 +1,4 @@ -languageId: typescript +languageId: plaintext command: version: 1 spokenForm: chuck before line air diff --git a/src/test/suite/fixtures/recorded/positions/chuckBeforeVest.yml b/src/test/suite/fixtures/recorded/positions/chuckBeforeVest.yml index 66a1def52e..744847de38 100644 --- a/src/test/suite/fixtures/recorded/positions/chuckBeforeVest.yml +++ b/src/test/suite/fixtures/recorded/positions/chuckBeforeVest.yml @@ -1,4 +1,4 @@ -languageId: typescript +languageId: plaintext command: version: 1 spokenForm: chuck before vest diff --git a/src/test/suite/fixtures/recorded/positions/chuckPastAfterLook.yml b/src/test/suite/fixtures/recorded/positions/chuckPastAfterLook.yml index 005c07a9f3..f6757b62ac 100644 --- a/src/test/suite/fixtures/recorded/positions/chuckPastAfterLook.yml +++ b/src/test/suite/fixtures/recorded/positions/chuckPastAfterLook.yml @@ -1,4 +1,4 @@ -languageId: typescript +languageId: plaintext command: version: 1 spokenForm: chuck past after look diff --git a/src/test/suite/fixtures/recorded/positions/chuckPastBeforeTrap.yml b/src/test/suite/fixtures/recorded/positions/chuckPastBeforeTrap.yml index e9940b52ad..eaf03d5562 100644 --- a/src/test/suite/fixtures/recorded/positions/chuckPastBeforeTrap.yml +++ b/src/test/suite/fixtures/recorded/positions/chuckPastBeforeTrap.yml @@ -1,4 +1,4 @@ -languageId: typescript +languageId: plaintext command: version: 1 spokenForm: chuck past before trap diff --git a/src/test/suite/fixtures/recorded/positions/chuckPastEndOfLine.yml b/src/test/suite/fixtures/recorded/positions/chuckPastEndOfLine.yml index 2aa194fa69..23f9986b7b 100644 --- a/src/test/suite/fixtures/recorded/positions/chuckPastEndOfLine.yml +++ b/src/test/suite/fixtures/recorded/positions/chuckPastEndOfLine.yml @@ -1,4 +1,4 @@ -languageId: typescript +languageId: plaintext command: version: 1 spokenForm: chuck past end of line diff --git a/src/test/suite/fixtures/recorded/positions/chuckPastEndOfLook.yml b/src/test/suite/fixtures/recorded/positions/chuckPastEndOfLook.yml index 7effdfdc01..78c3a15c6f 100644 --- a/src/test/suite/fixtures/recorded/positions/chuckPastEndOfLook.yml +++ b/src/test/suite/fixtures/recorded/positions/chuckPastEndOfLook.yml @@ -1,4 +1,4 @@ -languageId: typescript +languageId: plaintext command: version: 1 spokenForm: chuck past end of look diff --git a/src/test/suite/fixtures/recorded/positions/chuckPastStartOfTrap.yml b/src/test/suite/fixtures/recorded/positions/chuckPastStartOfTrap.yml index 1bf8a8c856..cd5bb2dd3a 100644 --- a/src/test/suite/fixtures/recorded/positions/chuckPastStartOfTrap.yml +++ b/src/test/suite/fixtures/recorded/positions/chuckPastStartOfTrap.yml @@ -1,4 +1,4 @@ -languageId: typescript +languageId: plaintext command: version: 1 spokenForm: chuck past start of trap diff --git a/src/test/suite/fixtures/recorded/positions/replaceAfterVestWithHallo.yml b/src/test/suite/fixtures/recorded/positions/replaceAfterVestWithHallo.yml index ea845c269f..e88678cefe 100644 --- a/src/test/suite/fixtures/recorded/positions/replaceAfterVestWithHallo.yml +++ b/src/test/suite/fixtures/recorded/positions/replaceAfterVestWithHallo.yml @@ -1,4 +1,4 @@ -languageId: typescript +languageId: plaintext command: version: 1 spokenForm: replace after vest with hallo diff --git a/src/test/suite/fixtures/recorded/positions/replaceBeforeVestWithHello.yml b/src/test/suite/fixtures/recorded/positions/replaceBeforeVestWithHello.yml index c461c1a82e..f73f55b0f2 100644 --- a/src/test/suite/fixtures/recorded/positions/replaceBeforeVestWithHello.yml +++ b/src/test/suite/fixtures/recorded/positions/replaceBeforeVestWithHello.yml @@ -1,4 +1,4 @@ -languageId: typescript +languageId: plaintext command: version: 1 spokenForm: replace before vest with hello diff --git a/src/test/suite/fixtures/recorded/positions/replaceEndOfVestWithHello.yml b/src/test/suite/fixtures/recorded/positions/replaceEndOfVestWithHello.yml index 695a21abc6..85d0ab5572 100644 --- a/src/test/suite/fixtures/recorded/positions/replaceEndOfVestWithHello.yml +++ b/src/test/suite/fixtures/recorded/positions/replaceEndOfVestWithHello.yml @@ -1,4 +1,4 @@ -languageId: typescript +languageId: plaintext command: version: 1 spokenForm: replace end of vest with hello diff --git a/src/test/suite/fixtures/recorded/positions/replaceStartOfVestWithHello.yml b/src/test/suite/fixtures/recorded/positions/replaceStartOfVestWithHello.yml index 8ff693acd0..87db443c78 100644 --- a/src/test/suite/fixtures/recorded/positions/replaceStartOfVestWithHello.yml +++ b/src/test/suite/fixtures/recorded/positions/replaceStartOfVestWithHello.yml @@ -1,4 +1,4 @@ -languageId: typescript +languageId: plaintext command: version: 1 spokenForm: replace start of vest with hello diff --git a/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockHarpBetweenFine.yml b/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockHarpBetweenFine.yml index 7c4f6374f0..b2047db96b 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockHarpBetweenFine.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockHarpBetweenFine.yml @@ -5,21 +5,14 @@ command: action: {name: remove} targets: - type: range - start: - type: primitive - selectionType: paragraph - mark: {type: decoratedSymbol, symbolColor: default, character: h} - end: - type: primitive - mark: {type: decoratedSymbol, symbolColor: default, character: f} - excludeStart: true - excludeEnd: true + excludeAnchor: true + excludeActive: true anchor: type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: h} modifiers: - type: containingScope - scopeType: {type: paragraph} + scopeType: {type: paragraph} active: type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: f} diff --git a/src/test/suite/runSingleRecordedTest.ts b/src/test/suite/runSingleRecordedTest.ts index f9ea62d9df..f159acda86 100644 --- a/src/test/suite/runSingleRecordedTest.ts +++ b/src/test/suite/runSingleRecordedTest.ts @@ -5,7 +5,7 @@ // example: // const filenameEnd = "textual/takePairRound.yml"; -const filenameEnd = ""; +const filenameEnd = "chuckBlockHarpBetweenFine.yml"; export function runSingleTest() { return !!filenameEnd; diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 9ab32559a0..c99cdcb65a 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -202,8 +202,8 @@ export interface PartialRangeTargetDesc { type: "range"; anchor: PartialPrimitiveTargetDesc; active: PartialPrimitiveTargetDesc; - excludeStart?: boolean; - excludeEnd?: boolean; + excludeAnchor?: boolean; + excludeActive?: boolean; rangeType?: RangeType; } From 04b1fddae462fa9f16be812230df2246dfa9640b Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 25 May 2022 15:09:04 +0200 Subject: [PATCH 192/314] Cleanup --- src/test/suite/runSingleRecordedTest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/suite/runSingleRecordedTest.ts b/src/test/suite/runSingleRecordedTest.ts index f159acda86..f9ea62d9df 100644 --- a/src/test/suite/runSingleRecordedTest.ts +++ b/src/test/suite/runSingleRecordedTest.ts @@ -5,7 +5,7 @@ // example: // const filenameEnd = "textual/takePairRound.yml"; -const filenameEnd = "chuckBlockHarpBetweenFine.yml"; +const filenameEnd = ""; export function runSingleTest() { return !!filenameEnd; From 0125212b647ef970c9637b6239896bf75d5c454b Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 25 May 2022 15:54:23 +0200 Subject: [PATCH 193/314] Fixed bug taking matching pair in error code --- .../findSurroundingPairParseTreeBased.ts | 9 +++-- .../recorded/selectionTypes/drinkEveryArg.yml | 40 +++++++++++++++++++ .../recorded/selectionTypes/pourEveryArg.yml | 40 +++++++++++++++++++ .../surroundingPair/parseTree/takeCore.yml | 37 +++++++++++++++++ 4 files changed, 122 insertions(+), 4 deletions(-) create mode 100644 src/test/suite/fixtures/recorded/selectionTypes/drinkEveryArg.yml create mode 100644 src/test/suite/fixtures/recorded/selectionTypes/pourEveryArg.yml create mode 100644 src/test/suite/fixtures/recorded/surroundingPair/parseTree/takeCore.yml diff --git a/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts b/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts index a3626d9992..ce1e24dee4 100644 --- a/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts +++ b/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts @@ -175,11 +175,12 @@ function findSurroundingPairContainedInNode( /** * A list of all delimiter nodes descending from `node`, as determined by - * their type + * their type. + * Handles the case of error nodes with no text. https://github.com/cursorless-dev/cursorless/issues/688 */ - const possibleDelimiterNodes = node.descendantsOfType( - individualDelimiters.map(({ text }) => text) - ); + const possibleDelimiterNodes = node + .descendantsOfType(individualDelimiters.map(({ text }) => text)) + .filter((node) => !(node.text === "" && node.hasError())); /** * A list of all delimiter occurrences, generated from the delimiter nodes. diff --git a/src/test/suite/fixtures/recorded/selectionTypes/drinkEveryArg.yml b/src/test/suite/fixtures/recorded/selectionTypes/drinkEveryArg.yml new file mode 100644 index 0000000000..fa6878b933 --- /dev/null +++ b/src/test/suite/fixtures/recorded/selectionTypes/drinkEveryArg.yml @@ -0,0 +1,40 @@ +languageId: typescript +command: + spokenForm: drink every arg + version: 2 + targets: + - type: primitive + modifiers: + - type: everyScope + scopeType: {type: argumentOrParameter} + usePrePhraseSnapshot: true + action: {name: editNewLineBefore} +initialState: + documentContents: |- + function whatever(a: number, b: number, c: number) { + + } + selections: + - anchor: {line: 0, character: 29} + active: {line: 0, character: 29} + marks: {} +finalState: + documentContents: |- + function whatever(, a: number, , b: number, , c: number) { + + } + selections: + - anchor: {line: 0, character: 18} + active: {line: 0, character: 18} + - anchor: {line: 0, character: 31} + active: {line: 0, character: 31} + - anchor: {line: 0, character: 44} + active: {line: 0, character: 44} + thatMark: + - anchor: {line: 0, character: 20} + active: {line: 0, character: 29} + - anchor: {line: 0, character: 33} + active: {line: 0, character: 42} + - anchor: {line: 0, character: 46} + active: {line: 0, character: 55} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: everyScope, scopeType: {type: argumentOrParameter}}]}] diff --git a/src/test/suite/fixtures/recorded/selectionTypes/pourEveryArg.yml b/src/test/suite/fixtures/recorded/selectionTypes/pourEveryArg.yml new file mode 100644 index 0000000000..a538ba34da --- /dev/null +++ b/src/test/suite/fixtures/recorded/selectionTypes/pourEveryArg.yml @@ -0,0 +1,40 @@ +languageId: typescript +command: + spokenForm: pour every arg + version: 2 + targets: + - type: primitive + modifiers: + - type: everyScope + scopeType: {type: argumentOrParameter} + usePrePhraseSnapshot: true + action: {name: editNewLineAfter} +initialState: + documentContents: |- + function whatever(a: number, b: number, c: number) { + + } + selections: + - anchor: {line: 0, character: 29} + active: {line: 0, character: 29} + marks: {} +finalState: + documentContents: |- + function whatever(a: number, , b: number, , c: number, ) { + + } + selections: + - anchor: {line: 0, character: 29} + active: {line: 0, character: 29} + - anchor: {line: 0, character: 42} + active: {line: 0, character: 42} + - anchor: {line: 0, character: 55} + active: {line: 0, character: 55} + thatMark: + - anchor: {line: 0, character: 18} + active: {line: 0, character: 27} + - anchor: {line: 0, character: 31} + active: {line: 0, character: 40} + - anchor: {line: 0, character: 44} + active: {line: 0, character: 53} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: everyScope, scopeType: {type: argumentOrParameter}}]}] diff --git a/src/test/suite/fixtures/recorded/surroundingPair/parseTree/takeCore.yml b/src/test/suite/fixtures/recorded/surroundingPair/parseTree/takeCore.yml new file mode 100644 index 0000000000..45e2518c9c --- /dev/null +++ b/src/test/suite/fixtures/recorded/surroundingPair/parseTree/takeCore.yml @@ -0,0 +1,37 @@ +languageId: typescript +command: + spokenForm: take core + version: 2 + targets: + - type: primitive + modifiers: + - type: containingScope + scopeType: {type: surroundingPair, delimiter: any} + - {type: interiorOnly} + usePrePhraseSnapshot: true + action: {name: setSelection} +initialState: + documentContents: | + async (editor, targets) => { + const edits = targets.map((target, i) =>( + text: i%2 === 0?left:right + ) + } + selections: + - anchor: {line: 2, character: 8} + active: {line: 2, character: 8} + marks: {} +finalState: + documentContents: | + async (editor, targets) => { + const edits = targets.map((target, i) =>( + text: i%2 === 0?left:right + ) + } + selections: + - anchor: {line: 1, character: 45} + active: {line: 3, character: 4} + thatMark: + - anchor: {line: 1, character: 45} + active: {line: 3, character: 4} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: containingScope, scopeType: {type: surroundingPair, delimiter: any}}, {type: interiorOnly}]}] From eec2f6520558422c067a0e0b6765107fb629a78b Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 25 May 2022 16:03:28 +0200 Subject: [PATCH 194/314] Added block tests --- .../recorded/selectionTypes/drinkBlock.yml | 32 +++++++++++++++++++ .../recorded/selectionTypes/pourBlock.yml | 32 +++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 src/test/suite/fixtures/recorded/selectionTypes/drinkBlock.yml create mode 100644 src/test/suite/fixtures/recorded/selectionTypes/pourBlock.yml diff --git a/src/test/suite/fixtures/recorded/selectionTypes/drinkBlock.yml b/src/test/suite/fixtures/recorded/selectionTypes/drinkBlock.yml new file mode 100644 index 0000000000..415d6ea4f0 --- /dev/null +++ b/src/test/suite/fixtures/recorded/selectionTypes/drinkBlock.yml @@ -0,0 +1,32 @@ +languageId: plaintext +command: + spokenForm: drink block + version: 2 + targets: + - type: primitive + modifiers: + - type: containingScope + scopeType: {type: paragraph} + usePrePhraseSnapshot: true + action: {name: editNewLineBefore} +initialState: + documentContents: |2 + hello there + hello there + selections: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 9} + marks: {} +finalState: + documentContents: |2 + + + hello there + hello there + selections: + - anchor: {line: 0, character: 4} + active: {line: 0, character: 4} + thatMark: + - anchor: {line: 2, character: 4} + active: {line: 3, character: 15} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: containingScope, scopeType: {type: paragraph}}]}] diff --git a/src/test/suite/fixtures/recorded/selectionTypes/pourBlock.yml b/src/test/suite/fixtures/recorded/selectionTypes/pourBlock.yml new file mode 100644 index 0000000000..99cf49af82 --- /dev/null +++ b/src/test/suite/fixtures/recorded/selectionTypes/pourBlock.yml @@ -0,0 +1,32 @@ +languageId: plaintext +command: + spokenForm: pour block + version: 2 + targets: + - type: primitive + modifiers: + - type: containingScope + scopeType: {type: paragraph} + usePrePhraseSnapshot: true + action: {name: editNewLineAfter} +initialState: + documentContents: |2 + hello there + hello there + selections: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 9} + marks: {} +finalState: + documentContents: |2 + hello there + hello there + + + selections: + - anchor: {line: 3, character: 4} + active: {line: 3, character: 4} + thatMark: + - anchor: {line: 0, character: 4} + active: {line: 1, character: 15} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: containingScope, scopeType: {type: paragraph}}]}] From d92f07a3d42002763c518b115490d1f94a773aba Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 25 May 2022 16:28:54 +0200 Subject: [PATCH 195/314] Fixed test --- .../upgradeV1ToV2/upgradeV1ToV2.ts | 2 + src/processTargets/processTargets.ts | 5 +- .../chuckBlockEachBetweenHarp.yml | 61 +++++++++++++++++++ .../chuckBlockEachUntilHarp.yml | 59 ++++++++++++++++++ .../chuckLineEachBetweenHarp.yml | 61 +++++++++++++++++++ .../chuckLineEachBetweenHarp2.yml | 60 ++++++++++++++++++ .../chuckLineEachUntilHarp.yml | 60 ++++++++++++++++++ src/typings/target.types.ts | 4 +- 8 files changed, 309 insertions(+), 3 deletions(-) create mode 100644 src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachBetweenHarp.yml create mode 100644 src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachUntilHarp.yml create mode 100644 src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachBetweenHarp.yml create mode 100644 src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachBetweenHarp2.yml create mode 100644 src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachUntilHarp.yml diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts index 593aec61ef..966de92f0c 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts @@ -161,6 +161,8 @@ function upgradeTarget(target: PartialTargetV0V1): PartialTargetDesc { ...target, anchor: upgradePrimitiveTarget(target.start), active: upgradePrimitiveTarget(target.end), + excludeAnchor: target.excludeStart ?? false, + excludeActive: target.excludeEnd ?? false, }; case "primitive": return upgradePrimitiveTarget(target); diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index b424fdd2fe..1bf8d126cc 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -152,7 +152,10 @@ function processContinuousRangeTarget( if (excludeEnd) { if (endTarget.isLine) { return { - range: new Range(contentRange.end, endTarget.contentRange.start), + range: new Range( + contentRange.end, + endTarget.leadingDelimiter!.range.end + ), highlight: new Range( contentRange.end, endTarget.contentRange.start.translate({ lineDelta: -1 }) diff --git a/src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachBetweenHarp.yml b/src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachBetweenHarp.yml new file mode 100644 index 0000000000..e5964a154e --- /dev/null +++ b/src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachBetweenHarp.yml @@ -0,0 +1,61 @@ +languageId: typescript +command: + spokenForm: chuck block each between harp + version: 2 + targets: + - type: range + start: + type: primitive + selectionType: paragraph + mark: {type: decoratedSymbol, symbolColor: default, character: e} + end: + type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: h} + excludeStart: true + excludeEnd: true + anchor: + type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: e} + modifiers: + - type: containingScope + scopeType: {type: paragraph} + active: + type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: h} + excludeAnchor: true + excludeActive: true + usePrePhraseSnapshot: true + action: {name: remove} +initialState: + documentContents: |- + hello there + hello there + + + hello there + hello there + hello + selections: + - anchor: {line: 5, character: 13} + active: {line: 5, character: 13} + marks: + default.e: + start: {line: 1, character: 6} + end: {line: 1, character: 11} + default.h: + start: {line: 3, character: 4} + end: {line: 3, character: 9} +finalState: + documentContents: |- + hello there + hello there + hello there + hello there + hello + selections: + - anchor: {line: 4, character: 13} + active: {line: 4, character: 13} + thatMark: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} +fullTargets: [{type: range, excludeAnchor: true, excludeActive: true, rangeType: continuous, anchor: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: e}, modifiers: &ref_0 [{type: containingScope, scopeType: {type: paragraph}}]}, active: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: h}, modifiers: *ref_0}}] diff --git a/src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachUntilHarp.yml b/src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachUntilHarp.yml new file mode 100644 index 0000000000..6557891323 --- /dev/null +++ b/src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachUntilHarp.yml @@ -0,0 +1,59 @@ +languageId: typescript +command: + spokenForm: chuck block each until harp + version: 2 + targets: + - type: range + start: + type: primitive + selectionType: paragraph + mark: {type: decoratedSymbol, symbolColor: default, character: e} + end: + type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: h} + excludeStart: false + excludeEnd: true + anchor: + type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: e} + modifiers: + - type: containingScope + scopeType: {type: paragraph} + active: + type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: h} + excludeAnchor: false + excludeActive: true + usePrePhraseSnapshot: true + action: {name: remove} +initialState: + documentContents: |- + hello there + hello there + + + hello there + hello there + hello + selections: + - anchor: {line: 5, character: 13} + active: {line: 5, character: 13} + marks: + default.e: + start: {line: 1, character: 6} + end: {line: 1, character: 11} + default.h: + start: {line: 3, character: 4} + end: {line: 3, character: 9} +finalState: + documentContents: |2- + hello there + hello there + hello + selections: + - anchor: {line: 2, character: 13} + active: {line: 2, character: 13} + thatMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} +fullTargets: [{type: range, excludeAnchor: false, excludeActive: true, rangeType: continuous, anchor: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: e}, modifiers: &ref_0 [{type: containingScope, scopeType: {type: paragraph}}]}, active: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: h}, modifiers: *ref_0}}] diff --git a/src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachBetweenHarp.yml b/src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachBetweenHarp.yml new file mode 100644 index 0000000000..b1c8c6590c --- /dev/null +++ b/src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachBetweenHarp.yml @@ -0,0 +1,61 @@ +languageId: typescript +command: + spokenForm: chuck line each between harp + version: 2 + targets: + - type: range + start: + type: primitive + selectionType: line + mark: {type: decoratedSymbol, symbolColor: default, character: e} + end: + type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: h} + excludeStart: true + excludeEnd: true + anchor: + type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: e} + modifiers: + - type: containingScope + scopeType: {type: line} + active: + type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: h} + excludeAnchor: true + excludeActive: true + usePrePhraseSnapshot: true + action: {name: remove} +initialState: + documentContents: |- + hello there + hello there + + + hello there + hello there + hello + selections: + - anchor: {line: 5, character: 13} + active: {line: 5, character: 13} + marks: + default.e: + start: {line: 1, character: 6} + end: {line: 1, character: 11} + default.h: + start: {line: 3, character: 4} + end: {line: 3, character: 9} +finalState: + documentContents: |- + hello there + hello there + hello there + hello there + hello + selections: + - anchor: {line: 4, character: 13} + active: {line: 4, character: 13} + thatMark: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} +fullTargets: [{type: range, excludeAnchor: true, excludeActive: true, rangeType: continuous, anchor: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: e}, modifiers: &ref_0 [{type: containingScope, scopeType: {type: line}}]}, active: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: h}, modifiers: *ref_0}}] diff --git a/src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachBetweenHarp2.yml b/src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachBetweenHarp2.yml new file mode 100644 index 0000000000..76a62f89f8 --- /dev/null +++ b/src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachBetweenHarp2.yml @@ -0,0 +1,60 @@ +languageId: typescript +command: + spokenForm: chuck line each between harp + version: 2 + targets: + - type: range + start: + type: primitive + selectionType: line + mark: {type: decoratedSymbol, symbolColor: default, character: e} + end: + type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: h} + excludeStart: true + excludeEnd: true + anchor: + type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: e} + modifiers: + - type: containingScope + scopeType: {type: line} + active: + type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: h} + excludeAnchor: true + excludeActive: true + usePrePhraseSnapshot: true + action: {name: remove} +initialState: + documentContents: |- + hello there + hello there + + hello there + hello there + hello + selections: + - anchor: {line: 5, character: 13} + active: {line: 5, character: 13} + marks: + default.e: + start: {line: 1, character: 6} + end: {line: 1, character: 11} + default.h: + start: {line: 3, character: 4} + end: {line: 3, character: 9} +finalState: + documentContents: |- + hello there + hello there + hello there + hello there + hello + selections: + - anchor: {line: 4, character: 13} + active: {line: 4, character: 13} + thatMark: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} +fullTargets: [{type: range, excludeAnchor: true, excludeActive: true, rangeType: continuous, anchor: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: e}, modifiers: &ref_0 [{type: containingScope, scopeType: {type: line}}]}, active: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: h}, modifiers: *ref_0}}] diff --git a/src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachUntilHarp.yml b/src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachUntilHarp.yml new file mode 100644 index 0000000000..12bb2bfc33 --- /dev/null +++ b/src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachUntilHarp.yml @@ -0,0 +1,60 @@ +languageId: typescript +command: + spokenForm: chuck line each until harp + version: 2 + targets: + - type: range + start: + type: primitive + selectionType: line + mark: {type: decoratedSymbol, symbolColor: default, character: e} + end: + type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: h} + excludeStart: false + excludeEnd: true + anchor: + type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: e} + modifiers: + - type: containingScope + scopeType: {type: line} + active: + type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: h} + excludeAnchor: false + excludeActive: true + usePrePhraseSnapshot: true + action: {name: remove} +initialState: + documentContents: |- + hello there + hello there + + + hello there + hello there + hello + selections: + - anchor: {line: 5, character: 13} + active: {line: 5, character: 13} + marks: + default.e: + start: {line: 1, character: 6} + end: {line: 1, character: 11} + default.h: + start: {line: 3, character: 4} + end: {line: 3, character: 9} +finalState: + documentContents: |- + hello there + hello there + hello there + hello + selections: + - anchor: {line: 3, character: 13} + active: {line: 3, character: 13} + thatMark: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} +fullTargets: [{type: range, excludeAnchor: false, excludeActive: true, rangeType: continuous, anchor: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: e}, modifiers: &ref_0 [{type: containingScope, scopeType: {type: line}}]}, active: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: h}, modifiers: *ref_0}}] diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index c99cdcb65a..e858d4a79f 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -202,8 +202,8 @@ export interface PartialRangeTargetDesc { type: "range"; anchor: PartialPrimitiveTargetDesc; active: PartialPrimitiveTargetDesc; - excludeAnchor?: boolean; - excludeActive?: boolean; + excludeAnchor: boolean; + excludeActive: boolean; rangeType?: RangeType; } From 7fbb1554eb27c1fc97a0ed76e9fef2c5585fe713 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 25 May 2022 20:23:27 +0200 Subject: [PATCH 196/314] Added support for custom delimiters in copy lines --- src/actions/CopyLines.ts | 183 +++++++++--------- src/actions/EditNew.ts | 30 +-- .../recorded/actions/cloneEveryArg.yml | 33 ++++ .../recorded/actions/cloneUpEveryArg.yml | 33 ++++ .../fixtures/recorded/actions/cloneUpVest.yml | 4 +- .../fixtures/recorded/actions/cloneVest.yml | 4 +- .../fixtures/recorded/actions/takeLast.yml | 33 ++++ .../chuckLineHarpBetweenFine.yml | 2 +- 8 files changed, 199 insertions(+), 123 deletions(-) create mode 100644 src/test/suite/fixtures/recorded/actions/cloneEveryArg.yml create mode 100644 src/test/suite/fixtures/recorded/actions/cloneUpEveryArg.yml create mode 100644 src/test/suite/fixtures/recorded/actions/takeLast.yml diff --git a/src/actions/CopyLines.ts b/src/actions/CopyLines.ts index f8bb55e54e..1622eb5b5f 100644 --- a/src/actions/CopyLines.ts +++ b/src/actions/CopyLines.ts @@ -1,104 +1,88 @@ -import { flatten } from "lodash"; +import { flatten, zip } from "lodash"; import { Range, Selection, TextEditor } from "vscode"; import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; +import { weakContainingLineStage } from "../processTargets/modifiers/commonWeakContainingScopeStages"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; import { displayPendingEditDecorationsForRanges } from "../util/editDisplayUtils"; -import { runOnTargetsForEachEditor } from "../util/targetUtils"; -import unifyRanges from "../util/unifyRanges"; +import { createThatMark, runOnTargetsForEachEditor } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; class CopyLines implements Action { - constructor(private graph: Graph, private isUp: boolean) { + getFinalStages = () => [weakContainingLineStage]; + + constructor(private graph: Graph, private isBefore: boolean) { this.run = this.run.bind(this); + this.runForEditor = this.runForEditor.bind(this); } - private getRanges(editor: TextEditor, targets: Target[]) { - const paragraphTargets = targets.filter((target) => target.isParagraph); - const ranges = targets.map((target) => - expandToContainingLine(editor, target.contentRange) - ); - const unifiedRanges = unifyRanges(ranges); - return unifiedRanges.map((range) => ({ - range, - isParagraph: - paragraphTargets.find((target) => target.contentRange.isEqual(range)) != - null, - })); - } + async runForEditor(editor: TextEditor, targets: Target[]) { + const edits = targets.map((target) => { + const delimiter = target.delimiter ?? ""; + const isLine = delimiter.includes("\n"); + + const range = getEditRange( + editor, + target.contentRange, + isLine, + !this.isBefore + ); + const padding = isLine + ? getLinePadding(editor, range, !this.isBefore) + : ""; + + const contentText = target.contentText; + const text = this.isBefore + ? delimiter + padding + contentText + : contentText + delimiter + padding; - private getEdits( - editor: TextEditor, - ranges: { range: Range; isParagraph: boolean }[] - ) { - return ranges.map(({ range, isParagraph }) => { - const delimiter = isParagraph ? "\n\n" : "\n"; - let text = editor.document.getText(range); - const length = text.length; - text = this.isUp ? `${delimiter}${text}` : `${text}${delimiter}`; - const newRange = this.isUp - ? new Range(range.end, range.end) - : new Range(range.start, range.start); return { - edit: { - editor, - range: newRange, - text, - isReplace: this.isUp, - }, - offset: delimiter.length, - length, + range, + isReplace: this.isBefore, + text, + offset: delimiter.length + padding.length, + length: contentText.length, }; }); + + const [updatedEditorSelections, updatedEditSelections, thatSelections] = + await performEditsAndUpdateSelections( + this.graph.rangeUpdater, + editor, + edits, + [ + editor.selections, + edits.map(({ range }) => new Selection(range.start, range.end)), + targets.map(({ contentSelection }) => contentSelection), + ] + ); + + editor.selections = updatedEditorSelections; + editor.revealRange(thatSelections[0]); + + const sourceSelections = zip(edits, updatedEditSelections).map( + ([edit, selection]) => { + const startOffset = editor.document.offsetAt(selection!.start); + const startIndex = this.isBefore + ? startOffset + edit!.offset + : startOffset - edit!.offset - edit!.length; + const endIndex = startIndex + edit!.length; + return new Selection( + editor.document.positionAt(startIndex), + editor.document.positionAt(endIndex) + ); + } + ); + + return { + sourceMark: createThatMark(targets, sourceSelections), + thatMark: createThatMark(targets, thatSelections), + }; } async run([targets]: [Target[]]): Promise { const results = flatten( - await runOnTargetsForEachEditor(targets, async (editor, targets) => { - const ranges = this.getRanges(editor, targets); - const editWrappers = this.getEdits(editor, ranges); - const rangeSelections = ranges.map( - ({ range }) => new Selection(range.start, range.end) - ); - - const [editorSelections, copySelections] = - await performEditsAndUpdateSelections( - this.graph.rangeUpdater, - editor, - editWrappers.map((wrapper) => wrapper.edit), - [editor.selections, rangeSelections] - ); - - editor.selections = editorSelections; - editor.revealRange(copySelections[0]); - - let sourceSelections; - if (this.isUp) { - sourceSelections = editWrappers.map((wrapper) => { - const startIndex = - editor.document.offsetAt(wrapper.edit.range.start) + - wrapper.offset; - const endIndex = startIndex + wrapper.length; - return new Selection( - editor.document.positionAt(startIndex), - editor.document.positionAt(endIndex) - ); - }); - } else { - sourceSelections = rangeSelections; - } - - return { - sourceMark: sourceSelections.map((selection) => ({ - editor, - selection, - })), - thatMark: copySelections.map((selection) => ({ - editor, - selection, - })), - }; - }) + await runOnTargetsForEachEditor(targets, this.runForEditor) ); await displayPendingEditDecorationsForRanges( @@ -111,10 +95,10 @@ class CopyLines implements Action { this.graph.editStyles.justAdded.token ); - const sourceMark = results.flatMap((result) => result.sourceMark); - const thatMark = results.flatMap((result) => result.thatMark); - - return { sourceMark, thatMark }; + return { + sourceMark: results.flatMap((result) => result.sourceMark), + thatMark: results.flatMap((result) => result.thatMark), + }; } } @@ -130,8 +114,27 @@ export class CopyLinesDown extends CopyLines { } } -function expandToContainingLine(editor: TextEditor, range: Range) { - const start = range.start.with({ character: 0 }); - const end = editor.document.lineAt(range.end).range.end; - return new Range(start, end); +export function getLinePadding( + editor: TextEditor, + range: Range, + isBefore: boolean +) { + const line = editor.document.lineAt(isBefore ? range.start : range.end); + const characterIndex = line.isEmptyOrWhitespace + ? range.start.character + : line.firstNonWhitespaceCharacterIndex; + return line.text.slice(0, characterIndex); +} + +export function getEditRange( + editor: TextEditor, + range: Range, + isLine: boolean, + isBefore: boolean +) { + // In case of trialing whitespaces we need to go to the end of the line(not content) + const editRange = + isLine && !isBefore ? editor.document.lineAt(range.end).range : range; + const position = isBefore ? editRange.start : editRange.end; + return new Range(position, position); } diff --git a/src/actions/EditNew.ts b/src/actions/EditNew.ts index 571a448a4a..486d853d6c 100644 --- a/src/actions/EditNew.ts +++ b/src/actions/EditNew.ts @@ -10,6 +10,7 @@ import { Graph } from "../typings/Types"; import { selectionFromRange } from "../util/selectionUtils"; import { createThatMark, ensureSingleEditor } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; +import { getEditRange, getLinePadding } from "./CopyLines"; class EditNew implements Action { getFinalStages = () => [weakContainingLineStage]; @@ -84,7 +85,7 @@ class EditNew implements Action { const edits = delimiterTargets.map(({ delimiter, isLine, cursorRange }) => { return { text: isLine - ? getLineEditText(editor, cursorRange, delimiter, this.isBefore) + ? delimiter + getLinePadding(editor, cursorRange, this.isBefore) : delimiter, range: cursorRange, isReplace: this.isBefore, @@ -183,33 +184,6 @@ function ensureSingleCommand(targets: CommandTarget[]) { return commands[0]; } -function getLineEditText( - editor: TextEditor, - range: Range, - delimiter: string, - isBefore: boolean -) { - const line = editor.document.lineAt(isBefore ? range.start : range.end); - const characterIndex = line.isEmptyOrWhitespace - ? range.start.character - : line.firstNonWhitespaceCharacterIndex; - const padding = line.text.slice(0, characterIndex); - return delimiter + padding; -} - -function getEditRange( - editor: TextEditor, - range: Range, - isLine: boolean, - isBefore: boolean -) { - // In case of trialing whitespaces we need to go to the end of the line(not content) - const editRange = - isLine && !isBefore ? editor.document.lineAt(range.end).range : range; - const position = isBefore ? editRange.start : editRange.end; - return new Range(position, position); -} - function updateTargets( targets: RichTarget[], updatedTargetRanges: Range[], diff --git a/src/test/suite/fixtures/recorded/actions/cloneEveryArg.yml b/src/test/suite/fixtures/recorded/actions/cloneEveryArg.yml new file mode 100644 index 0000000000..583a7baef1 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/cloneEveryArg.yml @@ -0,0 +1,33 @@ +languageId: typescript +command: + spokenForm: clone every arg + version: 2 + targets: + - type: primitive + modifiers: + - type: everyScope + scopeType: {type: argumentOrParameter} + usePrePhraseSnapshot: true + action: {name: insertCopyAfter} +initialState: + documentContents: "function myFunk(a: number, b: number) {}" + selections: + - anchor: {line: 0, character: 20} + active: {line: 0, character: 20} + marks: {} +finalState: + documentContents: "function myFunk(a: number, a: number, b: number, b: number) {}" + selections: + - anchor: {line: 0, character: 31} + active: {line: 0, character: 31} + thatMark: + - anchor: {line: 0, character: 27} + active: {line: 0, character: 36} + - anchor: {line: 0, character: 49} + active: {line: 0, character: 58} + sourceMark: + - anchor: {line: 0, character: 16} + active: {line: 0, character: 25} + - anchor: {line: 0, character: 38} + active: {line: 0, character: 47} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: everyScope, scopeType: {type: argumentOrParameter}}]}] diff --git a/src/test/suite/fixtures/recorded/actions/cloneUpEveryArg.yml b/src/test/suite/fixtures/recorded/actions/cloneUpEveryArg.yml new file mode 100644 index 0000000000..799d7c5f68 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/cloneUpEveryArg.yml @@ -0,0 +1,33 @@ +languageId: typescript +command: + spokenForm: clone up every arg + version: 2 + targets: + - type: primitive + modifiers: + - type: everyScope + scopeType: {type: argumentOrParameter} + usePrePhraseSnapshot: true + action: {name: insertCopyBefore} +initialState: + documentContents: "function myFunk(a: number, b: number) {}" + selections: + - anchor: {line: 0, character: 20} + active: {line: 0, character: 20} + marks: {} +finalState: + documentContents: "function myFunk(a: number, a: number, b: number, b: number) {}" + selections: + - anchor: {line: 0, character: 20} + active: {line: 0, character: 20} + thatMark: + - anchor: {line: 0, character: 16} + active: {line: 0, character: 25} + - anchor: {line: 0, character: 38} + active: {line: 0, character: 47} + sourceMark: + - anchor: {line: 0, character: 27} + active: {line: 0, character: 36} + - anchor: {line: 0, character: 49} + active: {line: 0, character: 58} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: everyScope, scopeType: {type: argumentOrParameter}}]}] diff --git a/src/test/suite/fixtures/recorded/actions/cloneUpVest.yml b/src/test/suite/fixtures/recorded/actions/cloneUpVest.yml index 1a8e927f44..e47758d770 100644 --- a/src/test/suite/fixtures/recorded/actions/cloneUpVest.yml +++ b/src/test/suite/fixtures/recorded/actions/cloneUpVest.yml @@ -23,9 +23,9 @@ finalState: - anchor: {line: 0, character: 15} active: {line: 0, character: 15} thatMark: - - anchor: {line: 0, character: 0} + - anchor: {line: 0, character: 4} active: {line: 0, character: 32} sourceMark: - - anchor: {line: 1, character: 0} + - anchor: {line: 1, character: 4} active: {line: 1, character: 32} fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: v}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: identity}}] diff --git a/src/test/suite/fixtures/recorded/actions/cloneVest.yml b/src/test/suite/fixtures/recorded/actions/cloneVest.yml index ccc683f614..0d2b2f6b34 100644 --- a/src/test/suite/fixtures/recorded/actions/cloneVest.yml +++ b/src/test/suite/fixtures/recorded/actions/cloneVest.yml @@ -23,9 +23,9 @@ finalState: - anchor: {line: 1, character: 15} active: {line: 1, character: 15} thatMark: - - anchor: {line: 1, character: 0} + - anchor: {line: 1, character: 4} active: {line: 1, character: 32} sourceMark: - - anchor: {line: 0, character: 0} + - anchor: {line: 0, character: 4} active: {line: 0, character: 32} fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: v}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: identity}}] diff --git a/src/test/suite/fixtures/recorded/actions/takeLast.yml b/src/test/suite/fixtures/recorded/actions/takeLast.yml new file mode 100644 index 0000000000..d0b0d3acde --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/takeLast.yml @@ -0,0 +1,33 @@ +languageId: typescript +command: + spokenForm: take last + version: 2 + targets: + - type: primitive + mark: {type: that} + usePrePhraseSnapshot: true + action: {name: setSelection} +initialState: + documentContents: "function myFunk(a: number, a: number, b: number, b: number) {}" + selections: + - anchor: {line: 0, character: 20} + active: {line: 0, character: 20} + marks: {} + thatMark: + - anchor: {line: 0, character: 16} + active: {line: 0, character: 25} + - anchor: {line: 0, character: 38} + active: {line: 0, character: 47} +finalState: + documentContents: "function myFunk(a: number, a: number, b: number, b: number) {}" + selections: + - anchor: {line: 0, character: 16} + active: {line: 0, character: 25} + - anchor: {line: 0, character: 38} + active: {line: 0, character: 47} + thatMark: + - anchor: {line: 0, character: 16} + active: {line: 0, character: 25} + - anchor: {line: 0, character: 38} + active: {line: 0, character: 47} +fullTargets: [{type: primitive, mark: {type: that}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/selectionTypes/chuckLineHarpBetweenFine.yml b/src/test/suite/fixtures/recorded/selectionTypes/chuckLineHarpBetweenFine.yml index 467c0fb4e7..47a2f54763 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/chuckLineHarpBetweenFine.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/chuckLineHarpBetweenFine.yml @@ -19,7 +19,7 @@ command: mark: {type: decoratedSymbol, symbolColor: default, character: h} modifiers: - type: containingScope - scopeType: {type: line} + scopeType: {type: line} active: type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: f} From 390a5411ff1fba2761703fdec963978a63b5ccc3 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Wed, 25 May 2022 20:17:12 +0100 Subject: [PATCH 197/314] Fix package json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fb28ac832e..0b9d0ca3ac 100644 --- a/package.json +++ b/package.json @@ -508,7 +508,7 @@ "pretest": "yarn run compile && yarn run lint && yarn run esbuild", "lint": "eslint src --ext ts", "test": "env CURSORLESS_TEST=true node ./out/test/runTest.js", - "unused-exports": "ts-unused-exports tsconfig.json --showLineNumber" + "unused-exports": "ts-unused-exports tsconfig.json --showLineNumber", "init-launch-sandbox": "node ./out/test/initLaunchSandbox.js", "prepare-for-extension-publish": "node ./out/scripts/prepareForExtensionPublish.js" }, From d32c5da82c61208d96a7ace457c14cb461adffae Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Wed, 25 May 2022 21:51:24 +0100 Subject: [PATCH 198/314] Fix one test --- .../fixtures/recorded/surroundingPair/parseTree/takeCore.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/suite/fixtures/recorded/surroundingPair/parseTree/takeCore.yml b/src/test/suite/fixtures/recorded/surroundingPair/parseTree/takeCore.yml index 45e2518c9c..cf8ae2f724 100644 --- a/src/test/suite/fixtures/recorded/surroundingPair/parseTree/takeCore.yml +++ b/src/test/suite/fixtures/recorded/surroundingPair/parseTree/takeCore.yml @@ -5,9 +5,9 @@ command: targets: - type: primitive modifiers: + - {type: interiorOnly} - type: containingScope scopeType: {type: surroundingPair, delimiter: any} - - {type: interiorOnly} usePrePhraseSnapshot: true action: {name: setSelection} initialState: From e877922e9e4ba8d73fe64176630895b31953d3d3 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 26 May 2022 08:46:29 +0200 Subject: [PATCH 199/314] Updated tests --- ...Harp.yml => chuckBlockEachBetweenLook.yml} | 26 +++++++++---------- ...ilHarp.yml => chuckBlockEachUntilLook.yml} | 26 +++++++++---------- third-party-licenses.csv | 17 +----------- 3 files changed, 27 insertions(+), 42 deletions(-) rename src/test/suite/fixtures/recorded/compoundTargets/{chuckBlockEachBetweenHarp.yml => chuckBlockEachBetweenLook.yml} (79%) rename src/test/suite/fixtures/recorded/compoundTargets/{chuckBlockEachUntilHarp.yml => chuckBlockEachUntilLook.yml} (79%) diff --git a/src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachBetweenHarp.yml b/src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachBetweenLook.yml similarity index 79% rename from src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachBetweenHarp.yml rename to src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachBetweenLook.yml index e5964a154e..997b7616c2 100644 --- a/src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachBetweenHarp.yml +++ b/src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachBetweenLook.yml @@ -1,6 +1,6 @@ languageId: typescript command: - spokenForm: chuck block each between harp + spokenForm: chuck block each between look version: 2 targets: - type: range @@ -10,7 +10,7 @@ command: mark: {type: decoratedSymbol, symbolColor: default, character: e} end: type: primitive - mark: {type: decoratedSymbol, symbolColor: default, character: h} + mark: {type: decoratedSymbol, symbolColor: default, character: l} excludeStart: true excludeEnd: true anchor: @@ -21,7 +21,7 @@ command: scopeType: {type: paragraph} active: type: primitive - mark: {type: decoratedSymbol, symbolColor: default, character: h} + mark: {type: decoratedSymbol, symbolColor: default, character: l} excludeAnchor: true excludeActive: true usePrePhraseSnapshot: true @@ -34,28 +34,28 @@ initialState: hello there hello there - hello + hello selections: - - anchor: {line: 5, character: 13} - active: {line: 5, character: 13} + - anchor: {line: 4, character: 9} + active: {line: 4, character: 9} marks: default.e: start: {line: 1, character: 6} end: {line: 1, character: 11} - default.h: - start: {line: 3, character: 4} - end: {line: 3, character: 9} + default.l: + start: {line: 4, character: 4} + end: {line: 4, character: 9} finalState: documentContents: |- hello there hello there hello there hello there - hello + hello selections: - - anchor: {line: 4, character: 13} - active: {line: 4, character: 13} + - anchor: {line: 2, character: 9} + active: {line: 2, character: 9} thatMark: - anchor: {line: 2, character: 0} active: {line: 2, character: 0} -fullTargets: [{type: range, excludeAnchor: true, excludeActive: true, rangeType: continuous, anchor: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: e}, modifiers: &ref_0 [{type: containingScope, scopeType: {type: paragraph}}]}, active: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: h}, modifiers: *ref_0}}] +fullTargets: [{type: range, excludeAnchor: true, excludeActive: true, rangeType: continuous, anchor: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: e}, modifiers: &ref_0 [{type: containingScope, scopeType: {type: paragraph}}]}, active: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: l}, modifiers: *ref_0}}] diff --git a/src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachUntilHarp.yml b/src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachUntilLook.yml similarity index 79% rename from src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachUntilHarp.yml rename to src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachUntilLook.yml index 6557891323..2dcff3828a 100644 --- a/src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachUntilHarp.yml +++ b/src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachUntilLook.yml @@ -1,6 +1,6 @@ languageId: typescript command: - spokenForm: chuck block each until harp + spokenForm: chuck block each until look version: 2 targets: - type: range @@ -10,7 +10,7 @@ command: mark: {type: decoratedSymbol, symbolColor: default, character: e} end: type: primitive - mark: {type: decoratedSymbol, symbolColor: default, character: h} + mark: {type: decoratedSymbol, symbolColor: default, character: l} excludeStart: false excludeEnd: true anchor: @@ -21,7 +21,7 @@ command: scopeType: {type: paragraph} active: type: primitive - mark: {type: decoratedSymbol, symbolColor: default, character: h} + mark: {type: decoratedSymbol, symbolColor: default, character: l} excludeAnchor: false excludeActive: true usePrePhraseSnapshot: true @@ -34,26 +34,26 @@ initialState: hello there hello there - hello + hello selections: - - anchor: {line: 5, character: 13} - active: {line: 5, character: 13} + - anchor: {line: 4, character: 9} + active: {line: 4, character: 9} marks: default.e: start: {line: 1, character: 6} end: {line: 1, character: 11} - default.h: - start: {line: 3, character: 4} - end: {line: 3, character: 9} + default.l: + start: {line: 4, character: 4} + end: {line: 4, character: 9} finalState: documentContents: |2- hello there hello there - hello + hello selections: - - anchor: {line: 2, character: 13} - active: {line: 2, character: 13} + - anchor: {line: 0, character: 9} + active: {line: 0, character: 9} thatMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 0} -fullTargets: [{type: range, excludeAnchor: false, excludeActive: true, rangeType: continuous, anchor: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: e}, modifiers: &ref_0 [{type: containingScope, scopeType: {type: paragraph}}]}, active: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: h}, modifiers: *ref_0}}] +fullTargets: [{type: range, excludeAnchor: false, excludeActive: true, rangeType: continuous, anchor: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: e}, modifiers: &ref_0 [{type: containingScope, scopeType: {type: paragraph}}]}, active: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: l}, modifiers: *ref_0}}] diff --git a/third-party-licenses.csv b/third-party-licenses.csv index d95fd3e299..80507fca48 100644 --- a/third-party-licenses.csv +++ b/third-party-licenses.csv @@ -1,19 +1,4 @@ "module name","licenses","repository","licenseUrl","parents" -"@docusaurus/core@2.0.0-beta.17","MIT","https://github.com/facebook/docusaurus","https://github.com/facebook/docusaurus/raw/master/LICENSE","website" -"@docusaurus/preset-classic@2.0.0-beta.17","MIT","https://github.com/facebook/docusaurus","https://github.com/facebook/docusaurus/raw/master/LICENSE","website" -"@mdx-js/react@1.6.22","MIT","https://github.com/mdx-js/mdx","https://github.com/mdx-js/mdx/raw/master/license","website" "@types/lodash@4.14.181","MIT","https://github.com/DefinitelyTyped/DefinitelyTyped","https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE","cursorless" -"ansicolor@1.1.100","Unlicense","https://github.com/xpl/ansicolor","https://github.com/xpl/ansicolor/raw/master/LICENSE","metals" -"brace-expansion@2.0.1","MIT","https://github.com/juliangruber/brace-expansion","https://github.com/juliangruber/brace-expansion/raw/master/LICENSE","vscode-fileutils" -"clsx@1.1.1","MIT","https://github.com/lukeed/clsx","https://github.com/lukeed/clsx/raw/master/license","website" "immutability-helper@3.1.1","MIT","https://github.com/kolodny/immutability-helper","https://github.com/kolodny/immutability-helper/raw/master/LICENSE","cursorless" -"jsonc-parser@2.3.1","MIT","https://github.com/microsoft/node-jsonc-parser","https://github.com/microsoft/node-jsonc-parser/raw/master/LICENSE.md","parse-tree" -"mdast-util-find-and-replace@2.1.0","MIT","https://github.com/syntax-tree/mdast-util-find-and-replace","https://github.com/syntax-tree/mdast-util-find-and-replace/raw/master/license","website" -"metals-languageclient@0.5.15","Apache-2.0","https://github.com/scalameta/metals-languageclient","https://github.com/scalameta/metals-languageclient/raw/master/LICENSE","metals" -"prism-react-renderer@1.3.1","MIT","https://github.com/FormidableLabs/prism-react-renderer","https://github.com/FormidableLabs/prism-react-renderer/raw/master/LICENSE","website" -"promisify-child-process@4.1.1","MIT","https://github.com/jcoreio/promisify-child-process","https://github.com/jcoreio/promisify-child-process/raw/master/LICENSE.md","metals" -"react-dom@17.0.2","MIT","https://github.com/facebook/react","https://github.com/facebook/react/raw/master/LICENSE","website" -"react@17.0.2","MIT","https://github.com/facebook/react","https://github.com/facebook/react/raw/master/LICENSE","website" -"tar@6.1.11","ISC","https://github.com/npm/node-tar","https://github.com/npm/node-tar/raw/master/LICENSE","parse-tree" -"unist-util-visit@4.1.0","MIT","https://github.com/syntax-tree/unist-util-visit","https://github.com/syntax-tree/unist-util-visit/raw/master/license","website" -"vscode-languageclient@7.0.0","MIT","https://github.com/Microsoft/vscode-languageserver-node","https://github.com/Microsoft/vscode-languageserver-node/raw/master/License.txt","metals" +"lodash@4.17.21","MIT","https://github.com/lodash/lodash","https://github.com/lodash/lodash/raw/master/LICENSE","cursorless" \ No newline at end of file From 1793c278e648cbd20cc76108ffb0c05134460daf Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 26 May 2022 06:46:53 +0000 Subject: [PATCH 200/314] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- third-party-licenses.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third-party-licenses.csv b/third-party-licenses.csv index 80507fca48..e6029ac60c 100644 --- a/third-party-licenses.csv +++ b/third-party-licenses.csv @@ -1,4 +1,4 @@ "module name","licenses","repository","licenseUrl","parents" "@types/lodash@4.14.181","MIT","https://github.com/DefinitelyTyped/DefinitelyTyped","https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE","cursorless" "immutability-helper@3.1.1","MIT","https://github.com/kolodny/immutability-helper","https://github.com/kolodny/immutability-helper/raw/master/LICENSE","cursorless" -"lodash@4.17.21","MIT","https://github.com/lodash/lodash","https://github.com/lodash/lodash/raw/master/LICENSE","cursorless" \ No newline at end of file +"lodash@4.17.21","MIT","https://github.com/lodash/lodash","https://github.com/lodash/lodash/raw/master/LICENSE","cursorless" From 2cbaaf5c2979d56837c9508abe402ec7b4273fa3 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 26 May 2022 09:36:22 +0200 Subject: [PATCH 201/314] Disabled phrase snapshot on recorded test runner --- src/test/suite/recorded.test.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/suite/recorded.test.ts b/src/test/suite/recorded.test.ts index 7e0bb6e351..b07dce7697 100644 --- a/src/test/suite/recorded.test.ts +++ b/src/test/suite/recorded.test.ts @@ -57,6 +57,10 @@ async function runTest(file: string) { const fixture = yaml.load(buffer.toString()) as TestCaseFixture; const excludeFields: ExcludableSnapshotField[] = []; + // TODO The snapshot gets messed up with timing issues when running the recorded tests + // "Couldn't find token default.a" + fixture.command.usePrePhraseSnapshot = false; + const cursorlessApi = await getCursorlessApi(); const graph = cursorlessApi.graph!; From 6432c47fce5fe4e756c73956bd0669be9561be4d Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 26 May 2022 11:31:36 +0200 Subject: [PATCH 202/314] Updated test and upgrade path --- src/actions/BringMoveSwap.ts | 13 +++++-- .../upgradeV1ToV2/upgradeV1ToV2.ts | 18 ++++++---- src/processTargets/processTargets.ts | 3 +- .../chuckBlockEachBetweenLook.yml | 9 ----- .../chuckBlockEachUntilLook.yml | 9 ----- ...nHarp.yml => chuckLineEachBetweenLook.yml} | 35 +++++++------------ ...arp2.yml => chuckLineEachBetweenLook2.yml} | 31 ++++++---------- ...tilHarp.yml => chuckLineEachUntilLook.yml} | 35 +++++++------------ .../chuckLineHarpBetweenFine.yml | 16 +++------ ...AndPointToThisAndStartOfWhaleTakeWhale.yml | 2 -- ...tAndHarpToThisAndStartOfWhaleTakeWhale.yml | 2 -- .../positions/bringStateFineToAfterBatt.yml | 2 +- .../recorded/selectionTypes/drinkCell.yml | 4 +-- .../recorded/selectionTypes/drinkCellEach.yml | 4 +-- .../recorded/selectionTypes/pourCell.yml | 4 +-- .../recorded/selectionTypes/pourCellEach.yml | 4 +-- .../parseTree/{ => typescript}/takeCore.yml | 0 src/test/suite/recorded.test.ts | 4 ++- 18 files changed, 76 insertions(+), 119 deletions(-) rename src/test/suite/fixtures/recorded/compoundTargets/{chuckLineEachBetweenHarp.yml => chuckLineEachBetweenLook.yml} (63%) rename src/test/suite/fixtures/recorded/compoundTargets/{chuckLineEachBetweenHarp2.yml => chuckLineEachBetweenLook2.yml} (67%) rename src/test/suite/fixtures/recorded/compoundTargets/{chuckLineEachUntilHarp.yml => chuckLineEachUntilLook.yml} (63%) rename src/test/suite/fixtures/recorded/{selectionTypes => compoundTargets}/chuckLineHarpBetweenFine.yml (71%) rename src/test/suite/fixtures/recorded/surroundingPair/parseTree/{ => typescript}/takeCore.yml (100%) diff --git a/src/actions/BringMoveSwap.ts b/src/actions/BringMoveSwap.ts index dcca5a1299..d353a0336a 100644 --- a/src/actions/BringMoveSwap.ts +++ b/src/actions/BringMoveSwap.ts @@ -1,4 +1,4 @@ -import { flatten } from "lodash"; +import { flatten, uniqWith } from "lodash"; import { DecorationRangeBehavior, Selection, TextEditor } from "vscode"; import { getSelectionInfo, @@ -240,13 +240,13 @@ class BringMoveSwap implements Action { const thatMark = this.type === "swap" ? markEntries - : markEntries.filter(({ isSource }) => !isSource); + : uniqMarks(markEntries.filter(({ isSource }) => !isSource)); // Only swap doesn't have a source mark const sourceMark = this.type === "swap" ? [] - : markEntries.filter(({ isSource }) => isSource); + : uniqMarks(markEntries.filter(({ isSource }) => isSource)); return { thatMark, sourceMark }; } @@ -294,3 +294,10 @@ function getTextWithPossibleDelimiter(source: Target, destination: Target) { const sourceText = source.contentText; return destination.maybeAddDelimiter(sourceText); } + +function uniqMarks(markEntries: MarkEntry[]): MarkEntry[] { + return uniqWith( + markEntries, + (a, b) => a.editor === b.editor && a.selection.isEqual(b.selection) + ); +} diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts index 966de92f0c..94cf77eb9b 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts @@ -88,12 +88,13 @@ function upgradePrimitiveTarget( target: PartialPrimitiveTargetV0V1 ): PartialPrimitiveTargetDesc { const { + type, + isImplicit, mark, insideOutsideType, modifier, selectionType, position, - ...rest } = target; const modifiers: Modifier[] = []; @@ -136,7 +137,8 @@ function upgradePrimitiveTarget( } return { - ...rest, + type, + isImplicit, // Cursor token is just cursor position but treated as a token. This is done in the pipeline for normal cursor now mark: mark?.type === "cursorToken" ? undefined : mark, // Empty array of modifiers is not allowed @@ -157,12 +159,14 @@ function upgradeTarget(target: PartialTargetV0V1): PartialTargetDesc { ), }; case "range": + const { type, rangeType, start, end, excludeStart, excludeEnd } = target; return { - ...target, - anchor: upgradePrimitiveTarget(target.start), - active: upgradePrimitiveTarget(target.end), - excludeAnchor: target.excludeStart ?? false, - excludeActive: target.excludeEnd ?? false, + type, + rangeType, + anchor: upgradePrimitiveTarget(start), + active: upgradePrimitiveTarget(end), + excludeAnchor: excludeStart ?? false, + excludeActive: excludeEnd ?? false, }; case "primitive": return upgradePrimitiveTarget(target); diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index 1bf8d126cc..b9ffa05126 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -239,7 +239,8 @@ function processPrimitiveTarget( let targets = markStage.run(context); const modifierStages = [ - ...target.modifiers.reverse().map(getModifierStage), + // Reverse target modifies because they are in reverse order from the api. Slice is needed to create a copy or the modifiers will be in wrong order in the test recorder. + ...target.modifiers.slice().reverse().map(getModifierStage), ...context.finalStages, ]; diff --git a/src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachBetweenLook.yml b/src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachBetweenLook.yml index 997b7616c2..26fa77e758 100644 --- a/src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachBetweenLook.yml +++ b/src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachBetweenLook.yml @@ -4,15 +4,6 @@ command: version: 2 targets: - type: range - start: - type: primitive - selectionType: paragraph - mark: {type: decoratedSymbol, symbolColor: default, character: e} - end: - type: primitive - mark: {type: decoratedSymbol, symbolColor: default, character: l} - excludeStart: true - excludeEnd: true anchor: type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: e} diff --git a/src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachUntilLook.yml b/src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachUntilLook.yml index 2dcff3828a..8892cd296b 100644 --- a/src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachUntilLook.yml +++ b/src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachUntilLook.yml @@ -4,15 +4,6 @@ command: version: 2 targets: - type: range - start: - type: primitive - selectionType: paragraph - mark: {type: decoratedSymbol, symbolColor: default, character: e} - end: - type: primitive - mark: {type: decoratedSymbol, symbolColor: default, character: l} - excludeStart: false - excludeEnd: true anchor: type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: e} diff --git a/src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachBetweenHarp.yml b/src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachBetweenLook.yml similarity index 63% rename from src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachBetweenHarp.yml rename to src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachBetweenLook.yml index b1c8c6590c..ef4aca5525 100644 --- a/src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachBetweenHarp.yml +++ b/src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachBetweenLook.yml @@ -1,18 +1,9 @@ -languageId: typescript +languageId: plaintext command: - spokenForm: chuck line each between harp + spokenForm: chuck line each between look version: 2 targets: - type: range - start: - type: primitive - selectionType: line - mark: {type: decoratedSymbol, symbolColor: default, character: e} - end: - type: primitive - mark: {type: decoratedSymbol, symbolColor: default, character: h} - excludeStart: true - excludeEnd: true anchor: type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: e} @@ -21,7 +12,7 @@ command: scopeType: {type: line} active: type: primitive - mark: {type: decoratedSymbol, symbolColor: default, character: h} + mark: {type: decoratedSymbol, symbolColor: default, character: l} excludeAnchor: true excludeActive: true usePrePhraseSnapshot: true @@ -34,28 +25,28 @@ initialState: hello there hello there - hello + hello selections: - - anchor: {line: 5, character: 13} - active: {line: 5, character: 13} + - anchor: {line: 4, character: 9} + active: {line: 4, character: 9} marks: default.e: start: {line: 1, character: 6} end: {line: 1, character: 11} - default.h: - start: {line: 3, character: 4} - end: {line: 3, character: 9} + default.l: + start: {line: 4, character: 4} + end: {line: 4, character: 9} finalState: documentContents: |- hello there hello there hello there hello there - hello + hello selections: - - anchor: {line: 4, character: 13} - active: {line: 4, character: 13} + - anchor: {line: 2, character: 9} + active: {line: 2, character: 9} thatMark: - anchor: {line: 2, character: 0} active: {line: 2, character: 0} -fullTargets: [{type: range, excludeAnchor: true, excludeActive: true, rangeType: continuous, anchor: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: e}, modifiers: &ref_0 [{type: containingScope, scopeType: {type: line}}]}, active: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: h}, modifiers: *ref_0}}] +fullTargets: [{type: range, excludeAnchor: true, excludeActive: true, rangeType: continuous, anchor: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: e}, modifiers: &ref_0 [{type: containingScope, scopeType: {type: line}}]}, active: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: l}, modifiers: *ref_0}}] diff --git a/src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachBetweenHarp2.yml b/src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachBetweenLook2.yml similarity index 67% rename from src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachBetweenHarp2.yml rename to src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachBetweenLook2.yml index 76a62f89f8..39b78be878 100644 --- a/src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachBetweenHarp2.yml +++ b/src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachBetweenLook2.yml @@ -1,18 +1,9 @@ -languageId: typescript +languageId: plaintext command: - spokenForm: chuck line each between harp + spokenForm: chuck line each between look version: 2 targets: - type: range - start: - type: primitive - selectionType: line - mark: {type: decoratedSymbol, symbolColor: default, character: e} - end: - type: primitive - mark: {type: decoratedSymbol, symbolColor: default, character: h} - excludeStart: true - excludeEnd: true anchor: type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: e} @@ -21,7 +12,7 @@ command: scopeType: {type: line} active: type: primitive - mark: {type: decoratedSymbol, symbolColor: default, character: h} + mark: {type: decoratedSymbol, symbolColor: default, character: l} excludeAnchor: true excludeActive: true usePrePhraseSnapshot: true @@ -33,15 +24,15 @@ initialState: hello there hello there - hello + hello selections: - - anchor: {line: 5, character: 13} - active: {line: 5, character: 13} + - anchor: {line: 3, character: 9} + active: {line: 3, character: 9} marks: default.e: start: {line: 1, character: 6} end: {line: 1, character: 11} - default.h: + default.l: start: {line: 3, character: 4} end: {line: 3, character: 9} finalState: @@ -50,11 +41,11 @@ finalState: hello there hello there hello there - hello + hello selections: - - anchor: {line: 4, character: 13} - active: {line: 4, character: 13} + - anchor: {line: 2, character: 9} + active: {line: 2, character: 9} thatMark: - anchor: {line: 2, character: 0} active: {line: 2, character: 0} -fullTargets: [{type: range, excludeAnchor: true, excludeActive: true, rangeType: continuous, anchor: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: e}, modifiers: &ref_0 [{type: containingScope, scopeType: {type: line}}]}, active: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: h}, modifiers: *ref_0}}] +fullTargets: [{type: range, excludeAnchor: true, excludeActive: true, rangeType: continuous, anchor: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: e}, modifiers: &ref_0 [{type: containingScope, scopeType: {type: line}}]}, active: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: l}, modifiers: *ref_0}}] diff --git a/src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachUntilHarp.yml b/src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachUntilLook.yml similarity index 63% rename from src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachUntilHarp.yml rename to src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachUntilLook.yml index 12bb2bfc33..730b9ad28f 100644 --- a/src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachUntilHarp.yml +++ b/src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachUntilLook.yml @@ -1,18 +1,9 @@ -languageId: typescript +languageId: plaintext command: - spokenForm: chuck line each until harp + spokenForm: chuck line each until look version: 2 targets: - type: range - start: - type: primitive - selectionType: line - mark: {type: decoratedSymbol, symbolColor: default, character: e} - end: - type: primitive - mark: {type: decoratedSymbol, symbolColor: default, character: h} - excludeStart: false - excludeEnd: true anchor: type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: e} @@ -21,7 +12,7 @@ command: scopeType: {type: line} active: type: primitive - mark: {type: decoratedSymbol, symbolColor: default, character: h} + mark: {type: decoratedSymbol, symbolColor: default, character: l} excludeAnchor: false excludeActive: true usePrePhraseSnapshot: true @@ -34,27 +25,27 @@ initialState: hello there hello there - hello + hello selections: - - anchor: {line: 5, character: 13} - active: {line: 5, character: 13} + - anchor: {line: 4, character: 9} + active: {line: 4, character: 9} marks: default.e: start: {line: 1, character: 6} end: {line: 1, character: 11} - default.h: - start: {line: 3, character: 4} - end: {line: 3, character: 9} + default.l: + start: {line: 4, character: 4} + end: {line: 4, character: 9} finalState: documentContents: |- hello there hello there hello there - hello + hello selections: - - anchor: {line: 3, character: 13} - active: {line: 3, character: 13} + - anchor: {line: 1, character: 9} + active: {line: 1, character: 9} thatMark: - anchor: {line: 1, character: 0} active: {line: 1, character: 0} -fullTargets: [{type: range, excludeAnchor: false, excludeActive: true, rangeType: continuous, anchor: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: e}, modifiers: &ref_0 [{type: containingScope, scopeType: {type: line}}]}, active: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: h}, modifiers: *ref_0}}] +fullTargets: [{type: range, excludeAnchor: false, excludeActive: true, rangeType: continuous, anchor: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: e}, modifiers: &ref_0 [{type: containingScope, scopeType: {type: line}}]}, active: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: l}, modifiers: *ref_0}}] diff --git a/src/test/suite/fixtures/recorded/selectionTypes/chuckLineHarpBetweenFine.yml b/src/test/suite/fixtures/recorded/compoundTargets/chuckLineHarpBetweenFine.yml similarity index 71% rename from src/test/suite/fixtures/recorded/selectionTypes/chuckLineHarpBetweenFine.yml rename to src/test/suite/fixtures/recorded/compoundTargets/chuckLineHarpBetweenFine.yml index 47a2f54763..5a9f977a4e 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/chuckLineHarpBetweenFine.yml +++ b/src/test/suite/fixtures/recorded/compoundTargets/chuckLineHarpBetweenFine.yml @@ -2,18 +2,8 @@ languageId: plaintext command: spokenForm: chuck line harp between fine version: 2 - action: {name: remove} targets: - type: range - start: - type: primitive - selectionType: line - mark: {type: decoratedSymbol, symbolColor: default, character: h} - end: - type: primitive - mark: {type: decoratedSymbol, symbolColor: default, character: f} - excludeStart: true - excludeEnd: true anchor: type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: h} @@ -23,8 +13,10 @@ command: active: type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: f} - modifiers: [] + excludeAnchor: true + excludeActive: true usePrePhraseSnapshot: true + action: {name: remove} initialState: documentContents: | @@ -53,4 +45,4 @@ finalState: thatMark: - anchor: {line: 2, character: 0} active: {line: 2, character: 0} -fullTargets: [{type: range, excludeAnchor: true, excludeActive: true, rangeType: continuous, anchor: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: h}, modifiers: &ref_0 [{type: containingScope, scopeType: line}]}, active: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: f}, modifiers: *ref_0}}] +fullTargets: [{type: range, excludeAnchor: true, excludeActive: true, rangeType: continuous, anchor: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: h}, modifiers: &ref_0 [{type: containingScope, scopeType: {type: line}}]}, active: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: f}, modifiers: *ref_0}}] diff --git a/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToThisAndStartOfWhaleTakeWhale.yml b/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToThisAndStartOfWhaleTakeWhale.yml index deee28f351..5b0f628113 100644 --- a/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToThisAndStartOfWhaleTakeWhale.yml +++ b/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToThisAndStartOfWhaleTakeWhale.yml @@ -52,8 +52,6 @@ finalState: thatMark: - anchor: {line: 0, character: 7} active: {line: 0, character: 13} - - anchor: {line: 0, character: 7} - active: {line: 0, character: 13} sourceMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 5} diff --git a/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToThisAndStartOfWhaleTakeWhale.yml b/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToThisAndStartOfWhaleTakeWhale.yml index fd08052d86..b0e369b641 100644 --- a/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToThisAndStartOfWhaleTakeWhale.yml +++ b/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToThisAndStartOfWhaleTakeWhale.yml @@ -52,8 +52,6 @@ finalState: thatMark: - anchor: {line: 0, character: 7} active: {line: 0, character: 13} - - anchor: {line: 0, character: 7} - active: {line: 0, character: 13} sourceMark: - anchor: {line: 0, character: 5} active: {line: 0, character: 6} diff --git a/src/test/suite/fixtures/recorded/positions/bringStateFineToAfterBatt.yml b/src/test/suite/fixtures/recorded/positions/bringStateFineToAfterBatt.yml index ce4633ab56..3f0fc86688 100644 --- a/src/test/suite/fixtures/recorded/positions/bringStateFineToAfterBatt.yml +++ b/src/test/suite/fixtures/recorded/positions/bringStateFineToAfterBatt.yml @@ -11,9 +11,9 @@ command: - type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: b} modifiers: + - {type: position, position: after} - type: containingScope scopeType: {type: statement} - - {type: position, position: after} usePrePhraseSnapshot: true action: {name: replaceWithTarget} initialState: diff --git a/src/test/suite/fixtures/recorded/selectionTypes/drinkCell.yml b/src/test/suite/fixtures/recorded/selectionTypes/drinkCell.yml index b86c6b5711..dabe7edab0 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/drinkCell.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/drinkCell.yml @@ -21,6 +21,6 @@ finalState: - anchor: {line: 1, character: 0} active: {line: 1, character: 0} thatMark: - - anchor: {line: 1, character: 0} - active: {line: 1, character: 0} + - anchor: {line: 1, character: 12} + active: {line: 1, character: 12} fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: notebookCell, position: contents, insideOutsideType: inside, modifier: {type: identity}}] diff --git a/src/test/suite/fixtures/recorded/selectionTypes/drinkCellEach.yml b/src/test/suite/fixtures/recorded/selectionTypes/drinkCellEach.yml index bc152f2168..5828044cf6 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/drinkCellEach.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/drinkCellEach.yml @@ -32,6 +32,6 @@ finalState: - anchor: {line: 1, character: 0} active: {line: 1, character: 0} thatMark: - - anchor: {line: 1, character: 0} - active: {line: 1, character: 0} + - anchor: {line: 1, character: 7} + active: {line: 1, character: 12} fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: e}, selectionType: notebookCell, position: contents, insideOutsideType: inside, modifier: {type: identity}}] diff --git a/src/test/suite/fixtures/recorded/selectionTypes/pourCell.yml b/src/test/suite/fixtures/recorded/selectionTypes/pourCell.yml index 4a4c3f5252..36c9c030b6 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/pourCell.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/pourCell.yml @@ -21,6 +21,6 @@ finalState: - anchor: {line: 3, character: 0} active: {line: 3, character: 0} thatMark: - - anchor: {line: 3, character: 0} - active: {line: 3, character: 0} + - anchor: {line: 1, character: 12} + active: {line: 1, character: 12} fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: notebookCell, position: contents, insideOutsideType: inside, modifier: {type: identity}}] diff --git a/src/test/suite/fixtures/recorded/selectionTypes/pourCellEach.yml b/src/test/suite/fixtures/recorded/selectionTypes/pourCellEach.yml index e034cdd54d..16de857e1d 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/pourCellEach.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/pourCellEach.yml @@ -32,6 +32,6 @@ finalState: - anchor: {line: 4, character: 0} active: {line: 4, character: 0} thatMark: - - anchor: {line: 4, character: 0} - active: {line: 4, character: 0} + - anchor: {line: 1, character: 7} + active: {line: 1, character: 12} fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: e}, selectionType: notebookCell, position: contents, insideOutsideType: inside, modifier: {type: identity}}] diff --git a/src/test/suite/fixtures/recorded/surroundingPair/parseTree/takeCore.yml b/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/takeCore.yml similarity index 100% rename from src/test/suite/fixtures/recorded/surroundingPair/parseTree/takeCore.yml rename to src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/takeCore.yml diff --git a/src/test/suite/recorded.test.ts b/src/test/suite/recorded.test.ts index b07dce7697..e4721e5c18 100644 --- a/src/test/suite/recorded.test.ts +++ b/src/test/suite/recorded.test.ts @@ -106,7 +106,9 @@ async function runTest(file: string) { await graph.hatTokenMap.addDecorations(); - const readableHatMap = await graph.hatTokenMap.getReadableMap(false); + const readableHatMap = await graph.hatTokenMap.getReadableMap( + fixture.command.usePrePhraseSnapshot + ); // Assert that recorded decorations are present checkMarks(fixture.initialState.marks, readableHatMap); From 5a09ee23e708cc228485cfd8d9623d0e5e4c708f Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Thu, 26 May 2022 11:12:25 +0100 Subject: [PATCH 203/314] Fixed failing hat map tests --- ...ngPointAndHarpToEndOfThisAndEndOfWhale.yml | 62 ------------------- ...dHarpToEndOfThisAndEndOfWhaleTakeWhale.yml | 2 +- 2 files changed, 1 insertion(+), 63 deletions(-) delete mode 100644 src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhale.yml diff --git a/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhale.yml b/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhale.yml deleted file mode 100644 index 2f60b6a671..0000000000 --- a/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhale.yml +++ /dev/null @@ -1,62 +0,0 @@ -languageId: plaintext -command: - version: 1 - spokenForm: bring point and harp to end of this and end of whale - action: replaceWithTarget - targets: - - type: list - elements: - - type: primitive - mark: {type: decoratedSymbol, symbolColor: default, character: .} - - type: primitive - mark: {type: decoratedSymbol, symbolColor: default, character: h} - - type: list - elements: - - type: primitive - position: after - insideOutsideType: inside - mark: {type: cursor} - - type: primitive - position: after - insideOutsideType: inside - mark: {type: decoratedSymbol, symbolColor: default, character: w} -marksToCheck: [default.w] -initialState: - documentContents: hello. world - selections: - - anchor: {line: 0, character: 12} - active: {line: 0, character: 12} - marks: - default..: - start: {line: 0, character: 5} - end: {line: 0, character: 6} - default.h: - start: {line: 0, character: 0} - end: {line: 0, character: 5} - default.w: - start: {line: 0, character: 7} - end: {line: 0, character: 12} -finalState: - documentContents: hello. world.hello - selections: - - anchor: {line: 0, character: 12} - active: {line: 0, character: 12} - marks: - default..: - start: {line: 0, character: 5} - end: {line: 0, character: 6} - default.h: - start: {line: 0, character: 0} - end: {line: 0, character: 5} - default.w: - start: {line: 0, character: 7} - end: {line: 0, character: 12} - thatMark: - - anchor: {line: 0, character: 12} - active: {line: 0, character: 18} - sourceMark: - - anchor: {line: 0, character: 5} - active: {line: 0, character: 6} - - anchor: {line: 0, character: 0} - active: {line: 0, character: 5} -fullTargets: [{type: list, elements: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: .}, selectionType: token, position: contents, insideOutsideType: null, modifier: {type: identity}}, {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: h}, selectionType: token, position: contents, insideOutsideType: null, modifier: {type: identity}}]}, {type: list, elements: [{type: primitive, mark: {type: cursor}, selectionType: token, position: after, insideOutsideType: inside, modifier: {type: identity}}, {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: w}, selectionType: token, position: after, insideOutsideType: inside, modifier: {type: identity}}]}] diff --git a/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhaleTakeWhale.yml b/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhaleTakeWhale.yml index 3d50804e9d..da58e0d3f5 100644 --- a/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhaleTakeWhale.yml +++ b/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhaleTakeWhale.yml @@ -50,7 +50,7 @@ finalState: end: {line: 0, character: 5} default.w: start: {line: 0, character: 7} - end: {line: 0, character: 12} + end: {line: 0, character: 18} thatMark: - anchor: {line: 0, character: 12} active: {line: 0, character: 18} From 3af398b934b94c8cca7d618ef47c618b14873806 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 26 May 2022 12:31:17 +0200 Subject: [PATCH 204/314] Added sleep option to recorded tests --- .../fixtures/recorded/actions/pourLine.yml | 1 + src/test/suite/recorded.test.ts | 19 ++++++++++++------- src/testUtil/TestCase.ts | 1 + 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/test/suite/fixtures/recorded/actions/pourLine.yml b/src/test/suite/fixtures/recorded/actions/pourLine.yml index 200974a6d2..557db2a4a8 100644 --- a/src/test/suite/fixtures/recorded/actions/pourLine.yml +++ b/src/test/suite/fixtures/recorded/actions/pourLine.yml @@ -1,4 +1,5 @@ languageId: python +sleep: 10 command: spokenForm: pour line version: 2 diff --git a/src/test/suite/recorded.test.ts b/src/test/suite/recorded.test.ts index e4721e5c18..279569f01c 100644 --- a/src/test/suite/recorded.test.ts +++ b/src/test/suite/recorded.test.ts @@ -1,16 +1,17 @@ import * as assert from "assert"; -import serialize from "../../testUtil/serialize"; import { promises as fsp } from "fs"; import * as yaml from "js-yaml"; +import * as sinon from "sinon"; import * as vscode from "vscode"; -import { TestCaseFixture } from "../../testUtil/TestCase"; import HatTokenMap from "../../core/HatTokenMap"; -import * as sinon from "sinon"; -import { Clipboard } from "../../util/Clipboard"; +import { ReadOnlyHatMap } from "../../core/IndividualHatMap"; +import { extractTargetedMarks } from "../../testUtil/extractTargetedMarks"; +import serialize from "../../testUtil/serialize"; import { ExcludableSnapshotField, takeSnapshot, } from "../../testUtil/takeSnapshot"; +import { TestCaseFixture } from "../../testUtil/TestCase"; import { marksToPlainObject, PositionPlainObject, @@ -18,11 +19,11 @@ import { SelectionPlainObject, SerializedMarks, } from "../../testUtil/toPlainObject"; +import { Clipboard } from "../../util/Clipboard"; import { getCursorlessApi } from "../../util/getExtensionApi"; -import { extractTargetedMarks } from "../../testUtil/extractTargetedMarks"; -import asyncSafety from "../util/asyncSafety"; -import { ReadOnlyHatMap } from "../../core/IndividualHatMap"; +import sleep from "../../util/sleep"; import { openNewEditor } from "../openNewEditor"; +import asyncSafety from "../util/asyncSafety"; import { getRecordedTestPaths } from "../util/getFixturePaths"; import { runSingleTest } from "./runSingleRecordedTest"; @@ -69,6 +70,10 @@ async function runTest(file: string) { fixture.languageId ); + if (fixture.sleep != null) { + await sleep(fixture.sleep); + } + if (!fixture.initialState.documentContents.includes("\n")) { await editor.edit((editBuilder) => { editBuilder.setEndOfLine(vscode.EndOfLine.LF); diff --git a/src/testUtil/TestCase.ts b/src/testUtil/TestCase.ts index 28868b0dc5..8e0ae2e86a 100644 --- a/src/testUtil/TestCase.ts +++ b/src/testUtil/TestCase.ts @@ -29,6 +29,7 @@ export type TestCaseContext = { export type TestCaseFixture = { languageId: string; + sleep?: number; command: TestCaseCommand; /** From af9407f8d52caf65e8176f704bf46596a691d7e5 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Thu, 26 May 2022 11:38:13 +0100 Subject: [PATCH 205/314] Verbosity for the win --- src/test/suite/fixtures/recorded/actions/pourLine.yml | 2 +- src/test/suite/recorded.test.ts | 4 ++-- src/testUtil/TestCase.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/suite/fixtures/recorded/actions/pourLine.yml b/src/test/suite/fixtures/recorded/actions/pourLine.yml index 557db2a4a8..0bf41d7ce7 100644 --- a/src/test/suite/fixtures/recorded/actions/pourLine.yml +++ b/src/test/suite/fixtures/recorded/actions/pourLine.yml @@ -1,5 +1,5 @@ languageId: python -sleep: 10 +postEditorOpenSleepTimeMs: 10 command: spokenForm: pour line version: 2 diff --git a/src/test/suite/recorded.test.ts b/src/test/suite/recorded.test.ts index 279569f01c..4936547b23 100644 --- a/src/test/suite/recorded.test.ts +++ b/src/test/suite/recorded.test.ts @@ -70,8 +70,8 @@ async function runTest(file: string) { fixture.languageId ); - if (fixture.sleep != null) { - await sleep(fixture.sleep); + if (fixture.postEditorOpenSleepTimeMs != null) { + await sleep(fixture.postEditorOpenSleepTimeMs); } if (!fixture.initialState.documentContents.includes("\n")) { diff --git a/src/testUtil/TestCase.ts b/src/testUtil/TestCase.ts index 8e0ae2e86a..6979d700b7 100644 --- a/src/testUtil/TestCase.ts +++ b/src/testUtil/TestCase.ts @@ -29,7 +29,7 @@ export type TestCaseContext = { export type TestCaseFixture = { languageId: string; - sleep?: number; + postEditorOpenSleepTimeMs?: number; command: TestCaseCommand; /** From db462c9b7d3f87a8792512711be87c9f77cebc27 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Thu, 26 May 2022 12:31:19 +0100 Subject: [PATCH 206/314] Tweak modify of week stage --- src/actions/WrapWithSnippet.ts | 4 ++-- ...iningScopeStage.ts => ModifyIfWeakStage.ts} | 13 ++++++++----- .../commonWeakContainingScopeStages.ts | 6 +++--- src/processTargets/targets/BaseTarget.ts | 18 +++++++++--------- src/typings/target.types.ts | 2 +- 5 files changed, 23 insertions(+), 20 deletions(-) rename src/processTargets/modifiers/{WeakContainingScopeStage.ts => ModifyIfWeakStage.ts} (55%) diff --git a/src/actions/WrapWithSnippet.ts b/src/actions/WrapWithSnippet.ts index c5b5c98f1c..7b824abbeb 100644 --- a/src/actions/WrapWithSnippet.ts +++ b/src/actions/WrapWithSnippet.ts @@ -1,6 +1,6 @@ import { commands } from "vscode"; import { callFunctionAndUpdateSelections } from "../core/updateSelections/updateSelections"; -import WeakContainingScopeStage from "../processTargets/modifiers/WeakContainingScopeStage"; +import ModifyIfWeakStage from "../processTargets/modifiers/ModifyIfWeakStage"; import { SnippetDefinition } from "../typings/snippet"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; @@ -36,7 +36,7 @@ export default class WrapWithSnippet implements Action { } return [ - new WeakContainingScopeStage({ + new ModifyIfWeakStage({ type: "containingScope", scopeType: { type: defaultScopeType, diff --git a/src/processTargets/modifiers/WeakContainingScopeStage.ts b/src/processTargets/modifiers/ModifyIfWeakStage.ts similarity index 55% rename from src/processTargets/modifiers/WeakContainingScopeStage.ts rename to src/processTargets/modifiers/ModifyIfWeakStage.ts index 113519d855..6d31899e90 100644 --- a/src/processTargets/modifiers/WeakContainingScopeStage.ts +++ b/src/processTargets/modifiers/ModifyIfWeakStage.ts @@ -1,17 +1,20 @@ -import { ContainingScopeModifier, Target } from "../../typings/target.types"; +import { Modifier, Target } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import getModifierStage from "../getModifierStage"; import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { - constructor(private nestedModifier: ContainingScopeModifier) {} + private nestedStage: ModifierStage; + + constructor(nestedModifier: Modifier) { + this.nestedStage = getModifierStage(nestedModifier); + } run(context: ProcessedTargetsContext, target: Target): Target[] { if (target.isWeak) { - const stage = getModifierStage(this.nestedModifier); - return stage + return this.nestedStage .run(context, target) - .map((newTarget) => newTarget.withWeakTarget(target)); + .map((newTarget) => newTarget.withThatTarget(target)); } return [target]; } diff --git a/src/processTargets/modifiers/commonWeakContainingScopeStages.ts b/src/processTargets/modifiers/commonWeakContainingScopeStages.ts index 3f4aee6271..22ed334c4e 100644 --- a/src/processTargets/modifiers/commonWeakContainingScopeStages.ts +++ b/src/processTargets/modifiers/commonWeakContainingScopeStages.ts @@ -1,11 +1,11 @@ -import WeakContainingScopeStage from "./WeakContainingScopeStage"; +import ModifyIfWeakStage from "./ModifyIfWeakStage"; -export const weakContainingSurroundingPairStage = new WeakContainingScopeStage({ +export const weakContainingSurroundingPairStage = new ModifyIfWeakStage({ type: "containingScope", scopeType: { type: "surroundingPair", delimiter: "any" }, }); -export const weakContainingLineStage = new WeakContainingScopeStage({ +export const weakContainingLineStage = new ModifyIfWeakStage({ type: "containingScope", scopeType: { type: "line" }, }); diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index 8dfe5fd9da..dac62b302e 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -14,7 +14,7 @@ export function extractCommonParameters(parameters: CommonTargetParameters) { isReversed: parameters.isReversed, contentRange: parameters.contentRange, position: parameters.position, - weakTarget: parameters.weakTarget, + thatTarget: parameters.thatTarget, }; } @@ -24,12 +24,12 @@ export interface CommonTargetParameters { isReversed: boolean; contentRange: Range; position?: Position; - weakTarget?: Target; + thatTarget?: Target; } export interface CloneWithParameters { position?: Position; - weakTarget?: Target; + thatTarget?: Target; } export interface BaseTargetParameters extends CommonTargetParameters { @@ -44,7 +44,7 @@ interface BaseTargetState { readonly editor: TextEditor; readonly isReversed: boolean; readonly contentRange: Range; - readonly weakTarget?: Target; + readonly thatTarget?: Target; readonly delimiter: string; readonly removalRange?: Range; readonly leadingDelimiter?: RemovalRange; @@ -65,7 +65,7 @@ export default abstract class BaseTarget implements Target { removalRange: parameters.removalRange, leadingDelimiter: parameters.leadingDelimiter, trailingDelimiter: parameters.trailingDelimiter, - weakTarget: parameters.weakTarget, + thatTarget: parameters.thatTarget, }; } @@ -98,8 +98,8 @@ export default abstract class BaseTarget implements Target { } get thatTarget(): Target { - return this.state.weakTarget != null - ? this.state.weakTarget.thatTarget + return this.state.thatTarget != null + ? this.state.thatTarget.thatTarget : this; } @@ -262,8 +262,8 @@ export default abstract class BaseTarget implements Target { return this.cloneWith({ position }); } - withWeakTarget(weakTarget: Target): Target { - return this.cloneWith({ weakTarget }); + withThatTarget(thatTarget: Target): Target { + return this.cloneWith({ thatTarget }); } abstract cloneWith(parameters: CloneWithParameters): Target; diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index e858d4a79f..29843f2945 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -310,5 +310,5 @@ export interface Target { getRemovalHighlightRange(): Range | undefined; getEditNewContext(isBefore: boolean): EditNewContext; withPosition(position: Position): Target; - withWeakTarget(weakTarget: Target): Target; + withThatTarget(thatTarget: Target): Target; } From 0f307fccfd59ebaf689e92ceee91ed45dbfc60ab Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Thu, 26 May 2022 12:37:02 +0100 Subject: [PATCH 207/314] Minor python cleanup --- .../src/modifiers/surrounding_pair.py | 6 +- failing-tests.txt | 2953 +++++++++++++++++ 2 files changed, 2955 insertions(+), 4 deletions(-) create mode 100644 failing-tests.txt diff --git a/cursorless-talon/src/modifiers/surrounding_pair.py b/cursorless-talon/src/modifiers/surrounding_pair.py index 7dbd359263..92f990bb1a 100644 --- a/cursorless-talon/src/modifiers/surrounding_pair.py +++ b/cursorless-talon/src/modifiers/surrounding_pair.py @@ -1,3 +1,4 @@ +from contextlib import suppress from typing import Any from talon import Context, Module @@ -23,9 +24,6 @@ ) -import contextlib - - @mod.capture( rule=( " |" @@ -57,7 +55,7 @@ def cursorless_surrounding_pair(m) -> dict[str, Any]: "delimiter": surrounding_pair_scope_type, } - with contextlib.suppress(AttributeError): + with suppress(AttributeError): scope_type["forceDirection"] = m.cursorless_delimiter_force_direction return { diff --git a/failing-tests.txt b/failing-tests.txt new file mode 100644 index 0000000000..e0c696801a --- /dev/null +++ b/failing-tests.txt @@ -0,0 +1,2953 @@ +Activating tree-sitter... +Activating tree-sitter... +Creating communication dir /var/folders/cr/8g7qm5_j7z31ltt30_4s5tdc0000gn/T/vscode-command-server-501 +Creating communication dir /var/folders/cr/8g7qm5_j7z31ltt30_4s5tdc0000gn/T/vscode-command-server-501 + + Backward compatibility + ✓ Backward compatibility (163ms) + breakpoints + ✓ breakpoint harp add (91ms) + ✓ breakpoint token harp add (45ms) + ✓ breakpoint harp remove (39ms) + ✓ breakpoint token harp remove (47ms) + Cross-cell set selection + ✓ Cross-cell set selection (1062ms) + Edit new cell + ✓ drink cell (1146ms) + ✓ pour cell (1090ms) + Extension Test Suite + ✓ Sample test + fold + ✓ fold made (1082ms) + ✓ unfold made (245ms) + followLink + ✓ follow definition (122ms) + ✓ follow link (153ms) + Group by document + ✓ Group by document (137ms) + inferFullTargets + - inferFullTargets 0 + - inferFullTargets 1 + - inferFullTargets 2 + - inferFullTargets 3 + - inferFullTargets 4 + - inferFullTargets 5 + - inferFullTargets 6 + - inferFullTargets 7 + - inferFullTargets 8 + - inferFullTargets 9 + - inferFullTargets 10 + - inferFullTargets 11 + - inferFullTargets 12 + - inferFullTargets 13 + - inferFullTargets 14 + - inferFullTargets 15 + - inferFullTargets 16 + - inferFullTargets 17 + - inferFullTargets 18 + - inferFullTargets 19 + - inferFullTargets 20 + - inferFullTargets 21 + - inferFullTargets 22 + - inferFullTargets 23 + - inferFullTargets 24 + - inferFullTargets 25 + - inferFullTargets 26 + - inferFullTargets 27 + - inferFullTargets 28 + - inferFullTargets 29 + - inferFullTargets 30 + - inferFullTargets 31 + - inferFullTargets 32 + - inferFullTargets 33 + - inferFullTargets 34 + - inferFullTargets 35 + - inferFullTargets 36 + - inferFullTargets 37 + - inferFullTargets 38 + - inferFullTargets 39 + - inferFullTargets 40 + - inferFullTargets 41 + - inferFullTargets 42 + - inferFullTargets 43 + - inferFullTargets 44 + - inferFullTargets 45 + - inferFullTargets 46 + - inferFullTargets 47 + - inferFullTargets 48 + - inferFullTargets 49 + - inferFullTargets 50 + - inferFullTargets 51 + - inferFullTargets 52 + - inferFullTargets 53 + - inferFullTargets 54 + Pre-phrase snapshots + ✓ Pre-phrase snapshot; single phrase (88ms) + ✓ Pre-phrase snapshot; multiple phrase (61ms) + ✓ No snapshot; single phrase (61ms) + ✓ No snapshot; multiple phrase (49ms) + recorded test cases + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/bringAirAndBatAndCap (70ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/bringAirAndBatAndCapToAfterDrum (63ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/bringAirAndBatAndCapToAfterItemEach (75ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/bringAirAndBatAndCapToBeforeDrum (70ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/bringAirAndBatAndCapToBeforeItemEach (68ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/bringArgueFineAndZip (72ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/bringArgueOxAndZipToAfterJustLeper (64ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/bringLineAirAndBatAndCapToAfterDrum (90ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/bringLineAirAndBatAndCapToBeforeDrum (71ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/bringLineHarpAndWhale (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/bringVest (63ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/bringVestToCap (55ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/callFine (68ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/callVest (60ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/callVestOnCap (62ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/carveVest (71ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/chuckArgMadeAndAir (73ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/chuckArgMadeAndAirAndJustSoon (71ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/chuckEveryArgMade (82ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/chuckVest (93ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/clearVest (62ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/cloneEveryArg (67ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/cloneHarp (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/cloneHarp2 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/cloneUpEveryArg (57ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/cloneUpHarp (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/cloneUpHarp2 (42ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/cloneUpVest (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/cloneVest (43ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/commentVest (74ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/copyVest (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/curlyRepackRound (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/customHarp (384ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/cutEveryArgMade (82ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/dedentVest (66ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/defineVest (79ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/drinkArg (89ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/drinkBlock (66ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/drinkLine (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/drinkVest (61ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/dropVest (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/findVest (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/floatVest (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveAfterDot (54ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveAirAndBang (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveBat (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveBat2 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveBeforeDot (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveBlueQuote (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveBlueQuoteAndQuote (56ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveCap (58ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveDot (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveDot2 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveDrum (53ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveEqualsPastColon (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveHarp (54ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveHarpAndWhale (58ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveQuote (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveQuoteAndAir (61ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveQuoteAndBang (57ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveVestAndHarp (63ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/indentVest (76ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/moveEveryArgMade (92ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/moveVest (68ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/moveVestToCap (57ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/pasteCap (85ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/phonesSpy (58ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/postVest (70ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/pourArg (79ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/pourBlock (67ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/pourLine (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/pourVest (61ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/preeVest (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/puffVest (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/reformatHarpAsSnake (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/reformatHarpAsSnake2 (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/replaceAirAndBatAndCapWithCount (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/replaceVestWithWhatever (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/reverseAirAndBatAndCap (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/roundWrapThis (64ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/roundWrapVest (67ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/roundWrapVest2 (65ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/shuffleThis (58ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/sortAirAndCapAndBat (57ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/squareRepackHarp (57ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/squareRepackLeper + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/squareRepackPair (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/squareRepackThis (38ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/swapVestWithCap (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/swapWithVest (59ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/takeLast (53ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/takeVest (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/bringAirToAfterBatVerticalPastFine (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/bringAirToBatVerticalPastFine (54ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/bringAirToBeforeBatVerticalPastFine (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/bringAirToEndOfBatVerticalPastFine (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/bringAirToStartOfBatVerticalPastFine (47ms) + 1) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachBetweenHarp + 2) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachUntilHarp + 3) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachBetweenHarp +TextEditor#edit not possible on closed editors +Error: TextEditor#edit not possible on closed editors + at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) + at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) + at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) + at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) + at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) + at performEditsAndUpdateInternal (/Users/pokey/src/cursorless-vscode/dist/extension.js:5805:9) + at performEditsAndUpdateRanges (/Users/pokey/src/cursorless-vscode/dist/extension.js:5802:10) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:10753:37 + at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 + at Array.map () + at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) + at runOnTargetsForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6285:10) + at Delete.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10746:57) + at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +TextEditor#edit not possible on closed editors +Error: TextEditor#edit not possible on closed editors + at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) + at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) + at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) + at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) + at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) + at performEditsAndUpdateInternal (/Users/pokey/src/cursorless-vscode/dist/extension.js:5805:9) + at performEditsAndUpdateRanges (/Users/pokey/src/cursorless-vscode/dist/extension.js:5802:10) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:10753:37 + at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 + at Array.map () + at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) + at runOnTargetsForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6285:10) + at Delete.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10746:57) + at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +TextEditor#edit not possible on closed editors +Error: TextEditor#edit not possible on closed editors + at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) + at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) + at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) + at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) + at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) + at performEditsAndUpdateInternal (/Users/pokey/src/cursorless-vscode/dist/extension.js:5805:9) + at performEditsAndUpdateRanges (/Users/pokey/src/cursorless-vscode/dist/extension.js:5802:10) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:10753:37 + at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 + at Array.map () + at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) + at runOnTargetsForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6285:10) + at Delete.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10746:57) + at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +TextEditor#edit not possible on closed editors +Error: TextEditor#edit not possible on closed editors + at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) + at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) + at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) + at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) + at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) + at performEditsAndUpdateInternal (/Users/pokey/src/cursorless-vscode/dist/extension.js:5805:9) + at performEditsAndUpdateRanges (/Users/pokey/src/cursorless-vscode/dist/extension.js:5802:10) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:10753:37 + at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 + at Array.map () + at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) + at runOnTargetsForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6285:10) + at Delete.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10746:57) + at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +TextEditor#edit not possible on closed editors +Error: TextEditor#edit not possible on closed editors + at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) + at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) + at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) + at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) + at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) + at performEditsAndUpdateInternal (/Users/pokey/src/cursorless-vscode/dist/extension.js:5805:9) + at performEditsAndUpdateRanges (/Users/pokey/src/cursorless-vscode/dist/extension.js:5802:10) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:10753:37 + at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 + at Array.map () + at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) + at runOnTargetsForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6285:10) + at Delete.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10746:57) + at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +TextEditor#edit not possible on closed editors +Error: TextEditor#edit not possible on closed editors + at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) + at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) + at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) + at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) + at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) + at performEditsAndUpdateInternal (/Users/pokey/src/cursorless-vscode/dist/extension.js:5805:9) + at performEditsAndUpdateRanges (/Users/pokey/src/cursorless-vscode/dist/extension.js:5802:10) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:10753:37 + at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 + at Array.map () + at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) + at runOnTargetsForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6285:10) + at Delete.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10746:57) + at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) + 4) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachBetweenHarp2 + 5) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachUntilHarp + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/postBatVerticalUntilFine (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/preBatVerticalBetweenFine + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/takeBatVerticalPastFine + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/takeCapAndVestAndHarp (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/takeCapPastHarp (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/takeFineVerticalPastBat (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/takeHarpAndVestAndCap (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/takeHarpPastCap (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/takeLineVestAndAir (68ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/takePastEndOfToken (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/takePastStartOfToken (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/takePastTrap (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/takeTokenPastTrap (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/takeVerticalPastFine (71ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/takeVestTweenWhale (77ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/takeVestUntilWhale (60ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/takeWhaleTweenVest (170ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/takeWhaleUntilVest (97ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringAirToThirdCarWhaleTakeWhale (86ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringCommaToEndOfPointTakePoint (82ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringCommaToStartOfPointTakePoint (75ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAfterWhaleTakeWhale (52ms) + 6) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToEndOfThisAndEndOfWhaleTakeWhale + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToThisAndStartOfWhaleTakeWhale (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpBeforeWhaleTakeWhale (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpTakeWhale (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpToEndOfPointTakePoint (53ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpToStartOfPointTakePoint (61ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpToStartOfWhaleTakeWhale (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAfterFirstCarWhaleTakeWhale (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfSecondCarWhaleAndEndOfWhaleTakeWhale (50ms) + 7) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhale + 8) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhaleTakeWhale + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToStartOfSecondCarWhaleAndStartOfWhaleTakeWhale (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToThisAndStartOfWhaleTakeWhale (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndPointToEndOfSecondCarWhaleAndEndOfWhaleTakeWhale (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndPointToStartOfSecondCarWhaleAndStartOfWhaleTakeWhale (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringPointToEndOfWhaleTakeWhale (43ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringPointToStartOfWhaleTakeWhale (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringPointToThirdCarWhaleTakeWhale (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/chuckFirstTwoCarWhaleTakeWhale (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/chuckFourthCarWhalePastThirdCarAirTakeWhale (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/chuckHarpPastAirTakeWhale (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/chuckLastTwoCarWhaleTakeWhale (74ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/chuckSecondPastThirdCarWhaleTakeWhale (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/chuckThirdCarHarpPastSecondCarWhaleTakeWhale (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/moveFourthCarHarpPastSecondCarWhaleToEndOfWhaleTakeWhale (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/takeHarp (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/headTail/takeHead (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/headTail/takeHeadVest (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/headTail/takeTail (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/headTail/takeTailVest (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/bringLineBatPastEndOfFunkToThis (69ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/bringLineLookToJustAir (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/bringMapAirToLineHarp (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/bringMapAirToTokenHarp (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/bringOddToLine (63ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/bringOddToState (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/bringOddToToken (61ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/bringTokenHarpToMapAir (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/ifWrapTokenFine (68ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeAfterVestPastAir (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeAfterVestPastBeforeAir (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeAirPastEndOfLine (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeEachPastStartOfLine (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeFirstWord (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeHarpAndStringEach (59ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeHarpPastStringEach (59ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeLastChar (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeLinePastAir (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeLineVestAndAir (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeLineVestPastAir (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeOddPastEndOfState (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeOddPastLine (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeOddPastState (53ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeOddPastToken (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takePastLineAir (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeStringHarpAndEach (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeStringHarpPastEach (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeVestAndLineAir (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeVestPastAfterAir (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeVestPastBeforeAir (38ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeVestPastLineAir (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/c/clearFunk (70ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/chuckItemFine (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/chuckItemFine2 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/chuckItemZip + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/chuckItemZip2 (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearArgue (56ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearArgue2 (58ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearArgue3 (43ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearCall (42ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearCall2 (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearComment (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearCondition (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearEveryItem (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearEveryKey (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearEveryValue (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearFunk (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearFunk2 (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearIfState (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearItem (38ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearItem2 (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearItem3 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearItem4 (43ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearItem5 (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearItem6 (53ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearItemBat (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearItemBatClearItemBat (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearItemFine (54ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearItemWhale (54ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearItemZip (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearKey (42ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearKeyWhale (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearKeyWhale2 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearKeyZip (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearKeyZip2 (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearLambda (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearLambda2 (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearList (56ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearList2 (53ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearMap (54ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearName (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearName2 (63ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearValueBat (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearValueZip (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/takeValue (42ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/takeValueBat (38ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/takeValueBat2 (43ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/takeValueFine (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/takeValueFine2 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/takeValueWhale (38ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/takeValueZip + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/takeValueZip2 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/chuckTypeAir (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/chuckTypeSoon (155ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/chuckValue (164ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/clearName (61ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/clearValue (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/elseStateWrapThis (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/ifElseWrapThis (53ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/ifStateWrapThis (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeArg (66ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeArg2 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeAttribute (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeCall + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeClass (99ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeClass2 (105ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeClassName (64ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeClassName2 (64ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeClassName3 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeComment (42ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeEveryArg + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeEveryItem (69ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeFunk + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeFunk2 (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeFunkName + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeFunkName2 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeFunkName3 (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeIf + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeIf2 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeItem + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeItem2 (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeLambda + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeList (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeList2 (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeName + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeName2 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeName3 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeState + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeState2 (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeState3 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeString + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeType (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeType2 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeType3 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeValue (42ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeValue2 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeValue3 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/tryCatchWrapThis (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/tryCatchWrapThis2 (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/csharp/chuckTypeSoon (64ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/csharp/chuckTypeSoon2 (57ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/csharp/chuckValue (56ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/csharp/clearName (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/csharp/clearName2 (43ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/csharp/clearName3 (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/csharp/clearValue (42ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/csharp/clearValue2 (57ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/csharp/clearValue3 (65ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/csharp/elseStateWrapThis (55ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/csharp/ifElseWrapThis (53ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/csharp/ifStateWrapThis (58ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/csharp/tryCatchWrapThis (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/csharp/tryCatchWrapThis2 (54ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeArgue (143ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeArgue2 (77ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeArgue3 (78ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeArgue4 (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeArgue5 (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeComment (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeEveryArgue (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeEveryArgue2 (54ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeEveryArgue3 (82ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeItem (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeKey (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeKey2 (62ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeName (56ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeName2 (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeName3 (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeName6 (77ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeRound (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeSelector (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeSelector2 (56ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeSelector3 (56ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeSelector4 (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeSelector5 (61ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeState (53ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeState5 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeStateAir (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeStateHarp (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeValue (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeValue2 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeValue4 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeValue6 (78ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeValue9 (63ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/chuckArgue (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/chuckArgue2 (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/chuckArgue3 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/chuckArgue4 (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/chuckArgue5 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/chuckArgue6 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/chuckArgue7 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/chuckArgue8 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/chuckEveryArgue2 (53ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/chuckState (58ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/chuckState2 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/chuckValue (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/chuckValue2 (58ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/chuckValue3 (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/chuckArg (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/chuckArg2 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/chuckValue (43ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/clearCondition (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/clearIfState (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/clearPair (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/clearState (43ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeArg (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeArg2 (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeArg3 (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeCall (43ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeComment (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeEveryItem (60ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeEveryKey + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeFunk + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeFunkName (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeItem + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeKey + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeKey2 (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeList (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeMap (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeState (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeString (38ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeType + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeValue + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeValue2 (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/html/chuckValueInk (175ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/html/clearAttributeVest (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/html/clearComment (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/html/clearElement (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/html/clearEndTag (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/html/clearKey (42ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/html/clearName (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/html/clearStartTag (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/html/clearString (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/html/clearTags (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/chuckTypeNear (62ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/chuckTypeUrge (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/chuckValue (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/clearName (54ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/clearState (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/clearState2 (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/clearValue (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/elseStateWrapThis (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/ifElseWrapThis (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/ifStateWrapThis (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeArg (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeArg2 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeCall + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeClass + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeClassName + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeComment + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeCondition (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeCondition2 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeCondition3 (75ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeEveryArg + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeEveryArg2 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeEveryItem (38ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeFunk (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeFunk2 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeFunkName + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeFunkName2 (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeIf (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeItem (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeList + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeMap + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeName + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeName2 (43ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeName3 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeState + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeString + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeType + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeType2 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeType3 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeTypeBlueLook (43ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeTypeGust + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeTypeGust2 (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeTypeHarp + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeTypeLook (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeTypePit + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeTypeSoon (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeTypeSoon2 (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeTypeTrap (38ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeTypeTrap2 (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeTypeYank (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeValue (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/tryCatchWrapThis (84ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/tryCatchWrapThis2 (53ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/json/takeItem (137ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/json/takeItem2 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/json/takeKey (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/json/takeList (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/json/takeString (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/json/takeValue (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/jsx/takeAttribute (83ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/jsx/takeElement (113ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/jsx/takeEndTag (66ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/jsx/takeEveryAttribute (66ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/jsx/takeKey (86ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/jsx/takeStartTag (93ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/jsx/takeTags (64ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/jsx/takeValue (67ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/markdown/changeName (64ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/markdown/changeName2 (55ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/markdown/changeOneSection (114ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/markdown/changeOneSection2 (65ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/markdown/changeSection (56ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/markdown/changeSection2 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/markdown/changeSection3 (69ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/markdown/changeSection4 (70ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/markdown/changeSection5 (55ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/markdown/changeSection6 (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/markdown/chuckItem (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/markdown/chuckName (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/markdown/clearComment (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/markdown/clearItem (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/markdown/clearList (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeArg (122ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeArg10 (94ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeArg2 (63ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeArg3 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeArg4 (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeArg5 (64ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeArg6 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeArg7 (64ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeArg8 (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeArg9 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeCall (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeCall2 (73ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeClass (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeClassName (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeComment (64ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeEveryArg (91ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeEveryItem (57ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeFunk (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeFunkName (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeFunkName2 (65ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeIfState (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeItem (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeItem2 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeItem3 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeItem4 (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeItem5 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeKey (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeKey2 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeLambda (57ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeLambda2 (55ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeLambda3 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeLambda4 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeName (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeName2 (76ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeName3 (62ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeName4 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeName5 (53ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeName6 (58ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeRound (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeString (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeString2 (59ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeType (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeType2 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeType3 (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeType4 (62ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeType5 (56ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeType6 (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeValue (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeValue2 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeValue3 (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeValue4 (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeValue5 (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeValue6 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeValue7 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckArg (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckArg10 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckArg2 (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckArg3 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckArg4 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckArg5 (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckArg6 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckArg7 (38ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckArg8 (43ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckArg9 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckEveryArg (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckEveryItem (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckFunk (38ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckFunk2 (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckInside + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckItem + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckItem2 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckItem3 (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckItem4 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckItem5 (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckKey (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckKey2 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckPair (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckType + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckType2 (67ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckType3 (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckType4 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckType5 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckValue (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckValue10 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckValue2 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckValue3 (38ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckValue4 (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckValue5 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckValue6 (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckValue7 (38ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckValue8 (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckValue9 (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/elseWrapThis (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/ifElseWrapThis (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/ifWrapThis (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/tryWrapThis (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/tryWrapThis2 (64ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/chuckArgDrum (60ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/chuckArgFine (60ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/chuckArgWhale (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/chuckEveryArgAir (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/chuckEveryArgRed (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/chuckEveryArgSit (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/chuckKey (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/chuckKey2 (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/chuckType (42ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/chuckTypeSoon + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/chuckTypeTrap (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/chuckValue (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/chuckValue2 (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/chuckValue3 (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/clearEveryValue (61ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/clearName (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/clearValue + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/clearValue2 (43ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/clearValue3 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/elseStateWrapThis (90ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/ifElseWrapThis (57ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/ifStateWrapThis (56ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeArg (43ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeArg2 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeArgDrum (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeArgRed (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeArgWhale + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeCall + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeClass + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeClass2 (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeClassName + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeComment (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeCondition (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeCondition2 (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeEveryArg + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeEveryArg2 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeEveryItem + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeEveryItem2 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeEveryItem3 (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeFunk (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeFunk2 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeFunkName + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeIf (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeItem + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeItem2 (38ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeItem3 (42ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeKey + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeLambda (65ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeLambdaMade (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeLambdaPit + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeList + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeList2 (38ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeMap (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeName + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeName2 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeName3 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeState + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeString + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeType + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeType2 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeValue (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeValue2 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeValueZero (59ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/tryCatchWrapThis (81ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/tryCatchWrapThis2 (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeArg (157ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeArgWhale (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeArgWhale2 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeArgWhale3 (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeCall (42ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeClass (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeComment (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeComment2 (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeComment3 (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeCondition (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeEveryArg (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeEveryArg2 (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeEveryArg3 (42ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeEveryItem (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeEveryKey (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeEveryKey2 (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeEveryKey3 (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeEveryKey4 (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeFunk (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeIfState (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeItemThis (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeKey (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeKey2 (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeLambda (42ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeLambda2 (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeLambda3 (85ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeLambda4 (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeLambda5 (64ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeList (59ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeList2 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeList3 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeMap (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeName (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeName2 (60ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeNameThis (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeRegex (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeRound (56ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeRound2 (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeState (54ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeState2 (56ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeState3 (63ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeState4 (53ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeState5 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeString (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeString2 (55ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeValue (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckArg (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckArg2 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckArg3 (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckEveryArg (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckEveryArg2 (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckEveryItem (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckItem (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckItem2 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckItem3 (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckItem4 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckItem5 (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckItem6 (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckItem7 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckNameThis (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckNameThis2 (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckState (57ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckState10 (53ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckState11 (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckState2 (38ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckState3 (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckState4 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckState5 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckState6 (42ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckState7 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckState8 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckState9 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckValue (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckValue2 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckValue3 (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckValue5 (60ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckValue6 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/clearState (53ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/clearState2 (55ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckArgFine (284ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckArgFine2 (126ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckArgFine3 (64ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckConditionFine (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeBat + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeFine (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeFine2 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeFine3 (38ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeLook + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeLook2 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeLook3 (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeOdd (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeOdd2 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeOdd3 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeRed (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeRed2 (38ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeSit + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeSit2 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeSun + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeSun2 (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeSun3 (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeSun4 (38ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeSun5 (42ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeTrap + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckValue + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckValueOdd (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckValueRed + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckValueSit (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearArgFine (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearArgFine2 (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearArgFine3 (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearCallMade (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearClass (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearClass2 (43ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearClass3 (42ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearClass4 (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearClassName + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearClassName2 (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearClassName3 (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearClassName4 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearComment (38ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearComment2 (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearConditionEquals + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearConditionFine (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearFunkFour (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearFunkNameFour (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearIfState (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearIfState2 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearLambdaPlus (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearLambdaPlus2 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearLambdaPlus3 (83ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearName (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearNameFour (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearNameFour2 (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearRoundWhale (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearRoundWhale2 (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearString (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearString2 (42ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearStringOdd (54ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearType (38ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeBat (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeComma (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeFine (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeFine2 (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeFine3 (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeLook (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeLook2 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeLook3 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeOdd (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeOdd2 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeOdd3 (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeRed (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeRed2 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeSit (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeSit2 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeSun (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeSun2 (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeSun3 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeSun4 (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeSun5 (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeTrap (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearValue (60ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearValueOdd (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearValueRed (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearValueSit (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeArgue (63ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeArgue2 (124ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeArgue3 (92ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeArgue4 (77ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeArgue5 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeArgue6 (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeComment (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeComment2 (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeEveryArgue (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeEveryArgue2 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeEveryArgue3 (62ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeFunk (85ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeFunk2 (81ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeItem (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeKey (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeKey2 (63ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeName (55ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeName2 (122ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeName3 (130ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeName4 (61ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeName5 (55ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeName6 (66ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeName7 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeName8 (80ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeName9 (74ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeRound (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeSelector (55ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeSelector2 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeSelector3 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeState (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeState4 (66ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeState5 (56ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeState6 (57ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeStateAir (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeStateHarp (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeValue (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeValue10 (78ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeValue11 (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeValue12 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeValue13 (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeValue14 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeValue15 (60ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeValue2 (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeValue3 (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeValue4 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeValue5 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeValue6 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeValue7 (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeValue8 (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeValue9 (53ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/chuckArgue (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/chuckArgue2 (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/chuckArgue3 (69ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/chuckArgue4 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/chuckArgue5 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/chuckArgue6 (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/chuckArgue7 (91ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/chuckArgue8 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/chuckArgue9 (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/chuckEveryArgue (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/chuckState (83ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/chuckState2 (55ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/chuckValue (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/chuckValue2 (83ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/chuckValue3 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/changeFunk (74ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/changeName (83ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/changeValue (70ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/chuckKey (70ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/chuckTypeRam (99ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/chuckTypeSoon (95ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/chuckTypeSoon2 (75ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/chuckTypeTrap (69ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/chuckTypeYank (80ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/chuckValue (91ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearFunk (82ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearFunk2 (87ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearKey (65ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearLambda (93ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearLambda2 (72ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearLambda3 (63ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearLambda4 (77ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearName (70ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearType (76ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearType2 (83ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearTypeAir (67ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearTypeBat (71ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearTypeLangle (63ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearTypeNear (92ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearTypeNear2 (74ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearTypeOx (61ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearTypeOx2 (63ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearTypeUrge (66ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearTypeWhale (58ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearTypeWrangle (62ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearValue (59ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/elseStateWrapThis (68ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/ifElseWrapThis (66ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/ifStateWrapThis (66ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeArg (54ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeArg2 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeArrow (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeCall (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeClass (53ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeClassName (60ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeComment (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeCondition (82ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeCondition2 (68ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeCondition3 (64ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeEveryArgAir (58ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeEveryArgBat (54ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeEveryArgRam (53ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeEveryItem (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeEveryItem2 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeEveryItem3 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeEveryItem4 (58ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeEveryItem5 (53ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeEveryKey (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeEveryKey2 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeEveryValue (53ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeEveryValue2 (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunk (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunk10 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunk11 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunk12 (56ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunk13 (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunk2 (89ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunk3 (66ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunk4 (54ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunk5 (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunk6 (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunk7 (55ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunk8 (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunk9 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunkCap (61ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunkMade (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunkMade2 (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunkName (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunkName10 (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunkName11 (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunkName2 (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunkName3 (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunkName4 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunkName5 (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunkName6 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunkName7 (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunkName8 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunkName9 (61ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunkSoon (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeIf (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeItem (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeItem2 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeItem3 (62ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeItem4 (62ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeItemAir (64ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeItemBrace (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeItemComma (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeItemOne (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeKey (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeList (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeList2 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeMap (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeMap2 (62ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeName (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeName2 (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeRegex (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeState (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeState2 (53ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeString (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeType (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeType2 (60ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeValue (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeValue2 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeValue3 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeValue4 (48ms) + 9) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/tryCatchWrapThis + 10) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/tryCatchWrapThis2 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/xml/clearAtHerThen (67ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/xml/clearCore (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/xml/clearCore2 (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/xml/clearEli (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/xml/clearEndTag (42ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/xml/clearEveryAtHer (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/xml/clearEveryEli (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/xml/clearEveryTags (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/xml/clearKeyThen (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/xml/clearName (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/xml/clearPair (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/xml/clearPair2 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/xml/clearRound (66ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/xml/clearStartTag (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/xml/clearTags (61ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/xml/scratchClearValue (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/lineEndings/chuckVestLF (55ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/lineEndings/chuckVestLFCR (66ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/lineEndings/dropVestLF (54ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/lineEndings/dropVestLFCR (57ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/marks/chuckNothing (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/marks/highlightHarp + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/marks/takeDownOne (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/marks/takeDownOnePastThree (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/marks/takeRowFive (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/marks/takeRowFour (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/marks/takeRowOne (60ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/marks/takeRowTwoPastDownThree (55ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/marks/takeRowTwoPastFour (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/marks/takeSource (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/marks/takeThat (68ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/marks/takeThis (57ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/marks/takeUpOnePastDownOne (55ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/marks/takeUpOnePastRowFour (50ms) +Couldn't find mark default 'h' +Error: Couldn't find mark default 'h' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +Couldn't find mark default 'h' +Error: Couldn't find mark default 'h' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +Couldn't find mark default 'h' +Error: Couldn't find mark default 'h' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +Couldn't find mark default 'h' +Error: Couldn't find mark default 'h' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +Couldn't find mark default 'h' +Error: Couldn't find mark default 'h' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +Couldn't find mark default 'h' +Error: Couldn't find mark default 'h' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) + 11) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/bringHarpToAfterFile +TextEditor#edit not possible on closed editors +Error: TextEditor#edit not possible on closed editors + at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) + at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) + at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) + at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) + at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 + at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 + at Array.map () + at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) + at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) + at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) + at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +TextEditor#edit not possible on closed editors +Error: TextEditor#edit not possible on closed editors + at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) + at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) + at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) + at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) + at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 + at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 + at Array.map () + at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) + at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) + at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) + at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +TextEditor#edit not possible on closed editors +Error: TextEditor#edit not possible on closed editors + at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) + at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) + at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) + at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) + at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 + at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 + at Array.map () + at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) + at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) + at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) + at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +TextEditor#edit not possible on closed editors +Error: TextEditor#edit not possible on closed editors + at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) + at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) + at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) + at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) + at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 + at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 + at Array.map () + at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) + at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) + at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) + at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +TextEditor#edit not possible on closed editors +Error: TextEditor#edit not possible on closed editors + at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) + at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) + at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) + at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) + at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 + at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 + at Array.map () + at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) + at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) + at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) + at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +TextEditor#edit not possible on closed editors +Error: TextEditor#edit not possible on closed editors + at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) + at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) + at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) + at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) + at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 + at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 + at Array.map () + at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) + at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) + at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) + at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) + 12) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/bringStateFineToAfterBatt +Couldn't find mark default 'w' +Error: Couldn't find mark default 'w' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +Couldn't find mark default 'w' +Error: Couldn't find mark default 'w' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +Couldn't find mark default 'w' +Error: Couldn't find mark default 'w' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +Couldn't find mark default 'w' +Error: Couldn't find mark default 'w' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +Couldn't find mark default 'w' +Error: Couldn't find mark default 'w' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +Couldn't find mark default 'w' +Error: Couldn't find mark default 'w' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) + 13) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/bringWhaleToBeforeFile + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckAfterBlockVest (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckAfterHarp + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckAfterLineVest (38ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckAfterLook (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckAfterVest (53ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckAir (65ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckBeforeAir (69ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckBeforeBlockAir (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckBeforeEach (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckBeforeHarp (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckBeforeLineAir (71ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckBeforeVest (58ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckPastAfterLook (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckPastBeforeTrap (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckPastEndOfLine (42ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckPastEndOfLook (38ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckPastStartOfTrap (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/replaceAfterVestWithHallo + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/replaceBeforeVestWithHello (53ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/replaceEndOfVestWithHello (42ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/replaceStartOfVestWithHello (46ms) +TextEditor#edit not possible on closed editors +Error: TextEditor#edit not possible on closed editors + at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) + at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) + at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) + at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) + at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 + at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 + at Array.map () + at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) + at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) + at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) + at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +TextEditor#edit not possible on closed editors +Error: TextEditor#edit not possible on closed editors + at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) + at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) + at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) + at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) + at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 + at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 + at Array.map () + at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) + at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) + at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) + at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +TextEditor#edit not possible on closed editors +Error: TextEditor#edit not possible on closed editors + at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) + at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) + at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) + at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) + at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 + at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 + at Array.map () + at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) + at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) + at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) + at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +TextEditor#edit not possible on closed editors +Error: TextEditor#edit not possible on closed editors + at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) + at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) + at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) + at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) + at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 + at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 + at Array.map () + at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) + at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) + at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) + at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +TextEditor#edit not possible on closed editors +Error: TextEditor#edit not possible on closed editors + at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) + at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) + at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) + at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) + at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 + at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 + at Array.map () + at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) + at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) + at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) + at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +TextEditor#edit not possible on closed editors +Error: TextEditor#edit not possible on closed editors + at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) + at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) + at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) + at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) + at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 + at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 + at Array.map () + at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) + at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) + at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) + at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) + 14) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/bringHarpToAfterFile +TextEditor#edit not possible on closed editors +Error: TextEditor#edit not possible on closed editors + at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) + at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) + at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) + at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) + at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 + at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 + at Array.map () + at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) + at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) + at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) + at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +TextEditor#edit not possible on closed editors +Error: TextEditor#edit not possible on closed editors + at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) + at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) + at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) + at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) + at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 + at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 + at Array.map () + at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) + at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) + at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) + at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +TextEditor#edit not possible on closed editors +Error: TextEditor#edit not possible on closed editors + at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) + at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) + at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) + at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) + at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 + at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 + at Array.map () + at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) + at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) + at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) + at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +TextEditor#edit not possible on closed editors +Error: TextEditor#edit not possible on closed editors + at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) + at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) + at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) + at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) + at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 + at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 + at Array.map () + at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) + at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) + at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) + at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +TextEditor#edit not possible on closed editors +Error: TextEditor#edit not possible on closed editors + at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) + at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) + at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) + at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) + at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 + at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 + at Array.map () + at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) + at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) + at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) + at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +TextEditor#edit not possible on closed editors +Error: TextEditor#edit not possible on closed editors + at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) + at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) + at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) + at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) + at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 + at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 + at Array.map () + at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) + at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) + at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) + at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) + 15) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/bringWhaleToBeforeFile + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockAir (56ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockAir2 (55ms) +Couldn't find mark default 'f' +Error: Couldn't find mark default 'f' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processRangeTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9725:25) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9718:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +Couldn't find mark default 'f' +Error: Couldn't find mark default 'f' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processRangeTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9725:25) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9718:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +Couldn't find mark default 'f' +Error: Couldn't find mark default 'f' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processRangeTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9725:25) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9718:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +Couldn't find mark default 'f' +Error: Couldn't find mark default 'f' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processRangeTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9725:25) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9718:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +Couldn't find mark default 'f' +Error: Couldn't find mark default 'f' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processRangeTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9725:25) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9718:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +Couldn't find mark default 'f' +Error: Couldn't find mark default 'f' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processRangeTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9725:25) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9718:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) + 16) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockHarpBetweenFine + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockVest (81ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/chuckFile (81ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/chuckFile2 (76ms) +Couldn't find mark default 'f' +Error: Couldn't find mark default 'f' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processRangeTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9725:25) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9718:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +Couldn't find mark default 'f' +Error: Couldn't find mark default 'f' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processRangeTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9725:25) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9718:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +Couldn't find mark default 'f' +Error: Couldn't find mark default 'f' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processRangeTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9725:25) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9718:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +Couldn't find mark default 'f' +Error: Couldn't find mark default 'f' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processRangeTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9725:25) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9718:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +Couldn't find mark default 'f' +Error: Couldn't find mark default 'f' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processRangeTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9725:25) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9718:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +Couldn't find mark default 'f' +Error: Couldn't find mark default 'f' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processRangeTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9725:25) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9718:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) + 17) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/chuckLineHarpBetweenFine + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/chuckLineVest (80ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/chuckLineVest2 (80ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/chuckLinkMade (74ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/chuckLinkMadePastLinkAir (74ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/chuckLinkPit (63ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/chuckPaintBatt (64ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/chuckTokenVest (67ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/clearLinePair (93ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/clearPaint (76ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/clearPaintBatt (126ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/clearPaintBattPastBlueBatt (66ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/drinkBlock (72ms) + 18) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/drinkCell + 19) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/drinkCellEach + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/drinkEveryArg (84ms) +Couldn't find mark default 'f' +Error: Couldn't find mark default 'f' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +Couldn't find mark default 'f' +Error: Couldn't find mark default 'f' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +Couldn't find mark default 'f' +Error: Couldn't find mark default 'f' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +Couldn't find mark default 'f' +Error: Couldn't find mark default 'f' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +Couldn't find mark default 'f' +Error: Couldn't find mark default 'f' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) +Couldn't find mark default 'f' +Error: Couldn't find mark default 'f' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) + 20) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/drinkJustFine + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/drinkToken (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/pourBlock (58ms) + 21) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/pourCell + 22) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/pourCellEach + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/pourEveryArg (65ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/takeBlockAir (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock2 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock3 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/takeEveryFile + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine2 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine3 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/takeFile + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/takeLineVest (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/takeTokenVest (55ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/chuckFirstCharVest (66ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/chuckFirstWordVest (62ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/chuckLastCharVest (63ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/chuckLastWordVest (55ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/chuckSecondWordVest (53ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/chuckSixthCharVest (80ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/clearFirstCharVest (98ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/clearFirstWordVest (61ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/clearLastCharVest (66ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/clearLastWordVest (54ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/clearSecondWordVest (74ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/clearSixthCharVest (62ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeFirstChar (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeFirstChar2 (64ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeFirstChar3 (58ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeFirstChar4 (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeFirstChar5 (56ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeFirstPastLastCharHarp (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeFirstPastLastWordHarp (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeFirstPastSecondWordHarp (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeFirstThreeCharHarp (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeFirstTwoWordHarp (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeFirstWord (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeLastPastFirstCharHarp (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeLastPastFirstWordHarp (38ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeLastThreeCharHarp (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeLastTwoWordHarp (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeSecondCharLookPastEndOfToken (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeSecondCharLookPastSecondCharTrap (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeSecondWord (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeThirdPastSecondWordHarp (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearBoundsBatt (53ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearBoundsEach (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearBoundsHarp (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearBoundsOx (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearBoundsRam (53ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearCurly (63ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair10 (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair11 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair12 (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair13 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair14 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair15 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair16 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair17 (70ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair2 (79ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair3 (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair4 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair5 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair6 (43ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair7 (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair8 (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair9 (57ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPairBatt (56ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPairOx (59ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPairRam (54ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearRound (60ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearRound2 (157ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearBound (63ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearCore (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearCore2 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearPair (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearPair2 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearPair3 (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearPair4 (57ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/cpp/clearOutside (63ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/cpp/clearRound8 (58ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/java/clearQuad3 (54ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/java/clearRound10 (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/java/clearRound11 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/json/clearPair (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/json/clearPair2 (67ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/json/clearRound (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/json/clearRound2 (57ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/chuckMatching (53ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/chuckMatching2 (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/chuckMatching3 (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/chuckPair (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/chuckRound (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearCurly (60ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearCurly3 (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearMatching (59ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearMatching10 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearMatching11 (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearMatching2 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearMatching3 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearMatching4 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearMatching5 (57ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearMatching6 (54ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearMatching7 (65ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearMatching8 (60ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearMatching9 (56ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearOutside7 (64ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearOutside8 (54ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearPair (64ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearPair2 (60ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearPair3 (62ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearPair4 (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearPairCurly (57ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearQuad2 (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearQuad4 (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearRound (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearRound5 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearRound6 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearRound7 (70ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearSquare (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearSquare2 (53ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/shellscript/clearCurly4 (158ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/shellscript/clearOutside23 (82ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/shellscript/clearPair (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/shellscript/clearString5 (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/takeCore (76ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair10 (136ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair11 (70ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair12 (65ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair13 (65ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair14 (76ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair15 (71ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair16 (75ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair17 (72ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair18 (65ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair19 (74ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair20 (71ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair21 (66ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair23 (64ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair4 (65ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair5 (82ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair6 (67ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair7 (73ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair8 (69ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair9 (70ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearMatching14 (78ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearMatching15 (71ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside10 (76ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside11 (63ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside12 (67ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside13 (62ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside14 (68ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside15 (59ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside16 (66ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside17 (83ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside18 (88ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside19 (71ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside2 (66ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside20 (83ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside21 (70ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside22 (78ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside3 (80ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside4 (76ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside5 (73ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside6 (75ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside9 (79ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair (74ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair10 (60ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair2 (71ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair3 (75ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair4 (71ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair5 (66ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair6 (95ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair7 (85ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair8 (79ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair9 (63ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearQuad (62ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearRound2 (55ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearRound3 (69ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearRound4 (78ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearSkis (68ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearSquare3 (57ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearSquare4 (57ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearSquare5 (61ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearSquareLack (71ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearSquareRack (81ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearString (81ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearString2 (62ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearString3 (69ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/takePairBatt (60ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/chuckInsideRound (66ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/chuckPairRound (83ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/chuckRound2 (58ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/clearCurly2 (80ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/clearOutsideGreenDouble (65ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/clearRound9 (71ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeInsideRound (61ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeInsideRound2 (63ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside (58ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside11 (57ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside12 (59ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside13 (62ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside14 (65ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside15 (59ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside16 (86ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside17 (67ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside18 (61ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside19 (53ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside2 (63ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside20 (57ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside21 (72ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside22 (57ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside23 (65ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside24 (69ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside25 (64ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside26 (73ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside3 (112ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside4 (115ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside5 (68ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside6 (59ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside7 (63ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside8 (59ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside9 (73ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutsideLeper (61ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutsideRack (59ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairDouble (56ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairRound (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairRound2 (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeQuad (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeQuad2 (65ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeQuad3 (61ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeQuad4 (58ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeQuad5 (56ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeQuad6 (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound10 (56ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound11 (59ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound12 (54ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound13 (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound14 (57ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound15 (54ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound16 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound17 (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound18 (73ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound19 (91ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound2 (63ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound20 (61ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound21 (60ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound22 (67ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound23 (63ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound3 (65ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound4 (61ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound5 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound6 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound7 (54ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound8 (54ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound9 (56ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRoundLeper (59ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRoundRepper (56ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeSquare (56ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/chuckInsideRound (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/chuckPairHarp + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/chuckPairRound (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/chuckRound2 (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearBoundsBatt2 (38ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearBoundsEach2 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearBoundsOx2 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearBoundsRam2 (57ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearCurly2 (84ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearEscapedSquare (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearOutsideGreenDouble (66ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearPair (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearPair10 (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearPair11 (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearPair12 (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearPair13 (43ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearPair14 (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearPair15 (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearPair16 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearPair2 (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearPair3 (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearPair4 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearPair5 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearPair6 (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearPair7 (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearPair8 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearPair9 (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearRound (81ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearRound9 (43ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearSquare (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearString4 (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/tailTakeEscapedQuad (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeEscapedQuad (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeEscapedQuad2 (38ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeEscapedQuad3 (43ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeEscapedQuad4 (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeEscapedQuad5 (42ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeInsideRound (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeInsideRound2 (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeLeftQuad + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeLeftQuad2 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeLeftQuad3 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeLeftQuad4 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeLeftQuad5 (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeLeftQuad6 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeLeftQuad7 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside (38ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside10 (42ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside11 (38ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside12 (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside13 (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside14 (38ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside15 (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside16 (43ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside17 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside18 (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside19 (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside2 (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside20 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside21 (75ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside22 (56ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside23 (62ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside24 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside25 (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside26 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside27 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside3 (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside4 (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside5 (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside6 (71ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside7 (109ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside8 (63ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside9 (58ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutsideFine (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutsideLeper (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutsideRack (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutsideUrge (55ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takePairDouble (42ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takePairRound (38ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takePairRound2 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeQuad (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeQuad2 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeQuad3 (54ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeQuad4 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeQuad5 (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeQuad6 (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRightQuad (42ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRightQuad2 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRightQuad3 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRightQuad4 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRightQuad5 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRightQuad6 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRightQuad7 (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound10 (42ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound11 (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound12 (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound13 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound14 (56ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound15 (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound16 (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound17 (42ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound18 (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound19 (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound2 (43ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound20 (42ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound21 (43ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound22 (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound23 (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound3 (43ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound4 (43ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound5 (55ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound6 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound7 (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound8 (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound9 (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRoundLeper (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRoundRepper (61ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeSquare (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringFine (49ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringFineAfterThirdCarThis (48ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringFineAfterThis (75ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringFineAfterThis2 (82ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringFineBeforeThis (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringFineToFirstCarWhale (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringFineToFirstTwoCar (50ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringFineToLastCarWhale (45ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringFineToLastTwoCar (52ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringFineToThirdCarWhale (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringFineToWhale (47ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringFineToWhale2 (103ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringFineToWhale3 (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringFineToWhale4 (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringFineToWhale5 (43ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringHarpToEndOfWhale (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringHarpToFourthCarWhalePastSecondCarHarp (42ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringHarpToSecondCarFinePastThirdCarHarp (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringHarpToSecondCarFinePastThirdCarWhale (56ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringHarpToStartOfWhale (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringWhale (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringWhaleAfterFine (39ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringWhaleAfterThis (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringWhaleAfterThis2 + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringWhaleBeforeThis (42ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringWhaleToEndOfFine (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringWhaleToFine (40ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/chuckFirstCarWhale (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/chuckFirstPastSecondCar (44ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/chuckFourthPastFifthCar (51ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/chuckLastCarWhale (57ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/chuckSecondCarFinePastThirdCarWhale (46ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/chuckSecondPastThirdCar (41ms) + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/chuckThirdCarWhalePastSecondCarHarp + ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/commentTrap (62ms) + scroll + ✓ top whale + ✓ bottom whale (43ms) + subtoken regex matcher + ✓ QuickBrownFox + ✓ quickBrownFox + ✓ quick_brown_fox + ✓ QUICK_BROWN_FOX + ✓ quick-brown-fox + ✓ QUICK-BROWN-FOX + ✓ quick.brown.fox + ✓ QUICK.BROWN.FOX + ✓ ../quick/brown/.fox + ✓ ../QUICK/BROWN/.FOX + ✓ quick::brown::fox + ✓ QUICK::BROWN::FOX + ✓ APIClientFactory + ✓ MockAPIClientFactory + ✓ mockAPIClientFactory + ✓ mockAPIClient123Factory + toggle decorations + ✓ toggle decorations + tokenizer + ✓ 0.0 0 1 120 2.5 0.1 + ✓ 1.22.4 + ✓ my variable + ✓ My Variable + ✓ myVariable + ✓ MyVariable + ✓ my_variable + ✓ MY_VARIABLE + ✓ my__variable + ✓ my-variable + ✓ my.variable + ✓ my/variable + ✓ my::variable + ✓ _a + ✓ "my variable" + ✓ 'my variable' + ✓ ! + ✓ " + ✓ # + ✓ $ + ✓ % + ✓ & + ✓ ' + ✓ ( + ✓ ) + ✓ * + ✓ + + ✓ , + ✓ - + ✓ . + ✓ / + ✓ : + ✓ ; + ✓ < + ✓ = + ✓ > + ✓ ? + ✓ @ + ✓ [ + ✓ \ + ✓ ] + ✓ ^ + ✓ _ + ✓ ` + ✓ { + ✓ | + ✓ } + ✓ ~ + ✓ ---|||///+++ + ✓ !!(()){{}} + ✓ !=>=!==== + ✓ => + ✓ :: + ✓ -> + ✓ ?? + ✓ \r\n\t + ✓ """hello""" + ✓ ```typescript + ✓ """""" + ✓ `````` + ✓ "" + ✓ '' + ✓ `` + ✓ // Hello world + ✓ /* Hello world */ + ✓ + ✓ #aaaaaa + ✓ #11aaaa + ✓ #aa11aa + ✓ #aaaa11 + ✓ #111111 + ✓ aåäöb + 1549 passing (2m) + 55 pending + 22 failing + 1) recorded test cases + /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachBetweenHarp: + + AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: ++ actual - expected + + { + end: { ++ character: 13, ++ line: 6 +- character: 9, +- line: 3 + }, + start: { ++ character: 8, ++ line: 6 +- character: 4, +- line: 3 + } + } + + expected - actual + + { + "end": { + - "character": 13 + - "line": 6 + + "character": 9 + + "line": 3 + } + "start": { + - "character": 8 + - "line": 6 + + "character": 4 + + "line": 3 + } + } + + at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:126:16 + at Array.forEach () + at checkMarks (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:122:27) + at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:100:9 + at Generator.next () + at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) + + 2) recorded test cases + /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachUntilHarp: + + AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: ++ actual - expected + + { + end: { ++ character: 13, ++ line: 6 +- character: 9, +- line: 3 + }, + start: { ++ character: 8, ++ line: 6 +- character: 4, +- line: 3 + } + } + + expected - actual + + { + "end": { + - "character": 13 + - "line": 6 + + "character": 9 + + "line": 3 + } + "start": { + - "character": 8 + - "line": 6 + + "character": 4 + + "line": 3 + } + } + + at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:126:16 + at Array.forEach () + at checkMarks (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:122:27) + at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:100:9 + at Generator.next () + at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) + + 3) recorded test cases + /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachBetweenHarp: + + AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: ++ actual - expected + + { + end: { ++ character: 13, ++ line: 6 +- character: 9, +- line: 3 + }, + start: { ++ character: 8, ++ line: 6 +- character: 4, +- line: 3 + } + } + + expected - actual + + { + "end": { + - "character": 13 + - "line": 6 + + "character": 9 + + "line": 3 + } + "start": { + - "character": 8 + - "line": 6 + + "character": 4 + + "line": 3 + } + } + + at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:126:16 + at Array.forEach () + at checkMarks (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:122:27) + at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:100:9 + at Generator.next () + at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) + + 4) recorded test cases + /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachBetweenHarp2: + Error: TextEditor#edit not possible on closed editors + at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) + at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) + at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) + at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) + at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) + at performEditsAndUpdateInternal (/Users/pokey/src/cursorless-vscode/dist/extension.js:5805:9) + at performEditsAndUpdateRanges (/Users/pokey/src/cursorless-vscode/dist/extension.js:5802:10) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:10753:37 + at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 + at Array.map () + at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) + at runOnTargetsForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6285:10) + at Delete.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10746:57) + at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) + + 5) recorded test cases + /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachUntilHarp: + + AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: ++ actual - expected + + { + end: { ++ character: 13, ++ line: 6 +- character: 9, +- line: 3 + }, + start: { ++ character: 8, ++ line: 6 +- character: 4, +- line: 3 + } + } + + expected - actual + + { + "end": { + - "character": 13 + - "line": 6 + + "character": 9 + + "line": 3 + } + "start": { + - "character": 8 + - "line": 6 + + "character": 4 + + "line": 3 + } + } + + at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:126:16 + at Array.forEach () + at checkMarks (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:122:27) + at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:100:9 + at Generator.next () + at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) + + 6) recorded test cases + /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToEndOfThisAndEndOfWhaleTakeWhale: + + AssertionError [ERR_ASSERTION]: Unexpected final state + + expected - actual + + "character": 12 + "line": 0 + } + } + - { + - "active": { + - "character": 18 + - "line": 0 + - } + - "anchor": { + - "character": 12 + - "line": 0 + - } + - } + ] + } + + at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:113:20 + at Generator.next () + at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) + at runMicrotasks () + at processTicksAndRejections (node:internal/process/task_queues:96:5) + + 7) recorded test cases + /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhale: + + AssertionError [ERR_ASSERTION]: Unexpected final state + + expected - actual + + } + } + "default.w": { + "end": { + - "character": 18 + + "character": 12 + "line": 0 + } + "start": { + "character": 7 +-- + "character": 12 + "line": 0 + } + } + - { + - "active": { + - "character": 18 + - "line": 0 + - } + - "anchor": { + - "character": 12 + - "line": 0 + - } + - } + ] + } + + at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:113:20 + at Generator.next () + at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) + at runMicrotasks () + at processTicksAndRejections (node:internal/process/task_queues:96:5) + + 8) recorded test cases + /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhaleTakeWhale: + + AssertionError [ERR_ASSERTION]: Unexpected final state + + expected - actual + + } + } + "default.w": { + "end": { + - "character": 18 + + "character": 12 + "line": 0 + } + "start": { + "character": 7 +-- + "character": 12 + "line": 0 + } + } + - { + - "active": { + - "character": 18 + - "line": 0 + - } + - "anchor": { + - "character": 12 + - "line": 0 + - } + - } + ] + } + + at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:113:20 + at Generator.next () + at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) + at runMicrotasks () + at processTicksAndRejections (node:internal/process/task_queues:96:5) + + 9) recorded test cases + /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/tryCatchWrapThis: + + AssertionError [ERR_ASSERTION]: Unexpected final state + + expected - actual + + { + - "documentContents": "try {\n const foo = \"hello\";\n} catch (err) {\n \n}" + + "documentContents": "try {\n const foo = \"hello\";\n} catch () {\n \n}" + "selections": [ + { + "active": { + - "character": 4 + - "line": 3 + + "character": 9 + + "line": 2 + } + "anchor": { + - "character": 4 + - "line": 3 + + "character": 9 + + "line": 2 + } + } + ] + "thatMark": [ + + at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:113:20 + at Generator.next () + at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) + at runMicrotasks () + at processTicksAndRejections (node:internal/process/task_queues:96:5) + + 10) recorded test cases + /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/tryCatchWrapThis2: + + AssertionError [ERR_ASSERTION]: Unexpected final state + + expected - actual + + { + - "documentContents": "try {\n if (true) {\n const foo = \"hello\";\n }\n} catch (err) {\n \n}\n\ntry {\n const bar = \"hello\";\n} catch (err) {\n \n}" + + "documentContents": "try {\n if (true) {\n const foo = \"hello\";\n }\n} catch () {\n \n}\n\ntry {\n const bar = \"hello\";\n} catch () {\n \n}" + "selections": [ + { + "active": { + - "character": 4 + - "line": 11 + + "character": 9 + + "line": 10 + } + "anchor": { + - "character": 4 + - "line": 11 + + "character": 9 + + "line": 10 + } + } + { + "active": { + - "character": 4 + - "line": 5 + + "character": 9 + + "line": 4 + } + "anchor": { + - "character": 4 + - "line": 5 + + "character": 9 + + "line": 4 + } + } + ] + "thatMark": [ + + at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:113:20 + at Generator.next () + at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) + at runMicrotasks () + at processTicksAndRejections (node:internal/process/task_queues:96:5) + + 11) recorded test cases + /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/bringHarpToAfterFile: + Error: Couldn't find mark default 'h' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) + + 12) recorded test cases + /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/bringStateFineToAfterBatt: + Error: TextEditor#edit not possible on closed editors + at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) + at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) + at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) + at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) + at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 + at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 + at Array.map () + at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) + at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) + at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) + at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) + + 13) recorded test cases + /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/bringWhaleToBeforeFile: + Error: Couldn't find mark default 'w' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) + + 14) recorded test cases + /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/bringHarpToAfterFile: + Error: TextEditor#edit not possible on closed editors + at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) + at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) + at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) + at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) + at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 + at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 + at Array.map () + at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) + at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) + at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) + at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) + + 15) recorded test cases + /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/bringWhaleToBeforeFile: + Error: TextEditor#edit not possible on closed editors + at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) + at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) + at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) + at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) + at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 + at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 + at Array.map () + at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) + at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) + at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) + at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) + + 16) recorded test cases + /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockHarpBetweenFine: + Error: Couldn't find mark default 'f' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processRangeTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9725:25) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9718:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) + + 17) recorded test cases + /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/chuckLineHarpBetweenFine: + Error: Couldn't find mark default 'f' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processRangeTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9725:25) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9718:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) + + 18) recorded test cases + /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/drinkCell: + + AssertionError [ERR_ASSERTION]: Unexpected final state + + expected - actual + + ] + "thatMark": [ + { + "active": { + - "character": 12 + + "character": 0 + "line": 1 + } + "anchor": { + - "character": 12 + + "character": 0 + "line": 1 + } + } + ] + + at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:113:20 + at Generator.next () + at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) + at runMicrotasks () + at processTicksAndRejections (node:internal/process/task_queues:96:5) + + 19) recorded test cases + /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/drinkCellEach: + + AssertionError [ERR_ASSERTION]: Unexpected final state + + expected - actual + + ] + "thatMark": [ + { + "active": { + - "character": 12 + + "character": 0 + "line": 1 + } + "anchor": { + - "character": 7 + + "character": 0 + "line": 1 + } + } + ] + + at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:113:20 + at Generator.next () + at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) + at runMicrotasks () + at processTicksAndRejections (node:internal/process/task_queues:96:5) + + 20) recorded test cases + /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/drinkJustFine: + Error: Couldn't find mark default 'f' + at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) + at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) + at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) + at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 + at Array.map () + at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) + at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) + at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) + + 21) recorded test cases + /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/pourCell: + + AssertionError [ERR_ASSERTION]: Unexpected final state + + expected - actual + + ] + "thatMark": [ + { + "active": { + - "character": 12 + - "line": 1 + + "character": 0 + + "line": 3 + } + "anchor": { + - "character": 12 + - "line": 1 + + "character": 0 + + "line": 3 + } + } + ] + } + + at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:113:20 + at Generator.next () + at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) + at runMicrotasks () + at processTicksAndRejections (node:internal/process/task_queues:96:5) + + 22) recorded test cases + /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/pourCellEach: + + AssertionError [ERR_ASSERTION]: Unexpected final state + + expected - actual + + ] + "thatMark": [ + { + "active": { + - "character": 12 + - "line": 1 + + "character": 0 + + "line": 4 + } + "anchor": { + - "character": 7 + - "line": 1 + + "character": 0 + + "line": 4 + } + } + ] + } + + at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:113:20 + at Generator.next () + at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) + at runMicrotasks () + at processTicksAndRejections (node:internal/process/task_queues:96:5) + +Error: 22 tests failed. + at /Users/pokey/src/cursorless-vscode/out/test/suite/index.js:27:27 + at done (/Users/pokey/src/cursorless-vscode/node_modules/mocha/lib/mocha.js:1053:7) + at runMicrotasks () + at processTicksAndRejections (node:internal/process/task_queues:96:5) From d3216a879bd6e4c2d89df597b0ee788744f9f1b5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 26 May 2022 11:37:34 +0000 Subject: [PATCH 208/314] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- failing-tests.txt | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/failing-tests.txt b/failing-tests.txt index e0c696801a..0cbff4a9e8 100644 --- a/failing-tests.txt +++ b/failing-tests.txt @@ -2367,7 +2367,7 @@ Error: Couldn't find mark default 'f' + "line": 3 } } - + at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:126:16 at Array.forEach () at checkMarks (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:122:27) @@ -2411,7 +2411,7 @@ Error: Couldn't find mark default 'f' + "line": 3 } } - + at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:126:16 at Array.forEach () at checkMarks (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:122:27) @@ -2455,7 +2455,7 @@ Error: Couldn't find mark default 'f' + "line": 3 } } - + at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:126:16 at Array.forEach () at checkMarks (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:122:27) @@ -2518,7 +2518,7 @@ Error: Couldn't find mark default 'f' + "line": 3 } } - + at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:126:16 at Array.forEach () at checkMarks (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:122:27) @@ -2548,7 +2548,7 @@ Error: Couldn't find mark default 'f' - } ] } - + at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:113:20 at Generator.next () at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) @@ -2588,7 +2588,7 @@ Error: Couldn't find mark default 'f' - } ] } - + at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:113:20 at Generator.next () at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) @@ -2628,7 +2628,7 @@ Error: Couldn't find mark default 'f' - } ] } - + at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:113:20 at Generator.next () at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) @@ -2661,7 +2661,7 @@ Error: Couldn't find mark default 'f' } ] "thatMark": [ - + at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:113:20 at Generator.next () at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) @@ -2708,7 +2708,7 @@ Error: Couldn't find mark default 'f' } ] "thatMark": [ - + at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:113:20 at Generator.next () at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) @@ -2837,7 +2837,7 @@ Error: Couldn't find mark default 'f' } } ] - + at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:113:20 at Generator.next () at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) @@ -2865,7 +2865,7 @@ Error: Couldn't find mark default 'f' } } ] - + at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:113:20 at Generator.next () at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) @@ -2908,7 +2908,7 @@ Error: Couldn't find mark default 'f' } ] } - + at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:113:20 at Generator.next () at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) @@ -2939,7 +2939,7 @@ Error: Couldn't find mark default 'f' } ] } - + at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:113:20 at Generator.next () at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) From 1fd4be3e0298a4a7a7071b34539fab4aa8128311 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Thu, 26 May 2022 13:40:45 +0100 Subject: [PATCH 209/314] Don't de duplicate that mark --- failing-tests.txt | 2953 ----------------- src/actions/BringMoveSwap.ts | 13 +- .../modifiers/ModifyIfWeakStage.ts | 12 +- ...takePairRound.yml => clearBoundsRound.yml} | 0 src/util/targetUtils.ts | 3 +- 5 files changed, 13 insertions(+), 2968 deletions(-) delete mode 100644 failing-tests.txt rename src/test/suite/fixtures/recorded/surroundingPair/textual/{takePairRound.yml => clearBoundsRound.yml} (100%) diff --git a/failing-tests.txt b/failing-tests.txt deleted file mode 100644 index 0cbff4a9e8..0000000000 --- a/failing-tests.txt +++ /dev/null @@ -1,2953 +0,0 @@ -Activating tree-sitter... -Activating tree-sitter... -Creating communication dir /var/folders/cr/8g7qm5_j7z31ltt30_4s5tdc0000gn/T/vscode-command-server-501 -Creating communication dir /var/folders/cr/8g7qm5_j7z31ltt30_4s5tdc0000gn/T/vscode-command-server-501 - - Backward compatibility - ✓ Backward compatibility (163ms) - breakpoints - ✓ breakpoint harp add (91ms) - ✓ breakpoint token harp add (45ms) - ✓ breakpoint harp remove (39ms) - ✓ breakpoint token harp remove (47ms) - Cross-cell set selection - ✓ Cross-cell set selection (1062ms) - Edit new cell - ✓ drink cell (1146ms) - ✓ pour cell (1090ms) - Extension Test Suite - ✓ Sample test - fold - ✓ fold made (1082ms) - ✓ unfold made (245ms) - followLink - ✓ follow definition (122ms) - ✓ follow link (153ms) - Group by document - ✓ Group by document (137ms) - inferFullTargets - - inferFullTargets 0 - - inferFullTargets 1 - - inferFullTargets 2 - - inferFullTargets 3 - - inferFullTargets 4 - - inferFullTargets 5 - - inferFullTargets 6 - - inferFullTargets 7 - - inferFullTargets 8 - - inferFullTargets 9 - - inferFullTargets 10 - - inferFullTargets 11 - - inferFullTargets 12 - - inferFullTargets 13 - - inferFullTargets 14 - - inferFullTargets 15 - - inferFullTargets 16 - - inferFullTargets 17 - - inferFullTargets 18 - - inferFullTargets 19 - - inferFullTargets 20 - - inferFullTargets 21 - - inferFullTargets 22 - - inferFullTargets 23 - - inferFullTargets 24 - - inferFullTargets 25 - - inferFullTargets 26 - - inferFullTargets 27 - - inferFullTargets 28 - - inferFullTargets 29 - - inferFullTargets 30 - - inferFullTargets 31 - - inferFullTargets 32 - - inferFullTargets 33 - - inferFullTargets 34 - - inferFullTargets 35 - - inferFullTargets 36 - - inferFullTargets 37 - - inferFullTargets 38 - - inferFullTargets 39 - - inferFullTargets 40 - - inferFullTargets 41 - - inferFullTargets 42 - - inferFullTargets 43 - - inferFullTargets 44 - - inferFullTargets 45 - - inferFullTargets 46 - - inferFullTargets 47 - - inferFullTargets 48 - - inferFullTargets 49 - - inferFullTargets 50 - - inferFullTargets 51 - - inferFullTargets 52 - - inferFullTargets 53 - - inferFullTargets 54 - Pre-phrase snapshots - ✓ Pre-phrase snapshot; single phrase (88ms) - ✓ Pre-phrase snapshot; multiple phrase (61ms) - ✓ No snapshot; single phrase (61ms) - ✓ No snapshot; multiple phrase (49ms) - recorded test cases - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/bringAirAndBatAndCap (70ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/bringAirAndBatAndCapToAfterDrum (63ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/bringAirAndBatAndCapToAfterItemEach (75ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/bringAirAndBatAndCapToBeforeDrum (70ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/bringAirAndBatAndCapToBeforeItemEach (68ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/bringArgueFineAndZip (72ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/bringArgueOxAndZipToAfterJustLeper (64ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/bringLineAirAndBatAndCapToAfterDrum (90ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/bringLineAirAndBatAndCapToBeforeDrum (71ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/bringLineHarpAndWhale (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/bringVest (63ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/bringVestToCap (55ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/callFine (68ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/callVest (60ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/callVestOnCap (62ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/carveVest (71ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/chuckArgMadeAndAir (73ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/chuckArgMadeAndAirAndJustSoon (71ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/chuckEveryArgMade (82ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/chuckVest (93ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/clearVest (62ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/cloneEveryArg (67ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/cloneHarp (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/cloneHarp2 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/cloneUpEveryArg (57ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/cloneUpHarp (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/cloneUpHarp2 (42ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/cloneUpVest (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/cloneVest (43ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/commentVest (74ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/copyVest (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/curlyRepackRound (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/customHarp (384ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/cutEveryArgMade (82ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/dedentVest (66ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/defineVest (79ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/drinkArg (89ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/drinkBlock (66ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/drinkLine (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/drinkVest (61ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/dropVest (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/findVest (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/floatVest (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveAfterDot (54ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveAirAndBang (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveBat (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveBat2 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveBeforeDot (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveBlueQuote (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveBlueQuoteAndQuote (56ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveCap (58ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveDot (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveDot2 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveDrum (53ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveEqualsPastColon (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveHarp (54ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveHarpAndWhale (58ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveQuote (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveQuoteAndAir (61ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveQuoteAndBang (57ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/giveVestAndHarp (63ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/indentVest (76ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/moveEveryArgMade (92ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/moveVest (68ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/moveVestToCap (57ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/pasteCap (85ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/phonesSpy (58ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/postVest (70ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/pourArg (79ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/pourBlock (67ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/pourLine (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/pourVest (61ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/preeVest (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/puffVest (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/reformatHarpAsSnake (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/reformatHarpAsSnake2 (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/replaceAirAndBatAndCapWithCount (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/replaceVestWithWhatever (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/reverseAirAndBatAndCap (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/roundWrapThis (64ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/roundWrapVest (67ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/roundWrapVest2 (65ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/shuffleThis (58ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/sortAirAndCapAndBat (57ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/squareRepackHarp (57ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/squareRepackLeper - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/squareRepackPair (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/squareRepackThis (38ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/swapVestWithCap (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/swapWithVest (59ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/takeLast (53ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/actions/takeVest (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/bringAirToAfterBatVerticalPastFine (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/bringAirToBatVerticalPastFine (54ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/bringAirToBeforeBatVerticalPastFine (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/bringAirToEndOfBatVerticalPastFine (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/bringAirToStartOfBatVerticalPastFine (47ms) - 1) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachBetweenHarp - 2) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachUntilHarp - 3) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachBetweenHarp -TextEditor#edit not possible on closed editors -Error: TextEditor#edit not possible on closed editors - at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) - at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) - at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) - at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) - at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) - at performEditsAndUpdateInternal (/Users/pokey/src/cursorless-vscode/dist/extension.js:5805:9) - at performEditsAndUpdateRanges (/Users/pokey/src/cursorless-vscode/dist/extension.js:5802:10) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:10753:37 - at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 - at Array.map () - at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) - at runOnTargetsForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6285:10) - at Delete.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10746:57) - at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -TextEditor#edit not possible on closed editors -Error: TextEditor#edit not possible on closed editors - at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) - at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) - at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) - at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) - at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) - at performEditsAndUpdateInternal (/Users/pokey/src/cursorless-vscode/dist/extension.js:5805:9) - at performEditsAndUpdateRanges (/Users/pokey/src/cursorless-vscode/dist/extension.js:5802:10) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:10753:37 - at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 - at Array.map () - at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) - at runOnTargetsForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6285:10) - at Delete.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10746:57) - at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -TextEditor#edit not possible on closed editors -Error: TextEditor#edit not possible on closed editors - at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) - at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) - at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) - at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) - at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) - at performEditsAndUpdateInternal (/Users/pokey/src/cursorless-vscode/dist/extension.js:5805:9) - at performEditsAndUpdateRanges (/Users/pokey/src/cursorless-vscode/dist/extension.js:5802:10) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:10753:37 - at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 - at Array.map () - at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) - at runOnTargetsForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6285:10) - at Delete.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10746:57) - at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -TextEditor#edit not possible on closed editors -Error: TextEditor#edit not possible on closed editors - at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) - at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) - at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) - at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) - at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) - at performEditsAndUpdateInternal (/Users/pokey/src/cursorless-vscode/dist/extension.js:5805:9) - at performEditsAndUpdateRanges (/Users/pokey/src/cursorless-vscode/dist/extension.js:5802:10) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:10753:37 - at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 - at Array.map () - at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) - at runOnTargetsForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6285:10) - at Delete.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10746:57) - at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -TextEditor#edit not possible on closed editors -Error: TextEditor#edit not possible on closed editors - at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) - at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) - at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) - at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) - at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) - at performEditsAndUpdateInternal (/Users/pokey/src/cursorless-vscode/dist/extension.js:5805:9) - at performEditsAndUpdateRanges (/Users/pokey/src/cursorless-vscode/dist/extension.js:5802:10) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:10753:37 - at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 - at Array.map () - at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) - at runOnTargetsForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6285:10) - at Delete.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10746:57) - at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -TextEditor#edit not possible on closed editors -Error: TextEditor#edit not possible on closed editors - at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) - at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) - at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) - at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) - at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) - at performEditsAndUpdateInternal (/Users/pokey/src/cursorless-vscode/dist/extension.js:5805:9) - at performEditsAndUpdateRanges (/Users/pokey/src/cursorless-vscode/dist/extension.js:5802:10) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:10753:37 - at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 - at Array.map () - at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) - at runOnTargetsForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6285:10) - at Delete.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10746:57) - at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) - 4) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachBetweenHarp2 - 5) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachUntilHarp - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/postBatVerticalUntilFine (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/preBatVerticalBetweenFine - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/takeBatVerticalPastFine - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/takeCapAndVestAndHarp (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/takeCapPastHarp (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/takeFineVerticalPastBat (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/takeHarpAndVestAndCap (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/takeHarpPastCap (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/takeLineVestAndAir (68ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/takePastEndOfToken (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/takePastStartOfToken (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/takePastTrap (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/takeTokenPastTrap (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/takeVerticalPastFine (71ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/takeVestTweenWhale (77ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/takeVestUntilWhale (60ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/takeWhaleTweenVest (170ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/takeWhaleUntilVest (97ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringAirToThirdCarWhaleTakeWhale (86ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringCommaToEndOfPointTakePoint (82ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringCommaToStartOfPointTakePoint (75ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAfterWhaleTakeWhale (52ms) - 6) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToEndOfThisAndEndOfWhaleTakeWhale - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToThisAndStartOfWhaleTakeWhale (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpBeforeWhaleTakeWhale (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpTakeWhale (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpToEndOfPointTakePoint (53ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpToStartOfPointTakePoint (61ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpToStartOfWhaleTakeWhale (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAfterFirstCarWhaleTakeWhale (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfSecondCarWhaleAndEndOfWhaleTakeWhale (50ms) - 7) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhale - 8) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhaleTakeWhale - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToStartOfSecondCarWhaleAndStartOfWhaleTakeWhale (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToThisAndStartOfWhaleTakeWhale (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndPointToEndOfSecondCarWhaleAndEndOfWhaleTakeWhale (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndPointToStartOfSecondCarWhaleAndStartOfWhaleTakeWhale (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringPointToEndOfWhaleTakeWhale (43ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringPointToStartOfWhaleTakeWhale (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringPointToThirdCarWhaleTakeWhale (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/chuckFirstTwoCarWhaleTakeWhale (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/chuckFourthCarWhalePastThirdCarAirTakeWhale (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/chuckHarpPastAirTakeWhale (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/chuckLastTwoCarWhaleTakeWhale (74ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/chuckSecondPastThirdCarWhaleTakeWhale (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/chuckThirdCarHarpPastSecondCarWhaleTakeWhale (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/moveFourthCarHarpPastSecondCarWhaleToEndOfWhaleTakeWhale (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/takeHarp (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/headTail/takeHead (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/headTail/takeHeadVest (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/headTail/takeTail (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/headTail/takeTailVest (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/bringLineBatPastEndOfFunkToThis (69ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/bringLineLookToJustAir (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/bringMapAirToLineHarp (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/bringMapAirToTokenHarp (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/bringOddToLine (63ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/bringOddToState (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/bringOddToToken (61ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/bringTokenHarpToMapAir (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/ifWrapTokenFine (68ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeAfterVestPastAir (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeAfterVestPastBeforeAir (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeAirPastEndOfLine (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeEachPastStartOfLine (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeFirstWord (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeHarpAndStringEach (59ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeHarpPastStringEach (59ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeLastChar (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeLinePastAir (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeLineVestAndAir (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeLineVestPastAir (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeOddPastEndOfState (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeOddPastLine (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeOddPastState (53ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeOddPastToken (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takePastLineAir (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeStringHarpAndEach (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeStringHarpPastEach (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeVestAndLineAir (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeVestPastAfterAir (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeVestPastBeforeAir (38ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/inference/takeVestPastLineAir (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/c/clearFunk (70ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/chuckItemFine (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/chuckItemFine2 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/chuckItemZip - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/chuckItemZip2 (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearArgue (56ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearArgue2 (58ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearArgue3 (43ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearCall (42ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearCall2 (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearComment (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearCondition (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearEveryItem (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearEveryKey (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearEveryValue (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearFunk (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearFunk2 (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearIfState (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearItem (38ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearItem2 (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearItem3 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearItem4 (43ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearItem5 (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearItem6 (53ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearItemBat (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearItemBatClearItemBat (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearItemFine (54ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearItemWhale (54ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearItemZip (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearKey (42ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearKeyWhale (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearKeyWhale2 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearKeyZip (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearKeyZip2 (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearLambda (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearLambda2 (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearList (56ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearList2 (53ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearMap (54ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearName (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearName2 (63ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearValueBat (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/clearValueZip (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/takeValue (42ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/takeValueBat (38ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/takeValueBat2 (43ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/takeValueFine (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/takeValueFine2 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/takeValueWhale (38ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/takeValueZip - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/clojure/takeValueZip2 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/chuckTypeAir (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/chuckTypeSoon (155ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/chuckValue (164ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/clearName (61ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/clearValue (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/elseStateWrapThis (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/ifElseWrapThis (53ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/ifStateWrapThis (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeArg (66ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeArg2 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeAttribute (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeCall - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeClass (99ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeClass2 (105ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeClassName (64ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeClassName2 (64ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeClassName3 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeComment (42ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeEveryArg - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeEveryItem (69ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeFunk - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeFunk2 (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeFunkName - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeFunkName2 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeFunkName3 (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeIf - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeIf2 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeItem - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeItem2 (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeLambda - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeList (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeList2 (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeName - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeName2 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeName3 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeState - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeState2 (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeState3 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeString - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeType (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeType2 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeType3 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeValue (42ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeValue2 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/takeValue3 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/tryCatchWrapThis (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/cpp/tryCatchWrapThis2 (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/csharp/chuckTypeSoon (64ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/csharp/chuckTypeSoon2 (57ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/csharp/chuckValue (56ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/csharp/clearName (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/csharp/clearName2 (43ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/csharp/clearName3 (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/csharp/clearValue (42ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/csharp/clearValue2 (57ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/csharp/clearValue3 (65ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/csharp/elseStateWrapThis (55ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/csharp/ifElseWrapThis (53ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/csharp/ifStateWrapThis (58ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/csharp/tryCatchWrapThis (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/csharp/tryCatchWrapThis2 (54ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeArgue (143ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeArgue2 (77ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeArgue3 (78ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeArgue4 (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeArgue5 (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeComment (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeEveryArgue (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeEveryArgue2 (54ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeEveryArgue3 (82ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeItem (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeKey (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeKey2 (62ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeName (56ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeName2 (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeName3 (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeName6 (77ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeRound (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeSelector (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeSelector2 (56ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeSelector3 (56ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeSelector4 (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeSelector5 (61ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeState (53ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeState5 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeStateAir (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeStateHarp (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeValue (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeValue2 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeValue4 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeValue6 (78ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/changeValue9 (63ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/chuckArgue (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/chuckArgue2 (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/chuckArgue3 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/chuckArgue4 (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/chuckArgue5 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/chuckArgue6 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/chuckArgue7 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/chuckArgue8 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/chuckEveryArgue2 (53ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/chuckState (58ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/chuckState2 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/chuckValue (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/chuckValue2 (58ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/css/chuckValue3 (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/chuckArg (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/chuckArg2 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/chuckValue (43ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/clearCondition (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/clearIfState (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/clearPair (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/clearState (43ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeArg (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeArg2 (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeArg3 (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeCall (43ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeComment (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeEveryItem (60ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeEveryKey - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeFunk - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeFunkName (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeItem - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeKey - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeKey2 (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeList (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeMap (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeState (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeString (38ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeType - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeValue - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/go/takeValue2 (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/html/chuckValueInk (175ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/html/clearAttributeVest (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/html/clearComment (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/html/clearElement (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/html/clearEndTag (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/html/clearKey (42ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/html/clearName (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/html/clearStartTag (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/html/clearString (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/html/clearTags (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/chuckTypeNear (62ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/chuckTypeUrge (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/chuckValue (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/clearName (54ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/clearState (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/clearState2 (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/clearValue (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/elseStateWrapThis (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/ifElseWrapThis (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/ifStateWrapThis (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeArg (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeArg2 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeCall - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeClass - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeClassName - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeComment - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeCondition (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeCondition2 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeCondition3 (75ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeEveryArg - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeEveryArg2 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeEveryItem (38ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeFunk (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeFunk2 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeFunkName - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeFunkName2 (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeIf (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeItem (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeList - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeMap - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeName - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeName2 (43ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeName3 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeState - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeString - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeType - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeType2 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeType3 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeTypeBlueLook (43ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeTypeGust - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeTypeGust2 (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeTypeHarp - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeTypeLook (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeTypePit - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeTypeSoon (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeTypeSoon2 (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeTypeTrap (38ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeTypeTrap2 (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeTypeYank (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/takeValue (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/tryCatchWrapThis (84ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/java/tryCatchWrapThis2 (53ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/json/takeItem (137ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/json/takeItem2 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/json/takeKey (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/json/takeList (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/json/takeString (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/json/takeValue (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/jsx/takeAttribute (83ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/jsx/takeElement (113ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/jsx/takeEndTag (66ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/jsx/takeEveryAttribute (66ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/jsx/takeKey (86ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/jsx/takeStartTag (93ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/jsx/takeTags (64ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/jsx/takeValue (67ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/markdown/changeName (64ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/markdown/changeName2 (55ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/markdown/changeOneSection (114ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/markdown/changeOneSection2 (65ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/markdown/changeSection (56ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/markdown/changeSection2 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/markdown/changeSection3 (69ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/markdown/changeSection4 (70ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/markdown/changeSection5 (55ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/markdown/changeSection6 (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/markdown/chuckItem (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/markdown/chuckName (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/markdown/clearComment (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/markdown/clearItem (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/markdown/clearList (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeArg (122ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeArg10 (94ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeArg2 (63ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeArg3 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeArg4 (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeArg5 (64ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeArg6 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeArg7 (64ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeArg8 (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeArg9 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeCall (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeCall2 (73ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeClass (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeClassName (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeComment (64ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeEveryArg (91ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeEveryItem (57ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeFunk (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeFunkName (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeFunkName2 (65ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeIfState (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeItem (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeItem2 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeItem3 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeItem4 (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeItem5 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeKey (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeKey2 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeLambda (57ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeLambda2 (55ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeLambda3 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeLambda4 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeName (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeName2 (76ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeName3 (62ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeName4 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeName5 (53ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeName6 (58ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeRound (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeString (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeString2 (59ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeType (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeType2 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeType3 (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeType4 (62ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeType5 (56ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeType6 (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeValue (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeValue2 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeValue3 (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeValue4 (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeValue5 (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeValue6 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/changeValue7 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckArg (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckArg10 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckArg2 (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckArg3 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckArg4 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckArg5 (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckArg6 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckArg7 (38ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckArg8 (43ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckArg9 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckEveryArg (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckEveryItem (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckFunk (38ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckFunk2 (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckInside - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckItem - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckItem2 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckItem3 (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckItem4 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckItem5 (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckKey (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckKey2 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckPair (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckType - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckType2 (67ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckType3 (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckType4 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckType5 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckValue (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckValue10 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckValue2 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckValue3 (38ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckValue4 (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckValue5 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckValue6 (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckValue7 (38ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckValue8 (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/chuckValue9 (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/elseWrapThis (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/ifElseWrapThis (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/ifWrapThis (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/tryWrapThis (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/php/tryWrapThis2 (64ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/chuckArgDrum (60ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/chuckArgFine (60ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/chuckArgWhale (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/chuckEveryArgAir (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/chuckEveryArgRed (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/chuckEveryArgSit (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/chuckKey (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/chuckKey2 (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/chuckType (42ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/chuckTypeSoon - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/chuckTypeTrap (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/chuckValue (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/chuckValue2 (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/chuckValue3 (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/clearEveryValue (61ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/clearName (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/clearValue - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/clearValue2 (43ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/clearValue3 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/elseStateWrapThis (90ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/ifElseWrapThis (57ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/ifStateWrapThis (56ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeArg (43ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeArg2 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeArgDrum (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeArgRed (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeArgWhale - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeCall - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeClass - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeClass2 (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeClassName - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeComment (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeCondition (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeCondition2 (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeEveryArg - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeEveryArg2 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeEveryItem - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeEveryItem2 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeEveryItem3 (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeFunk (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeFunk2 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeFunkName - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeIf (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeItem - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeItem2 (38ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeItem3 (42ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeKey - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeLambda (65ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeLambdaMade (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeLambdaPit - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeList - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeList2 (38ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeMap (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeName - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeName2 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeName3 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeState - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeString - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeType - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeType2 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeValue (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeValue2 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/takeValueZero (59ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/tryCatchWrapThis (81ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/python/tryCatchWrapThis2 (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeArg (157ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeArgWhale (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeArgWhale2 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeArgWhale3 (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeCall (42ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeClass (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeComment (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeComment2 (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeComment3 (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeCondition (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeEveryArg (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeEveryArg2 (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeEveryArg3 (42ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeEveryItem (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeEveryKey (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeEveryKey2 (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeEveryKey3 (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeEveryKey4 (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeFunk (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeIfState (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeItemThis (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeKey (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeKey2 (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeLambda (42ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeLambda2 (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeLambda3 (85ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeLambda4 (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeLambda5 (64ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeList (59ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeList2 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeList3 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeMap (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeName (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeName2 (60ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeNameThis (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeRegex (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeRound (56ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeRound2 (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeState (54ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeState2 (56ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeState3 (63ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeState4 (53ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeState5 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeString (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeString2 (55ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/changeValue (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckArg (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckArg2 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckArg3 (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckEveryArg (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckEveryArg2 (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckEveryItem (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckItem (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckItem2 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckItem3 (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckItem4 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckItem5 (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckItem6 (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckItem7 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckNameThis (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckNameThis2 (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckState (57ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckState10 (53ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckState11 (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckState2 (38ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckState3 (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckState4 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckState5 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckState6 (42ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckState7 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckState8 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckState9 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckValue (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckValue2 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckValue3 (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckValue5 (60ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/chuckValue6 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/clearState (53ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/ruby/clearState2 (55ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckArgFine (284ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckArgFine2 (126ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckArgFine3 (64ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckConditionFine (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeBat - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeFine (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeFine2 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeFine3 (38ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeLook - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeLook2 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeLook3 (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeOdd (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeOdd2 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeOdd3 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeRed (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeRed2 (38ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeSit - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeSit2 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeSun - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeSun2 (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeSun3 (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeSun4 (38ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeSun5 (42ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckTypeTrap - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckValue - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckValueOdd (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckValueRed - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/chuckValueSit (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearArgFine (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearArgFine2 (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearArgFine3 (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearCallMade (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearClass (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearClass2 (43ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearClass3 (42ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearClass4 (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearClassName - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearClassName2 (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearClassName3 (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearClassName4 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearComment (38ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearComment2 (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearConditionEquals - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearConditionFine (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearFunkFour (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearFunkNameFour (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearIfState (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearIfState2 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearLambdaPlus (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearLambdaPlus2 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearLambdaPlus3 (83ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearName (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearNameFour (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearNameFour2 (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearRoundWhale (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearRoundWhale2 (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearString (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearString2 (42ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearStringOdd (54ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearType (38ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeBat (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeComma (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeFine (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeFine2 (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeFine3 (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeLook (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeLook2 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeLook3 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeOdd (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeOdd2 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeOdd3 (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeRed (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeRed2 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeSit (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeSit2 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeSun (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeSun2 (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeSun3 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeSun4 (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeSun5 (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearTypeTrap (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearValue (60ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearValueOdd (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearValueRed (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scala/clearValueSit (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeArgue (63ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeArgue2 (124ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeArgue3 (92ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeArgue4 (77ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeArgue5 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeArgue6 (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeComment (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeComment2 (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeEveryArgue (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeEveryArgue2 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeEveryArgue3 (62ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeFunk (85ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeFunk2 (81ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeItem (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeKey (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeKey2 (63ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeName (55ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeName2 (122ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeName3 (130ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeName4 (61ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeName5 (55ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeName6 (66ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeName7 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeName8 (80ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeName9 (74ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeRound (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeSelector (55ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeSelector2 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeSelector3 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeState (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeState4 (66ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeState5 (56ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeState6 (57ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeStateAir (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeStateHarp (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeValue (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeValue10 (78ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeValue11 (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeValue12 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeValue13 (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeValue14 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeValue15 (60ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeValue2 (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeValue3 (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeValue4 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeValue5 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeValue6 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeValue7 (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeValue8 (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/changeValue9 (53ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/chuckArgue (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/chuckArgue2 (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/chuckArgue3 (69ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/chuckArgue4 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/chuckArgue5 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/chuckArgue6 (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/chuckArgue7 (91ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/chuckArgue8 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/chuckArgue9 (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/chuckEveryArgue (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/chuckState (83ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/chuckState2 (55ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/chuckValue (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/chuckValue2 (83ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/scss/chuckValue3 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/changeFunk (74ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/changeName (83ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/changeValue (70ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/chuckKey (70ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/chuckTypeRam (99ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/chuckTypeSoon (95ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/chuckTypeSoon2 (75ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/chuckTypeTrap (69ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/chuckTypeYank (80ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/chuckValue (91ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearFunk (82ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearFunk2 (87ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearKey (65ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearLambda (93ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearLambda2 (72ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearLambda3 (63ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearLambda4 (77ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearName (70ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearType (76ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearType2 (83ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearTypeAir (67ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearTypeBat (71ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearTypeLangle (63ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearTypeNear (92ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearTypeNear2 (74ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearTypeOx (61ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearTypeOx2 (63ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearTypeUrge (66ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearTypeWhale (58ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearTypeWrangle (62ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/clearValue (59ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/elseStateWrapThis (68ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/ifElseWrapThis (66ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/ifStateWrapThis (66ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeArg (54ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeArg2 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeArrow (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeCall (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeClass (53ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeClassName (60ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeComment (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeCondition (82ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeCondition2 (68ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeCondition3 (64ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeEveryArgAir (58ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeEveryArgBat (54ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeEveryArgRam (53ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeEveryItem (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeEveryItem2 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeEveryItem3 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeEveryItem4 (58ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeEveryItem5 (53ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeEveryKey (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeEveryKey2 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeEveryValue (53ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeEveryValue2 (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunk (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunk10 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunk11 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunk12 (56ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunk13 (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunk2 (89ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunk3 (66ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunk4 (54ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunk5 (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunk6 (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunk7 (55ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunk8 (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunk9 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunkCap (61ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunkMade (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunkMade2 (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunkName (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunkName10 (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunkName11 (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunkName2 (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunkName3 (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunkName4 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunkName5 (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunkName6 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunkName7 (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunkName8 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunkName9 (61ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeFunkSoon (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeIf (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeItem (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeItem2 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeItem3 (62ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeItem4 (62ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeItemAir (64ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeItemBrace (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeItemComma (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeItemOne (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeKey (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeList (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeList2 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeMap (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeMap2 (62ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeName (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeName2 (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeRegex (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeState (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeState2 (53ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeString (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeType (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeType2 (60ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeValue (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeValue2 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeValue3 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/takeValue4 (48ms) - 9) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/tryCatchWrapThis - 10) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/tryCatchWrapThis2 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/xml/clearAtHerThen (67ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/xml/clearCore (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/xml/clearCore2 (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/xml/clearEli (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/xml/clearEndTag (42ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/xml/clearEveryAtHer (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/xml/clearEveryEli (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/xml/clearEveryTags (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/xml/clearKeyThen (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/xml/clearName (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/xml/clearPair (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/xml/clearPair2 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/xml/clearRound (66ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/xml/clearStartTag (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/xml/clearTags (61ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/xml/scratchClearValue (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/lineEndings/chuckVestLF (55ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/lineEndings/chuckVestLFCR (66ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/lineEndings/dropVestLF (54ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/lineEndings/dropVestLFCR (57ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/marks/chuckNothing (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/marks/highlightHarp - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/marks/takeDownOne (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/marks/takeDownOnePastThree (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/marks/takeRowFive (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/marks/takeRowFour (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/marks/takeRowOne (60ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/marks/takeRowTwoPastDownThree (55ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/marks/takeRowTwoPastFour (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/marks/takeSource (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/marks/takeThat (68ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/marks/takeThis (57ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/marks/takeUpOnePastDownOne (55ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/marks/takeUpOnePastRowFour (50ms) -Couldn't find mark default 'h' -Error: Couldn't find mark default 'h' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -Couldn't find mark default 'h' -Error: Couldn't find mark default 'h' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -Couldn't find mark default 'h' -Error: Couldn't find mark default 'h' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -Couldn't find mark default 'h' -Error: Couldn't find mark default 'h' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -Couldn't find mark default 'h' -Error: Couldn't find mark default 'h' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -Couldn't find mark default 'h' -Error: Couldn't find mark default 'h' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) - 11) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/bringHarpToAfterFile -TextEditor#edit not possible on closed editors -Error: TextEditor#edit not possible on closed editors - at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) - at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) - at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) - at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) - at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 - at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 - at Array.map () - at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) - at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) - at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) - at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -TextEditor#edit not possible on closed editors -Error: TextEditor#edit not possible on closed editors - at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) - at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) - at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) - at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) - at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 - at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 - at Array.map () - at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) - at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) - at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) - at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -TextEditor#edit not possible on closed editors -Error: TextEditor#edit not possible on closed editors - at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) - at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) - at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) - at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) - at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 - at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 - at Array.map () - at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) - at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) - at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) - at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -TextEditor#edit not possible on closed editors -Error: TextEditor#edit not possible on closed editors - at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) - at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) - at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) - at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) - at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 - at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 - at Array.map () - at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) - at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) - at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) - at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -TextEditor#edit not possible on closed editors -Error: TextEditor#edit not possible on closed editors - at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) - at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) - at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) - at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) - at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 - at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 - at Array.map () - at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) - at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) - at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) - at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -TextEditor#edit not possible on closed editors -Error: TextEditor#edit not possible on closed editors - at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) - at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) - at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) - at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) - at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 - at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 - at Array.map () - at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) - at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) - at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) - at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) - 12) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/bringStateFineToAfterBatt -Couldn't find mark default 'w' -Error: Couldn't find mark default 'w' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -Couldn't find mark default 'w' -Error: Couldn't find mark default 'w' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -Couldn't find mark default 'w' -Error: Couldn't find mark default 'w' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -Couldn't find mark default 'w' -Error: Couldn't find mark default 'w' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -Couldn't find mark default 'w' -Error: Couldn't find mark default 'w' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -Couldn't find mark default 'w' -Error: Couldn't find mark default 'w' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) - 13) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/bringWhaleToBeforeFile - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckAfterBlockVest (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckAfterHarp - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckAfterLineVest (38ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckAfterLook (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckAfterVest (53ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckAir (65ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckBeforeAir (69ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckBeforeBlockAir (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckBeforeEach (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckBeforeHarp (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckBeforeLineAir (71ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckBeforeVest (58ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckPastAfterLook (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckPastBeforeTrap (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckPastEndOfLine (42ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckPastEndOfLook (38ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/chuckPastStartOfTrap (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/replaceAfterVestWithHallo - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/replaceBeforeVestWithHello (53ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/replaceEndOfVestWithHello (42ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/replaceStartOfVestWithHello (46ms) -TextEditor#edit not possible on closed editors -Error: TextEditor#edit not possible on closed editors - at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) - at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) - at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) - at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) - at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 - at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 - at Array.map () - at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) - at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) - at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) - at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -TextEditor#edit not possible on closed editors -Error: TextEditor#edit not possible on closed editors - at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) - at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) - at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) - at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) - at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 - at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 - at Array.map () - at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) - at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) - at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) - at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -TextEditor#edit not possible on closed editors -Error: TextEditor#edit not possible on closed editors - at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) - at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) - at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) - at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) - at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 - at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 - at Array.map () - at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) - at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) - at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) - at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -TextEditor#edit not possible on closed editors -Error: TextEditor#edit not possible on closed editors - at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) - at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) - at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) - at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) - at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 - at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 - at Array.map () - at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) - at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) - at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) - at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -TextEditor#edit not possible on closed editors -Error: TextEditor#edit not possible on closed editors - at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) - at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) - at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) - at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) - at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 - at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 - at Array.map () - at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) - at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) - at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) - at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -TextEditor#edit not possible on closed editors -Error: TextEditor#edit not possible on closed editors - at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) - at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) - at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) - at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) - at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 - at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 - at Array.map () - at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) - at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) - at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) - at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) - 14) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/bringHarpToAfterFile -TextEditor#edit not possible on closed editors -Error: TextEditor#edit not possible on closed editors - at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) - at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) - at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) - at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) - at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 - at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 - at Array.map () - at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) - at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) - at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) - at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -TextEditor#edit not possible on closed editors -Error: TextEditor#edit not possible on closed editors - at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) - at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) - at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) - at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) - at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 - at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 - at Array.map () - at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) - at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) - at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) - at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -TextEditor#edit not possible on closed editors -Error: TextEditor#edit not possible on closed editors - at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) - at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) - at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) - at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) - at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 - at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 - at Array.map () - at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) - at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) - at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) - at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -TextEditor#edit not possible on closed editors -Error: TextEditor#edit not possible on closed editors - at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) - at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) - at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) - at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) - at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 - at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 - at Array.map () - at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) - at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) - at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) - at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -TextEditor#edit not possible on closed editors -Error: TextEditor#edit not possible on closed editors - at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) - at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) - at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) - at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) - at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 - at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 - at Array.map () - at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) - at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) - at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) - at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -TextEditor#edit not possible on closed editors -Error: TextEditor#edit not possible on closed editors - at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) - at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) - at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) - at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) - at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 - at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 - at Array.map () - at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) - at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) - at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) - at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) - 15) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/bringWhaleToBeforeFile - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockAir (56ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockAir2 (55ms) -Couldn't find mark default 'f' -Error: Couldn't find mark default 'f' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processRangeTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9725:25) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9718:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -Couldn't find mark default 'f' -Error: Couldn't find mark default 'f' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processRangeTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9725:25) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9718:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -Couldn't find mark default 'f' -Error: Couldn't find mark default 'f' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processRangeTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9725:25) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9718:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -Couldn't find mark default 'f' -Error: Couldn't find mark default 'f' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processRangeTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9725:25) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9718:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -Couldn't find mark default 'f' -Error: Couldn't find mark default 'f' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processRangeTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9725:25) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9718:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -Couldn't find mark default 'f' -Error: Couldn't find mark default 'f' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processRangeTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9725:25) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9718:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) - 16) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockHarpBetweenFine - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockVest (81ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/chuckFile (81ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/chuckFile2 (76ms) -Couldn't find mark default 'f' -Error: Couldn't find mark default 'f' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processRangeTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9725:25) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9718:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -Couldn't find mark default 'f' -Error: Couldn't find mark default 'f' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processRangeTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9725:25) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9718:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -Couldn't find mark default 'f' -Error: Couldn't find mark default 'f' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processRangeTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9725:25) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9718:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -Couldn't find mark default 'f' -Error: Couldn't find mark default 'f' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processRangeTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9725:25) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9718:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -Couldn't find mark default 'f' -Error: Couldn't find mark default 'f' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processRangeTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9725:25) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9718:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -Couldn't find mark default 'f' -Error: Couldn't find mark default 'f' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processRangeTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9725:25) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9718:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) - 17) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/chuckLineHarpBetweenFine - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/chuckLineVest (80ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/chuckLineVest2 (80ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/chuckLinkMade (74ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/chuckLinkMadePastLinkAir (74ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/chuckLinkPit (63ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/chuckPaintBatt (64ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/chuckTokenVest (67ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/clearLinePair (93ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/clearPaint (76ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/clearPaintBatt (126ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/clearPaintBattPastBlueBatt (66ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/drinkBlock (72ms) - 18) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/drinkCell - 19) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/drinkCellEach - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/drinkEveryArg (84ms) -Couldn't find mark default 'f' -Error: Couldn't find mark default 'f' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -Couldn't find mark default 'f' -Error: Couldn't find mark default 'f' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -Couldn't find mark default 'f' -Error: Couldn't find mark default 'f' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -Couldn't find mark default 'f' -Error: Couldn't find mark default 'f' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -Couldn't find mark default 'f' -Error: Couldn't find mark default 'f' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) -Couldn't find mark default 'f' -Error: Couldn't find mark default 'f' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) - 20) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/drinkJustFine - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/drinkToken (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/pourBlock (58ms) - 21) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/pourCell - 22) /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/pourCellEach - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/pourEveryArg (65ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/takeBlockAir (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock2 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/takeEveryBlock3 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/takeEveryFile - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine2 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/takeEveryLine3 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/takeFile - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/takeLineVest (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/takeTokenVest (55ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/chuckFirstCharVest (66ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/chuckFirstWordVest (62ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/chuckLastCharVest (63ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/chuckLastWordVest (55ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/chuckSecondWordVest (53ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/chuckSixthCharVest (80ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/clearFirstCharVest (98ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/clearFirstWordVest (61ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/clearLastCharVest (66ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/clearLastWordVest (54ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/clearSecondWordVest (74ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/clearSixthCharVest (62ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeFirstChar (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeFirstChar2 (64ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeFirstChar3 (58ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeFirstChar4 (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeFirstChar5 (56ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeFirstPastLastCharHarp (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeFirstPastLastWordHarp (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeFirstPastSecondWordHarp (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeFirstThreeCharHarp (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeFirstTwoWordHarp (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeFirstWord (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeLastPastFirstCharHarp (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeLastPastFirstWordHarp (38ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeLastThreeCharHarp (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeLastTwoWordHarp (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeSecondCharLookPastEndOfToken (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeSecondCharLookPastSecondCharTrap (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeSecondWord (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/subtoken/takeThirdPastSecondWordHarp (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearBoundsBatt (53ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearBoundsEach (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearBoundsHarp (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearBoundsOx (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearBoundsRam (53ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearCurly (63ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair10 (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair11 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair12 (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair13 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair14 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair15 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair16 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair17 (70ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair2 (79ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair3 (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair4 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair5 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair6 (43ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair7 (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair8 (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPair9 (57ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPairBatt (56ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPairOx (59ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearPairRam (54ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearRound (60ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/html/clearRound2 (157ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearBound (63ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearCore (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearCore2 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearPair (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearPair2 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearPair3 (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearPair4 (57ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/cpp/clearOutside (63ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/cpp/clearRound8 (58ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/java/clearQuad3 (54ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/java/clearRound10 (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/java/clearRound11 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/json/clearPair (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/json/clearPair2 (67ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/json/clearRound (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/json/clearRound2 (57ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/chuckMatching (53ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/chuckMatching2 (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/chuckMatching3 (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/chuckPair (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/chuckRound (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearCurly (60ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearCurly3 (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearMatching (59ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearMatching10 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearMatching11 (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearMatching2 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearMatching3 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearMatching4 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearMatching5 (57ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearMatching6 (54ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearMatching7 (65ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearMatching8 (60ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearMatching9 (56ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearOutside7 (64ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearOutside8 (54ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearPair (64ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearPair2 (60ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearPair3 (62ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearPair4 (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearPairCurly (57ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearQuad2 (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearQuad4 (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearRound (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearRound5 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearRound6 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearRound7 (70ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearSquare (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/python/clearSquare2 (53ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/shellscript/clearCurly4 (158ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/shellscript/clearOutside23 (82ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/shellscript/clearPair (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/shellscript/clearString5 (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/takeCore (76ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair10 (136ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair11 (70ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair12 (65ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair13 (65ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair14 (76ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair15 (71ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair16 (75ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair17 (72ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair18 (65ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair19 (74ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair20 (71ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair21 (66ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair23 (64ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair4 (65ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair5 (82ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair6 (67ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair7 (73ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair8 (69ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/tsx/clearPair9 (70ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearMatching14 (78ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearMatching15 (71ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside10 (76ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside11 (63ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside12 (67ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside13 (62ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside14 (68ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside15 (59ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside16 (66ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside17 (83ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside18 (88ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside19 (71ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside2 (66ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside20 (83ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside21 (70ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside22 (78ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside3 (80ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside4 (76ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside5 (73ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside6 (75ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearOutside9 (79ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair (74ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair10 (60ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair2 (71ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair3 (75ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair4 (71ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair5 (66ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair6 (95ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair7 (85ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair8 (79ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearPair9 (63ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearQuad (62ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearRound2 (55ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearRound3 (69ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearRound4 (78ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearSkis (68ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearSquare3 (57ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearSquare4 (57ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearSquare5 (61ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearSquareLack (71ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearSquareRack (81ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearString (81ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearString2 (62ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/clearString3 (69ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTree/typescript/takePairBatt (60ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/chuckInsideRound (66ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/chuckPairRound (83ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/chuckRound2 (58ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/clearCurly2 (80ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/clearOutsideGreenDouble (65ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/clearRound9 (71ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeInsideRound (61ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeInsideRound2 (63ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside (58ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside11 (57ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside12 (59ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside13 (62ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside14 (65ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside15 (59ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside16 (86ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside17 (67ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside18 (61ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside19 (53ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside2 (63ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside20 (57ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside21 (72ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside22 (57ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside23 (65ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside24 (69ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside25 (64ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside26 (73ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside3 (112ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside4 (115ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside5 (68ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside6 (59ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside7 (63ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside8 (59ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutside9 (73ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutsideLeper (61ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeOutsideRack (59ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairDouble (56ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairRound (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairRound2 (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeQuad (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeQuad2 (65ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeQuad3 (61ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeQuad4 (58ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeQuad5 (56ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeQuad6 (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound10 (56ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound11 (59ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound12 (54ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound13 (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound14 (57ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound15 (54ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound16 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound17 (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound18 (73ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound19 (91ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound2 (63ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound20 (61ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound21 (60ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound22 (67ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound23 (63ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound3 (65ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound4 (61ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound5 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound6 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound7 (54ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound8 (54ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRound9 (56ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRoundLeper (59ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeRoundRepper (56ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takeSquare (56ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/chuckInsideRound (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/chuckPairHarp - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/chuckPairRound (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/chuckRound2 (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearBoundsBatt2 (38ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearBoundsEach2 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearBoundsOx2 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearBoundsRam2 (57ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearCurly2 (84ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearEscapedSquare (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearOutsideGreenDouble (66ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearPair (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearPair10 (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearPair11 (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearPair12 (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearPair13 (43ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearPair14 (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearPair15 (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearPair16 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearPair2 (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearPair3 (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearPair4 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearPair5 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearPair6 (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearPair7 (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearPair8 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearPair9 (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearRound (81ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearRound9 (43ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearSquare (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/clearString4 (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/tailTakeEscapedQuad (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeEscapedQuad (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeEscapedQuad2 (38ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeEscapedQuad3 (43ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeEscapedQuad4 (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeEscapedQuad5 (42ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeInsideRound (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeInsideRound2 (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeLeftQuad - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeLeftQuad2 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeLeftQuad3 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeLeftQuad4 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeLeftQuad5 (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeLeftQuad6 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeLeftQuad7 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside (38ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside10 (42ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside11 (38ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside12 (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside13 (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside14 (38ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside15 (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside16 (43ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside17 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside18 (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside19 (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside2 (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside20 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside21 (75ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside22 (56ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside23 (62ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside24 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside25 (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside26 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside27 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside3 (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside4 (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside5 (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside6 (71ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside7 (109ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside8 (63ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutside9 (58ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutsideFine (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutsideLeper (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutsideRack (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeOutsideUrge (55ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takePairDouble (42ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takePairRound (38ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takePairRound2 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeQuad (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeQuad2 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeQuad3 (54ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeQuad4 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeQuad5 (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeQuad6 (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRightQuad (42ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRightQuad2 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRightQuad3 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRightQuad4 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRightQuad5 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRightQuad6 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRightQuad7 (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound10 (42ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound11 (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound12 (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound13 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound14 (56ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound15 (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound16 (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound17 (42ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound18 (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound19 (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound2 (43ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound20 (42ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound21 (43ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound22 (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound23 (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound3 (43ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound4 (43ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound5 (55ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound6 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound7 (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound8 (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRound9 (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRoundLeper (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeRoundRepper (61ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/surroundingPair/textual/takeSquare (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringFine (49ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringFineAfterThirdCarThis (48ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringFineAfterThis (75ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringFineAfterThis2 (82ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringFineBeforeThis (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringFineToFirstCarWhale (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringFineToFirstTwoCar (50ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringFineToLastCarWhale (45ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringFineToLastTwoCar (52ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringFineToThirdCarWhale (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringFineToWhale (47ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringFineToWhale2 (103ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringFineToWhale3 (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringFineToWhale4 (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringFineToWhale5 (43ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringHarpToEndOfWhale (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringHarpToFourthCarWhalePastSecondCarHarp (42ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringHarpToSecondCarFinePastThirdCarHarp (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringHarpToSecondCarFinePastThirdCarWhale (56ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringHarpToStartOfWhale (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringWhale (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringWhaleAfterFine (39ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringWhaleAfterThis (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringWhaleAfterThis2 - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringWhaleBeforeThis (42ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringWhaleToEndOfFine (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/bringWhaleToFine (40ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/chuckFirstCarWhale (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/chuckFirstPastSecondCar (44ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/chuckFourthPastFifthCar (51ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/chuckLastCarWhale (57ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/chuckSecondCarFinePastThirdCarWhale (46ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/chuckSecondPastThirdCar (41ms) - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/chuckThirdCarWhalePastSecondCarHarp - ✓ /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/updateSelections/commentTrap (62ms) - scroll - ✓ top whale - ✓ bottom whale (43ms) - subtoken regex matcher - ✓ QuickBrownFox - ✓ quickBrownFox - ✓ quick_brown_fox - ✓ QUICK_BROWN_FOX - ✓ quick-brown-fox - ✓ QUICK-BROWN-FOX - ✓ quick.brown.fox - ✓ QUICK.BROWN.FOX - ✓ ../quick/brown/.fox - ✓ ../QUICK/BROWN/.FOX - ✓ quick::brown::fox - ✓ QUICK::BROWN::FOX - ✓ APIClientFactory - ✓ MockAPIClientFactory - ✓ mockAPIClientFactory - ✓ mockAPIClient123Factory - toggle decorations - ✓ toggle decorations - tokenizer - ✓ 0.0 0 1 120 2.5 0.1 - ✓ 1.22.4 - ✓ my variable - ✓ My Variable - ✓ myVariable - ✓ MyVariable - ✓ my_variable - ✓ MY_VARIABLE - ✓ my__variable - ✓ my-variable - ✓ my.variable - ✓ my/variable - ✓ my::variable - ✓ _a - ✓ "my variable" - ✓ 'my variable' - ✓ ! - ✓ " - ✓ # - ✓ $ - ✓ % - ✓ & - ✓ ' - ✓ ( - ✓ ) - ✓ * - ✓ + - ✓ , - ✓ - - ✓ . - ✓ / - ✓ : - ✓ ; - ✓ < - ✓ = - ✓ > - ✓ ? - ✓ @ - ✓ [ - ✓ \ - ✓ ] - ✓ ^ - ✓ _ - ✓ ` - ✓ { - ✓ | - ✓ } - ✓ ~ - ✓ ---|||///+++ - ✓ !!(()){{}} - ✓ !=>=!==== - ✓ => - ✓ :: - ✓ -> - ✓ ?? - ✓ \r\n\t - ✓ """hello""" - ✓ ```typescript - ✓ """""" - ✓ `````` - ✓ "" - ✓ '' - ✓ `` - ✓ // Hello world - ✓ /* Hello world */ - ✓ - ✓ #aaaaaa - ✓ #11aaaa - ✓ #aa11aa - ✓ #aaaa11 - ✓ #111111 - ✓ aåäöb - 1549 passing (2m) - 55 pending - 22 failing - 1) recorded test cases - /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachBetweenHarp: - - AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: -+ actual - expected - - { - end: { -+ character: 13, -+ line: 6 -- character: 9, -- line: 3 - }, - start: { -+ character: 8, -+ line: 6 -- character: 4, -- line: 3 - } - } - + expected - actual - - { - "end": { - - "character": 13 - - "line": 6 - + "character": 9 - + "line": 3 - } - "start": { - - "character": 8 - - "line": 6 - + "character": 4 - + "line": 3 - } - } - - at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:126:16 - at Array.forEach () - at checkMarks (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:122:27) - at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:100:9 - at Generator.next () - at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) - - 2) recorded test cases - /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/chuckBlockEachUntilHarp: - - AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: -+ actual - expected - - { - end: { -+ character: 13, -+ line: 6 -- character: 9, -- line: 3 - }, - start: { -+ character: 8, -+ line: 6 -- character: 4, -- line: 3 - } - } - + expected - actual - - { - "end": { - - "character": 13 - - "line": 6 - + "character": 9 - + "line": 3 - } - "start": { - - "character": 8 - - "line": 6 - + "character": 4 - + "line": 3 - } - } - - at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:126:16 - at Array.forEach () - at checkMarks (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:122:27) - at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:100:9 - at Generator.next () - at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) - - 3) recorded test cases - /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachBetweenHarp: - - AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: -+ actual - expected - - { - end: { -+ character: 13, -+ line: 6 -- character: 9, -- line: 3 - }, - start: { -+ character: 8, -+ line: 6 -- character: 4, -- line: 3 - } - } - + expected - actual - - { - "end": { - - "character": 13 - - "line": 6 - + "character": 9 - + "line": 3 - } - "start": { - - "character": 8 - - "line": 6 - + "character": 4 - + "line": 3 - } - } - - at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:126:16 - at Array.forEach () - at checkMarks (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:122:27) - at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:100:9 - at Generator.next () - at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) - - 4) recorded test cases - /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachBetweenHarp2: - Error: TextEditor#edit not possible on closed editors - at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) - at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) - at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) - at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) - at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) - at performEditsAndUpdateInternal (/Users/pokey/src/cursorless-vscode/dist/extension.js:5805:9) - at performEditsAndUpdateRanges (/Users/pokey/src/cursorless-vscode/dist/extension.js:5802:10) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:10753:37 - at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 - at Array.map () - at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) - at runOnTargetsForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6285:10) - at Delete.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10746:57) - at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) - - 5) recorded test cases - /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/compoundTargets/chuckLineEachUntilHarp: - - AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: -+ actual - expected - - { - end: { -+ character: 13, -+ line: 6 -- character: 9, -- line: 3 - }, - start: { -+ character: 8, -+ line: 6 -- character: 4, -- line: 3 - } - } - + expected - actual - - { - "end": { - - "character": 13 - - "line": 6 - + "character": 9 - + "line": 3 - } - "start": { - - "character": 8 - - "line": 6 - + "character": 4 - + "line": 3 - } - } - - at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:126:16 - at Array.forEach () - at checkMarks (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:122:27) - at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:100:9 - at Generator.next () - at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) - - 6) recorded test cases - /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToEndOfThisAndEndOfWhaleTakeWhale: - - AssertionError [ERR_ASSERTION]: Unexpected final state - + expected - actual - - "character": 12 - "line": 0 - } - } - - { - - "active": { - - "character": 18 - - "line": 0 - - } - - "anchor": { - - "character": 12 - - "line": 0 - - } - - } - ] - } - - at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:113:20 - at Generator.next () - at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) - at runMicrotasks () - at processTicksAndRejections (node:internal/process/task_queues:96:5) - - 7) recorded test cases - /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhale: - - AssertionError [ERR_ASSERTION]: Unexpected final state - + expected - actual - - } - } - "default.w": { - "end": { - - "character": 18 - + "character": 12 - "line": 0 - } - "start": { - "character": 7 --- - "character": 12 - "line": 0 - } - } - - { - - "active": { - - "character": 18 - - "line": 0 - - } - - "anchor": { - - "character": 12 - - "line": 0 - - } - - } - ] - } - - at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:113:20 - at Generator.next () - at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) - at runMicrotasks () - at processTicksAndRejections (node:internal/process/task_queues:96:5) - - 8) recorded test cases - /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhaleTakeWhale: - - AssertionError [ERR_ASSERTION]: Unexpected final state - + expected - actual - - } - } - "default.w": { - "end": { - - "character": 18 - + "character": 12 - "line": 0 - } - "start": { - "character": 7 --- - "character": 12 - "line": 0 - } - } - - { - - "active": { - - "character": 18 - - "line": 0 - - } - - "anchor": { - - "character": 12 - - "line": 0 - - } - - } - ] - } - - at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:113:20 - at Generator.next () - at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) - at runMicrotasks () - at processTicksAndRejections (node:internal/process/task_queues:96:5) - - 9) recorded test cases - /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/tryCatchWrapThis: - - AssertionError [ERR_ASSERTION]: Unexpected final state - + expected - actual - - { - - "documentContents": "try {\n const foo = \"hello\";\n} catch (err) {\n \n}" - + "documentContents": "try {\n const foo = \"hello\";\n} catch () {\n \n}" - "selections": [ - { - "active": { - - "character": 4 - - "line": 3 - + "character": 9 - + "line": 2 - } - "anchor": { - - "character": 4 - - "line": 3 - + "character": 9 - + "line": 2 - } - } - ] - "thatMark": [ - - at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:113:20 - at Generator.next () - at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) - at runMicrotasks () - at processTicksAndRejections (node:internal/process/task_queues:96:5) - - 10) recorded test cases - /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/languages/typescript/tryCatchWrapThis2: - - AssertionError [ERR_ASSERTION]: Unexpected final state - + expected - actual - - { - - "documentContents": "try {\n if (true) {\n const foo = \"hello\";\n }\n} catch (err) {\n \n}\n\ntry {\n const bar = \"hello\";\n} catch (err) {\n \n}" - + "documentContents": "try {\n if (true) {\n const foo = \"hello\";\n }\n} catch () {\n \n}\n\ntry {\n const bar = \"hello\";\n} catch () {\n \n}" - "selections": [ - { - "active": { - - "character": 4 - - "line": 11 - + "character": 9 - + "line": 10 - } - "anchor": { - - "character": 4 - - "line": 11 - + "character": 9 - + "line": 10 - } - } - { - "active": { - - "character": 4 - - "line": 5 - + "character": 9 - + "line": 4 - } - "anchor": { - - "character": 4 - - "line": 5 - + "character": 9 - + "line": 4 - } - } - ] - "thatMark": [ - - at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:113:20 - at Generator.next () - at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) - at runMicrotasks () - at processTicksAndRejections (node:internal/process/task_queues:96:5) - - 11) recorded test cases - /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/bringHarpToAfterFile: - Error: Couldn't find mark default 'h' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) - - 12) recorded test cases - /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/bringStateFineToAfterBatt: - Error: TextEditor#edit not possible on closed editors - at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) - at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) - at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) - at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) - at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 - at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 - at Array.map () - at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) - at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) - at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) - at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) - - 13) recorded test cases - /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/positions/bringWhaleToBeforeFile: - Error: Couldn't find mark default 'w' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) - - 14) recorded test cases - /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/bringHarpToAfterFile: - Error: TextEditor#edit not possible on closed editors - at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) - at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) - at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) - at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) - at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 - at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 - at Array.map () - at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) - at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) - at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) - at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) - - 15) recorded test cases - /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/bringWhaleToBeforeFile: - Error: TextEditor#edit not possible on closed editors - at Object.edit (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:81:51791) - at performDocumentEdits (/Users/pokey/src/cursorless-vscode/dist/extension.js:5708:41) - at func (/Users/pokey/src/cursorless-vscode/dist/extension.js:5810:36) - at callFunctionAndUpdateSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5790:9) - at performEditsAndUpdateFullSelectionInfos (/Users/pokey/src/cursorless-vscode/dist/extension.js:5815:9) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:10008:63 - at /Users/pokey/src/cursorless-vscode/dist/extension.js:6282:94 - at Array.map () - at runForEachEditor (/Users/pokey/src/cursorless-vscode/dist/extension.js:6282:61) - at Bring.performEditsAndComputeThatMark (/Users/pokey/src/cursorless-vscode/dist/extension.js:10004:47) - at Bring.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:10038:36) - at async CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17169:11) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) - - 16) recorded test cases - /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockHarpBetweenFine: - Error: Couldn't find mark default 'f' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processRangeTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9725:25) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9718:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) - - 17) recorded test cases - /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/chuckLineHarpBetweenFine: - Error: Couldn't find mark default 'f' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processRangeTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9725:25) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9718:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) - - 18) recorded test cases - /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/drinkCell: - - AssertionError [ERR_ASSERTION]: Unexpected final state - + expected - actual - - ] - "thatMark": [ - { - "active": { - - "character": 12 - + "character": 0 - "line": 1 - } - "anchor": { - - "character": 12 - + "character": 0 - "line": 1 - } - } - ] - - at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:113:20 - at Generator.next () - at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) - at runMicrotasks () - at processTicksAndRejections (node:internal/process/task_queues:96:5) - - 19) recorded test cases - /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/drinkCellEach: - - AssertionError [ERR_ASSERTION]: Unexpected final state - + expected - actual - - ] - "thatMark": [ - { - "active": { - - "character": 12 - + "character": 0 - "line": 1 - } - "anchor": { - - "character": 7 - + "character": 0 - "line": 1 - } - } - ] - - at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:113:20 - at Generator.next () - at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) - at runMicrotasks () - at processTicksAndRejections (node:internal/process/task_queues:96:5) - - 20) recorded test cases - /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/drinkJustFine: - Error: Couldn't find mark default 'f' - at DecoratedSymbolStage_default.run (/Users/pokey/src/cursorless-vscode/dist/extension.js:6460:13) - at processPrimitiveTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9839:27) - at processTarget (/Users/pokey/src/cursorless-vscode/dist/extension.js:9720:14) - at /Users/pokey/src/cursorless-vscode/dist/extension.js:9711:51 - at Array.map () - at processTargets_default (/Users/pokey/src/cursorless-vscode/dist/extension.js:9711:18) - at CommandRunner.runCommand (/Users/pokey/src/cursorless-vscode/dist/extension.js:17154:23) - at async o._executeContributedCommand (/Applications/Visual Studio Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:83:31325) - - 21) recorded test cases - /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/pourCell: - - AssertionError [ERR_ASSERTION]: Unexpected final state - + expected - actual - - ] - "thatMark": [ - { - "active": { - - "character": 12 - - "line": 1 - + "character": 0 - + "line": 3 - } - "anchor": { - - "character": 12 - - "line": 1 - + "character": 0 - + "line": 3 - } - } - ] - } - - at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:113:20 - at Generator.next () - at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) - at runMicrotasks () - at processTicksAndRejections (node:internal/process/task_queues:96:5) - - 22) recorded test cases - /Users/pokey/src/cursorless-vscode/src/test/suite/fixtures/recorded/selectionTypes/pourCellEach: - - AssertionError [ERR_ASSERTION]: Unexpected final state - + expected - actual - - ] - "thatMark": [ - { - "active": { - - "character": 12 - - "line": 1 - + "character": 0 - + "line": 4 - } - "anchor": { - - "character": 7 - - "line": 1 - + "character": 0 - + "line": 4 - } - } - ] - } - - at /Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:113:20 - at Generator.next () - at fulfilled (/Users/pokey/src/cursorless-vscode/out/test/suite/recorded.test.js:5:58) - at runMicrotasks () - at processTicksAndRejections (node:internal/process/task_queues:96:5) - -Error: 22 tests failed. - at /Users/pokey/src/cursorless-vscode/out/test/suite/index.js:27:27 - at done (/Users/pokey/src/cursorless-vscode/node_modules/mocha/lib/mocha.js:1053:7) - at runMicrotasks () - at processTicksAndRejections (node:internal/process/task_queues:96:5) diff --git a/src/actions/BringMoveSwap.ts b/src/actions/BringMoveSwap.ts index d353a0336a..dcca5a1299 100644 --- a/src/actions/BringMoveSwap.ts +++ b/src/actions/BringMoveSwap.ts @@ -1,4 +1,4 @@ -import { flatten, uniqWith } from "lodash"; +import { flatten } from "lodash"; import { DecorationRangeBehavior, Selection, TextEditor } from "vscode"; import { getSelectionInfo, @@ -240,13 +240,13 @@ class BringMoveSwap implements Action { const thatMark = this.type === "swap" ? markEntries - : uniqMarks(markEntries.filter(({ isSource }) => !isSource)); + : markEntries.filter(({ isSource }) => !isSource); // Only swap doesn't have a source mark const sourceMark = this.type === "swap" ? [] - : uniqMarks(markEntries.filter(({ isSource }) => isSource)); + : markEntries.filter(({ isSource }) => isSource); return { thatMark, sourceMark }; } @@ -294,10 +294,3 @@ function getTextWithPossibleDelimiter(source: Target, destination: Target) { const sourceText = source.contentText; return destination.maybeAddDelimiter(sourceText); } - -function uniqMarks(markEntries: MarkEntry[]): MarkEntry[] { - return uniqWith( - markEntries, - (a, b) => a.editor === b.editor && a.selection.isEqual(b.selection) - ); -} diff --git a/src/processTargets/modifiers/ModifyIfWeakStage.ts b/src/processTargets/modifiers/ModifyIfWeakStage.ts index 6d31899e90..449e8b163a 100644 --- a/src/processTargets/modifiers/ModifyIfWeakStage.ts +++ b/src/processTargets/modifiers/ModifyIfWeakStage.ts @@ -4,10 +4,16 @@ import getModifierStage from "../getModifierStage"; import { ModifierStage } from "../PipelineStages.types"; export default class implements ModifierStage { - private nestedStage: ModifierStage; + private nestedStage_?: ModifierStage; - constructor(nestedModifier: Modifier) { - this.nestedStage = getModifierStage(nestedModifier); + constructor(private nestedModifier: Modifier) {} + + private get nestedStage() { + if (this.nestedStage_ == null) { + this.nestedStage_ = getModifierStage(this.nestedModifier); + } + + return this.nestedStage_; } run(context: ProcessedTargetsContext, target: Target): Target[] { diff --git a/src/test/suite/fixtures/recorded/surroundingPair/textual/takePairRound.yml b/src/test/suite/fixtures/recorded/surroundingPair/textual/clearBoundsRound.yml similarity index 100% rename from src/test/suite/fixtures/recorded/surroundingPair/textual/takePairRound.yml rename to src/test/suite/fixtures/recorded/surroundingPair/textual/clearBoundsRound.yml diff --git a/src/util/targetUtils.ts b/src/util/targetUtils.ts index 1b58914277..84c5dd1029 100644 --- a/src/util/targetUtils.ts +++ b/src/util/targetUtils.ts @@ -9,7 +9,6 @@ import { } from "../typings/Types"; import { groupBy } from "./itertools"; import { isReversed } from "./selectionUtils"; -import uniqDeep from "./uniqDeep"; export function ensureSingleEditor(targets: Target[]) { if (targets.length === 0) { @@ -108,7 +107,7 @@ export function createThatMark( editor: target!.editor, selection: target.contentSelection, })); - return uniqDeep(thatMark); + return thatMark; } export function getRemovalRange(target: Target) { From 0bce7271eab09d1aa01ac1a187c8b45837297a9d Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 26 May 2022 15:24:08 +0200 Subject: [PATCH 210/314] Use utility function to set selection that deduplicates --- src/actions/BringMoveSwap.ts | 3 ++- src/actions/CommandAction.ts | 3 ++- src/actions/CopyLines.ts | 5 +++-- src/actions/Deselect.ts | 10 +++++++--- src/actions/EditNew.ts | 5 ++++- src/actions/InsertEmptyLines.ts | 3 ++- src/actions/Wrap.ts | 3 ++- src/util/setSelectionsAndFocusEditor.ts | 10 +++++++++- 8 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/actions/BringMoveSwap.ts b/src/actions/BringMoveSwap.ts index dcca5a1299..70c5f8aa03 100644 --- a/src/actions/BringMoveSwap.ts +++ b/src/actions/BringMoveSwap.ts @@ -7,6 +7,7 @@ import { import { Target } from "../typings/target.types"; import { Edit, Graph } from "../typings/Types"; import displayPendingEditDecorations from "../util/editDisplayUtils"; +import { setSelectionsWithoutFocusingEditor } from "../util/setSelectionsAndFocusEditor"; import { getContentRange, getRemovalRange, @@ -199,7 +200,7 @@ class BringMoveSwap implements Action { [editSelectionInfos, cursorSelectionInfos] ); - editor.selections = cursorSelections; + setSelectionsWithoutFocusingEditor(editor, cursorSelections); return edits.map((edit, index): MarkEntry => { const selection = updatedEditSelections[index]; diff --git a/src/actions/CommandAction.ts b/src/actions/CommandAction.ts index 9386c6c3fe..5c967867e7 100644 --- a/src/actions/CommandAction.ts +++ b/src/actions/CommandAction.ts @@ -7,6 +7,7 @@ import displayPendingEditDecorations from "../util/editDisplayUtils"; import { focusEditor, setSelectionsAndFocusEditor, + setSelectionsWithoutFocusingEditor, } from "../util/setSelectionsAndFocusEditor"; import { ensureSingleEditor, @@ -60,7 +61,7 @@ export default class CommandAction implements Action { // Reset original selections if (options.restoreSelection) { - editor.selections = updatedOriginalSelections; + setSelectionsWithoutFocusingEditor(editor, updatedOriginalSelections); } return updatedTargetSelections.map((selection) => ({ diff --git a/src/actions/CopyLines.ts b/src/actions/CopyLines.ts index 1622eb5b5f..0e68dd7318 100644 --- a/src/actions/CopyLines.ts +++ b/src/actions/CopyLines.ts @@ -5,6 +5,7 @@ import { weakContainingLineStage } from "../processTargets/modifiers/commonWeakC import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; import { displayPendingEditDecorationsForRanges } from "../util/editDisplayUtils"; +import { setSelectionsWithoutFocusingEditor } from "../util/setSelectionsAndFocusEditor"; import { createThatMark, runOnTargetsForEachEditor } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; @@ -57,8 +58,8 @@ class CopyLines implements Action { ] ); - editor.selections = updatedEditorSelections; - editor.revealRange(thatSelections[0]); + setSelectionsWithoutFocusingEditor(editor, updatedEditorSelections); + editor.revealRange(editor.selection); const sourceSelections = zip(edits, updatedEditSelections).map( ([edit, selection]) => { diff --git a/src/actions/Deselect.ts b/src/actions/Deselect.ts index e6ff981df1..553f939cd5 100644 --- a/src/actions/Deselect.ts +++ b/src/actions/Deselect.ts @@ -1,6 +1,7 @@ import { Selection } from "vscode"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; +import { setSelectionsWithoutFocusingEditor } from "../util/setSelectionsAndFocusEditor"; import { createThatMark, runOnTargetsForEachEditor } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; @@ -20,9 +21,12 @@ export default class Deselect implements Action { }) ); // The editor requires at least one selection. Keep "primary" selection active - editor.selections = newSelections.length - ? newSelections - : [new Selection(editor.selection.active, editor.selection.active)]; + setSelectionsWithoutFocusingEditor( + editor, + newSelections.length > 0 + ? newSelections + : [new Selection(editor.selection.active, editor.selection.active)] + ); }); return { diff --git a/src/actions/EditNew.ts b/src/actions/EditNew.ts index 486d853d6c..6d2bd5cd32 100644 --- a/src/actions/EditNew.ts +++ b/src/actions/EditNew.ts @@ -8,6 +8,7 @@ import { weakContainingLineStage } from "../processTargets/modifiers/commonWeakC import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; import { selectionFromRange } from "../util/selectionUtils"; +import { setSelectionsAndFocusEditor } from "../util/setSelectionsAndFocusEditor"; import { createThatMark, ensureSingleEditor } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; import { getEditRange, getLinePadding } from "./CopyLines"; @@ -63,11 +64,13 @@ class EditNew implements Action { await this.runCommandTargets(editor, richTargets); await this.runDelimiterTargets(editor, richTargets); - editor.selections = richTargets.map((target) => + const newSelections = richTargets.map((target) => selectionFromRange(target.target.isReversed, target.cursorRange) ); const targetRanges = richTargets.map((target) => target.targetRange); + await setSelectionsAndFocusEditor(editor, newSelections); + return { thatMark: createThatMark(targets, targetRanges), }; diff --git a/src/actions/InsertEmptyLines.ts b/src/actions/InsertEmptyLines.ts index e6c5ad5782..bb5224a671 100644 --- a/src/actions/InsertEmptyLines.ts +++ b/src/actions/InsertEmptyLines.ts @@ -4,6 +4,7 @@ import { performEditsAndUpdateSelections } from "../core/updateSelections/update import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; import { displayPendingEditDecorationsForRanges } from "../util/editDisplayUtils"; +import { setSelectionsWithoutFocusingEditor } from "../util/setSelectionsAndFocusEditor"; import { runOnTargetsForEachEditor } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; @@ -58,7 +59,7 @@ class InsertEmptyLines implements Action { ] ); - editor.selections = updatedOriginalSelections; + setSelectionsWithoutFocusingEditor(editor, updatedOriginalSelections); return { thatMark: updatedSelections.map((selection) => ({ diff --git a/src/actions/Wrap.ts b/src/actions/Wrap.ts index 630747b363..56193a9108 100644 --- a/src/actions/Wrap.ts +++ b/src/actions/Wrap.ts @@ -8,6 +8,7 @@ import { Target } from "../typings/target.types"; import { Edit, Graph, SelectionWithEditor } from "../typings/Types"; import { FullSelectionInfo } from "../typings/updateSelections"; import { decorationSleep } from "../util/editDisplayUtils"; +import { setSelectionsWithoutFocusingEditor } from "../util/setSelectionsAndFocusEditor"; import { runOnTargetsForEachEditor } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; @@ -93,7 +94,7 @@ export default class Wrap implements Action { ] ); - editor.selections = cursorSelections; + setSelectionsWithoutFocusingEditor(editor, cursorSelections); editor.setDecorations( this.graph.editStyles.justAdded.token, diff --git a/src/util/setSelectionsAndFocusEditor.ts b/src/util/setSelectionsAndFocusEditor.ts index 004b6081b3..4c9401e3e4 100644 --- a/src/util/setSelectionsAndFocusEditor.ts +++ b/src/util/setSelectionsAndFocusEditor.ts @@ -1,6 +1,7 @@ import { range } from "lodash"; import { commands, Selection, TextEditor, ViewColumn, window } from "vscode"; import { getCellIndex, getNotebookFromCellDocument } from "./notebook"; +import uniqDeep from "./uniqDeep"; const columnFocusCommands = { [ViewColumn.One]: "workbench.action.focusFirstEditorGroup", @@ -21,7 +22,7 @@ export async function setSelectionsAndFocusEditor( selections: Selection[], revealRange: boolean = true ) { - editor.selections = selections; + setSelectionsWithoutFocusingEditor(editor, selections); if (revealRange) { editor.revealRange(editor.selection); @@ -32,6 +33,13 @@ export async function setSelectionsAndFocusEditor( await focusEditor(editor); } +export function setSelectionsWithoutFocusingEditor( + editor: TextEditor, + selections: Selection[] +) { + editor.selections = uniqDeep(selections); +} + export async function focusEditor(editor: TextEditor) { if (editor.viewColumn != null) { await commands.executeCommand(columnFocusCommands[editor.viewColumn]); From 419922d9879494a3073524f4c0f04208b2da1533 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 26 May 2022 15:37:13 +0200 Subject: [PATCH 211/314] Make document content range the entire file including white lines --- .../scopeTypeStages/DocumentStage.ts | 34 +++--------- src/processTargets/targets/DocumentTarget.ts | 54 +++++++++++++------ .../targets/SurroundingPairTarget.ts | 2 +- 3 files changed, 46 insertions(+), 44 deletions(-) diff --git a/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts b/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts index ca304596d9..341eda1d2d 100644 --- a/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts @@ -1,4 +1,4 @@ -import { Range, TextEditor } from "vscode"; +import { Position, Range, TextEditor } from "vscode"; import { ContainingScopeModifier, EveryScopeModifier, @@ -7,7 +7,6 @@ import { import { ProcessedTargetsContext } from "../../../typings/Types"; import { ModifierStage } from "../../PipelineStages.types"; import DocumentTarget from "../../targets/DocumentTarget"; -import { fitRangeToLineContent } from "./LineStage"; export default class implements ModifierStage { constructor(private modifier: ContainingScopeModifier | EveryScopeModifier) {} @@ -17,36 +16,15 @@ export default class implements ModifierStage { new DocumentTarget({ editor: target.editor, isReversed: target.isReversed, - contentRange: getDocumentContentRange(target.editor), + contentRange: getDocumentRange(target.editor), }), ]; } } -function getDocumentContentRange(editor: TextEditor) { - const { document } = editor; - let firstLineNum = 0; - let lastLineNum = document.lineCount - 1; - - for (let i = firstLineNum; i < document.lineCount; ++i) { - if (!document.lineAt(i).isEmptyOrWhitespace) { - firstLineNum = i; - break; - } - } - - for (let i = lastLineNum; i > -1; --i) { - if (!document.lineAt(i).isEmptyOrWhitespace) { - lastLineNum = i; - break; - } - } - - const firstLine = document.lineAt(firstLineNum); - const lastLine = document.lineAt(lastLineNum); - - return fitRangeToLineContent( - editor, - new Range(firstLine.range.start, lastLine.range.end) +function getDocumentRange(editor: TextEditor) { + return new Range( + new Position(0, 0), + editor.document.lineAt(editor.document.lineCount - 1).range.end ); } diff --git a/src/processTargets/targets/DocumentTarget.ts b/src/processTargets/targets/DocumentTarget.ts index 3a0b2836ef..7fd5e3e9ea 100644 --- a/src/processTargets/targets/DocumentTarget.ts +++ b/src/processTargets/targets/DocumentTarget.ts @@ -1,9 +1,12 @@ -import { Range } from "vscode"; +import { Range, TextEditor } from "vscode"; +import { Target } from "../../typings/target.types"; +import { fitRangeToLineContent } from "../modifiers/scopeTypeStages/LineStage"; import BaseTarget, { CloneWithParameters, CommonTargetParameters, extractCommonParameters, } from "./BaseTarget"; +import WeakTarget from "./WeakTarget"; export default class DocumentTarget extends BaseTarget { constructor(parameters: CommonTargetParameters) { @@ -17,24 +20,45 @@ export default class DocumentTarget extends BaseTarget { return true; } - getRemovalHighlightRange(): Range | undefined { - if (this.position != null) { - return undefined; - } - return this.contentRange; + getInteriorStrict(): Target[] { + return [ + new WeakTarget({ + editor: this.editor, + isReversed: this.isReversed, + contentRange: getDocumentContentRange(this.editor), + }), + ]; + } + + cloneWith(parameters: CloneWithParameters): DocumentTarget { + return new DocumentTarget({ ...this.state, ...parameters }); } +} - protected getRemovalContentRange(): Range { - if (this.position != null) { - return this.contentRange; +function getDocumentContentRange(editor: TextEditor) { + const { document } = editor; + let firstLineNum = 0; + let lastLineNum = document.lineCount - 1; + + for (let i = firstLineNum; i < document.lineCount; ++i) { + if (!document.lineAt(i).isEmptyOrWhitespace) { + firstLineNum = i; + break; } - return new Range( - this.editor.document.lineAt(0).range.start, - this.editor.document.lineAt(this.editor.document.lineCount - 1).range.end - ); } - cloneWith(parameters: CloneWithParameters): DocumentTarget { - return new DocumentTarget({ ...this.state, ...parameters }); + for (let i = lastLineNum; i > -1; --i) { + if (!document.lineAt(i).isEmptyOrWhitespace) { + lastLineNum = i; + break; + } } + + const firstLine = document.lineAt(firstLineNum); + const lastLine = document.lineAt(lastLineNum); + + return fitRangeToLineContent( + editor, + new Range(firstLine.range.start, lastLine.range.end) + ); } diff --git a/src/processTargets/targets/SurroundingPairTarget.ts b/src/processTargets/targets/SurroundingPairTarget.ts index 5a78fe92b9..6f83304171 100644 --- a/src/processTargets/targets/SurroundingPairTarget.ts +++ b/src/processTargets/targets/SurroundingPairTarget.ts @@ -39,7 +39,7 @@ export default class SurroundingPairTarget extends BaseTarget { getInteriorStrict(): Target[] { if (this.interiorRange_ == null || this.position != null) { - throw Error("No available interior"); + super.getInteriorStrict(); } return [ new WeakTarget({ From 81af818eb1549004d7226436617292ffbb42bf45 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 26 May 2022 15:51:45 +0200 Subject: [PATCH 212/314] Added source mark to wrap action --- src/actions/Wrap.ts | 177 +++++++++++++----------- src/processTargets/marks/SourceStage.ts | 3 + src/processTargets/marks/ThatStage.ts | 3 + 3 files changed, 103 insertions(+), 80 deletions(-) diff --git a/src/actions/Wrap.ts b/src/actions/Wrap.ts index 56193a9108..38b4ed23c9 100644 --- a/src/actions/Wrap.ts +++ b/src/actions/Wrap.ts @@ -1,11 +1,10 @@ -import { flatten } from "lodash"; import { DecorationRangeBehavior, Selection } from "vscode"; import { getSelectionInfo, performEditsAndUpdateFullSelectionInfos, } from "../core/updateSelections/updateSelections"; import { Target } from "../typings/target.types"; -import { Edit, Graph, SelectionWithEditor } from "../typings/Types"; +import { Edit, Graph } from "../typings/Types"; import { FullSelectionInfo } from "../typings/updateSelections"; import { decorationSleep } from "../util/editDisplayUtils"; import { setSelectionsWithoutFocusingEditor } from "../util/setSelectionsAndFocusEditor"; @@ -22,95 +21,113 @@ export default class Wrap implements Action { left: string, right: string ): Promise { - const thatMark = flatten( - await runOnTargetsForEachEditor( - targets, - async (editor, targets) => { - const { document } = editor; - const boundaries = targets.map((target) => ({ - start: new Selection( - target.contentRange.start, - target.contentRange.start - ), - end: new Selection( - target.contentRange.end, - target.contentRange.end - ), - })); + const results = await runOnTargetsForEachEditor( + targets, + async (editor, targets) => { + const { document } = editor; + const boundaries = targets.map((target) => ({ + start: new Selection( + target.contentRange.start, + target.contentRange.start + ), + end: new Selection(target.contentRange.end, target.contentRange.end), + })); - const edits: Edit[] = boundaries.flatMap(({ start, end }) => [ - { - text: left, - range: start, - }, - { - text: right, - range: end, - isReplace: true, - }, - ]); + const edits: Edit[] = boundaries.flatMap(({ start, end }) => [ + { + text: left, + range: start, + }, + { + text: right, + range: end, + isReplace: true, + }, + ]); - const delimiterSelectionInfos: FullSelectionInfo[] = - boundaries.flatMap(({ start, end }) => { - return [ - getSelectionInfo( - document, - start, - DecorationRangeBehavior.OpenClosed - ), - getSelectionInfo( - document, - end, - DecorationRangeBehavior.ClosedOpen - ), - ]; - }); + const delimiterSelectionInfos: FullSelectionInfo[] = boundaries.flatMap( + ({ start, end }) => { + return [ + getSelectionInfo( + document, + start, + DecorationRangeBehavior.OpenClosed + ), + getSelectionInfo( + document, + end, + DecorationRangeBehavior.ClosedOpen + ), + ]; + } + ); - const cursorSelectionInfos = editor.selections.map((selection) => - getSelectionInfo( - document, - selection, - DecorationRangeBehavior.ClosedClosed - ) - ); + const cursorSelectionInfos = editor.selections.map((selection) => + getSelectionInfo( + document, + selection, + DecorationRangeBehavior.ClosedClosed + ) + ); + + const sourceMarkSelectionInfos = targets.map((target) => + getSelectionInfo( + document, + target.contentSelection, + DecorationRangeBehavior.ClosedClosed + ) + ); - const thatMarkSelectionInfos = targets.map((target) => - getSelectionInfo( - document, - target.contentSelection, - DecorationRangeBehavior.OpenOpen - ) - ); + const thatMarkSelectionInfos = targets.map((target) => + getSelectionInfo( + document, + target.contentSelection, + DecorationRangeBehavior.OpenOpen + ) + ); - const [delimiterSelections, cursorSelections, thatMarkSelections] = - await performEditsAndUpdateFullSelectionInfos( - this.graph.rangeUpdater, - editor, - edits, - [ - delimiterSelectionInfos, - cursorSelectionInfos, - thatMarkSelectionInfos, - ] - ); + const [ + delimiterSelections, + cursorSelections, + sourceMarkSelections, + thatMarkSelections, + ] = await performEditsAndUpdateFullSelectionInfos( + this.graph.rangeUpdater, + editor, + edits, + [ + delimiterSelectionInfos, + cursorSelectionInfos, + sourceMarkSelectionInfos, + thatMarkSelectionInfos, + ] + ); - setSelectionsWithoutFocusingEditor(editor, cursorSelections); + setSelectionsWithoutFocusingEditor(editor, cursorSelections); - editor.setDecorations( - this.graph.editStyles.justAdded.token, - delimiterSelections - ); - await decorationSleep(); - editor.setDecorations(this.graph.editStyles.justAdded.token, []); + editor.setDecorations( + this.graph.editStyles.justAdded.token, + delimiterSelections + ); + await decorationSleep(); + editor.setDecorations(this.graph.editStyles.justAdded.token, []); - return thatMarkSelections.map((selection) => ({ + return { + sourceMark: sourceMarkSelections.map((selection) => ({ + editor, + selection, + })), + thatMark: thatMarkSelections.map((selection) => ({ editor, selection, - })); - } - ) + })), + }; + } ); - return { thatMark }; + return { + thatMark: results.flatMap(({ thatMark }) => thatMark), + sourceMark: results.flatMap(({ sourceMark }) => sourceMark), + }; } } diff --git a/src/processTargets/marks/SourceStage.ts b/src/processTargets/marks/SourceStage.ts index 11585875c2..ad03603042 100644 --- a/src/processTargets/marks/SourceStage.ts +++ b/src/processTargets/marks/SourceStage.ts @@ -9,6 +9,9 @@ export default class implements MarkStage { constructor(private modifier: SourceMark) {} run(context: ProcessedTargetsContext): Target[] { + if (context.sourceMark.length === 0) { + throw Error("No available source marks"); + } return context.sourceMark.map((selection) => { return new WeakTarget({ ...getTokenDelimiters(selection.editor, selection.selection), diff --git a/src/processTargets/marks/ThatStage.ts b/src/processTargets/marks/ThatStage.ts index 2f193bfd31..eb6539ad46 100644 --- a/src/processTargets/marks/ThatStage.ts +++ b/src/processTargets/marks/ThatStage.ts @@ -9,6 +9,9 @@ export default class implements MarkStage { constructor(private modifier: ThatMark) {} run(context: ProcessedTargetsContext): Target[] { + if (context.thatMark.length === 0) { + throw Error("No available that marks"); + } return context.thatMark.map((selection) => { return new WeakTarget({ ...getTokenDelimiters(selection.editor, selection.selection), From 1f96954039c0e246abfa124abee52f41d0697df8 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 26 May 2022 16:07:53 +0200 Subject: [PATCH 213/314] Added source mark to actions wrap and rewrap --- src/actions/Rewrap.ts | 39 +++++++++++++++++++++++---------------- src/actions/Wrap.ts | 2 +- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/src/actions/Rewrap.ts b/src/actions/Rewrap.ts index ff93afc27c..95b369ac2a 100644 --- a/src/actions/Rewrap.ts +++ b/src/actions/Rewrap.ts @@ -1,4 +1,3 @@ -import { flatten } from "lodash"; import { performEditsAndUpdateRanges } from "../core/updateSelections/updateSelections"; import { weakContainingSurroundingPairStage } from "../processTargets/modifiers/commonWeakContainingScopeStages"; import { Target } from "../typings/target.types"; @@ -34,28 +33,36 @@ export default class Rewrap implements Action { this.graph.editStyles.pendingModification0 ); - const thatMark = flatten( - await runOnTargetsForEachEditor( - boundaryTargets, - async (editor, boundaryTargets) => { - const edits = boundaryTargets.map((target, i) => ({ - editor, - range: target.contentRange, - text: i % 2 === 0 ? left : right, - })); + const results = await runOnTargetsForEachEditor( + boundaryTargets, + async (editor, boundaryTargets) => { + const edits = boundaryTargets.map((target, i) => ({ + editor, + range: target.contentRange, + text: i % 2 === 0 ? left : right, + })); - const [updatedThatRanges] = await performEditsAndUpdateRanges( + const [updatedSourceRanges, updatedThatRanges] = + await performEditsAndUpdateRanges( this.graph.rangeUpdater, editor, edits, - [targets.map((target) => target.contentRange)] + [ + targets.map((target) => target.thatTarget.contentRange), + targets.map((target) => target.contentRange), + ] ); - return createThatMark(targets, updatedThatRanges); - } - ) + return { + sourceMark: createThatMark(targets, updatedSourceRanges), + thatMark: createThatMark(targets, updatedThatRanges), + }; + } ); - return { thatMark }; + return { + sourceMark: results.flatMap(({ sourceMark }) => sourceMark), + thatMark: results.flatMap(({ thatMark }) => thatMark), + }; } } diff --git a/src/actions/Wrap.ts b/src/actions/Wrap.ts index 38b4ed23c9..61e4a85cef 100644 --- a/src/actions/Wrap.ts +++ b/src/actions/Wrap.ts @@ -126,8 +126,8 @@ export default class Wrap implements Action { ); return { - thatMark: results.flatMap(({ thatMark }) => thatMark), sourceMark: results.flatMap(({ sourceMark }) => sourceMark), + thatMark: results.flatMap(({ thatMark }) => thatMark), }; } } From 8bb43b1fa7aaac6afe2698ba054863aff7014983 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 26 May 2022 16:28:18 +0200 Subject: [PATCH 214/314] Updated error messages --- .../modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts | 4 +++- src/processTargets/modifiers/scopeTypeStages/LineStage.ts | 4 +++- .../modifiers/scopeTypeStages/ParagraphStage.ts | 4 +++- src/processTargets/modifiers/scopeTypeStages/RegexStage.ts | 4 +++- src/processTargets/modifiers/scopeTypeStages/TokenStage.ts | 4 +++- 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts b/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts index 48aa47b568..2638fd7a1f 100644 --- a/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts @@ -51,7 +51,9 @@ export default class implements ModifierStage { }); if (scopeNodes == null) { - throw new Error(`Couldn't find containing ${this.modifier.scopeType}`); + throw new Error( + `Couldn't find containing ${this.modifier.scopeType.type}` + ); } return scopeNodes.map( diff --git a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts index 082261b1a2..ec1ca18a1b 100644 --- a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts @@ -35,7 +35,9 @@ export default class implements ModifierStage { } if (targets.length === 0) { - throw new Error(`Couldn't find containing ${this.modifier.scopeType}`); + throw new Error( + `Couldn't find containing ${this.modifier.scopeType.type}` + ); } return targets; diff --git a/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts b/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts index 139043b406..5d15bb28fd 100644 --- a/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts @@ -63,7 +63,9 @@ export default class implements ModifierStage { } if (targets.length === 0) { - throw new Error(`Couldn't find containing ${this.modifier.scopeType}`); + throw new Error( + `Couldn't find containing ${this.modifier.scopeType.type}` + ); } return targets; diff --git a/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts b/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts index 892aa2d9ab..804386863b 100644 --- a/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts @@ -47,7 +47,9 @@ class RegexStage implements ModifierStage { if (targets.length === 0) { if (targets.length === 0) { - throw new Error(`Couldn't find containing ${this.modifier.scopeType}`); + throw new Error( + `Couldn't find containing ${this.modifier.scopeType.type}` + ); } } diff --git a/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts index 516bef261e..bb7306f80c 100644 --- a/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts @@ -38,7 +38,9 @@ export default class implements ModifierStage { ); if (targets.length === 0) { - throw new Error(`Couldn't find containing ${this.modifier.scopeType}`); + throw new Error( + `Couldn't find containing ${this.modifier.scopeType.type}` + ); } return targets; From 816847289191e2f3758aa01ccda189861dee9dca Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 26 May 2022 18:32:44 +0200 Subject: [PATCH 215/314] Updated tests --- src/actions/Call.ts | 4 ++- .../recorded/actions/curlyRepackRound.yml | 5 +++ .../recorded/actions/roundWrapThis.yml | 3 ++ .../recorded/actions/roundWrapVest.yml | 3 ++ .../recorded/actions/roundWrapVest2.yml | 3 ++ .../recorded/actions/squareRepackHarp.yml | 3 ++ .../recorded/actions/squareRepackLeper.yml | 3 ++ .../recorded/actions/squareRepackPair.yml | 3 ++ .../recorded/actions/squareRepackThis.yml | 3 ++ ...PointToEndOfThisAndEndOfWhaleTakeWhale.yml | 2 ++ ...AndPointToThisAndStartOfWhaleTakeWhale.yml | 2 ++ ...dHarpToEndOfThisAndEndOfWhaleTakeWhale.yml | 2 ++ ...tAndHarpToThisAndStartOfWhaleTakeWhale.yml | 2 ++ .../recorded/selectionTypes/takeEveryFile.yml | 32 +++++++++---------- .../recorded/selectionTypes/takeFile.yml | 12 +++---- ...kePairDouble.yml => clearBoundsDouble.yml} | 2 ++ ...takePairRound.yml => clearBoundsRound.yml} | 2 ++ ...kePairDouble.yml => clearBoundsDouble.yml} | 2 ++ .../textual/clearBoundsRound.yml | 2 ++ 19 files changed, 67 insertions(+), 23 deletions(-) rename src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/{takePairDouble.yml => clearBoundsDouble.yml} (92%) rename src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/{takePairRound.yml => clearBoundsRound.yml} (91%) rename src/test/suite/fixtures/recorded/surroundingPair/textual/{takePairDouble.yml => clearBoundsDouble.yml} (92%) diff --git a/src/actions/Call.ts b/src/actions/Call.ts index ff07daf74a..ef59c6d01b 100644 --- a/src/actions/Call.ts +++ b/src/actions/Call.ts @@ -21,10 +21,12 @@ export default class Call implements Action { } ); - return this.graph.actions.wrapWithPairedDelimiter.run( + const { thatMark } = await this.graph.actions.wrapWithPairedDelimiter.run( [destinations], texts[0] + "(", ")" ); + + return { thatMark }; } } diff --git a/src/test/suite/fixtures/recorded/actions/curlyRepackRound.yml b/src/test/suite/fixtures/recorded/actions/curlyRepackRound.yml index ea183bad76..53f7a16533 100644 --- a/src/test/suite/fixtures/recorded/actions/curlyRepackRound.yml +++ b/src/test/suite/fixtures/recorded/actions/curlyRepackRound.yml @@ -26,6 +26,11 @@ finalState: active: {line: 0, character: 5} - anchor: {line: 1, character: 5} active: {line: 1, character: 5} + sourceMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 9} + - anchor: {line: 1, character: 0} + active: {line: 1, character: 7} thatMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 9} diff --git a/src/test/suite/fixtures/recorded/actions/roundWrapThis.yml b/src/test/suite/fixtures/recorded/actions/roundWrapThis.yml index 412d39cc85..6660d51b60 100644 --- a/src/test/suite/fixtures/recorded/actions/roundWrapThis.yml +++ b/src/test/suite/fixtures/recorded/actions/roundWrapThis.yml @@ -22,6 +22,9 @@ finalState: selections: - anchor: {line: 0, character: 1} active: {line: 0, character: 1} + sourceMark: + - anchor: {line: 0, character: 1} + active: {line: 0, character: 1} thatMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 2} diff --git a/src/test/suite/fixtures/recorded/actions/roundWrapVest.yml b/src/test/suite/fixtures/recorded/actions/roundWrapVest.yml index 962855a402..71f842c403 100644 --- a/src/test/suite/fixtures/recorded/actions/roundWrapVest.yml +++ b/src/test/suite/fixtures/recorded/actions/roundWrapVest.yml @@ -25,6 +25,9 @@ finalState: selections: - anchor: {line: 1, character: 12} active: {line: 1, character: 12} + sourceMark: + - anchor: {line: 1, character: 7} + active: {line: 1, character: 12} thatMark: - anchor: {line: 1, character: 6} active: {line: 1, character: 13} diff --git a/src/test/suite/fixtures/recorded/actions/roundWrapVest2.yml b/src/test/suite/fixtures/recorded/actions/roundWrapVest2.yml index e003ea366b..51bae071e6 100644 --- a/src/test/suite/fixtures/recorded/actions/roundWrapVest2.yml +++ b/src/test/suite/fixtures/recorded/actions/roundWrapVest2.yml @@ -25,6 +25,9 @@ finalState: selections: - anchor: {line: 1, character: 14} active: {line: 1, character: 14} + sourceMark: + - anchor: {line: 1, character: 7} + active: {line: 1, character: 12} thatMark: - anchor: {line: 1, character: 6} active: {line: 1, character: 13} diff --git a/src/test/suite/fixtures/recorded/actions/squareRepackHarp.yml b/src/test/suite/fixtures/recorded/actions/squareRepackHarp.yml index 531856ea3c..d72406534f 100644 --- a/src/test/suite/fixtures/recorded/actions/squareRepackHarp.yml +++ b/src/test/suite/fixtures/recorded/actions/squareRepackHarp.yml @@ -23,6 +23,9 @@ finalState: selections: - anchor: {line: 1, character: 0} active: {line: 1, character: 0} + sourceMark: + - anchor: {line: 0, character: 1} + active: {line: 0, character: 6} thatMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 7} diff --git a/src/test/suite/fixtures/recorded/actions/squareRepackLeper.yml b/src/test/suite/fixtures/recorded/actions/squareRepackLeper.yml index 4195092d77..bd5846a0a8 100644 --- a/src/test/suite/fixtures/recorded/actions/squareRepackLeper.yml +++ b/src/test/suite/fixtures/recorded/actions/squareRepackLeper.yml @@ -23,6 +23,9 @@ finalState: selections: - anchor: {line: 1, character: 0} active: {line: 1, character: 0} + sourceMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 1} thatMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 7} diff --git a/src/test/suite/fixtures/recorded/actions/squareRepackPair.yml b/src/test/suite/fixtures/recorded/actions/squareRepackPair.yml index b61acd7532..492adeed1f 100644 --- a/src/test/suite/fixtures/recorded/actions/squareRepackPair.yml +++ b/src/test/suite/fixtures/recorded/actions/squareRepackPair.yml @@ -20,6 +20,9 @@ finalState: selections: - anchor: {line: 0, character: 2} active: {line: 0, character: 2} + sourceMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 7} thatMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 7} diff --git a/src/test/suite/fixtures/recorded/actions/squareRepackThis.yml b/src/test/suite/fixtures/recorded/actions/squareRepackThis.yml index 3e91e57bdb..7a43a285e9 100644 --- a/src/test/suite/fixtures/recorded/actions/squareRepackThis.yml +++ b/src/test/suite/fixtures/recorded/actions/squareRepackThis.yml @@ -18,6 +18,9 @@ finalState: selections: - anchor: {line: 0, character: 4} active: {line: 0, character: 4} + sourceMark: + - anchor: {line: 0, character: 4} + active: {line: 0, character: 4} thatMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 7} diff --git a/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToEndOfThisAndEndOfWhaleTakeWhale.yml b/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToEndOfThisAndEndOfWhaleTakeWhale.yml index ba8dfd6fb6..47adf5fb01 100644 --- a/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToEndOfThisAndEndOfWhaleTakeWhale.yml +++ b/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToEndOfThisAndEndOfWhaleTakeWhale.yml @@ -54,6 +54,8 @@ finalState: thatMark: - anchor: {line: 0, character: 12} active: {line: 0, character: 18} + - anchor: {line: 0, character: 12} + active: {line: 0, character: 18} sourceMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 5} diff --git a/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToThisAndStartOfWhaleTakeWhale.yml b/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToThisAndStartOfWhaleTakeWhale.yml index 5b0f628113..deee28f351 100644 --- a/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToThisAndStartOfWhaleTakeWhale.yml +++ b/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToThisAndStartOfWhaleTakeWhale.yml @@ -52,6 +52,8 @@ finalState: thatMark: - anchor: {line: 0, character: 7} active: {line: 0, character: 13} + - anchor: {line: 0, character: 7} + active: {line: 0, character: 13} sourceMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 5} diff --git a/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhaleTakeWhale.yml b/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhaleTakeWhale.yml index da58e0d3f5..a572792994 100644 --- a/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhaleTakeWhale.yml +++ b/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhaleTakeWhale.yml @@ -54,6 +54,8 @@ finalState: thatMark: - anchor: {line: 0, character: 12} active: {line: 0, character: 18} + - anchor: {line: 0, character: 12} + active: {line: 0, character: 18} sourceMark: - anchor: {line: 0, character: 5} active: {line: 0, character: 6} diff --git a/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToThisAndStartOfWhaleTakeWhale.yml b/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToThisAndStartOfWhaleTakeWhale.yml index b0e369b641..fd08052d86 100644 --- a/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToThisAndStartOfWhaleTakeWhale.yml +++ b/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToThisAndStartOfWhaleTakeWhale.yml @@ -52,6 +52,8 @@ finalState: thatMark: - anchor: {line: 0, character: 7} active: {line: 0, character: 13} + - anchor: {line: 0, character: 7} + active: {line: 0, character: 13} sourceMark: - anchor: {line: 0, character: 5} active: {line: 0, character: 6} diff --git a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryFile.yml b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryFile.yml index 4747e078aa..8d11d3f324 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/takeEveryFile.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/takeEveryFile.yml @@ -2,37 +2,37 @@ languageId: plaintext command: spokenForm: take every file version: 2 - action: {name: setSelection} targets: - type: primitive modifiers: - type: everyScope scopeType: {type: document} usePrePhraseSnapshot: true + action: {name: setSelection} initialState: - documentContents: | + documentContents: |2+ + + + foo - a + bar - b c - d e - f g selections: - anchor: {line: 6, character: 0} active: {line: 6, character: 0} marks: {} finalState: - documentContents: | + documentContents: |2+ - a - b c - d e - f g + foo + + bar + selections: - - anchor: {line: 1, character: 0} - active: {line: 5, character: 5} + - anchor: {line: 0, character: 0} + active: {line: 6, character: 0} thatMark: - - anchor: {line: 1, character: 0} - active: {line: 5, character: 5} -fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: everyScope, scopeType: document}]}] + - anchor: {line: 0, character: 0} + active: {line: 6, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: everyScope, scopeType: {type: document}}]}] diff --git a/src/test/suite/fixtures/recorded/selectionTypes/takeFile.yml b/src/test/suite/fixtures/recorded/selectionTypes/takeFile.yml index 461233a6d0..874f7e2711 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/takeFile.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/takeFile.yml @@ -2,13 +2,13 @@ languageId: plaintext command: spokenForm: take file version: 2 - action: {name: setSelection} targets: - type: primitive modifiers: - type: containingScope scopeType: {type: document} usePrePhraseSnapshot: true + action: {name: setSelection} initialState: documentContents: |2+ @@ -30,9 +30,9 @@ finalState: bar selections: - - anchor: {line: 2, character: 4} - active: {line: 4, character: 7} + - anchor: {line: 0, character: 0} + active: {line: 6, character: 0} thatMark: - - anchor: {line: 2, character: 4} - active: {line: 4, character: 7} -fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: containingScope, scopeType: document}]}] + - anchor: {line: 0, character: 0} + active: {line: 6, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: containingScope, scopeType: {type: document}}]}] diff --git a/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairDouble.yml b/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/clearBoundsDouble.yml similarity index 92% rename from src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairDouble.yml rename to src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/clearBoundsDouble.yml index 4f1f3520bc..8c0835de11 100644 --- a/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairDouble.yml +++ b/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/clearBoundsDouble.yml @@ -20,4 +20,6 @@ finalState: thatMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 0} + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: '"'}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: surroundingPair, delimiter: null, delimiterInclusion: delimitersOnly}}] diff --git a/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairRound.yml b/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/clearBoundsRound.yml similarity index 91% rename from src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairRound.yml rename to src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/clearBoundsRound.yml index 384343be9d..c9e4396ed4 100644 --- a/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairRound.yml +++ b/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/clearBoundsRound.yml @@ -19,4 +19,6 @@ finalState: thatMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 0} + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: surroundingPair, delimiter: parentheses, delimiterInclusion: delimitersOnly}}] diff --git a/src/test/suite/fixtures/recorded/surroundingPair/textual/takePairDouble.yml b/src/test/suite/fixtures/recorded/surroundingPair/textual/clearBoundsDouble.yml similarity index 92% rename from src/test/suite/fixtures/recorded/surroundingPair/textual/takePairDouble.yml rename to src/test/suite/fixtures/recorded/surroundingPair/textual/clearBoundsDouble.yml index d58ca06205..88702f4831 100644 --- a/src/test/suite/fixtures/recorded/surroundingPair/textual/takePairDouble.yml +++ b/src/test/suite/fixtures/recorded/surroundingPair/textual/clearBoundsDouble.yml @@ -20,4 +20,6 @@ finalState: thatMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 0} + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: '"'}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: surroundingPair, delimiter: null, delimiterInclusion: delimitersOnly}}] diff --git a/src/test/suite/fixtures/recorded/surroundingPair/textual/clearBoundsRound.yml b/src/test/suite/fixtures/recorded/surroundingPair/textual/clearBoundsRound.yml index 1226f21476..4c53f678c0 100644 --- a/src/test/suite/fixtures/recorded/surroundingPair/textual/clearBoundsRound.yml +++ b/src/test/suite/fixtures/recorded/surroundingPair/textual/clearBoundsRound.yml @@ -19,4 +19,6 @@ finalState: thatMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 0} + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: surroundingPair, delimiter: parentheses, delimiterInclusion: delimitersOnly}}] From bce013e58aa9e90be399b840bb1c07d787f15bd3 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 26 May 2022 18:49:21 +0200 Subject: [PATCH 216/314] Don't focus editor on notebook cell insertion --- src/actions/EditNew.ts | 22 +++++++++++++++---- .../targets/NotebookCellTarget.ts | 1 + src/typings/target.types.ts | 1 + 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/actions/EditNew.ts b/src/actions/EditNew.ts index 6d2bd5cd32..6492f4ec16 100644 --- a/src/actions/EditNew.ts +++ b/src/actions/EditNew.ts @@ -8,7 +8,10 @@ import { weakContainingLineStage } from "../processTargets/modifiers/commonWeakC import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; import { selectionFromRange } from "../util/selectionUtils"; -import { setSelectionsAndFocusEditor } from "../util/setSelectionsAndFocusEditor"; +import { + setSelectionsAndFocusEditor, + setSelectionsWithoutFocusingEditor, +} from "../util/setSelectionsAndFocusEditor"; import { createThatMark, ensureSingleEditor } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; import { getEditRange, getLinePadding } from "./CopyLines"; @@ -23,12 +26,11 @@ class EditNew implements Action { async run([targets]: [Target[]]): Promise { const editor = ensureSingleEditor(targets); - const richTargets: RichTarget[] = targets.map((target, index) => { + const richTargets: RichTarget[] = targets.map((target) => { const context = target.getEditNewContext(this.isBefore); const common = { target, - index, targetRange: target.thatTarget.contentRange, cursorRange: getEditRange( editor, @@ -42,6 +44,7 @@ class EditNew implements Action { return { ...common, type: "command", + focusOnSelection: !context.noFocusOnSelection, command: context.command, }; case "delimiter": @@ -49,6 +52,7 @@ class EditNew implements Action { return { ...common, type: "delimiter", + focusOnSelection: true, delimiter: context.delimiter, isLine, cursorRange: getEditRange( @@ -69,7 +73,16 @@ class EditNew implements Action { ); const targetRanges = richTargets.map((target) => target.targetRange); - await setSelectionsAndFocusEditor(editor, newSelections); + // Only set selection if all targets are agreeing on this + const focusOnSelection = !richTargets.find( + ({ focusOnSelection }) => !focusOnSelection + ); + + if (focusOnSelection) { + await setSelectionsAndFocusEditor(editor, newSelections); + } else { + setSelectionsWithoutFocusingEditor(editor, newSelections); + } return { thatMark: createThatMark(targets, targetRanges), @@ -167,6 +180,7 @@ interface CommonTarget { target: Target; targetRange: Range; cursorRange: Range; + focusOnSelection: boolean; } interface CommandTarget extends CommonTarget { type: "command"; diff --git a/src/processTargets/targets/NotebookCellTarget.ts b/src/processTargets/targets/NotebookCellTarget.ts index efcc19817c..aa75af6b74 100644 --- a/src/processTargets/targets/NotebookCellTarget.ts +++ b/src/processTargets/targets/NotebookCellTarget.ts @@ -18,6 +18,7 @@ export default class NotebookCellTarget extends BaseTarget { if (this.isNotebookEditor(this.editor)) { return { type: "command", + noFocusOnSelection: true, command: isBefore ? "notebook.cell.insertCodeCellAbove" : "notebook.cell.insertCodeCellBelow", diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 29843f2945..8b34ea72c9 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -257,6 +257,7 @@ export interface RemovalRange { export interface EditNewCommandContext { type: "command"; command: string; + noFocusOnSelection?: boolean; } export interface EditNewDelimiterContext { type: "delimiter"; From f484db445004eb0bfb46008f9d85e3c16efc1af2 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 26 May 2022 18:56:57 +0200 Subject: [PATCH 217/314] Cleanup --- src/actions/EditNew.ts | 2 +- src/processTargets/targets/NotebookCellTarget.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/actions/EditNew.ts b/src/actions/EditNew.ts index 6492f4ec16..657efea4d5 100644 --- a/src/actions/EditNew.ts +++ b/src/actions/EditNew.ts @@ -73,7 +73,7 @@ class EditNew implements Action { ); const targetRanges = richTargets.map((target) => target.targetRange); - // Only set selection if all targets are agreeing on this + // Only set focus if all targets are agreeing on this const focusOnSelection = !richTargets.find( ({ focusOnSelection }) => !focusOnSelection ); diff --git a/src/processTargets/targets/NotebookCellTarget.ts b/src/processTargets/targets/NotebookCellTarget.ts index aa75af6b74..34338b61b1 100644 --- a/src/processTargets/targets/NotebookCellTarget.ts +++ b/src/processTargets/targets/NotebookCellTarget.ts @@ -18,7 +18,6 @@ export default class NotebookCellTarget extends BaseTarget { if (this.isNotebookEditor(this.editor)) { return { type: "command", - noFocusOnSelection: true, command: isBefore ? "notebook.cell.insertCodeCellAbove" : "notebook.cell.insertCodeCellBelow", @@ -26,6 +25,7 @@ export default class NotebookCellTarget extends BaseTarget { } return { type: "command", + noFocusOnSelection: true, command: isBefore ? "jupyter.insertCellAbove" : "jupyter.insertCellBelow", }; } From 25dafe4aa400510db4f595788184d6218ca1dc10 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 26 May 2022 19:15:27 +0200 Subject: [PATCH 218/314] Don't update selection on notebook cell insertion --- src/actions/EditNew.ts | 43 ++++++++----------- .../targets/NotebookCellTarget.ts | 3 +- src/typings/target.types.ts | 2 +- 3 files changed, 20 insertions(+), 28 deletions(-) diff --git a/src/actions/EditNew.ts b/src/actions/EditNew.ts index 657efea4d5..85bdafae5c 100644 --- a/src/actions/EditNew.ts +++ b/src/actions/EditNew.ts @@ -8,10 +8,7 @@ import { weakContainingLineStage } from "../processTargets/modifiers/commonWeakC import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; import { selectionFromRange } from "../util/selectionUtils"; -import { - setSelectionsAndFocusEditor, - setSelectionsWithoutFocusingEditor, -} from "../util/setSelectionsAndFocusEditor"; +import { setSelectionsAndFocusEditor } from "../util/setSelectionsAndFocusEditor"; import { createThatMark, ensureSingleEditor } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; import { getEditRange, getLinePadding } from "./CopyLines"; @@ -32,27 +29,27 @@ class EditNew implements Action { const common = { target, targetRange: target.thatTarget.contentRange, - cursorRange: getEditRange( - editor, - target.contentRange, - false, - this.isBefore - ), }; switch (context.type) { case "command": return { ...common, type: "command", - focusOnSelection: !context.noFocusOnSelection, + updateSelection: !context.dontUpdateSelection, command: context.command, + cursorRange: getEditRange( + editor, + target.contentRange, + false, + this.isBefore + ), }; case "delimiter": const isLine = context.delimiter.includes("\n"); return { ...common, type: "delimiter", - focusOnSelection: true, + updateSelection: true, delimiter: context.delimiter, isLine, cursorRange: getEditRange( @@ -68,22 +65,16 @@ class EditNew implements Action { await this.runCommandTargets(editor, richTargets); await this.runDelimiterTargets(editor, richTargets); - const newSelections = richTargets.map((target) => - selectionFromRange(target.target.isReversed, target.cursorRange) - ); - const targetRanges = richTargets.map((target) => target.targetRange); - - // Only set focus if all targets are agreeing on this - const focusOnSelection = !richTargets.find( - ({ focusOnSelection }) => !focusOnSelection - ); - - if (focusOnSelection) { + // Only update selection if all targets are agreeing on this + if (!richTargets.find(({ updateSelection }) => !updateSelection)) { + const newSelections = richTargets.map((target) => + selectionFromRange(target.target.isReversed, target.cursorRange) + ); await setSelectionsAndFocusEditor(editor, newSelections); - } else { - setSelectionsWithoutFocusingEditor(editor, newSelections); } + const targetRanges = richTargets.map((target) => target.targetRange); + return { thatMark: createThatMark(targets, targetRanges), }; @@ -180,7 +171,7 @@ interface CommonTarget { target: Target; targetRange: Range; cursorRange: Range; - focusOnSelection: boolean; + updateSelection: boolean; } interface CommandTarget extends CommonTarget { type: "command"; diff --git a/src/processTargets/targets/NotebookCellTarget.ts b/src/processTargets/targets/NotebookCellTarget.ts index 34338b61b1..0e52ff4cb6 100644 --- a/src/processTargets/targets/NotebookCellTarget.ts +++ b/src/processTargets/targets/NotebookCellTarget.ts @@ -18,6 +18,7 @@ export default class NotebookCellTarget extends BaseTarget { if (this.isNotebookEditor(this.editor)) { return { type: "command", + dontUpdateSelection: true, command: isBefore ? "notebook.cell.insertCodeCellAbove" : "notebook.cell.insertCodeCellBelow", @@ -25,7 +26,7 @@ export default class NotebookCellTarget extends BaseTarget { } return { type: "command", - noFocusOnSelection: true, + dontUpdateSelection: true, command: isBefore ? "jupyter.insertCellAbove" : "jupyter.insertCellBelow", }; } diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 8b34ea72c9..62a20f5f2c 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -257,7 +257,7 @@ export interface RemovalRange { export interface EditNewCommandContext { type: "command"; command: string; - noFocusOnSelection?: boolean; + dontUpdateSelection?: boolean; } export interface EditNewDelimiterContext { type: "delimiter"; From d7dac9b68de709e25951c02adf58dfbd2c9adb0e Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Thu, 26 May 2022 19:48:23 +0100 Subject: [PATCH 219/314] Add comment --- src/actions/Call.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/actions/Call.ts b/src/actions/Call.ts index ef59c6d01b..11399a388d 100644 --- a/src/actions/Call.ts +++ b/src/actions/Call.ts @@ -21,6 +21,7 @@ export default class Call implements Action { } ); + // NB: We unwrap and then rewrap the return value here so that we don't include the source mark const { thatMark } = await this.graph.actions.wrapWithPairedDelimiter.run( [destinations], texts[0] + "(", From 4cca7c790ef1867b34302a19b60f56d2b9f08514 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Thu, 26 May 2022 19:58:26 +0100 Subject: [PATCH 220/314] Various fixes --- src/processTargets/marks/CursorStage.ts | 6 ++---- src/processTargets/marks/DecoratedSymbolStage.ts | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/processTargets/marks/CursorStage.ts b/src/processTargets/marks/CursorStage.ts index a782595070..ae97453caf 100644 --- a/src/processTargets/marks/CursorStage.ts +++ b/src/processTargets/marks/CursorStage.ts @@ -1,17 +1,15 @@ import { CursorMark, Target } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { isReversed } from "../../util/selectionUtils"; -import { getTokenDelimiters } from "../modifiers/scopeTypeStages/TokenStage"; import { MarkStage } from "../PipelineStages.types"; import WeakTarget from "../targets/WeakTarget"; -export default class implements MarkStage { - constructor(private modifier: CursorMark) {} +export default class CursorStage implements MarkStage { + constructor(_modifier: CursorMark) {} run(context: ProcessedTargetsContext): Target[] { return context.currentSelections.map((selection) => { return new WeakTarget({ - ...getTokenDelimiters(selection.editor, selection.selection), editor: selection.editor, isReversed: isReversed(selection.selection), contentRange: selection.selection, diff --git a/src/processTargets/marks/DecoratedSymbolStage.ts b/src/processTargets/marks/DecoratedSymbolStage.ts index 5e95167735..b1939c026e 100644 --- a/src/processTargets/marks/DecoratedSymbolStage.ts +++ b/src/processTargets/marks/DecoratedSymbolStage.ts @@ -1,6 +1,5 @@ import { DecoratedSymbolMark, Target } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; -import { getTokenDelimiters } from "../modifiers/scopeTypeStages/TokenStage"; import { MarkStage } from "../PipelineStages.types"; import WeakTarget from "../targets/WeakTarget"; @@ -12,14 +11,15 @@ export default class implements MarkStage { this.modifier.symbolColor, this.modifier.character ); + if (token == null) { throw new Error( `Couldn't find mark ${this.modifier.symbolColor} '${this.modifier.character}'` ); } + return [ new WeakTarget({ - ...getTokenDelimiters(token.editor, token.range), editor: token.editor, contentRange: token.range, isReversed: false, From bb237014fd7f3c7efee3c9c8debc3e41e6492ff0 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Thu, 26 May 2022 20:27:02 +0100 Subject: [PATCH 221/314] More renames and stuff --- .../modifiers/scopeTypeStages/LineStage.ts | 1 + src/processTargets/targets/BaseTarget.ts | 10 +++++----- src/processTargets/targets/LineTarget.ts | 6 +++--- src/processTargets/targets/ParagraphTarget.ts | 6 +++--- src/processTargets/targets/ScopeTypeTarget.ts | 2 +- src/util/targetUtils.ts | 2 +- 6 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts index ec1ca18a1b..fe0ebc67f5 100644 --- a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts @@ -100,6 +100,7 @@ export function fitRangeToLineContent(editor: TextEditor, range: Range) { const endCharacterIndex = endLine.range.end.character - (endLine.text.length - endLine.text.trimEnd().length); + return new Range( startLine.lineNumber, startLine.firstNonWhitespaceCharacterIndex, diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index dac62b302e..a8e5861661 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -6,7 +6,7 @@ import { Target, } from "../../typings/target.types"; import { selectionFromRange } from "../../util/selectionUtils"; -import { parseRemovalRange } from "../../util/targetUtils"; +import { processRemovalRange } from "../../util/targetUtils"; export function extractCommonParameters(parameters: CommonTargetParameters) { return { @@ -185,8 +185,8 @@ export default abstract class BaseTarget implements Target { protected getRemovalContentRange(): Range { const removalRange = this.removalRange ?? this.contentRange; const delimiter = - parseRemovalRange(this.trailingDelimiter) ?? - parseRemovalRange(this.leadingDelimiter); + processRemovalRange(this.trailingDelimiter) ?? + processRemovalRange(this.leadingDelimiter); return delimiter != null ? removalRange.union(delimiter.range) : removalRange; @@ -195,8 +195,8 @@ export default abstract class BaseTarget implements Target { protected getRemovalContentHighlightRange() { const removalRange = this.removalRange ?? this.contentRange; const delimiter = - parseRemovalRange(this.trailingDelimiter) ?? - parseRemovalRange(this.leadingDelimiter); + processRemovalRange(this.trailingDelimiter) ?? + processRemovalRange(this.leadingDelimiter); return delimiter != null ? removalRange.union(delimiter.highlight) : removalRange; diff --git a/src/processTargets/targets/LineTarget.ts b/src/processTargets/targets/LineTarget.ts index f628ba9a11..110d5cd39d 100644 --- a/src/processTargets/targets/LineTarget.ts +++ b/src/processTargets/targets/LineTarget.ts @@ -1,6 +1,6 @@ import { Range } from "vscode"; import { RemovalRange } from "../../typings/target.types"; -import { parseRemovalRange } from "../../util/targetUtils"; +import { processRemovalRange } from "../../util/targetUtils"; import BaseTarget, { CloneWithParameters, CommonTargetParameters, @@ -42,8 +42,8 @@ export default class LineTarget extends BaseTarget { this.editor.document.lineAt(this.contentRange.end).range.end ); const delimiter = - parseRemovalRange(this.trailingDelimiter) ?? - parseRemovalRange(this.leadingDelimiter); + processRemovalRange(this.trailingDelimiter) ?? + processRemovalRange(this.leadingDelimiter); return delimiter != null ? removalRange.union(delimiter.range) : removalRange; diff --git a/src/processTargets/targets/ParagraphTarget.ts b/src/processTargets/targets/ParagraphTarget.ts index 28eba327aa..916c4d0240 100644 --- a/src/processTargets/targets/ParagraphTarget.ts +++ b/src/processTargets/targets/ParagraphTarget.ts @@ -1,6 +1,6 @@ import { Range } from "vscode"; import { RemovalRange } from "../../typings/target.types"; -import { parseRemovalRange } from "../../util/targetUtils"; +import { processRemovalRange } from "../../util/targetUtils"; import BaseTarget, { CloneWithParameters, CommonTargetParameters, @@ -40,8 +40,8 @@ export default class ParagraphTarget extends BaseTarget { this.editor.document.lineAt(this.contentRange.end).range.end ); const delimiterRange = (() => { - const leadingDelimiter = parseRemovalRange(this.leadingDelimiter); - const trailingDelimiter = parseRemovalRange(this.trailingDelimiter); + const leadingDelimiter = processRemovalRange(this.leadingDelimiter); + const trailingDelimiter = processRemovalRange(this.trailingDelimiter); if (trailingDelimiter != null) { const { document } = this.editor; // Trailing delimiter to end of file. Need to remove leading new line delimiter diff --git a/src/processTargets/targets/ScopeTypeTarget.ts b/src/processTargets/targets/ScopeTypeTarget.ts index 02d6ae2bde..46eba360a9 100644 --- a/src/processTargets/targets/ScopeTypeTarget.ts +++ b/src/processTargets/targets/ScopeTypeTarget.ts @@ -35,11 +35,11 @@ export default class ScopeTypeTarget extends BaseTarget { function getDelimiter(scopeType: SimpleScopeTypeType): string { switch (scopeType) { - case "namedFunction": case "anonymousFunction": case "statement": case "ifStatement": return "\n"; + case "namedFunction": case "class": return "\n\n"; default: diff --git a/src/util/targetUtils.ts b/src/util/targetUtils.ts index 84c5dd1029..e7425a5c6e 100644 --- a/src/util/targetUtils.ts +++ b/src/util/targetUtils.ts @@ -114,7 +114,7 @@ export function getRemovalRange(target: Target) { return target.getRemovalRange(); } -export function parseRemovalRange( +export function processRemovalRange( range?: RemovalRange ): Required | undefined { return range != null && !range.exclude From 6282e9105e9061450e8fb2a2a82c1edd5a456f07 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 26 May 2022 23:23:42 +0200 Subject: [PATCH 222/314] Fix bug with missing delimiters in weak targets --- src/processTargets/targets/WeakTarget.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/processTargets/targets/WeakTarget.ts b/src/processTargets/targets/WeakTarget.ts index 33b26b3e8e..a2bb166e00 100644 --- a/src/processTargets/targets/WeakTarget.ts +++ b/src/processTargets/targets/WeakTarget.ts @@ -19,11 +19,13 @@ interface WeakTargetParameters extends CommonTargetParameters { */ export default class WeakTarget extends BaseTarget { constructor(parameters: WeakTargetParameters) { + const { delimiter, leadingDelimiter, trailingDelimiter } = + getTokenDelimiters(parameters.editor, parameters.contentRange); super({ ...extractCommonParameters(parameters), - ...getTokenDelimiters(parameters.editor, parameters.contentRange), - leadingDelimiter: parameters.leadingDelimiter, - trailingDelimiter: parameters.trailingDelimiter, + delimiter, + leadingDelimiter: parameters.leadingDelimiter ?? leadingDelimiter, + trailingDelimiter: parameters.trailingDelimiter ?? trailingDelimiter, }); } From 551421545171d6ed21009b85fae892a7b347a3a1 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 26 May 2022 23:54:18 +0200 Subject: [PATCH 223/314] Update src/processTargets/processTargets.ts Co-authored-by: Will Sommers --- 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 b9ffa05126..350fd59c65 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -239,7 +239,7 @@ function processPrimitiveTarget( let targets = markStage.run(context); const modifierStages = [ - // Reverse target modifies because they are in reverse order from the api. Slice is needed to create a copy or the modifiers will be in wrong order in the test recorder. + // Reverse target modifiers because they are returned in reverse order from the api. Slice is needed to create a copy or the modifiers will be in wrong order in the test recorder. ...target.modifiers.slice().reverse().map(getModifierStage), ...context.finalStages, ]; From 41997d9ff5dee31bb4a2718a26e8b7c9c7f70cee Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Fri, 27 May 2022 00:04:44 +0200 Subject: [PATCH 224/314] Unify implementation of copy lines and edit new actions --- src/actions/CopyLines.ts | 123 ++++------------- src/actions/EditNew.ts | 114 +++++++--------- .../fixtures/recorded/actions/pourLine.yml | 2 +- src/util/textInsertion.ts | 127 ++++++++++++++++++ 4 files changed, 205 insertions(+), 161 deletions(-) create mode 100644 src/util/textInsertion.ts diff --git a/src/actions/CopyLines.ts b/src/actions/CopyLines.ts index 0e68dd7318..ddbf5844b1 100644 --- a/src/actions/CopyLines.ts +++ b/src/actions/CopyLines.ts @@ -1,12 +1,12 @@ -import { flatten, zip } from "lodash"; -import { Range, Selection, TextEditor } from "vscode"; -import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; +import { flatten } from "lodash"; +import { TextEditor } from "vscode"; import { weakContainingLineStage } from "../processTargets/modifiers/commonWeakContainingScopeStages"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; import { displayPendingEditDecorationsForRanges } from "../util/editDisplayUtils"; import { setSelectionsWithoutFocusingEditor } from "../util/setSelectionsAndFocusEditor"; import { createThatMark, runOnTargetsForEachEditor } from "../util/targetUtils"; +import { insertTextAfter, insertTextBefore } from "../util/textInsertion"; import { Action, ActionReturnValue } from "./actions.types"; class CopyLines implements Action { @@ -17,70 +17,6 @@ class CopyLines implements Action { this.runForEditor = this.runForEditor.bind(this); } - async runForEditor(editor: TextEditor, targets: Target[]) { - const edits = targets.map((target) => { - const delimiter = target.delimiter ?? ""; - const isLine = delimiter.includes("\n"); - - const range = getEditRange( - editor, - target.contentRange, - isLine, - !this.isBefore - ); - const padding = isLine - ? getLinePadding(editor, range, !this.isBefore) - : ""; - - const contentText = target.contentText; - const text = this.isBefore - ? delimiter + padding + contentText - : contentText + delimiter + padding; - - return { - range, - isReplace: this.isBefore, - text, - offset: delimiter.length + padding.length, - length: contentText.length, - }; - }); - - const [updatedEditorSelections, updatedEditSelections, thatSelections] = - await performEditsAndUpdateSelections( - this.graph.rangeUpdater, - editor, - edits, - [ - editor.selections, - edits.map(({ range }) => new Selection(range.start, range.end)), - targets.map(({ contentSelection }) => contentSelection), - ] - ); - - setSelectionsWithoutFocusingEditor(editor, updatedEditorSelections); - editor.revealRange(editor.selection); - - const sourceSelections = zip(edits, updatedEditSelections).map( - ([edit, selection]) => { - const startOffset = editor.document.offsetAt(selection!.start); - const startIndex = this.isBefore - ? startOffset + edit!.offset - : startOffset - edit!.offset - edit!.length; - const endIndex = startIndex + edit!.length; - return new Selection( - editor.document.positionAt(startIndex), - editor.document.positionAt(endIndex) - ); - } - ); - - return { - sourceMark: createThatMark(targets, sourceSelections), - thatMark: createThatMark(targets, thatSelections), - }; - } - async run([targets]: [Target[]]): Promise { const results = flatten( await runOnTargetsForEachEditor(targets, this.runForEditor) @@ -97,8 +33,32 @@ class CopyLines implements Action { ); return { - sourceMark: results.flatMap((result) => result.sourceMark), - thatMark: results.flatMap((result) => result.thatMark), + sourceMark: results.flatMap(({ sourceMark }) => sourceMark), + thatMark: results.flatMap(({ thatMark }) => thatMark), + }; + } + + private async runForEditor(editor: TextEditor, targets: Target[]) { + const textInsertions = targets.map((target) => { + return { + range: target.contentRange, + text: target.contentText, + delimiter: target.delimiter ?? "", + }; + }); + + const { updatedEditorSelections, updatedContentRanges, insertionRanges } = + // isBefore is inverted because we want the selections to stay with what is to the user the "copy" + this.isBefore + ? await insertTextAfter(this.graph, editor, textInsertions) + : await insertTextBefore(this.graph, editor, textInsertions); + + setSelectionsWithoutFocusingEditor(editor, updatedEditorSelections); + editor.revealRange(editor.selection); + + return { + sourceMark: createThatMark(targets, insertionRanges), + thatMark: createThatMark(targets, updatedContentRanges), }; } } @@ -114,28 +74,3 @@ export class CopyLinesDown extends CopyLines { super(graph, false); } } - -export function getLinePadding( - editor: TextEditor, - range: Range, - isBefore: boolean -) { - const line = editor.document.lineAt(isBefore ? range.start : range.end); - const characterIndex = line.isEmptyOrWhitespace - ? range.start.character - : line.firstNonWhitespaceCharacterIndex; - return line.text.slice(0, characterIndex); -} - -export function getEditRange( - editor: TextEditor, - range: Range, - isLine: boolean, - isBefore: boolean -) { - // In case of trialing whitespaces we need to go to the end of the line(not content) - const editRange = - isLine && !isBefore ? editor.document.lineAt(range.end).range : range; - const position = isBefore ? editRange.start : editRange.end; - return new Range(position, position); -} diff --git a/src/actions/EditNew.ts b/src/actions/EditNew.ts index 85bdafae5c..7d60466d00 100644 --- a/src/actions/EditNew.ts +++ b/src/actions/EditNew.ts @@ -1,17 +1,14 @@ import { zip } from "lodash"; import { commands, Range, TextEditor } from "vscode"; -import { - callFunctionAndUpdateRanges, - performEditsAndUpdateRanges, -} from "../core/updateSelections/updateSelections"; +import { callFunctionAndUpdateRanges } from "../core/updateSelections/updateSelections"; import { weakContainingLineStage } from "../processTargets/modifiers/commonWeakContainingScopeStages"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; import { selectionFromRange } from "../util/selectionUtils"; import { setSelectionsAndFocusEditor } from "../util/setSelectionsAndFocusEditor"; import { createThatMark, ensureSingleEditor } from "../util/targetUtils"; +import { insertTextAfter, insertTextBefore } from "../util/textInsertion"; import { Action, ActionReturnValue } from "./actions.types"; -import { getEditRange, getLinePadding } from "./CopyLines"; class EditNew implements Action { getFinalStages = () => [weakContainingLineStage]; @@ -25,45 +22,42 @@ class EditNew implements Action { const richTargets: RichTarget[] = targets.map((target) => { const context = target.getEditNewContext(this.isBefore); - const common = { target, targetRange: target.thatTarget.contentRange, + cursorRange: target.contentRange, }; switch (context.type) { case "command": return { ...common, type: "command", - updateSelection: !context.dontUpdateSelection, command: context.command, - cursorRange: getEditRange( - editor, - target.contentRange, - false, - this.isBefore - ), + updateSelection: !context.dontUpdateSelection, }; case "delimiter": - const isLine = context.delimiter.includes("\n"); return { ...common, type: "delimiter", - updateSelection: true, delimiter: context.delimiter, - isLine, - cursorRange: getEditRange( - editor, - target.contentRange, - isLine, - this.isBefore - ), + updateSelection: true, }; } }); - await this.runCommandTargets(editor, richTargets); - await this.runDelimiterTargets(editor, richTargets); + const commandTargets: CommandTarget[] = richTargets.filter( + (target): target is CommandTarget => target.type === "command" + ); + const delimiterTargets: DelimiterTarget[] = richTargets.filter( + (target): target is DelimiterTarget => target.type === "delimiter" + ); + + if (commandTargets.length > 0) { + await this.runCommandTargets(editor, richTargets, commandTargets); + } + if (delimiterTargets.length > 0) { + await this.runDelimiterTargets(editor, commandTargets, delimiterTargets); + } // Only update selection if all targets are agreeing on this if (!richTargets.find(({ updateSelection }) => !updateSelection)) { @@ -80,48 +74,33 @@ class EditNew implements Action { }; } - async runDelimiterTargets(editor: TextEditor, targets: RichTarget[]) { - const delimiterTargets: DelimiterTarget[] = targets.filter( - (target): target is DelimiterTarget => target.type === "delimiter" - ); - - if (delimiterTargets.length === 0) { - return; - } - - const edits = delimiterTargets.map(({ delimiter, isLine, cursorRange }) => { + async runDelimiterTargets( + editor: TextEditor, + commandTargets: CommandTarget[], + delimiterTargets: DelimiterTarget[] + ) { + const textInsertions = delimiterTargets.map((target) => { return { - text: isLine - ? delimiter + getLinePadding(editor, cursorRange, this.isBefore) - : delimiter, - range: cursorRange, - isReplace: this.isBefore, + range: target.targetRange, + delimiter: target.delimiter, + text: "", }; }); - const [updatedTargetRanges, updatedCursorRanges] = - await performEditsAndUpdateRanges( - this.graph.rangeUpdater, - editor, - edits, - [ - targets.map(({ targetRange }) => targetRange), - targets.map(({ cursorRange }) => cursorRange), - ] - ); + const { updatedEditorSelections, updatedContentRanges, insertionRanges } = + this.isBefore + ? await insertTextBefore(this.graph, editor, textInsertions) + : await insertTextAfter(this.graph, editor, textInsertions); - updateTargets(targets, updatedTargetRanges, updatedCursorRanges); + updateTargets(delimiterTargets, updatedContentRanges, insertionRanges); + updateCommandTargets(commandTargets, updatedEditorSelections); } - async runCommandTargets(editor: TextEditor, targets: RichTarget[]) { - const commandTargets: CommandTarget[] = targets.filter( - (target): target is CommandTarget => target.type === "command" - ); - - if (commandTargets.length === 0) { - return; - } - + async runCommandTargets( + editor: TextEditor, + targets: RichTarget[], + commandTargets: CommandTarget[] + ) { const command = ensureSingleCommand(commandTargets); if (this.isBefore) { @@ -146,12 +125,7 @@ class EditNew implements Action { ); updateTargets(targets, updatedTargetRanges, updatedCursorRanges); - - zip(commandTargets, editor.selections).forEach( - ([commandTarget, cursorSelection]) => { - commandTarget!.cursorRange = cursorSelection!; - } - ); + updateCommandTargets(commandTargets, editor.selections); } } @@ -180,7 +154,6 @@ interface CommandTarget extends CommonTarget { interface DelimiterTarget extends CommonTarget { type: "delimiter"; delimiter: string; - isLine: boolean; } type RichTarget = CommandTarget | DelimiterTarget; @@ -192,6 +165,15 @@ function ensureSingleCommand(targets: CommandTarget[]) { return commands[0]; } +function updateCommandTargets( + targets: CommandTarget[], + cursorRanges: readonly Range[] +) { + targets.forEach((target, i) => { + target.cursorRange = cursorRanges[i]; + }); +} + function updateTargets( targets: RichTarget[], updatedTargetRanges: Range[], diff --git a/src/test/suite/fixtures/recorded/actions/pourLine.yml b/src/test/suite/fixtures/recorded/actions/pourLine.yml index 0bf41d7ce7..ccccd8e1c5 100644 --- a/src/test/suite/fixtures/recorded/actions/pourLine.yml +++ b/src/test/suite/fixtures/recorded/actions/pourLine.yml @@ -1,5 +1,5 @@ languageId: python -postEditorOpenSleepTimeMs: 10 +postEditorOpenSleepTimeMs: 50 command: spokenForm: pour line version: 2 diff --git a/src/util/textInsertion.ts b/src/util/textInsertion.ts new file mode 100644 index 0000000000..12b0ec9e5f --- /dev/null +++ b/src/util/textInsertion.ts @@ -0,0 +1,127 @@ +import { zip } from "lodash"; +import { Position, Range, Selection, TextEditor } from "vscode"; +import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; +import { Graph } from "../typings/Types"; + +interface TextInsertion { + range: Range; + text: string; + delimiter: string; +} + +export async function insertTextBefore( + graph: Graph, + editor: TextEditor, + textInsertions: TextInsertion[] +) { + return insertText(graph, editor, textInsertions, true); +} + +export async function insertTextAfter( + graph: Graph, + editor: TextEditor, + textInsertions: TextInsertion[] +) { + return insertText(graph, editor, textInsertions, false); +} + +async function insertText( + graph: Graph, + editor: TextEditor, + textInsertions: TextInsertion[], + isBefore: boolean +) { + const edits = createEdits(editor, textInsertions, isBefore); + const editSelections = edits.map( + ({ range }) => new Selection(range.start, range.end) + ); + const contentSelections = textInsertions.map( + ({ range }) => new Selection(range.start, range.end) + ); + + const [ + updatedEditorSelections, + updatedEditSelections, + updatedContentSelections, + ] = await performEditsAndUpdateSelections(graph.rangeUpdater, editor, edits, [ + editor.selections, + editSelections, + contentSelections, + ]); + + const insertionRanges = zip(edits, updatedEditSelections).map( + ([edit, selection]) => { + const startOffset = editor.document.offsetAt(selection!.start); + const startIndex = isBefore + ? startOffset - edit!.offset - edit!.length + : startOffset + edit!.offset; + const endIndex = startIndex + edit!.length; + return new Range( + editor.document.positionAt(startIndex), + editor.document.positionAt(endIndex) + ); + } + ); + + return { + updatedEditorSelections, + updatedContentRanges: updatedContentSelections as Range[], + insertionRanges, + }; +} + +function createEdits( + editor: TextEditor, + textInsertions: TextInsertion[], + isBefore: boolean +) { + return textInsertions.map((insertion) => { + const { range: contentRange, text, delimiter } = insertion; + const isLine = delimiter.includes("\n"); + + const range = getEditRange(editor, contentRange, isLine, isBefore); + const padding = isLine ? getLinePadding(editor, range, isBefore) : ""; + + const editText = isBefore + ? text + delimiter + padding + : delimiter + padding + text; + + return { + range, + isReplace: !isBefore, + text: editText, + offset: delimiter.length + padding.length, + length: text.length, + }; + }); +} + +function getLinePadding(editor: TextEditor, range: Range, isBefore: boolean) { + const line = editor.document.lineAt(isBefore ? range.start : range.end); + const characterIndex = line.isEmptyOrWhitespace + ? range.start.character + : line.firstNonWhitespaceCharacterIndex; + return line.text.slice(0, characterIndex); +} + +function getEditRange( + editor: TextEditor, + range: Range, + isLine: boolean, + isBefore: boolean +) { + let position: Position; + if (isLine) { + const line = editor.document.lineAt(isBefore ? range.start : range.end); + if (isBefore) { + position = line.isEmptyOrWhitespace + ? range.start + : new Position(line.lineNumber, line.firstNonWhitespaceCharacterIndex); + } else { + position = line.range.end; + } + } else { + position = isBefore ? range.start : range.end; + } + return new Range(position, position); +} From 13451aedd57f00e72e9795a4c84e3f21f7a662d2 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Fri, 27 May 2022 00:13:58 +0200 Subject: [PATCH 225/314] Rename --- src/actions/Actions.ts | 17 ++++++++++------- src/actions/{CopyLines.ts => InsertCopy.ts} | 6 +++--- 2 files changed, 13 insertions(+), 10 deletions(-) rename src/actions/{CopyLines.ts => InsertCopy.ts} (94%) diff --git a/src/actions/Actions.ts b/src/actions/Actions.ts index 811281ae02..9e1f0e788a 100644 --- a/src/actions/Actions.ts +++ b/src/actions/Actions.ts @@ -4,7 +4,10 @@ import { Bring, Move, Swap } from "./BringMoveSwap"; import Call from "./Call"; import Clear from "./Clear"; import { CommentLines } from "./Comment"; -import { CopyLinesDown, CopyLinesUp } from "./CopyLines"; +import { + CopyContentAfter as InsertCopyAfter, + CopyContentBefore as InsertCopyBefore, +} from "./InsertCopy"; import { Copy, Cut, Paste } from "./CutCopyPaste"; import Deselect from "./Deselect"; import { EditNewBefore, EditNewAfter } from "./EditNew"; @@ -17,8 +20,8 @@ import GetText from "./GetText"; import Highlight from "./Highlight"; import { IndentLines, OutdentLines } from "./Indent"; import { - InsertEmptyLineAbove, - InsertEmptyLineBelow, + InsertEmptyLineAbove as InsertEmptyLineBefore, + InsertEmptyLineBelow as InsertEmptyLineAfter, InsertEmptyLinesAround, } from "./InsertEmptyLines"; import Remove from "./Remove"; @@ -53,10 +56,10 @@ class Actions implements ActionRecord { getText = new GetText(this.graph); highlight = new Highlight(this.graph); indentLine = new IndentLines(this.graph); - insertCopyAfter = new CopyLinesDown(this.graph); - insertCopyBefore = new CopyLinesUp(this.graph); - insertEmptyLineAfter = new InsertEmptyLineBelow(this.graph); - insertEmptyLineBefore = new InsertEmptyLineAbove(this.graph); + insertCopyAfter = new InsertCopyAfter(this.graph); + insertCopyBefore = new InsertCopyBefore(this.graph); + insertEmptyLineAfter = new InsertEmptyLineAfter(this.graph); + insertEmptyLineBefore = new InsertEmptyLineBefore(this.graph); insertEmptyLinesAround = new InsertEmptyLinesAround(this.graph); moveToTarget = new Move(this.graph); outdentLine = new OutdentLines(this.graph); diff --git a/src/actions/CopyLines.ts b/src/actions/InsertCopy.ts similarity index 94% rename from src/actions/CopyLines.ts rename to src/actions/InsertCopy.ts index ddbf5844b1..47492e9dfd 100644 --- a/src/actions/CopyLines.ts +++ b/src/actions/InsertCopy.ts @@ -9,7 +9,7 @@ import { createThatMark, runOnTargetsForEachEditor } from "../util/targetUtils"; import { insertTextAfter, insertTextBefore } from "../util/textInsertion"; import { Action, ActionReturnValue } from "./actions.types"; -class CopyLines implements Action { +class InsertCopy implements Action { getFinalStages = () => [weakContainingLineStage]; constructor(private graph: Graph, private isBefore: boolean) { @@ -63,13 +63,13 @@ class CopyLines implements Action { } } -export class CopyLinesUp extends CopyLines { +export class CopyContentBefore extends InsertCopy { constructor(graph: Graph) { super(graph, true); } } -export class CopyLinesDown extends CopyLines { +export class CopyContentAfter extends InsertCopy { constructor(graph: Graph) { super(graph, false); } From 6c4f8c843d1449549f40cd380cdcf90cd1239ca6 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Fri, 27 May 2022 12:40:00 +0200 Subject: [PATCH 226/314] Started working on lazy removal --- src/processTargets/marks/SourceStage.ts | 2 - src/processTargets/marks/ThatStage.ts | 2 - .../modifiers/OrdinalRangeSubTokenStage.ts | 10 +- .../ContainingSyntaxScopeStage.ts | 31 ++- .../modifiers/scopeTypeStages/LineStage.ts | 30 +-- .../scopeTypeStages/ParagraphStage.ts | 88 +------- .../modifiers/scopeTypeStages/RegexStage.ts | 4 +- .../modifiers/scopeTypeStages/TokenStage.ts | 54 ----- src/processTargets/processTargets.ts | 118 ++-------- .../targetUtil/getLineDelimiters.ts | 18 ++ .../targetUtil/getTokenDelimiters.ts | 43 ++++ .../targetUtil/maybeAddDelimiter.ts | 18 ++ src/processTargets/targets/BaseTarget.ts | 203 +++++------------- .../targets/ContinuousRangeTarget.ts | 165 ++++++++++++++ src/processTargets/targets/LineTarget.ts | 54 +++-- src/processTargets/targets/ParagraphTarget.ts | 154 +++++++++---- src/processTargets/targets/ScopeTypeTarget.ts | 46 +++- .../targets/SurroundingPairTarget.ts | 3 +- src/processTargets/targets/TokenTarget.ts | 3 +- src/processTargets/targets/WeakTarget.ts | 16 +- src/typings/Types.ts | 14 -- src/typings/target.types.ts | 17 +- src/util/targetUtils.ts | 78 +------ 23 files changed, 539 insertions(+), 632 deletions(-) create mode 100644 src/processTargets/targetUtil/getLineDelimiters.ts create mode 100644 src/processTargets/targetUtil/getTokenDelimiters.ts create mode 100644 src/processTargets/targetUtil/maybeAddDelimiter.ts create mode 100644 src/processTargets/targets/ContinuousRangeTarget.ts diff --git a/src/processTargets/marks/SourceStage.ts b/src/processTargets/marks/SourceStage.ts index ad03603042..fca3f7d62f 100644 --- a/src/processTargets/marks/SourceStage.ts +++ b/src/processTargets/marks/SourceStage.ts @@ -1,7 +1,6 @@ import { SourceMark, Target } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { isReversed } from "../../util/selectionUtils"; -import { getTokenDelimiters } from "../modifiers/scopeTypeStages/TokenStage"; import { MarkStage } from "../PipelineStages.types"; import WeakTarget from "../targets/WeakTarget"; @@ -14,7 +13,6 @@ export default class implements MarkStage { } return context.sourceMark.map((selection) => { return new WeakTarget({ - ...getTokenDelimiters(selection.editor, selection.selection), editor: selection.editor, isReversed: isReversed(selection.selection), contentRange: selection.selection, diff --git a/src/processTargets/marks/ThatStage.ts b/src/processTargets/marks/ThatStage.ts index eb6539ad46..22e0e27dd7 100644 --- a/src/processTargets/marks/ThatStage.ts +++ b/src/processTargets/marks/ThatStage.ts @@ -1,7 +1,6 @@ import { Target, ThatMark } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { isReversed } from "../../util/selectionUtils"; -import { getTokenDelimiters } from "../modifiers/scopeTypeStages/TokenStage"; import { MarkStage } from "../PipelineStages.types"; import WeakTarget from "../targets/WeakTarget"; @@ -14,7 +13,6 @@ export default class implements MarkStage { } return context.thatMark.map((selection) => { return new WeakTarget({ - ...getTokenDelimiters(selection.editor, selection.selection), editor: selection.editor, isReversed: isReversed(selection.selection), contentRange: selection.selection, diff --git a/src/processTargets/modifiers/OrdinalRangeSubTokenStage.ts b/src/processTargets/modifiers/OrdinalRangeSubTokenStage.ts index 38bd2a8aaa..19e12938d4 100644 --- a/src/processTargets/modifiers/OrdinalRangeSubTokenStage.ts +++ b/src/processTargets/modifiers/OrdinalRangeSubTokenStage.ts @@ -116,14 +116,8 @@ export default class implements ModifierStage { contentRange: new Range(anchor, active), scopeTypeType: this.modifier.scopeType.type, delimiter: containingListDelimiter ?? "", - leadingDelimiter: - leadingDelimiterRange != null - ? { range: leadingDelimiterRange } - : undefined, - trailingDelimiter: - trailingDelimiterRange != null - ? { range: trailingDelimiterRange } - : undefined, + leadingDelimiterRange, + trailingDelimiterRange, }), ]; } diff --git a/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts b/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts index 2638fd7a1f..ca2643b2e6 100644 --- a/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts @@ -7,7 +7,6 @@ import { SimpleScopeType, Target, } from "../../../typings/target.types"; -import ScopeTypeTarget from "../../targets/ScopeTypeTarget"; import { NodeMatcher, ProcessedTargetsContext, @@ -15,8 +14,8 @@ import { SelectionWithEditorWithContext, } from "../../../typings/Types"; import { selectionWithEditorFromRange } from "../../../util/selectionUtils"; -import { selectionWithEditorWithContextToTarget } from "../../../util/targetUtils"; import { ModifierStage } from "../../PipelineStages.types"; +import ScopeTypeTarget from "../../targets/ScopeTypeTarget"; export interface SimpleContainingScopeModifier extends ContainingScopeModifier { scopeType: SimpleScopeType; @@ -56,14 +55,26 @@ export default class implements ModifierStage { ); } - return scopeNodes.map( - (scope) => - new ScopeTypeTarget({ - ...selectionWithEditorWithContextToTarget(scope), - scopeTypeType: this.modifier.scopeType.type, - isReversed: target.isReversed, - }) - ); + return scopeNodes.map((scope) => { + const { + containingListDelimiter, + leadingDelimiterRange, + trailingDelimiterRange, + removalRange, + } = scope.context; + const { editor, selection: contentSelection } = scope.selection; + + return new ScopeTypeTarget({ + scopeTypeType: this.modifier.scopeType.type, + editor, + isReversed: target.isReversed, + contentRange: contentSelection, + contentRemovalRange: removalRange, + delimiter: containingListDelimiter, + leadingDelimiterRange, + trailingDelimiterRange, + }); + }); } } diff --git a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts index fe0ebc67f5..a97a2724c6 100644 --- a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts @@ -1,4 +1,4 @@ -import { Position, Range, TextEditor } from "vscode"; +import { Range, TextEditor } from "vscode"; import { ContainingScopeModifier, EveryScopeModifier, @@ -61,36 +61,10 @@ export function createLineTarget( range: Range, isReversed: boolean ) { - const { document } = editor; - const contentRange = fitRangeToLineContent(editor, range); - const { start, end } = contentRange; - - const removalRange = new Range( - new Position(start.line, 0), - editor.document.lineAt(end).range.end - ); - - const leadingDelimiterRange = - start.line > 0 - ? new Range(document.lineAt(start.line - 1).range.end, removalRange.start) - : undefined; - const trailingDelimiterRange = - end.line + 1 < document.lineCount - ? new Range(removalRange.end, new Position(end.line + 1, 0)) - : undefined; - return new LineTarget({ editor, isReversed, - contentRange, - leadingDelimiter: - leadingDelimiterRange != null - ? { range: leadingDelimiterRange } - : undefined, - trailingDelimiter: - trailingDelimiterRange != null - ? { range: trailingDelimiterRange } - : undefined, + contentRange: fitRangeToLineContent(editor, range), }); } diff --git a/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts b/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts index 5d15bb28fd..c9abde566e 100644 --- a/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts @@ -1,4 +1,4 @@ -import { Range, TextDocument, TextLine } from "vscode"; +import { Range } from "vscode"; import { ContainingScopeModifier, EveryScopeModifier, @@ -76,76 +76,14 @@ export default class implements ModifierStage { } getTargetFromRange(target: Target, range?: Range): ParagraphTarget { - const { document } = target.editor; - const { lineAt } = document; - if (range == null) { range = calculateRange(target); } - const startLine = lineAt(range.start); - const endLine = lineAt(range.end); - const contentRange = fitRangeToLineContent( - target.editor, - new Range(startLine.range.start, endLine.range.end) - ); - const leadingLine = getPreviousNonEmptyLine(document, startLine); - const trailingLine = getNextNonEmptyLine(document, endLine); - - const leadingDelimiter = (() => { - if (leadingLine != null) { - return { - range: new Range(leadingLine.range.end, startLine.range.start), - highlight: new Range( - lineAt(leadingLine.lineNumber + 1).range.start, - lineAt(startLine.lineNumber - 1).range.end - ), - }; - } - if (startLine.lineNumber > 0) { - const { start } = lineAt(0).range; - return { - range: new Range(start, startLine.range.start), - highlight: new Range( - start, - lineAt(startLine.lineNumber - 1).range.end - ), - }; - } - return undefined; - })(); - - const trailingDelimiter = (() => { - if (trailingLine != null) { - return { - range: new Range(endLine.range.end, trailingLine.range.start), - highlight: new Range( - lineAt(endLine.lineNumber + 1).range.start, - lineAt(trailingLine.lineNumber - 1).range.end - ), - }; - } - if (endLine.lineNumber < document.lineCount - 1) { - const lastLine = lineAt(document.lineCount - 1); - // If true there is an empty line after this one that isn't the last/final one - const highlightStart = - endLine.lineNumber !== document.lineCount - 1 - ? lineAt(endLine.lineNumber + 1).range.end - : lastLine.range.start; - return { - range: new Range(endLine.range.end, lastLine.range.end), - highlight: new Range(highlightStart, lastLine.range.end), - }; - } - return undefined; - })(); - return new ParagraphTarget({ editor: target.editor, isReversed: target.isReversed, - contentRange, - leadingDelimiter, - trailingDelimiter, + contentRange: fitRangeToLineContent(target.editor, range), }); } } @@ -174,25 +112,3 @@ function calculateRange(target: Target) { } return new Range(startLine.range.start, endLine.range.end); } - -function getPreviousNonEmptyLine(document: TextDocument, line: TextLine) { - while (line.lineNumber > 0) { - const previousLine = document.lineAt(line.lineNumber - 1); - if (!previousLine.isEmptyOrWhitespace) { - return previousLine; - } - line = previousLine; - } - return null; -} - -function getNextNonEmptyLine(document: TextDocument, line: TextLine) { - while (line.lineNumber + 1 < document.lineCount) { - const nextLine = document.lineAt(line.lineNumber + 1); - if (!nextLine.isEmptyOrWhitespace) { - return nextLine; - } - line = nextLine; - } - return null; -} diff --git a/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts b/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts index 804386863b..de7edc0898 100644 --- a/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts @@ -4,10 +4,9 @@ import { EveryScopeModifier, Target, } from "../../../typings/target.types"; -import ScopeTypeTarget from "../../targets/ScopeTypeTarget"; import { ProcessedTargetsContext } from "../../../typings/Types"; import { ModifierStage } from "../../PipelineStages.types"; -import { getTokenDelimiters } from "./TokenStage"; +import ScopeTypeTarget from "../../targets/ScopeTypeTarget"; type RegexModifier = NonWhitespaceSequenceModifier | UrlModifier; @@ -66,7 +65,6 @@ class RegexStage implements ModifierStage { getTargetFromRange(target: Target, range: Range): ScopeTypeTarget { return new ScopeTypeTarget({ - ...getTokenDelimiters(target.editor, range), scopeTypeType: this.modifier.scopeType.type, editor: target.editor, isReversed: target.isReversed, diff --git a/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts index bb7306f80c..5714d67490 100644 --- a/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts @@ -60,60 +60,6 @@ export default class implements ModifierStage { } } -export function getTokenDelimiters(editor: TextEditor, contentRange: Range) { - const { document } = editor; - const { start, end } = contentRange; - const endLine = document.lineAt(end); - - const startLine = document.lineAt(start); - const leadingText = startLine.text.slice(0, start.character); - const leadingDelimiters = leadingText.match(/\s+$/); - const leadingDelimiterRange = - leadingDelimiters != null - ? new Range( - start.line, - start.character - leadingDelimiters[0].length, - start.line, - start.character - ) - : undefined; - - const trailingText = endLine.text.slice(end.character); - const trailingDelimiters = trailingText.match(/^\s+/); - const trailingDelimiterRange = - trailingDelimiters != null - ? new Range( - end.line, - end.character, - end.line, - end.character + trailingDelimiters[0].length - ) - : undefined; - - const includeDelimitersInRemoval = - (leadingDelimiterRange != null || trailingDelimiterRange != null) && - (leadingDelimiterRange != null || start.character === 0) && - (trailingDelimiterRange != null || end.isEqual(endLine.range.end)); - - return { - delimiter: " ", - leadingDelimiter: - leadingDelimiterRange != null - ? { - range: leadingDelimiterRange, - exclude: !includeDelimitersInRemoval, - } - : undefined, - trailingDelimiter: - trailingDelimiterRange != null - ? { - range: trailingDelimiterRange, - exclude: !includeDelimitersInRemoval, - } - : undefined, - }; -} - /** * Given a selection returns a new range which contains the tokens * intersecting the given selection. Uses heuristics to tie break when the diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index 350fd59c65..b64b3baad3 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -1,5 +1,5 @@ import { zip } from "lodash"; -import { Position, Range } from "vscode"; +import { Range } from "vscode"; import { PrimitiveTargetDescriptor, RangeTargetDescriptor, @@ -11,7 +11,7 @@ import { ensureSingleEditor } from "../util/targetUtils"; import uniqDeep from "../util/uniqDeep"; import getMarkStage from "./getMarkStage"; import getModifierStage from "./getModifierStage"; -import BaseTarget from "./targets/BaseTarget"; +import ContinuousRangeTarget from "./targets/ContinuousRangeTarget"; import WeakTarget from "./targets/WeakTarget"; /** @@ -98,89 +98,15 @@ function processContinuousRangeTarget( excludeAnchor: boolean, excludeActive: boolean ): Target { - const { document } = ensureSingleEditor([anchorTarget, activeTarget]); - const isForward = calcIsForward(anchorTarget, activeTarget); - const startTarget = isForward ? anchorTarget : activeTarget; - const endTarget = isForward ? activeTarget : anchorTarget; - const excludeStart = isForward ? excludeAnchor : excludeActive; - const excludeEnd = isForward ? excludeActive : excludeAnchor; - - const contentStart = (() => { - if (excludeStart) { - if (startTarget.isLine) { - return new Position(startTarget.contentRange.end.line + 1, 0); - } - return startTarget.contentRange.end; - } - return startTarget.contentRange.start; - })(); - const contentEnd = (() => { - if (excludeEnd) { - if (endTarget.isLine) { - return document.lineAt(endTarget.contentRange.start.line - 1).range.end; - } - return endTarget.contentRange.start; - } - return endTarget.contentRange.end; - })(); - const contentRange = new Range(contentStart, contentEnd); - - const removalRange = (() => { - if (startTarget.removalRange == null && endTarget.removalRange == null) { - return undefined; - } - const startRange = startTarget.removalRange ?? startTarget.contentRange; - const endRange = endTarget.removalRange ?? endTarget.contentRange; - return new Range( - excludeStart ? startRange.end : startRange.start, - excludeEnd ? endRange.start : endRange.end - ); - })(); - - const leadingDelimiter = (() => { - if (excludeStart) { - if (startTarget.isLine) { - return { - range: new Range(contentRange.start, startTarget.contentRange.end), - }; - } - return startTarget.trailingDelimiter; - } - return startTarget.leadingDelimiter; - })(); - const trailingDelimiter = (() => { - if (excludeEnd) { - if (endTarget.isLine) { - return { - range: new Range( - contentRange.end, - endTarget.leadingDelimiter!.range.end - ), - highlight: new Range( - contentRange.end, - endTarget.contentRange.start.translate({ lineDelta: -1 }) - ), - }; - } - return endTarget.leadingDelimiter; - } - return endTarget.trailingDelimiter; - })(); - - // If both objects are of the same type create a new object of the same - const startConstructor = Object.getPrototypeOf(startTarget).constructor; - const endConstructor = Object.getPrototypeOf(endTarget).constructor; - const constructor = - startConstructor === endConstructor ? startConstructor : BaseTarget; - - return new constructor({ - editor: activeTarget.editor, - isReversed: !isForward, - delimiter: anchorTarget.delimiter, - contentRange, - removalRange, - leadingDelimiter, - trailingDelimiter, + ensureSingleEditor([anchorTarget, activeTarget]); + const isReversed = calcIsReversed(anchorTarget, activeTarget); + + return new ContinuousRangeTarget({ + startTarget: isReversed ? activeTarget : anchorTarget, + endTarget: isReversed ? anchorTarget : activeTarget, + excludeStart: isReversed ? excludeActive : excludeAnchor, + excludeEnd: isReversed ? excludeAnchor : excludeActive, + isReversed, }); } @@ -197,16 +123,16 @@ function processVerticalRangeTarget( excludeAnchor: boolean, excludeActive: boolean ): Target[] { - const isForward = calcIsForward(anchorTarget, activeTarget); - const delta = isForward ? 1 : -1; + const isReversed = calcIsReversed(anchorTarget, activeTarget); + const delta = isReversed ? -1 : 1; - const anchorPosition = isForward - ? anchorTarget.contentRange.end - : anchorTarget.contentRange.start; + const anchorPosition = isReversed + ? anchorTarget.contentRange.start + : anchorTarget.contentRange.end; const anchorLine = anchorPosition.line + (excludeAnchor ? delta : 0); - const activePosition = isForward - ? activeTarget.contentRange.end - : activeTarget.contentRange.start; + const activePosition = isReversed + ? activeTarget.contentRange.start + : activeTarget.contentRange.end; const activeLine = activePosition.line - (excludeActive ? delta : 0); const results: Target[] = []; @@ -221,8 +147,8 @@ function processVerticalRangeTarget( new WeakTarget({ editor: anchorTarget.editor, isReversed: anchorTarget.isReversed, - position: anchorTarget.position, contentRange, + position: anchorTarget.position, }) ); if (i === activeLine) { @@ -255,6 +181,6 @@ function processPrimitiveTarget( return targets; } -function calcIsForward(anchor: Target, active: Target) { - return anchor.contentRange.start.isBeforeOrEqual(active.contentRange.start); +function calcIsReversed(anchor: Target, active: Target) { + return anchor.contentRange.start.isAfter(active.contentRange.start); } diff --git a/src/processTargets/targetUtil/getLineDelimiters.ts b/src/processTargets/targetUtil/getLineDelimiters.ts new file mode 100644 index 0000000000..9976d92498 --- /dev/null +++ b/src/processTargets/targetUtil/getLineDelimiters.ts @@ -0,0 +1,18 @@ +import { TextEditor, Range, Position } from "vscode"; + +export function getLineLeadingDelimiterRange(editor: TextEditor, range: Range) { + const { start } = range; + return start.line > 0 + ? new Range(editor.document.lineAt(start.line - 1).range.end, range.start) + : undefined; +} + +export function getLineTrailingDelimiterRange( + editor: TextEditor, + range: Range +) { + const { end } = range; + return end.line + 1 < editor.document.lineCount + ? new Range(range.end, new Position(end.line + 1, 0)) + : undefined; +} diff --git a/src/processTargets/targetUtil/getTokenDelimiters.ts b/src/processTargets/targetUtil/getTokenDelimiters.ts new file mode 100644 index 0000000000..b8259ebd24 --- /dev/null +++ b/src/processTargets/targetUtil/getTokenDelimiters.ts @@ -0,0 +1,43 @@ +import { Range, TextEditor } from "vscode"; + +export function getTokenDelimiters(editor: TextEditor, contentRange: Range) { + const { document } = editor; + const { start, end } = contentRange; + const endLine = document.lineAt(end); + + const startLine = document.lineAt(start); + const leadingText = startLine.text.slice(0, start.character); + const leadingDelimiters = leadingText.match(/\s+$/); + const leadingDelimiterRange = + leadingDelimiters != null + ? new Range( + start.line, + start.character - leadingDelimiters[0].length, + start.line, + start.character + ) + : undefined; + + const trailingText = endLine.text.slice(end.character); + const trailingDelimiters = trailingText.match(/^\s+/); + const trailingDelimiterRange = + trailingDelimiters != null + ? new Range( + end.line, + end.character, + end.line, + end.character + trailingDelimiters[0].length + ) + : undefined; + + const includeDelimitersInRemoval = + (leadingDelimiterRange != null || trailingDelimiterRange != null) && + (leadingDelimiterRange != null || start.character === 0) && + (trailingDelimiterRange != null || end.isEqual(endLine.range.end)); + + return { + includeDelimitersInRemoval, + leadingDelimiterRange, + trailingDelimiterRange, + }; +} diff --git a/src/processTargets/targetUtil/maybeAddDelimiter.ts b/src/processTargets/targetUtil/maybeAddDelimiter.ts new file mode 100644 index 0000000000..11f50c086e --- /dev/null +++ b/src/processTargets/targetUtil/maybeAddDelimiter.ts @@ -0,0 +1,18 @@ +import { Position } from "../../typings/target.types"; + +/** Possibly add delimiter for positions before/after */ +export function maybeAddDelimiter( + text: string, + delimiter?: string, + position?: Position +): string { + if (delimiter != null) { + if (position === "before") { + return text + delimiter; + } + if (position === "after") { + return delimiter + text; + } + } + return text; +} diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index a8e5861661..6558cd0b64 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -1,12 +1,8 @@ import { Range, Selection, TextEditor } from "vscode"; -import { - EditNewContext, - Position, - RemovalRange, - Target, -} from "../../typings/target.types"; +import { EditNewContext, Position, Target } from "../../typings/target.types"; import { selectionFromRange } from "../../util/selectionUtils"; -import { processRemovalRange } from "../../util/targetUtils"; +import { getTokenDelimiters } from "../targetUtil/getTokenDelimiters"; +import { maybeAddDelimiter } from "../targetUtil/maybeAddDelimiter"; export function extractCommonParameters(parameters: CommonTargetParameters) { return { @@ -20,40 +16,24 @@ export function extractCommonParameters(parameters: CommonTargetParameters) { /** Parameters supported by all target classes */ export interface CommonTargetParameters { - editor: TextEditor; - isReversed: boolean; - contentRange: Range; - position?: Position; - thatTarget?: Target; + readonly editor: TextEditor; + readonly isReversed: boolean; + readonly contentRange: Range; + readonly position?: Position; + readonly thatTarget?: Target; } export interface CloneWithParameters { - position?: Position; - thatTarget?: Target; + readonly position?: Position; + readonly thatTarget?: Target; } export interface BaseTargetParameters extends CommonTargetParameters { - delimiter: string; - removalRange?: Range; - leadingDelimiter?: RemovalRange; - trailingDelimiter?: RemovalRange; - isLine?: boolean; -} - -interface BaseTargetState { - readonly editor: TextEditor; - readonly isReversed: boolean; - readonly contentRange: Range; - readonly thatTarget?: Target; readonly delimiter: string; - readonly removalRange?: Range; - readonly leadingDelimiter?: RemovalRange; - readonly trailingDelimiter?: RemovalRange; - readonly position?: Position; } export default abstract class BaseTarget implements Target { - protected readonly state: BaseTargetState; + protected readonly state: BaseTargetParameters; constructor(parameters: BaseTargetParameters) { this.state = { @@ -62,9 +42,6 @@ export default abstract class BaseTarget implements Target { contentRange: parameters.contentRange, position: parameters.position, delimiter: parameters.delimiter, - removalRange: parameters.removalRange, - leadingDelimiter: parameters.leadingDelimiter, - trailingDelimiter: parameters.trailingDelimiter, thatTarget: parameters.thatTarget, }; } @@ -72,27 +49,21 @@ export default abstract class BaseTarget implements Target { get position() { return this.state.position; } - get editor() { return this.state.editor; } - get isReversed() { return this.state.isReversed; } - - get removalRange() { - return this.state.removalRange; + get contentRemovalRange() { + return this.contentRange; } - get isLine() { return false; } - get isParagraph() { return false; } - get isWeak() { return false; } @@ -103,18 +74,16 @@ export default abstract class BaseTarget implements Target { : this; } - getInteriorStrict(): Target[] { - throw Error("No available interior"); + get contentText(): string { + return this.editor.document.getText(this.contentRange); } - getBoundaryStrict(): Target[] { - throw Error("No available boundaries"); + get contentSelection(): Selection { + return selectionFromRange(this.isReversed, this.contentRange); } get contentRange(): Range { switch (this.position) { - case undefined: - return this.state.contentRange; case "start": case "before": return new Range( @@ -127,17 +96,11 @@ export default abstract class BaseTarget implements Target { this.state.contentRange.end, this.state.contentRange.end ); + default: + return this.state.contentRange; } } - get contentText(): string { - return this.editor.document.getText(this.contentRange); - } - - get contentSelection(): Selection { - return selectionFromRange(this.isReversed, this.contentRange); - } - get delimiter(): string | undefined { switch (this.position) { // This it NOT a raw target. Joining with this should be done on empty delimiter. @@ -149,113 +112,56 @@ export default abstract class BaseTarget implements Target { } } - get leadingDelimiter() { - switch (this.position) { - case undefined: - case "before": - return this.state.leadingDelimiter; - default: - return undefined; - } + get leadingDelimiterRange() { + const { includeDelimitersInRemoval, leadingDelimiterRange } = + getTokenDelimiters(this.state.editor, this.state.contentRange); + return includeDelimitersInRemoval || this.position != null + ? leadingDelimiterRange + : undefined; } - get trailingDelimiter() { - switch (this.position) { - case undefined: - case "after": - return this.state.trailingDelimiter; - default: - return undefined; - } + get trailingDelimiterRange() { + const { includeDelimitersInRemoval, trailingDelimiterRange } = + getTokenDelimiters(this.state.editor, this.state.contentRange); + return includeDelimitersInRemoval || this.position != null + ? trailingDelimiterRange + : undefined; } - /** Possibly add delimiter for positions before/after */ maybeAddDelimiter(text: string): string { - if (this.delimiter != null) { - if (this.position === "before") { - return text + this.delimiter; - } - if (this.position === "after") { - return this.delimiter + text; - } - } - return text; - } - - protected getRemovalContentRange(): Range { - const removalRange = this.removalRange ?? this.contentRange; - const delimiter = - processRemovalRange(this.trailingDelimiter) ?? - processRemovalRange(this.leadingDelimiter); - return delimiter != null - ? removalRange.union(delimiter.range) - : removalRange; - } - - protected getRemovalContentHighlightRange() { - const removalRange = this.removalRange ?? this.contentRange; - const delimiter = - processRemovalRange(this.trailingDelimiter) ?? - processRemovalRange(this.leadingDelimiter); - return delimiter != null - ? removalRange.union(delimiter.highlight) - : removalRange; - } - - protected getRemovalBeforeRange(): Range { - return this.leadingDelimiter != null - ? this.leadingDelimiter.range - : this.contentRange; - } - - protected getRemovalAfterRange(): Range { - return this.trailingDelimiter != null - ? this.trailingDelimiter.range - : this.contentRange; - } - - protected getRemovalBeforeHighlightRange(): Range | undefined { - return this.leadingDelimiter != null - ? this.leadingDelimiter.highlight ?? this.leadingDelimiter.range - : undefined; + return maybeAddDelimiter(text, this.delimiter, this.position); } - protected getRemovalAfterHighlightRange(): Range | undefined { - return this.trailingDelimiter != null - ? this.trailingDelimiter.highlight ?? this.trailingDelimiter.range - : undefined; + getEditNewContext(isBefore: boolean): EditNewContext { + if (this.delimiter === "\n" && !isBefore) { + return { type: "command", command: "editor.action.insertLineAfter" }; + } + return { + type: "delimiter", + delimiter: this.delimiter ?? "", + }; } getRemovalRange(): Range { switch (this.position) { case "before": - return this.getRemovalBeforeRange(); + return this.leadingDelimiterRange ?? this.contentRange; case "after": - return this.getRemovalAfterRange(); + return this.trailingDelimiterRange ?? this.contentRange; + case "start": + case "end": + return this.contentRange; default: - return this.getRemovalContentRange(); + const delimiterRange = + this.trailingDelimiterRange ?? this.leadingDelimiterRange; + return delimiterRange != null + ? this.contentRemovalRange.union(delimiterRange) + : this.contentRemovalRange; } } getRemovalHighlightRange(): Range | undefined { - switch (this.position) { - case "before": - return this.getRemovalBeforeHighlightRange(); - case "after": - return this.getRemovalAfterHighlightRange(); - default: - return this.getRemovalContentHighlightRange(); - } - } - - getEditNewContext(isBefore: boolean): EditNewContext { - if (this.delimiter === "\n" && !isBefore) { - return { type: "command", command: "editor.action.insertLineAfter" }; - } - return { - type: "delimiter", - delimiter: this.delimiter ?? "", - }; + return this.getRemovalRange(); } withPosition(position: Position): Target { @@ -266,5 +172,12 @@ export default abstract class BaseTarget implements Target { return this.cloneWith({ thatTarget }); } + getInteriorStrict(): Target[] { + throw Error("No available interior"); + } + getBoundaryStrict(): Target[] { + throw Error("No available boundaries"); + } + abstract cloneWith(parameters: CloneWithParameters): Target; } diff --git a/src/processTargets/targets/ContinuousRangeTarget.ts b/src/processTargets/targets/ContinuousRangeTarget.ts new file mode 100644 index 0000000000..824d893eb0 --- /dev/null +++ b/src/processTargets/targets/ContinuousRangeTarget.ts @@ -0,0 +1,165 @@ +import { Range, Selection, Position as VS_Position } from "vscode"; +import { EditNewContext, Position, Target } from "../../typings/target.types"; +import { selectionFromRange } from "../../util/selectionUtils"; +import { + getLineLeadingDelimiterRange, + getLineTrailingDelimiterRange, +} from "../targetUtil/getLineDelimiters"; +import { maybeAddDelimiter } from "../targetUtil/maybeAddDelimiter"; + +interface ContinuousRangeTargetParameters { + readonly startTarget: Target; + readonly endTarget: Target; + readonly isReversed: boolean; + readonly excludeStart: boolean; + readonly excludeEnd: boolean; +} + +export default class ContinuousRangeTarget implements Target { + private startTarget_: Target; + private endTarget_: Target; + private isReversed_: boolean; + private excludeStart_: boolean; + private excludeEnd_: boolean; + + constructor(parameters: ContinuousRangeTargetParameters) { + this.startTarget_ = parameters.startTarget; + this.endTarget_ = parameters.endTarget; + this.isReversed_ = parameters.isReversed; + this.excludeStart_ = parameters.excludeStart; + this.excludeEnd_ = parameters.excludeEnd; + } + + get editor() { + return this.startTarget_.editor; + } + get isReversed() { + return this.isReversed_; + } + get position() { + return undefined; + } + get isLine() { + return false; + } + get isParagraph() { + return false; + } + get isWeak() { + return false; + } + get thatTarget() { + return this; + } + get contentText(): string { + return this.editor.document.getText(this.contentRange); + } + get contentSelection(): Selection { + return selectionFromRange(this.isReversed, this.contentRange); + } + + get delimiter() { + return ( + (this.startTarget_.delimiter === this.endTarget_.delimiter + ? this.startTarget_.delimiter + : null) ?? " " + ); + } + + get leadingDelimiterRange() { + const startTarget = this.startTarget_; + if (this.excludeStart_) { + if (startTarget.isLine) { + return getLineLeadingDelimiterRange(this.editor, this.contentRange); + } + return undefined; + } + return startTarget.leadingDelimiterRange; + } + + get trailingDelimiterRange() { + const endTarget = this.endTarget_; + if (this.excludeEnd_) { + if (endTarget.isLine) { + return getLineTrailingDelimiterRange(this.editor, this.contentRange); + } + return undefined; + } + return endTarget.trailingDelimiterRange; + } + + get contentRange() { + return this.processRanges( + this.startTarget_.contentRange, + this.endTarget_.contentRange + ); + } + + get contentRemovalRange() { + return this.processRanges( + this.startTarget_.contentRemovalRange, + this.endTarget_.contentRemovalRange + ); + } + + maybeAddDelimiter(text: string): string { + return maybeAddDelimiter(text, this.delimiter, this.position); + } + + getEditNewContext(_isBefore: boolean): EditNewContext { + return { + type: "delimiter", + delimiter: this.delimiter, + }; + } + + getRemovalRange(): Range { + const delimiterRange = + this.trailingDelimiterRange ?? this.leadingDelimiterRange; + return delimiterRange != null + ? this.contentRemovalRange.union(delimiterRange) + : this.contentRemovalRange; + } + + getRemovalHighlightRange(): Range | undefined { + return this.getRemovalRange(); + } + + getInteriorStrict(): Target[] { + throw Error("No available interior"); + } + getBoundaryStrict(): Target[] { + throw Error("No available boundaries"); + } + withPosition(_position: Position): Target { + throw new Error("Method not implemented"); + } + withThatTarget(_thatTarget: Target): Target { + throw new Error("Method not implemented"); + } + + private processRanges(startRange: Range, endRange: Range) { + const startTarget = this.startTarget_; + const endTarget = this.endTarget_; + const start = (() => { + if (this.excludeStart_) { + if (startTarget.isLine) { + return new VS_Position(startRange.end.line + 1, 0); + } + return startRange.end; + } + return startRange.start; + })(); + const end = (() => { + if (this.excludeEnd_) { + if (endTarget.isLine) { + const { lineAt } = this.editor.document; + return lineAt(endRange.start.line - 1).range.end; + } + return endRange.start; + } + return endRange.end; + })(); + return new Range(start, end); + } +} diff --git a/src/processTargets/targets/LineTarget.ts b/src/processTargets/targets/LineTarget.ts index 110d5cd39d..0115af754c 100644 --- a/src/processTargets/targets/LineTarget.ts +++ b/src/processTargets/targets/LineTarget.ts @@ -1,23 +1,18 @@ -import { Range } from "vscode"; -import { RemovalRange } from "../../typings/target.types"; -import { processRemovalRange } from "../../util/targetUtils"; +import { Position, Range } from "vscode"; +import { + getLineLeadingDelimiterRange, + getLineTrailingDelimiterRange, +} from "../targetUtil/getLineDelimiters"; import BaseTarget, { CloneWithParameters, CommonTargetParameters, extractCommonParameters, } from "./BaseTarget"; -interface LineTargetParameters extends CommonTargetParameters { - leadingDelimiter?: RemovalRange; - trailingDelimiter?: RemovalRange; -} - export default class LineTarget extends BaseTarget { - constructor(parameters: LineTargetParameters) { + constructor(parameters: CommonTargetParameters) { super({ ...extractCommonParameters(parameters), - leadingDelimiter: parameters.leadingDelimiter, - trailingDelimiter: parameters.trailingDelimiter, delimiter: "\n", }); } @@ -26,30 +21,29 @@ export default class LineTarget extends BaseTarget { return true; } - getRemovalHighlightRange(): Range | undefined { - if (this.position != null) { - return undefined; - } - return this.contentRange; + cloneWith(parameters: CloneWithParameters): LineTarget { + return new LineTarget({ ...this.state, ...parameters }); } - protected getRemovalContentRange(): Range { - if (this.position != null) { - return this.contentRange; - } - const removalRange = new Range( - this.editor.document.lineAt(this.contentRange.start).range.start, + get contentRemovalRange() { + return new Range( + new Position(this.contentRange.start.line, 0), this.editor.document.lineAt(this.contentRange.end).range.end ); - const delimiter = - processRemovalRange(this.trailingDelimiter) ?? - processRemovalRange(this.leadingDelimiter); - return delimiter != null - ? removalRange.union(delimiter.range) - : removalRange; } - cloneWith(parameters: CloneWithParameters): LineTarget { - return new LineTarget({ ...this.state, ...parameters }); + get leadingDelimiterRange() { + return getLineLeadingDelimiterRange(this.editor, this.contentRange); + } + + get trailingDelimiterRange() { + return getLineTrailingDelimiterRange(this.editor, this.contentRange); + } + + getRemovalHighlightRange(): Range | undefined { + if (this.position != null) { + return undefined; + } + return this.contentRange; } } diff --git a/src/processTargets/targets/ParagraphTarget.ts b/src/processTargets/targets/ParagraphTarget.ts index 916c4d0240..ae0191e2df 100644 --- a/src/processTargets/targets/ParagraphTarget.ts +++ b/src/processTargets/targets/ParagraphTarget.ts @@ -1,23 +1,14 @@ -import { Range } from "vscode"; -import { RemovalRange } from "../../typings/target.types"; -import { processRemovalRange } from "../../util/targetUtils"; +import { Position, Range, TextDocument, TextEditor, TextLine } from "vscode"; import BaseTarget, { CloneWithParameters, CommonTargetParameters, extractCommonParameters, } from "./BaseTarget"; -interface ParagraphTargetParameters extends CommonTargetParameters { - leadingDelimiter?: RemovalRange; - trailingDelimiter?: RemovalRange; -} - export default class ParagraphTarget extends BaseTarget { - constructor(parameters: ParagraphTargetParameters) { + constructor(parameters: CommonTargetParameters) { super({ ...extractCommonParameters(parameters), - leadingDelimiter: parameters.leadingDelimiter, - trailingDelimiter: parameters.trailingDelimiter, delimiter: "\n\n", }); } @@ -30,50 +21,137 @@ export default class ParagraphTarget extends BaseTarget { return true; } - cloneWith(parameters: CloneWithParameters): ParagraphTarget { - return new ParagraphTarget({ ...this.state, ...parameters }); - } - - getRemovalContentRange(): Range { - const removalRange = new Range( - this.editor.document.lineAt(this.contentRange.start).range.start, + get contentRemovalRange() { + return new Range( + new Position(this.contentRange.start.line, 0), this.editor.document.lineAt(this.contentRange.end).range.end ); + } + + get leadingDelimiterRange() { + return getLeadingDelimiter(this.editor, this.contentRange)?.range; + } + get trailingDelimiterRange() { + return getTrailingDelimiter(this.editor, this.contentRange)?.range; + } + + getRemovalRange(): Range { + switch (this.position) { + case "before": + return this.leadingDelimiterRange ?? this.contentRange; + case "after": + return this.trailingDelimiterRange ?? this.contentRange; + case "start": + case "end": + return this.contentRange; + } + const delimiterRange = (() => { - const leadingDelimiter = processRemovalRange(this.leadingDelimiter); - const trailingDelimiter = processRemovalRange(this.trailingDelimiter); - if (trailingDelimiter != null) { + const leadingDelimiterRange = this.leadingDelimiterRange; + const trailingDelimiterRange = this.trailingDelimiterRange; + if (trailingDelimiterRange != null) { const { document } = this.editor; // Trailing delimiter to end of file. Need to remove leading new line delimiter if ( - trailingDelimiter.range.end.line === document.lineCount - 1 && - leadingDelimiter != null + trailingDelimiterRange.end.line === document.lineCount - 1 && + leadingDelimiterRange != null ) { return new Range( document.lineAt(this.contentRange.start.line - 1).range.end, - trailingDelimiter.range.end + trailingDelimiterRange.end ); } - return trailingDelimiter.range; + return trailingDelimiterRange; } - if (leadingDelimiter) { - return leadingDelimiter.range; + if (leadingDelimiterRange) { + return leadingDelimiterRange; } return undefined; })(); + return delimiterRange != null - ? removalRange.union(delimiterRange) - : removalRange; + ? this.contentRemovalRange.union(delimiterRange) + : this.contentRemovalRange; } - protected getRemovalBeforeRange(): Range { - return this.leadingDelimiter != null - ? new Range( - this.leadingDelimiter.range.start, - this.editor.document.lineAt( - this.contentRange.start.line - 1 - ).range.start - ) - : this.contentRange; + cloneWith(parameters: CloneWithParameters): ParagraphTarget { + return new ParagraphTarget({ ...this.state, ...parameters }); + } +} + +function getLeadingDelimiter(editor: TextEditor, removalRange: Range) { + const { document } = editor; + const { lineAt } = document; + const startLine = lineAt(removalRange.start); + const leadingLine = getPreviousNonEmptyLine(document, startLine); + if (leadingLine != null) { + const startPosition = leadingLine.range.end.translate({ lineDelta: 1 }); + return { + range: new Range(startPosition, startLine.range.start), + highlight: new Range( + lineAt(leadingLine.lineNumber + 1).range.start, + lineAt(startLine.lineNumber - 1).range.end + ), + }; + } + if (startLine.lineNumber > 0) { + const { start } = lineAt(0).range; + return { + range: new Range(start, startLine.range.start), + highlight: new Range(start, lineAt(startLine.lineNumber - 1).range.end), + }; + } + return undefined; +} + +function getTrailingDelimiter(editor: TextEditor, removalRange: Range) { + const { document } = editor; + const { lineAt } = document; + const endLine = lineAt(removalRange.end); + const trailingLine = getNextNonEmptyLine(document, endLine); + if (trailingLine != null) { + const endPosition = trailingLine.range.start.translate({ lineDelta: -1 }); + return { + range: new Range(endLine.range.end, endPosition), + highlight: new Range( + lineAt(endLine.lineNumber + 1).range.start, + lineAt(trailingLine.lineNumber - 1).range.end + ), + }; + } + if (endLine.lineNumber < document.lineCount - 1) { + const lastLine = lineAt(document.lineCount - 1); + // If true there is an empty line after this one that isn't the last/final one + const highlightStart = + endLine.lineNumber !== document.lineCount - 1 + ? lineAt(endLine.lineNumber + 1).range.end + : lastLine.range.start; + return { + range: new Range(endLine.range.end, lastLine.range.end), + highlight: new Range(highlightStart, lastLine.range.end), + }; + } + return undefined; +} + +function getPreviousNonEmptyLine(document: TextDocument, line: TextLine) { + while (line.lineNumber > 0) { + const previousLine = document.lineAt(line.lineNumber - 1); + if (!previousLine.isEmptyOrWhitespace) { + return previousLine; + } + line = previousLine; + } + return null; +} + +function getNextNonEmptyLine(document: TextDocument, line: TextLine) { + while (line.lineNumber + 1 < document.lineCount) { + const nextLine = document.lineAt(line.lineNumber + 1); + if (!nextLine.isEmptyOrWhitespace) { + return nextLine; + } + line = nextLine; } + return null; } diff --git a/src/processTargets/targets/ScopeTypeTarget.ts b/src/processTargets/targets/ScopeTypeTarget.ts index 46eba360a9..e23696e7e6 100644 --- a/src/processTargets/targets/ScopeTypeTarget.ts +++ b/src/processTargets/targets/ScopeTypeTarget.ts @@ -1,5 +1,5 @@ import { Range } from "vscode"; -import { RemovalRange, SimpleScopeTypeType } from "../../typings/target.types"; +import { SimpleScopeTypeType } from "../../typings/target.types"; import BaseTarget, { CloneWithParameters, CommonTargetParameters, @@ -7,27 +7,55 @@ import BaseTarget, { } from "./BaseTarget"; export interface ScopeTypeTargetParameters extends CommonTargetParameters { - scopeTypeType: SimpleScopeTypeType; - delimiter?: string; - removalRange?: Range; - leadingDelimiter?: RemovalRange; - trailingDelimiter?: RemovalRange; + readonly scopeTypeType: SimpleScopeTypeType; + readonly delimiter?: string; + readonly contentRemovalRange?: Range; + readonly leadingDelimiterRange?: Range; + readonly trailingDelimiterRange?: Range; } export default class ScopeTypeTarget extends BaseTarget { + private contentRemovalRange_?: Range; + private leadingDelimiterRange_?: Range; + private trailingDelimiterRange_?: Range; + private hasDelimiterRange_: boolean; + constructor(parameters: ScopeTypeTargetParameters) { super({ ...extractCommonParameters(parameters), delimiter: parameters.delimiter ?? getDelimiter(parameters.scopeTypeType), - leadingDelimiter: parameters.leadingDelimiter, - trailingDelimiter: parameters.trailingDelimiter, - removalRange: parameters.removalRange, }); + this.contentRemovalRange_ = parameters.contentRemovalRange; + this.leadingDelimiterRange_ = parameters.leadingDelimiterRange; + this.trailingDelimiterRange_ = parameters.trailingDelimiterRange; + this.hasDelimiterRange_ = + !!this.leadingDelimiterRange_ || !!this.trailingDelimiterRange_; + } + + get contentRemovalRange() { + return this.contentRemovalRange_ ?? this.contentRange; + } + + get leadingDelimiterRange() { + if (this.hasDelimiterRange_) { + return this.leadingDelimiterRange_; + } + return super.leadingDelimiterRange; + } + + get trailingDelimiterRange() { + if (this.hasDelimiterRange_) { + return this.trailingDelimiterRange_; + } + return super.trailingDelimiterRange; } cloneWith(parameters: CloneWithParameters): ScopeTypeTarget { return new ScopeTypeTarget({ ...(this.state), + contentRemovalRange: this.contentRemovalRange_, + leadingDelimiterRange: this.leadingDelimiterRange_, + trailingDelimiterRange: this.trailingDelimiterRange_, ...parameters, }); } diff --git a/src/processTargets/targets/SurroundingPairTarget.ts b/src/processTargets/targets/SurroundingPairTarget.ts index 6f83304171..08c0bbafcc 100644 --- a/src/processTargets/targets/SurroundingPairTarget.ts +++ b/src/processTargets/targets/SurroundingPairTarget.ts @@ -1,6 +1,5 @@ import { Range } from "vscode"; import { Target } from "../../typings/target.types"; -import { getTokenDelimiters } from "../modifiers/scopeTypeStages/TokenStage"; import BaseTarget, { CloneWithParameters, CommonTargetParameters, @@ -31,7 +30,7 @@ export default class SurroundingPairTarget extends BaseTarget { constructor(parameters: SurroundingPairTargetParameters) { super({ ...extractCommonParameters(parameters), - ...getTokenDelimiters(parameters.editor, parameters.contentRange), + delimiter: " ", }); this.boundary_ = parameters.boundary; this.interiorRange_ = parameters.interiorRange; diff --git a/src/processTargets/targets/TokenTarget.ts b/src/processTargets/targets/TokenTarget.ts index ffc4dd99d5..a3da513ce1 100644 --- a/src/processTargets/targets/TokenTarget.ts +++ b/src/processTargets/targets/TokenTarget.ts @@ -1,4 +1,3 @@ -import { getTokenDelimiters } from "../modifiers/scopeTypeStages/TokenStage"; import BaseTarget, { CloneWithParameters, CommonTargetParameters, @@ -9,7 +8,7 @@ export default class TokenTarget extends BaseTarget { constructor(parameters: CommonTargetParameters) { super({ ...extractCommonParameters(parameters), - ...getTokenDelimiters(parameters.editor, parameters.contentRange), + delimiter: " ", }); } diff --git a/src/processTargets/targets/WeakTarget.ts b/src/processTargets/targets/WeakTarget.ts index a2bb166e00..b42da0240f 100644 --- a/src/processTargets/targets/WeakTarget.ts +++ b/src/processTargets/targets/WeakTarget.ts @@ -1,31 +1,19 @@ -import { RemovalRange } from "../../typings/target.types"; -import { getTokenDelimiters } from "../modifiers/scopeTypeStages/TokenStage"; import BaseTarget, { CloneWithParameters, CommonTargetParameters, extractCommonParameters, } from "./BaseTarget"; -interface WeakTargetParameters extends CommonTargetParameters { - // These are needed if constructed from a continuous range - leadingDelimiter?: RemovalRange; - trailingDelimiter?: RemovalRange; -} - /** * - Treated as "line" for "pour", "clone", and "breakpoint" * - Use token delimiters (space) for removal and insertion * - Expand to nearest containing pair when asked for boundary or interior */ export default class WeakTarget extends BaseTarget { - constructor(parameters: WeakTargetParameters) { - const { delimiter, leadingDelimiter, trailingDelimiter } = - getTokenDelimiters(parameters.editor, parameters.contentRange); + constructor(parameters: CommonTargetParameters) { super({ ...extractCommonParameters(parameters), - delimiter, - leadingDelimiter: parameters.leadingDelimiter ?? leadingDelimiter, - trailingDelimiter: parameters.trailingDelimiter ?? trailingDelimiter, + delimiter: " ", }); } diff --git a/src/typings/Types.ts b/src/typings/Types.ts index 2065e994dc..e6a902261a 100644 --- a/src/typings/Types.ts +++ b/src/typings/Types.ts @@ -60,20 +60,6 @@ export interface SelectionContext { * The range of the delimiter after the selection */ trailingDelimiterRange?: vscode.Range; - - /** - * Represents the boundary ranges of this selection. For example, for a - * surrounding pair this would be the opening and closing delimiter. For an if - * statement this would be the line of the guard as well as the closing brace. - */ - boundary?: [vscode.Range, vscode.Range]; - - /** - * Represents the interior ranges of this selection. For example, for a - * surrounding pair this would exclude the opening and closing delimiter. For an if - * statement this would be the statements in the body. - */ - interiorRange?: vscode.Range; } export type SelectionWithEditorWithContext = { diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 62a20f5f2c..84b5c4ba5e 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -245,15 +245,6 @@ export type TargetDescriptor = | RangeTargetDescriptor | ListTargetDescriptor; -export interface RemovalRange { - /** The range to be removed */ - range: Range; - /** Optional highlight range to be used for highlight instead of the removal range */ - highlight?: Range; - /** If true this range is excluded from delimiters by default */ - exclude?: boolean; -} - export interface EditNewCommandContext { type: "command"; command: string; @@ -279,14 +270,14 @@ export interface Target { /** If this selection has a delimiter. For example, new line for a line or paragraph and comma for a list or argument */ readonly delimiter?: string; - /** The range to remove the content */ - readonly removalRange?: Range; + /** The range to remove the content. This does not include any delimiters. */ + readonly contentRemovalRange: Range; /** The range of the delimiter before the content selection */ - readonly leadingDelimiter?: RemovalRange; + readonly leadingDelimiterRange?: Range; /** The range of the delimiter after the content selection */ - readonly trailingDelimiter?: RemovalRange; + readonly trailingDelimiterRange?: Range; /** The current position */ readonly position?: Position; diff --git a/src/util/targetUtils.ts b/src/util/targetUtils.ts index e7425a5c6e..7f2ecd97cb 100644 --- a/src/util/targetUtils.ts +++ b/src/util/targetUtils.ts @@ -1,14 +1,8 @@ import { zip } from "lodash"; import { Range, Selection, TextEditor } from "vscode"; -import { getTokenDelimiters } from "../processTargets/modifiers/scopeTypeStages/TokenStage"; -import { RemovalRange, Target } from "../typings/target.types"; -import { - SelectionContext, - SelectionWithEditor, - SelectionWithEditorWithContext, -} from "../typings/Types"; +import { Target } from "../typings/target.types"; +import { SelectionWithEditor } from "../typings/Types"; import { groupBy } from "./itertools"; -import { isReversed } from "./selectionUtils"; export function ensureSingleEditor(targets: Target[]) { if (targets.length === 0) { @@ -113,71 +107,3 @@ export function createThatMark( export function getRemovalRange(target: Target) { return target.getRemovalRange(); } - -export function processRemovalRange( - range?: RemovalRange -): Required | undefined { - return range != null && !range.exclude - ? { - range: range.range, - highlight: range.highlight ?? range.range, - exclude: false, - } - : undefined; -} - -export function selectionWithEditorWithContextToTarget( - selection: SelectionWithEditorWithContext -) { - // TODO Only use giving context in the future when all the containing scopes have proper delimiters. - // For now fall back on token context - const { context } = selection; - const { - containingListDelimiter, - interiorRange, - boundary, - leadingDelimiterRange, - trailingDelimiterRange, - removalRange, - } = context; - const { editor, selection: contentRange } = selection.selection; - - const tokenContext = useTokenContext(selection.context) - ? getTokenDelimiters(editor, contentRange) - : undefined; - - const leadingDelimiter = - tokenContext?.leadingDelimiter != null - ? tokenContext.leadingDelimiter - : leadingDelimiterRange != null - ? { range: leadingDelimiterRange } - : undefined; - - const trailingDelimiter = - tokenContext?.trailingDelimiter != null - ? tokenContext.trailingDelimiter - : trailingDelimiterRange != null - ? { range: trailingDelimiterRange } - : undefined; - - return { - editor, - isReversed: isReversed(contentRange), - contentRange, - interiorRange, - removalRange, - boundary, - delimiter: containingListDelimiter, - leadingDelimiter, - trailingDelimiter, - }; -} - -function useTokenContext(context: SelectionContext) { - return ( - context.containingListDelimiter == null && - context.removalRange == null && - context.leadingDelimiterRange == null && - context.trailingDelimiterRange == null - ); -} From 7bf31e9e502acbc504dc82170138d3f5ec5734c3 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Fri, 27 May 2022 11:46:46 +0100 Subject: [PATCH 227/314] Clarify processPrimitiveTarget --- src/processTargets/processTargets.ts | 59 ++++++++++++++++++++++------ src/typings/target.types.ts | 12 ++++++ 2 files changed, 59 insertions(+), 12 deletions(-) diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index 350fd59c65..35211c1833 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -1,4 +1,4 @@ -import { zip } from "lodash"; +import { flow, flowRight, zip } from "lodash"; import { Position, Range } from "vscode"; import { PrimitiveTargetDescriptor, @@ -231,28 +231,63 @@ function processVerticalRangeTarget( } } +/** + * This function implements the modifier pipeline that is at the core of Cursorless target processing. + * It proceeds as follows: + * + * 1. It begins by getting the output from the {@link markStage} (eg "air", "this", etc). + * This output is a list of zero or more targets. + * 2. It then constructs a pipeline from the modifiers on the {@link targetDescriptor} + * 3. It then runs each pipeline stage in turn, feeding the first stage with + * the list of targets output from the {@link markStage}. For each pipeline + * stage, it passes the targets from the previous stage to the pipeline stage + * one by one. For each target, the stage will output a list of zero or more output + * targets. It then concatenates all of these lists into the list of targets + * that will be passed to the next pipeline stage. + * + * @param context The context that captures the state of the environment used + * by each stage to process its input targets + * @param targetDescriptor The description of the target, consisting of a mark + * and zero or more modifiers + * @returns The output of running the modifier pipeline on the output from the mark + */ function processPrimitiveTarget( context: ProcessedTargetsContext, - target: PrimitiveTargetDescriptor + targetDescriptor: PrimitiveTargetDescriptor ): Target[] { - const markStage = getMarkStage(target.mark); - let targets = markStage.run(context); + // First, get the targets output by the mark + const markStage = getMarkStage(targetDescriptor.mark); + const markOutputTargets = markStage.run(context); + /** + * 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. Slice is needed to create a copy or the modifiers will be in wrong order in the test recorder. - ...target.modifiers.slice().reverse().map(getModifierStage), + // Reverse target modifiers because they are returned in reverse order from + // the api, to match the order in which they are spoken. Slice is needed + // to create a copy or the modifiers will be in wrong order in the test + // recorder. + ...targetDescriptor.modifiers.slice().reverse().map(getModifierStage), ...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; + + // 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) => { - const stageTargets: Target[] = []; - for (const target of targets) { - stageTargets.push(...stage.run(context, target)); - } - targets = stageTargets; + currentTargets = currentTargets.flatMap((target) => + stage.run(context, target) + ); }); - return targets; + // Then return the output from the final stage + return currentTargets; } function calcIsForward(anchor: Target, active: Target) { diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 62a20f5f2c..61ea0eb23f 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -218,7 +218,19 @@ export type PartialTargetDesc = | PartialListTargetDesc; export interface PrimitiveTargetDescriptor extends PartialPrimitiveTargetDesc { + /** + * The mark, eg "air", "this", "that", etc + */ mark: Mark; + + /** + * Zero or more modifiers that will be applied in sequence to the output from + * the mark. Note that the modifiers will be applied in reverse order. For + * example, if the user says "take first char name air", then we will apply + * "name" to the output of "air" to select the name of the function or + * statement containing "air", then apply "first char" to select the first + * character of the name. + */ modifiers: Modifier[]; } From c4a59e36f46e43e79a445c2c7fe87cb9afef9431 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Fri, 27 May 2022 11:47:38 +0100 Subject: [PATCH 228/314] Tweak --- src/processTargets/processTargets.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index 35211c1833..1693a4a427 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -243,7 +243,8 @@ function processVerticalRangeTarget( * stage, it passes the targets from the previous stage to the pipeline stage * one by one. For each target, the stage will output a list of zero or more output * targets. It then concatenates all of these lists into the list of targets - * that will be passed to the next pipeline stage. + * that will be passed to the next pipeline stage. This process is similar to + * the way that [jq](https://stedolan.github.io/jq/) processes its inputs. * * @param context The context that captures the state of the environment used * by each stage to process its input targets From 6bac95840727669ebb33172d3e4ffde434afb4ab Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Fri, 27 May 2022 11:50:52 +0100 Subject: [PATCH 229/314] Tweak again --- src/processTargets/processTargets.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index 1693a4a427..15972d9374 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -265,10 +265,8 @@ function processPrimitiveTarget( */ const modifierStages = [ // Reverse target modifiers because they are returned in reverse order from - // the api, to match the order in which they are spoken. Slice is needed - // to create a copy or the modifiers will be in wrong order in the test - // recorder. - ...targetDescriptor.modifiers.slice().reverse().map(getModifierStage), + // the api, to match the order in which they are spoken. + ...targetDescriptor.modifiers.map(getModifierStage).reverse(), ...context.finalStages, ]; From 7bf79eba640e045b122331b35ec519331ad7cf5d Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Fri, 27 May 2022 12:03:51 +0100 Subject: [PATCH 230/314] Imports fix --- 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 15972d9374..a82b8c10d5 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -1,4 +1,4 @@ -import { flow, flowRight, zip } from "lodash"; +import { zip } from "lodash"; import { Position, Range } from "vscode"; import { PrimitiveTargetDescriptor, From ecd486994b3bb8d49427c8851b27d49648c6f31f Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Fri, 27 May 2022 14:07:12 +0200 Subject: [PATCH 231/314] All tests pass --- .../targets/ContinuousRangeTarget.ts | 6 ++++ src/processTargets/targets/LineTarget.ts | 4 +-- src/processTargets/targets/ParagraphTarget.ts | 32 +++++++++++++++---- .../positions/chuckAfterBlockVest.yml | 16 ++++++---- .../positions/chuckBeforeBlockAir.yml | 17 ++++++---- .../selectionTypes/chuckBlockVest.yml | 2 +- 6 files changed, 55 insertions(+), 22 deletions(-) diff --git a/src/processTargets/targets/ContinuousRangeTarget.ts b/src/processTargets/targets/ContinuousRangeTarget.ts index 824d893eb0..eea2bbb912 100644 --- a/src/processTargets/targets/ContinuousRangeTarget.ts +++ b/src/processTargets/targets/ContinuousRangeTarget.ts @@ -68,6 +68,9 @@ export default class ContinuousRangeTarget implements Target { get leadingDelimiterRange() { const startTarget = this.startTarget_; + if (startTarget.position === "start") { + return undefined; + } if (this.excludeStart_) { if (startTarget.isLine) { return getLineLeadingDelimiterRange(this.editor, this.contentRange); @@ -79,6 +82,9 @@ export default class ContinuousRangeTarget implements Target { get trailingDelimiterRange() { const endTarget = this.endTarget_; + if (endTarget.position === "end") { + return undefined; + } if (this.excludeEnd_) { if (endTarget.isLine) { return getLineTrailingDelimiterRange(this.editor, this.contentRange); diff --git a/src/processTargets/targets/LineTarget.ts b/src/processTargets/targets/LineTarget.ts index 0115af754c..479dcc1ee3 100644 --- a/src/processTargets/targets/LineTarget.ts +++ b/src/processTargets/targets/LineTarget.ts @@ -33,11 +33,11 @@ export default class LineTarget extends BaseTarget { } get leadingDelimiterRange() { - return getLineLeadingDelimiterRange(this.editor, this.contentRange); + return getLineLeadingDelimiterRange(this.editor, this.contentRemovalRange); } get trailingDelimiterRange() { - return getLineTrailingDelimiterRange(this.editor, this.contentRange); + return getLineTrailingDelimiterRange(this.editor, this.contentRemovalRange); } getRemovalHighlightRange(): Range | undefined { diff --git a/src/processTargets/targets/ParagraphTarget.ts b/src/processTargets/targets/ParagraphTarget.ts index ae0191e2df..9d253f311b 100644 --- a/src/processTargets/targets/ParagraphTarget.ts +++ b/src/processTargets/targets/ParagraphTarget.ts @@ -29,10 +29,18 @@ export default class ParagraphTarget extends BaseTarget { } get leadingDelimiterRange() { - return getLeadingDelimiter(this.editor, this.contentRange)?.range; + return getLeadingDelimiter( + this.editor, + this.contentRange, + this.position == null + )?.range; } get trailingDelimiterRange() { - return getTrailingDelimiter(this.editor, this.contentRange)?.range; + return getTrailingDelimiter( + this.editor, + this.contentRange, + this.position == null + )?.range; } getRemovalRange(): Range { @@ -79,13 +87,19 @@ export default class ParagraphTarget extends BaseTarget { } } -function getLeadingDelimiter(editor: TextEditor, removalRange: Range) { +function getLeadingDelimiter( + editor: TextEditor, + removalRange: Range, + keepLastNewline: boolean +) { const { document } = editor; const { lineAt } = document; const startLine = lineAt(removalRange.start); const leadingLine = getPreviousNonEmptyLine(document, startLine); if (leadingLine != null) { - const startPosition = leadingLine.range.end.translate({ lineDelta: 1 }); + const startPosition = keepLastNewline + ? leadingLine.range.end + : leadingLine.range.end.translate({ lineDelta: 1 }); return { range: new Range(startPosition, startLine.range.start), highlight: new Range( @@ -104,13 +118,19 @@ function getLeadingDelimiter(editor: TextEditor, removalRange: Range) { return undefined; } -function getTrailingDelimiter(editor: TextEditor, removalRange: Range) { +function getTrailingDelimiter( + editor: TextEditor, + removalRange: Range, + keepLastNewline: boolean +) { const { document } = editor; const { lineAt } = document; const endLine = lineAt(removalRange.end); const trailingLine = getNextNonEmptyLine(document, endLine); if (trailingLine != null) { - const endPosition = trailingLine.range.start.translate({ lineDelta: -1 }); + const endPosition = keepLastNewline + ? trailingLine.range.start + : trailingLine.range.start.translate({ lineDelta: -1 }); return { range: new Range(endLine.range.end, endPosition), highlight: new Range( diff --git a/src/test/suite/fixtures/recorded/positions/chuckAfterBlockVest.yml b/src/test/suite/fixtures/recorded/positions/chuckAfterBlockVest.yml index b1db52badc..b88f3971c2 100644 --- a/src/test/suite/fixtures/recorded/positions/chuckAfterBlockVest.yml +++ b/src/test/suite/fixtures/recorded/positions/chuckAfterBlockVest.yml @@ -1,13 +1,16 @@ languageId: plaintext command: - version: 1 spokenForm: chuck after block vest - action: remove + version: 2 targets: - type: primitive - position: after - selectionType: paragraph mark: {type: decoratedSymbol, symbolColor: default, character: v} + modifiers: + - {type: position, position: after} + - type: containingScope + scopeType: {type: paragraph} + usePrePhraseSnapshot: true + action: {name: remove} initialState: documentContents: |- @@ -24,11 +27,12 @@ initialState: finalState: documentContents: |- - const value = "Hello world"; const value = "Hello world"; + const value = "Hello world"; + const value = "Hello world"; selections: - anchor: {line: 0, character: 0} active: {line: 0, character: 0} thatMark: - anchor: {line: 1, character: 28} active: {line: 1, character: 28} -fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: v}, selectionType: paragraph, position: after, modifier: {type: identity}, insideOutsideType: outside}] +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: v}, modifiers: [{type: position, position: after}, {type: containingScope, scopeType: {type: paragraph}}]}] diff --git a/src/test/suite/fixtures/recorded/positions/chuckBeforeBlockAir.yml b/src/test/suite/fixtures/recorded/positions/chuckBeforeBlockAir.yml index 19d5e41ddd..3136f1fa2e 100644 --- a/src/test/suite/fixtures/recorded/positions/chuckBeforeBlockAir.yml +++ b/src/test/suite/fixtures/recorded/positions/chuckBeforeBlockAir.yml @@ -1,13 +1,16 @@ languageId: plaintext command: - version: 1 spokenForm: chuck before block air - action: remove + version: 2 targets: - type: primitive - position: before - selectionType: paragraph mark: {type: decoratedSymbol, symbolColor: default, character: a} + modifiers: + - {type: position, position: before} + - type: containingScope + scopeType: {type: paragraph} + usePrePhraseSnapshot: true + action: {name: remove} initialState: documentContents: |- @@ -30,6 +33,6 @@ finalState: - anchor: {line: 0, character: 0} active: {line: 0, character: 0} thatMark: - - anchor: {line: 1, character: 28} - active: {line: 1, character: 28} -fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: a}, selectionType: paragraph, position: before, modifier: {type: identity}, insideOutsideType: outside}] + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: a}, modifiers: [{type: position, position: before}, {type: containingScope, scopeType: {type: paragraph}}]}] diff --git a/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockVest.yml b/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockVest.yml index 34c5915180..32dbc37684 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockVest.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockVest.yml @@ -1,4 +1,4 @@ -languageId: typescript +languageId: plaintext command: version: 1 spokenForm: chuck block vest From 956b159b809a869e23f430f174bf12eb4ab30fd7 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Fri, 27 May 2022 14:36:01 +0200 Subject: [PATCH 232/314] Updated highlights --- .../targets/ContinuousRangeTarget.ts | 24 +++++++++++++++++-- src/processTargets/targets/ParagraphTarget.ts | 24 +++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/processTargets/targets/ContinuousRangeTarget.ts b/src/processTargets/targets/ContinuousRangeTarget.ts index eea2bbb912..e1a473b9cb 100644 --- a/src/processTargets/targets/ContinuousRangeTarget.ts +++ b/src/processTargets/targets/ContinuousRangeTarget.ts @@ -40,7 +40,7 @@ export default class ContinuousRangeTarget implements Target { return undefined; } get isLine() { - return false; + return this.startTarget_.isLine && this.endTarget_.isLine; } get isParagraph() { return false; @@ -94,6 +94,21 @@ export default class ContinuousRangeTarget implements Target { return endTarget.trailingDelimiterRange; } + get leadingDelimiterHighlightRange() { + return this.leadingDelimiterRange; + } + + get trailingDelimiterHighlightRange() { + const endTarget = this.endTarget_; + if (this.excludeEnd_ && endTarget.isLine) { + return new Range( + this.contentRange.end, + endTarget.contentRange.start.translate({ lineDelta: -1 }) + ); + } + return this.trailingDelimiterRange; + } + get contentRange() { return this.processRanges( this.startTarget_.contentRange, @@ -128,7 +143,12 @@ export default class ContinuousRangeTarget implements Target { } getRemovalHighlightRange(): Range | undefined { - return this.getRemovalRange(); + const delimiterRange = + this.trailingDelimiterHighlightRange ?? + this.leadingDelimiterHighlightRange; + return delimiterRange != null + ? this.contentRemovalRange.union(delimiterRange) + : this.contentRemovalRange; } getInteriorStrict(): Target[] { diff --git a/src/processTargets/targets/ParagraphTarget.ts b/src/processTargets/targets/ParagraphTarget.ts index 9d253f311b..3173bc27a5 100644 --- a/src/processTargets/targets/ParagraphTarget.ts +++ b/src/processTargets/targets/ParagraphTarget.ts @@ -43,6 +43,21 @@ export default class ParagraphTarget extends BaseTarget { )?.range; } + get leadingDelimiterHighlightRange() { + return getLeadingDelimiter( + this.editor, + this.contentRange, + this.position == null + )?.highlight; + } + get trailingDelimiterHighlightRange() { + return getTrailingDelimiter( + this.editor, + this.contentRange, + this.position == null + )?.highlight; + } + getRemovalRange(): Range { switch (this.position) { case "before": @@ -82,6 +97,15 @@ export default class ParagraphTarget extends BaseTarget { : this.contentRemovalRange; } + getRemovalHighlightRange(): Range | undefined { + const delimiterRange = + this.trailingDelimiterHighlightRange ?? + this.leadingDelimiterHighlightRange; + return delimiterRange != null + ? this.contentRemovalRange.union(delimiterRange) + : this.contentRemovalRange; + } + cloneWith(parameters: CloneWithParameters): ParagraphTarget { return new ParagraphTarget({ ...this.state, ...parameters }); } From 637ec308fe8c25b9086cf9cf9d8e2210445c8c7d Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Fri, 27 May 2022 15:14:15 +0200 Subject: [PATCH 233/314] Highlight updates on continuous range target --- .../targets/ContinuousRangeTarget.ts | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/processTargets/targets/ContinuousRangeTarget.ts b/src/processTargets/targets/ContinuousRangeTarget.ts index e1a473b9cb..f93d4e9a47 100644 --- a/src/processTargets/targets/ContinuousRangeTarget.ts +++ b/src/processTargets/targets/ContinuousRangeTarget.ts @@ -95,18 +95,33 @@ export default class ContinuousRangeTarget implements Target { } get leadingDelimiterHighlightRange() { - return this.leadingDelimiterRange; + const leadingDelimiterRange = this.leadingDelimiterRange; + if (leadingDelimiterRange == null) { + return undefined; + } + const startTarget = this.startTarget_; + if (startTarget.isLine && !this.excludeStart_) { + return new Range(leadingDelimiterRange.end, this.contentRange.start); + } + return leadingDelimiterRange; } get trailingDelimiterHighlightRange() { + const trailingDelimiterRange = this.trailingDelimiterRange; + if (trailingDelimiterRange == null) { + return undefined; + } const endTarget = this.endTarget_; - if (this.excludeEnd_ && endTarget.isLine) { - return new Range( - this.contentRange.end, - endTarget.contentRange.start.translate({ lineDelta: -1 }) - ); + if (endTarget.isLine) { + if (this.excludeEnd_) { + return new Range( + this.contentRange.end, + endTarget.leadingDelimiterRange!.start + ); + } + return new Range(this.contentRange.end, trailingDelimiterRange.start); } - return this.trailingDelimiterRange; + return trailingDelimiterRange; } get contentRange() { From 2031899f40f6bf60a3b2cce681081ae45cd8e3b4 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Fri, 27 May 2022 19:26:36 +0200 Subject: [PATCH 234/314] Moved edit decorations into graph --- src/actions/BringMoveSwap.ts | 9 +- src/actions/CommandAction.ts | 3 +- src/actions/CutCopyPaste.ts | 8 +- src/actions/FollowLink.ts | 3 +- src/actions/GetText.ts | 3 +- src/actions/Highlight.ts | 5 +- src/actions/InsertCopy.ts | 6 +- src/actions/InsertEmptyLines.ts | 6 +- src/actions/Remove.ts | 3 +- src/actions/Replace.ts | 3 +- src/actions/Rewrap.ts | 3 +- src/actions/Scroll.ts | 6 +- src/actions/ToggleBreakpoint.ts | 3 +- src/actions/Wrap.ts | 13 +-- src/actions/WrapWithSnippet.ts | 3 +- src/core/editStyles.ts | 140 +++++++++++++++++++++++++++++++- src/util/editDisplayUtils.ts | 127 ----------------------------- 17 files changed, 172 insertions(+), 172 deletions(-) delete mode 100644 src/util/editDisplayUtils.ts diff --git a/src/actions/BringMoveSwap.ts b/src/actions/BringMoveSwap.ts index 70c5f8aa03..f26c0f90b5 100644 --- a/src/actions/BringMoveSwap.ts +++ b/src/actions/BringMoveSwap.ts @@ -6,7 +6,6 @@ import { } from "../core/updateSelections/updateSelections"; import { Target } from "../typings/target.types"; import { Edit, Graph } from "../typings/Types"; -import displayPendingEditDecorations from "../util/editDisplayUtils"; import { setSelectionsWithoutFocusingEditor } from "../util/setSelectionsAndFocusEditor"; import { getContentRange, @@ -70,12 +69,12 @@ class BringMoveSwap implements Action { private async decorateTargets(sources: Target[], destinations: Target[]) { const decorationContext = this.getDecorationContext(); await Promise.all([ - displayPendingEditDecorations( + this.graph.editStyles.displayPendingEditDecorations( sources, decorationContext.sourceStyle, decorationContext.getSourceRangeCallback ), - displayPendingEditDecorations( + this.graph.editStyles.displayPendingEditDecorations( destinations, decorationContext.destinationStyle ), @@ -221,12 +220,12 @@ class BringMoveSwap implements Action { const getRange = (target: Target) => thatMark.find((t) => t.target === target)!.selection; return Promise.all([ - displayPendingEditDecorations( + this.graph.editStyles.displayPendingEditDecorations( thatMark.filter(({ isSource }) => isSource).map(({ target }) => target), decorationContext.sourceStyle, getRange ), - displayPendingEditDecorations( + this.graph.editStyles.displayPendingEditDecorations( thatMark .filter(({ isSource }) => !isSource) .map(({ target }) => target), diff --git a/src/actions/CommandAction.ts b/src/actions/CommandAction.ts index 5c967867e7..824a717aac 100644 --- a/src/actions/CommandAction.ts +++ b/src/actions/CommandAction.ts @@ -3,7 +3,6 @@ import { commands, window } from "vscode"; import { callFunctionAndUpdateSelections } from "../core/updateSelections/updateSelections"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; -import displayPendingEditDecorations from "../util/editDisplayUtils"; import { focusEditor, setSelectionsAndFocusEditor, @@ -90,7 +89,7 @@ export default class CommandAction implements Action { const actualOptions = partialOptions as Required; if (actualOptions.showDecorations) { - await displayPendingEditDecorations( + await this.graph.editStyles.displayPendingEditDecorations( targets, this.graph.editStyles.referenced ); diff --git a/src/actions/CutCopyPaste.ts b/src/actions/CutCopyPaste.ts index e24fb88099..50c243c44e 100644 --- a/src/actions/CutCopyPaste.ts +++ b/src/actions/CutCopyPaste.ts @@ -1,7 +1,6 @@ import RawSelectionTarget from "../processTargets/targets/RawSelectionTarget"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; -import displayPendingEditDecorations from "../util/editDisplayUtils"; import { getOutsideOverflow } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; import CommandAction from "./CommandAction"; @@ -29,8 +28,11 @@ export class Cut implements Action { }); await Promise.all([ - displayPendingEditDecorations(targets, this.graph.editStyles.referenced), - displayPendingEditDecorations( + this.graph.editStyles.displayPendingEditDecorations( + targets, + this.graph.editStyles.referenced + ), + this.graph.editStyles.displayPendingEditDecorations( overflowTargets, this.graph.editStyles.pendingDelete ), diff --git a/src/actions/FollowLink.ts b/src/actions/FollowLink.ts index 2008b84cb9..574d87ea44 100644 --- a/src/actions/FollowLink.ts +++ b/src/actions/FollowLink.ts @@ -1,7 +1,6 @@ import { env, Uri, window } from "vscode"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; -import displayPendingEditDecorations from "../util/editDisplayUtils"; import { getLinkForTarget } from "../util/getLinks"; import { createThatMark, ensureSingleTarget } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; @@ -14,7 +13,7 @@ export default class FollowLink implements Action { async run([targets]: [Target[]]): Promise { const target = ensureSingleTarget(targets); - await displayPendingEditDecorations( + await this.graph.editStyles.displayPendingEditDecorations( targets, this.graph.editStyles.referenced ); diff --git a/src/actions/GetText.ts b/src/actions/GetText.ts index 65f845c092..3b8594dfac 100644 --- a/src/actions/GetText.ts +++ b/src/actions/GetText.ts @@ -1,6 +1,5 @@ import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; -import displayPendingEditDecorations from "../util/editDisplayUtils"; import { createThatMark, ensureSingleTarget } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; @@ -17,7 +16,7 @@ export default class GetText implements Action { } = {} ): Promise { if (showDecorations) { - await displayPendingEditDecorations( + await this.graph.editStyles.displayPendingEditDecorations( targets, this.graph.editStyles.referenced ); diff --git a/src/actions/Highlight.ts b/src/actions/Highlight.ts index db37097d2b..fc1657ea05 100644 --- a/src/actions/Highlight.ts +++ b/src/actions/Highlight.ts @@ -1,7 +1,6 @@ import { EditStyleName } from "../core/editStyles"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; -import { clearDecorations, setDecorations } from "../util/editDisplayUtils"; import { createThatMark } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; @@ -16,8 +15,8 @@ export default class Highlight implements Action { ): Promise { const style = this.graph.editStyles[styleName]; - clearDecorations(style); - await setDecorations(targets, style); + this.graph.editStyles.clearDecorations(style); + await this.graph.editStyles.setDecorations(targets, style); return { thatMark: createThatMark(targets), diff --git a/src/actions/InsertCopy.ts b/src/actions/InsertCopy.ts index 47492e9dfd..9677af1889 100644 --- a/src/actions/InsertCopy.ts +++ b/src/actions/InsertCopy.ts @@ -3,7 +3,6 @@ import { TextEditor } from "vscode"; import { weakContainingLineStage } from "../processTargets/modifiers/commonWeakContainingScopeStages"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; -import { displayPendingEditDecorationsForRanges } from "../util/editDisplayUtils"; import { setSelectionsWithoutFocusingEditor } from "../util/setSelectionsAndFocusEditor"; import { createThatMark, runOnTargetsForEachEditor } from "../util/targetUtils"; import { insertTextAfter, insertTextBefore } from "../util/textInsertion"; @@ -22,14 +21,15 @@ class InsertCopy implements Action { await runOnTargetsForEachEditor(targets, this.runForEditor) ); - await displayPendingEditDecorationsForRanges( + await this.graph.editStyles.displayPendingEditDecorationsForRanges( results.flatMap((result) => result.thatMark.map((that) => ({ editor: that.editor, range: that.selection, })) ), - this.graph.editStyles.justAdded.token + this.graph.editStyles.justAdded, + true ); return { diff --git a/src/actions/InsertEmptyLines.ts b/src/actions/InsertEmptyLines.ts index bb5224a671..e19705370b 100644 --- a/src/actions/InsertEmptyLines.ts +++ b/src/actions/InsertEmptyLines.ts @@ -3,7 +3,6 @@ import { Range, Selection } from "vscode"; import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; -import { displayPendingEditDecorationsForRanges } from "../util/editDisplayUtils"; import { setSelectionsWithoutFocusingEditor } from "../util/setSelectionsAndFocusEditor"; import { runOnTargetsForEachEditor } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; @@ -80,9 +79,10 @@ class InsertEmptyLines implements Action { }) ); - await displayPendingEditDecorationsForRanges( + await this.graph.editStyles.displayPendingEditDecorationsForRanges( results.flatMap((result) => result.lineSelections), - this.graph.editStyles.justAdded.line + this.graph.editStyles.justAdded, + false ); const thatMark = results.flatMap((result) => result.thatMark); diff --git a/src/actions/Remove.ts b/src/actions/Remove.ts index 621e045b23..44389181b6 100644 --- a/src/actions/Remove.ts +++ b/src/actions/Remove.ts @@ -2,7 +2,6 @@ import { flatten } from "lodash"; import { performEditsAndUpdateRanges } from "../core/updateSelections/updateSelections"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; -import displayPendingEditDecorations from "../util/editDisplayUtils"; import { createThatMark, getContentRange, @@ -27,7 +26,7 @@ export default class Delete implements Action { } if (showDecorations) { - await displayPendingEditDecorations( + await this.graph.editStyles.displayPendingEditDecorations( targets, this.graph.editStyles.pendingDelete, contentOnly ? getContentRange : getRemovalHighlightRange, diff --git a/src/actions/Replace.ts b/src/actions/Replace.ts index be51d5413a..256a0630ca 100644 --- a/src/actions/Replace.ts +++ b/src/actions/Replace.ts @@ -2,7 +2,6 @@ import { flatten, zip } from "lodash"; import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; -import displayPendingEditDecorations from "../util/editDisplayUtils"; import { runForEachEditor } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; @@ -35,7 +34,7 @@ export default class implements Action { [targets]: [Target[]], replaceWith: string[] | RangeGenerator ): Promise { - await displayPendingEditDecorations( + await this.graph.editStyles.displayPendingEditDecorations( targets, this.graph.editStyles.pendingModification0 ); diff --git a/src/actions/Rewrap.ts b/src/actions/Rewrap.ts index 95b369ac2a..8146b04f88 100644 --- a/src/actions/Rewrap.ts +++ b/src/actions/Rewrap.ts @@ -2,7 +2,6 @@ import { performEditsAndUpdateRanges } from "../core/updateSelections/updateSele import { weakContainingSurroundingPairStage } from "../processTargets/modifiers/commonWeakContainingScopeStages"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; -import displayPendingEditDecorations from "../util/editDisplayUtils"; import { createThatMark, runOnTargetsForEachEditor } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; @@ -28,7 +27,7 @@ export default class Rewrap implements Action { return boundary; }); - await displayPendingEditDecorations( + await this.graph.editStyles.displayPendingEditDecorations( boundaryTargets, this.graph.editStyles.pendingModification0 ); diff --git a/src/actions/Scroll.ts b/src/actions/Scroll.ts index ceec3706c1..7ef90f4acc 100644 --- a/src/actions/Scroll.ts +++ b/src/actions/Scroll.ts @@ -1,7 +1,6 @@ import { commands, window } from "vscode"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; -import { displayPendingEditDecorationsForTargets } from "../util/editDisplayUtils"; import { groupBy } from "../util/itertools"; import { focusEditor } from "../util/setSelectionsAndFocusEditor"; import { createThatMark } from "../util/targetUtils"; @@ -50,9 +49,10 @@ class Scroll implements Action { ); }); - await displayPendingEditDecorationsForTargets( + await this.graph.editStyles.displayPendingEditDecorationsForTargets( decorationTargets, - this.graph.editStyles.referenced.line + this.graph.editStyles.referenced, + false ); return { diff --git a/src/actions/ToggleBreakpoint.ts b/src/actions/ToggleBreakpoint.ts index 2a9735a4c5..1261a82bac 100644 --- a/src/actions/ToggleBreakpoint.ts +++ b/src/actions/ToggleBreakpoint.ts @@ -9,7 +9,6 @@ import { import { weakContainingLineStage } from "../processTargets/modifiers/commonWeakContainingScopeStages"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; -import displayPendingEditDecorations from "../util/editDisplayUtils"; import { createThatMark } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; @@ -32,7 +31,7 @@ export default class ToggleBreakpoint implements Action { async run([targets]: [Target[], Target[]]): Promise { const thatTargets = targets.map(({ thatTarget }) => thatTarget); - await displayPendingEditDecorations( + await this.graph.editStyles.displayPendingEditDecorations( thatTargets, this.graph.editStyles.referenced ); diff --git a/src/actions/Wrap.ts b/src/actions/Wrap.ts index 61e4a85cef..fa0173754d 100644 --- a/src/actions/Wrap.ts +++ b/src/actions/Wrap.ts @@ -6,7 +6,6 @@ import { import { Target } from "../typings/target.types"; import { Edit, Graph } from "../typings/Types"; import { FullSelectionInfo } from "../typings/updateSelections"; -import { decorationSleep } from "../util/editDisplayUtils"; import { setSelectionsWithoutFocusingEditor } from "../util/setSelectionsAndFocusEditor"; import { runOnTargetsForEachEditor } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; @@ -105,12 +104,14 @@ export default class Wrap implements Action { setSelectionsWithoutFocusingEditor(editor, cursorSelections); - editor.setDecorations( - this.graph.editStyles.justAdded.token, - delimiterSelections + this.graph.editStyles.displayPendingEditDecorationsForRanges( + delimiterSelections.map((selection) => ({ + editor, + range: selection, + })), + this.graph.editStyles.justAdded, + true ); - await decorationSleep(); - editor.setDecorations(this.graph.editStyles.justAdded.token, []); return { sourceMark: sourceMarkSelections.map((selection) => ({ diff --git a/src/actions/WrapWithSnippet.ts b/src/actions/WrapWithSnippet.ts index 7b824abbeb..6596fc04da 100644 --- a/src/actions/WrapWithSnippet.ts +++ b/src/actions/WrapWithSnippet.ts @@ -4,7 +4,6 @@ import ModifyIfWeakStage from "../processTargets/modifiers/ModifyIfWeakStage"; import { SnippetDefinition } from "../typings/snippet"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; -import displayPendingEditDecorations from "../util/editDisplayUtils"; import { ensureSingleEditor } from "../util/targetUtils"; import { Placeholder, @@ -80,7 +79,7 @@ export default class WrapWithSnippet implements Action { const snippetString = parsedSnippet.toTextmateString(); - await displayPendingEditDecorations( + await this.graph.editStyles.displayPendingEditDecorations( targets, this.graph.editStyles.pendingModification0 ); diff --git a/src/core/editStyles.ts b/src/core/editStyles.ts index 2c1c50c034..0bdaf95807 100644 --- a/src/core/editStyles.ts +++ b/src/core/editStyles.ts @@ -1,13 +1,24 @@ import { + DecorationRangeBehavior, + DecorationRenderOptions, + Range, + TextEditor, TextEditorDecorationType, ThemeColor, - DecorationRangeBehavior, window, - DecorationRenderOptions, + workspace, } from "vscode"; -import { Graph } from "../typings/Types"; +import { Target } from "../typings/target.types"; +import { Graph, RangeWithEditor } from "../typings/Types"; +import sleep from "../util/sleep"; +import { + getContentRange, + runForEachEditor, + runOnTargetsForEachEditor, +} from "../util/targetUtils"; export class EditStyle { + name: EditStyleThemeColorName; token: TextEditorDecorationType; line: TextEditorDecorationType; @@ -16,6 +27,7 @@ export class EditStyle { backgroundColor: new ThemeColor(`cursorless.${colorName}`), rangeBehavior: DecorationRangeBehavior.ClosedClosed, }; + this.name = colorName; this.token = window.createTextEditorDecorationType(options); this.line = window.createTextEditorDecorationType({ ...options, @@ -23,6 +35,10 @@ export class EditStyle { }); } + getDecoration(isToken: boolean) { + return isToken ? this.token : this.line; + } + dispose() { this.token.dispose(); this.line.dispose(); @@ -59,9 +75,127 @@ export class EditStyles implements Record { graph.extensionContext.subscriptions.push(this); } + async displayPendingEditDecorations( + targets: Target[], + style: EditStyle, + getRange: (target: Target) => Range | undefined = getContentRange, + contentOnly: boolean = false + ) { + await this.setDecorations(targets, style, getRange, contentOnly); + + await decorationSleep(); + + this.clearDecorations(style); + } + + displayPendingEditDecorationsForTargets( + targets: Target[], + style: EditStyle, + isToken: boolean + ) { + return this.displayPendingEditDecorationsForRanges( + targets.map(({ editor, contentRange }) => ({ + editor, + range: contentRange, + })), + style, + isToken + ); + } + + async displayPendingEditDecorationsForRanges( + ranges: RangeWithEditor[], + style: EditStyle, + isToken: boolean + ) { + await runForEachEditor( + ranges, + (range) => range.editor, + async (editor, ranges) => { + this.setEditorDecorations( + editor, + style, + isToken, + ranges.map((range) => range.range) + ); + } + ); + + await decorationSleep(); + + await runForEachEditor( + ranges, + (range) => range.editor, + async (editor) => { + editor.setDecorations(style.getDecoration(isToken), []); + } + ); + } + + async setDecorations( + targets: Target[], + style: EditStyle, + getRange: (target: Target) => Range | undefined = getContentRange, + contentOnly: boolean = false + ) { + await runOnTargetsForEachEditor(targets, async (editor, targets) => { + if (contentOnly) { + this.setEditorDecorations( + editor, + style, + true, + targets.map(getRange).filter((range): range is Range => !!range) + ); + } else { + this.setEditorDecorations( + editor, + style, + true, + targets + .filter((target) => !target.isLine) + .map(getRange) + .filter((range): range is Range => !!range) + ); + this.setEditorDecorations( + editor, + style, + false, + targets + .filter((target) => target.isLine) + .map(getRange) + .filter((range): range is Range => !!range) + ); + } + }); + } + + clearDecorations(style: EditStyle) { + window.visibleTextEditors.map((editor) => { + editor.setDecorations(style.token, []); + editor.setDecorations(style.line, []); + }); + } + + private setEditorDecorations( + editor: TextEditor, + style: EditStyle, + isToken: boolean, + ranges: Range[] + ) { + console.log(style.name, isToken); + editor.setDecorations(style.getDecoration(isToken), ranges); + } + dispose() { EDIT_STYLE_NAMES.forEach((editStyleName) => { this[editStyleName].dispose(); }); } } + +const decorationSleep = () => sleep(getPendingEditDecorationTime()); + +const getPendingEditDecorationTime = () => + workspace + .getConfiguration("cursorless") + .get("pendingEditDecorationTime")!; diff --git a/src/util/editDisplayUtils.ts b/src/util/editDisplayUtils.ts deleted file mode 100644 index b549f7b049..0000000000 --- a/src/util/editDisplayUtils.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { Range, TextEditorDecorationType, window, workspace } from "vscode"; -import { EditStyle } from "../core/editStyles"; -import isTesting from "../testUtil/isTesting"; -import { Target } from "../typings/target.types"; -import { RangeWithEditor } from "../typings/Types"; -import sleep from "./sleep"; -import { - getContentRange, - runForEachEditor, - runOnTargetsForEachEditor, -} from "./targetUtils"; - -const getPendingEditDecorationTime = () => - workspace - .getConfiguration("cursorless") - .get("pendingEditDecorationTime")!; - -export async function decorationSleep() { - if (isTesting()) { - return; - } - - await sleep(getPendingEditDecorationTime()); -} - -export async function displayPendingEditDecorationsForTargets( - targets: Target[], - style: TextEditorDecorationType -) { - await runForEachEditor( - targets, - (selection) => selection.editor, - async (editor, selections) => { - editor.setDecorations( - style, - selections.map((target) => target.contentRange) - ); - } - ); - - await decorationSleep(); - - await runForEachEditor( - targets, - (target) => target.editor, - async (editor) => { - editor.setDecorations(style, []); - } - ); -} - -export async function displayPendingEditDecorationsForRanges( - ranges: RangeWithEditor[], - style: TextEditorDecorationType -) { - await runForEachEditor( - ranges, - (range) => range.editor, - async (editor, ranges) => { - editor.setDecorations( - style, - ranges.map((range) => range.range) - ); - } - ); - - await decorationSleep(); - - await runForEachEditor( - ranges, - (range) => range.editor, - async (editor) => { - editor.setDecorations(style, []); - } - ); -} - -export default async function displayPendingEditDecorations( - targets: Target[], - editStyle: EditStyle, - getRange: (target: Target) => Range | undefined = getContentRange, - contentOnly?: boolean -) { - await setDecorations(targets, editStyle, getRange, contentOnly); - - await decorationSleep(); - - clearDecorations(editStyle); -} - -export function clearDecorations(editStyle: EditStyle) { - window.visibleTextEditors.map((editor) => { - editor.setDecorations(editStyle.token, []); - editor.setDecorations(editStyle.line, []); - }); -} - -export async function setDecorations( - targets: Target[], - editStyle: EditStyle, - getRange: (target: Target) => Range | undefined = getContentRange, - contentOnly?: boolean -) { - await runOnTargetsForEachEditor(targets, async (editor, targets) => { - if (contentOnly) { - editor.setDecorations( - editStyle.token, - targets.map(getRange).filter((range): range is Range => !!range) - ); - } else { - editor.setDecorations( - editStyle.token, - targets - .filter((target) => !target.isLine) - .map(getRange) - .filter((range): range is Range => !!range) - ); - editor.setDecorations( - editStyle.line, - targets - .filter((target) => target.isLine) - .map(getRange) - .filter((range): range is Range => !!range) - ); - } - }); -} From 49eb90b9ea5f01042b80a7c022f63474c7842c9e Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Fri, 27 May 2022 20:39:34 +0200 Subject: [PATCH 235/314] Added decorations to test recorder and runner --- src/core/commandRunner/CommandRunner.ts | 2 ++ src/core/editStyles.ts | 34 +++++++++++++++++-- .../targets/ContinuousRangeTarget.ts | 2 +- src/test/suite/recorded.test.ts | 5 +++ src/testUtil/TestCase.ts | 4 +++ src/testUtil/TestCaseRecorder.ts | 1 + src/testUtil/takeSnapshot.ts | 21 ++++++++++++ 7 files changed, 65 insertions(+), 4 deletions(-) diff --git a/src/core/commandRunner/CommandRunner.ts b/src/core/commandRunner/CommandRunner.ts index 96da4a40e2..4d31eff4c1 100644 --- a/src/core/commandRunner/CommandRunner.ts +++ b/src/core/commandRunner/CommandRunner.ts @@ -112,12 +112,14 @@ export default class CommandRunner { ); if (this.graph.testCaseRecorder.isActive()) { + this.graph.editStyles.testDecorations = []; const context = { targets: targetDescriptors, thatMark: this.thatMark, sourceMark: this.sourceMark, hatTokenMap: readableHatMap, spokenForm, + decorations: this.graph.editStyles.testDecorations, }; await this.graph.testCaseRecorder.preCommandHook( commandComplete, diff --git a/src/core/editStyles.ts b/src/core/editStyles.ts index 0bdaf95807..559771d002 100644 --- a/src/core/editStyles.ts +++ b/src/core/editStyles.ts @@ -1,6 +1,7 @@ import { DecorationRangeBehavior, DecorationRenderOptions, + Position, Range, TextEditor, TextEditorDecorationType, @@ -8,6 +9,7 @@ import { window, workspace, } from "vscode"; +import isTesting from "../testUtil/isTesting"; import { Target } from "../typings/target.types"; import { Graph, RangeWithEditor } from "../typings/Types"; import sleep from "../util/sleep"; @@ -58,6 +60,13 @@ const EDIT_STYLE_NAMES = [ export type EditStyleName = typeof EDIT_STYLE_NAMES[number]; type EditStyleThemeColorName = `${EditStyleName}Background`; +export interface TestDecoration { + name: EditStyleThemeColorName; + type: "token" | "line"; + start: Position; + end: Position; +} + export class EditStyles implements Record { pendingDelete!: EditStyle; referenced!: EditStyle; @@ -66,8 +75,9 @@ export class EditStyles implements Record { justAdded!: EditStyle; highlight0!: EditStyle; highlight1!: EditStyle; + testDecorations: TestDecoration[] = []; - constructor(graph: Graph) { + constructor(private graph: Graph) { EDIT_STYLE_NAMES.forEach((editStyleName) => { this[editStyleName] = new EditStyle(`${editStyleName}Background`); }); @@ -182,7 +192,19 @@ export class EditStyles implements Record { isToken: boolean, ranges: Range[] ) { - console.log(style.name, isToken); + if (this.graph.testCaseRecorder.isActive() || isTesting()) { + ranges.forEach((range) => { + this.testDecorations.push({ + name: style.name, + type: isToken ? "token" : "line", + start: range.start, + end: range.end, + }); + }); + if (isTesting()) { + return; + } + } editor.setDecorations(style.getDecoration(isToken), ranges); } @@ -193,7 +215,13 @@ export class EditStyles implements Record { } } -const decorationSleep = () => sleep(getPendingEditDecorationTime()); +function decorationSleep() { + if (isTesting()) { + return; + } + + sleep(getPendingEditDecorationTime()); +} const getPendingEditDecorationTime = () => workspace diff --git a/src/processTargets/targets/ContinuousRangeTarget.ts b/src/processTargets/targets/ContinuousRangeTarget.ts index f93d4e9a47..23e48ad9fe 100644 --- a/src/processTargets/targets/ContinuousRangeTarget.ts +++ b/src/processTargets/targets/ContinuousRangeTarget.ts @@ -43,7 +43,7 @@ export default class ContinuousRangeTarget implements Target { return this.startTarget_.isLine && this.endTarget_.isLine; } get isParagraph() { - return false; + return this.startTarget_.isParagraph && this.endTarget_.isParagraph; } get isWeak() { return false; diff --git a/src/test/suite/recorded.test.ts b/src/test/suite/recorded.test.ts index 4936547b23..46707a6815 100644 --- a/src/test/suite/recorded.test.ts +++ b/src/test/suite/recorded.test.ts @@ -109,6 +109,10 @@ async function runTest(file: string) { excludeFields.push("clipboard"); } + if (!fixture.initialState.decorations) { + excludeFields.push("decorations"); + } + await graph.hatTokenMap.addDecorations(); const readableHatMap = await graph.hatTokenMap.getReadableMap( @@ -138,6 +142,7 @@ async function runTest(file: string) { const { visibleRanges, ...resultState } = await takeSnapshot( cursorlessApi.thatMark, cursorlessApi.sourceMark, + graph.editStyles.testDecorations, excludeFields, [], marks diff --git a/src/testUtil/TestCase.ts b/src/testUtil/TestCase.ts index 6979d700b7..6294cf55d5 100644 --- a/src/testUtil/TestCase.ts +++ b/src/testUtil/TestCase.ts @@ -1,6 +1,7 @@ import { pick } from "lodash"; import * as vscode from "vscode"; import { CommandLatest } from "../core/commandRunner/command.types"; +import { TestDecoration } from "../core/editStyles"; import { ReadOnlyHatMap } from "../core/IndividualHatMap"; import { ThatMark } from "../core/ThatMark"; import { TargetDescriptor } from "../typings/target.types"; @@ -24,6 +25,7 @@ export type TestCaseContext = { thatMark: ThatMark; sourceMark: ThatMark; targets: TargetDescriptor[]; + decorations: TestDecoration[]; hatTokenMap: ReadOnlyHatMap; }; @@ -154,6 +156,7 @@ export class TestCase { this.initialState = await takeSnapshot( this.context.thatMark, this.context.sourceMark, + this.context.decorations, excludeFields, this.extraSnapshotFields, this.getMarks(), @@ -167,6 +170,7 @@ export class TestCase { this.finalState = await takeSnapshot( this.context.thatMark, this.context.sourceMark, + this.context.decorations, excludeFields, this.extraSnapshotFields, this.isHatTokenMapTest ? this.getMarks() : undefined, diff --git a/src/testUtil/TestCaseRecorder.ts b/src/testUtil/TestCaseRecorder.ts index a582e7f6e5..1b3d086f99 100644 --- a/src/testUtil/TestCaseRecorder.ts +++ b/src/testUtil/TestCaseRecorder.ts @@ -145,6 +145,7 @@ export class TestCaseRecorder { const snapshot = await takeSnapshot( undefined, undefined, + [], ["clipboard"], this.active ? this.extraSnapshotFields : undefined, marks, diff --git a/src/testUtil/takeSnapshot.ts b/src/testUtil/takeSnapshot.ts index 7f53cb6bd4..71886a3995 100644 --- a/src/testUtil/takeSnapshot.ts +++ b/src/testUtil/takeSnapshot.ts @@ -1,8 +1,11 @@ import * as vscode from "vscode"; +import { TestDecoration } from "../core/editStyles"; import { ThatMark } from "../core/ThatMark"; import { Clipboard } from "../util/Clipboard"; import { hrtimeBigintToSeconds } from "../util/timeUtils"; import { + PositionPlainObject, + positionToPlainObject, RangePlainObject, rangeToPlainObject, SelectionPlainObject, @@ -13,6 +16,13 @@ import { export type ExtraSnapshotField = keyof TestCaseSnapshot; export type ExcludableSnapshotField = keyof TestCaseSnapshot; +interface PlainTestDecoration { + name: string; + type: "token" | "line"; + start: PositionPlainObject; + end: PositionPlainObject; +} + export type TestCaseSnapshot = { documentContents: string; selections: SelectionPlainObject[]; @@ -23,6 +33,7 @@ export type TestCaseSnapshot = { marks?: SerializedMarks; thatMark?: SelectionPlainObject[]; sourceMark?: SelectionPlainObject[]; + decorations?: PlainTestDecoration[]; timeOffsetSeconds?: number; /** @@ -38,6 +49,7 @@ interface ExtraContext { export async function takeSnapshot( thatMark: ThatMark | undefined, sourceMark: ThatMark | undefined, + decorations: TestDecoration[], excludeFields: ExcludableSnapshotField[] = [], extraFields: ExtraSnapshotField[] = [], marks?: SerializedMarks, @@ -87,6 +99,15 @@ export async function takeSnapshot( .map((mark) => selectionToPlainObject(mark.selection)); } + if (decorations.length > 0 && !excludeFields.includes("decorations")) { + snapshot.decorations = decorations.map(({ name, type, start, end }) => ({ + name, + type, + start: positionToPlainObject(start), + end: positionToPlainObject(end), + })); + } + if (extraFields.includes("timeOffsetSeconds")) { const startTimestamp = extraContext?.startTimestamp; From 0b280bc95d5dda85adb1b7f868d69f90505d41da Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 28 May 2022 18:30:01 +0200 Subject: [PATCH 236/314] Updated to highlight recorder test --- src/core/editStyles.ts | 2 +- src/test/suite/recorded.test.ts | 13 ++++++++----- src/testUtil/TestCase.ts | 32 +++++++++++++++++++++++++++++--- src/testUtil/TestCaseRecorder.ts | 10 +++++++++- src/testUtil/takeSnapshot.ts | 21 --------------------- 5 files changed, 47 insertions(+), 31 deletions(-) diff --git a/src/core/editStyles.ts b/src/core/editStyles.ts index 559771d002..9946ec34cd 100644 --- a/src/core/editStyles.ts +++ b/src/core/editStyles.ts @@ -220,7 +220,7 @@ function decorationSleep() { return; } - sleep(getPendingEditDecorationTime()); + return sleep(getPendingEditDecorationTime()); } const getPendingEditDecorationTime = () => diff --git a/src/test/suite/recorded.test.ts b/src/test/suite/recorded.test.ts index 46707a6815..56ee019cf7 100644 --- a/src/test/suite/recorded.test.ts +++ b/src/test/suite/recorded.test.ts @@ -109,10 +109,6 @@ async function runTest(file: string) { excludeFields.push("clipboard"); } - if (!fixture.initialState.decorations) { - excludeFields.push("decorations"); - } - await graph.hatTokenMap.addDecorations(); const readableHatMap = await graph.hatTokenMap.getReadableMap( @@ -142,7 +138,6 @@ async function runTest(file: string) { const { visibleRanges, ...resultState } = await takeSnapshot( cursorlessApi.thatMark, cursorlessApi.sourceMark, - graph.editStyles.testDecorations, excludeFields, [], marks @@ -158,6 +153,14 @@ async function runTest(file: string) { "Unexpected final state" ); + if (fixture.decorations != null) { + assert.deepStrictEqual( + graph.editStyles.testDecorations, + fixture.decorations, + "Unexpected decorations" + ); + } + assert.deepStrictEqual( returnValue, fixture.returnValue, diff --git a/src/testUtil/TestCase.ts b/src/testUtil/TestCase.ts index 6294cf55d5..ec8746b399 100644 --- a/src/testUtil/TestCase.ts +++ b/src/testUtil/TestCase.ts @@ -17,7 +17,12 @@ import { takeSnapshot, TestCaseSnapshot, } from "./takeSnapshot"; -import { marksToPlainObject, SerializedMarks } from "./toPlainObject"; +import { + marksToPlainObject, + PositionPlainObject, + positionToPlainObject, + SerializedMarks, +} from "./toPlainObject"; export type TestCaseCommand = CommandLatest; @@ -29,6 +34,13 @@ export type TestCaseContext = { hatTokenMap: ReadOnlyHatMap; }; +interface PlainTestDecoration { + name: string; + type: "token" | "line"; + start: PositionPlainObject; + end: PositionPlainObject; +} + export type TestCaseFixture = { languageId: string; postEditorOpenSleepTimeMs?: number; @@ -41,6 +53,7 @@ export type TestCaseFixture = { initialState: TestCaseSnapshot; finalState: TestCaseSnapshot; + decorations?: PlainTestDecoration[]; returnValue: unknown; /** Inferred full targets added for context; not currently used in testing */ fullTargets: TargetDescriptor[]; @@ -51,6 +64,7 @@ export class TestCase { fullTargets: TargetDescriptor[]; initialState: TestCaseSnapshot | null = null; finalState: TestCaseSnapshot | null = null; + decorations?: PlainTestDecoration[]; returnValue: unknown = null; targetKeys: string[]; private _awaitingFinalMarkInfo: boolean; @@ -61,6 +75,7 @@ export class TestCase { command: TestCaseCommand, private context: TestCaseContext, private isHatTokenMapTest: boolean = false, + private isDecorationsTest: boolean = false, private startTimestamp: bigint, private extraSnapshotFields?: ExtraSnapshotField[] ) { @@ -76,6 +91,18 @@ export class TestCase { this._awaitingFinalMarkInfo = isHatTokenMapTest; } + recordDecorations() { + const decorations = this.context.decorations; + if (this.isDecorationsTest && decorations.length > 0) { + this.decorations = decorations.map(({ name, type, start, end }) => ({ + name, + type, + start: positionToPlainObject(start), + end: positionToPlainObject(end), + })); + } + } + private getMarks() { let marks: Record; @@ -145,6 +172,7 @@ export class TestCase { marksToCheck: this.marksToCheck, initialState: this.initialState, finalState: this.finalState, + decorations: this.decorations, returnValue: this.returnValue, fullTargets: this.fullTargets, }; @@ -156,7 +184,6 @@ export class TestCase { this.initialState = await takeSnapshot( this.context.thatMark, this.context.sourceMark, - this.context.decorations, excludeFields, this.extraSnapshotFields, this.getMarks(), @@ -170,7 +197,6 @@ export class TestCase { this.finalState = await takeSnapshot( this.context.thatMark, this.context.sourceMark, - this.context.decorations, excludeFields, this.extraSnapshotFields, this.isHatTokenMapTest ? this.getMarks() : undefined, diff --git a/src/testUtil/TestCaseRecorder.ts b/src/testUtil/TestCaseRecorder.ts index 1b3d086f99..b26d7cd2da 100644 --- a/src/testUtil/TestCaseRecorder.ts +++ b/src/testUtil/TestCaseRecorder.ts @@ -29,6 +29,9 @@ interface RecordTestCaseCommandArg { */ isHatTokenMapTest?: boolean; + /** If true decorations will be added to the test fixture */ + isDecorationsTest?: boolean; + /** * The directory in which to store the test cases that we record. If left out * the user will be prompted to select a directory within the default recorded @@ -58,6 +61,7 @@ export class TestCaseRecorder { private targetDirectory: string | null = null; private testCase: TestCase | null = null; private isHatTokenMapTest: boolean = false; + private isDecorationsTest: boolean = false; private disposables: vscode.Disposable[] = []; private isSilent?: boolean; private startTimestamp?: bigint; @@ -145,7 +149,6 @@ export class TestCaseRecorder { const snapshot = await takeSnapshot( undefined, undefined, - [], ["clipboard"], this.active ? this.extraSnapshotFields : undefined, marks, @@ -166,6 +169,7 @@ export class TestCaseRecorder { async start(arg?: RecordTestCaseCommandArg) { const { isHatTokenMapTest = false, + isDecorationsTest = false, directory, isSilent = false, extraSnapshotFields = [], @@ -187,6 +191,7 @@ export class TestCaseRecorder { this.startTimestamp = process.hrtime.bigint(); const timestampISO = new Date().toISOString(); this.isHatTokenMapTest = isHatTokenMapTest; + this.isDecorationsTest = isDecorationsTest; this.isSilent = isSilent; this.extraSnapshotFields = extraSnapshotFields; this.paused = false; @@ -237,6 +242,7 @@ export class TestCaseRecorder { command, context, this.isHatTokenMapTest, + this.isDecorationsTest, this.startTimestamp!, this.extraSnapshotFields ); @@ -260,6 +266,8 @@ export class TestCaseRecorder { return; } + this.testCase.recordDecorations(); + await this.finishTestCase(); } diff --git a/src/testUtil/takeSnapshot.ts b/src/testUtil/takeSnapshot.ts index 71886a3995..7f53cb6bd4 100644 --- a/src/testUtil/takeSnapshot.ts +++ b/src/testUtil/takeSnapshot.ts @@ -1,11 +1,8 @@ import * as vscode from "vscode"; -import { TestDecoration } from "../core/editStyles"; import { ThatMark } from "../core/ThatMark"; import { Clipboard } from "../util/Clipboard"; import { hrtimeBigintToSeconds } from "../util/timeUtils"; import { - PositionPlainObject, - positionToPlainObject, RangePlainObject, rangeToPlainObject, SelectionPlainObject, @@ -16,13 +13,6 @@ import { export type ExtraSnapshotField = keyof TestCaseSnapshot; export type ExcludableSnapshotField = keyof TestCaseSnapshot; -interface PlainTestDecoration { - name: string; - type: "token" | "line"; - start: PositionPlainObject; - end: PositionPlainObject; -} - export type TestCaseSnapshot = { documentContents: string; selections: SelectionPlainObject[]; @@ -33,7 +23,6 @@ export type TestCaseSnapshot = { marks?: SerializedMarks; thatMark?: SelectionPlainObject[]; sourceMark?: SelectionPlainObject[]; - decorations?: PlainTestDecoration[]; timeOffsetSeconds?: number; /** @@ -49,7 +38,6 @@ interface ExtraContext { export async function takeSnapshot( thatMark: ThatMark | undefined, sourceMark: ThatMark | undefined, - decorations: TestDecoration[], excludeFields: ExcludableSnapshotField[] = [], extraFields: ExtraSnapshotField[] = [], marks?: SerializedMarks, @@ -99,15 +87,6 @@ export async function takeSnapshot( .map((mark) => selectionToPlainObject(mark.selection)); } - if (decorations.length > 0 && !excludeFields.includes("decorations")) { - snapshot.decorations = decorations.map(({ name, type, start, end }) => ({ - name, - type, - start: positionToPlainObject(start), - end: positionToPlainObject(end), - })); - } - if (extraFields.includes("timeOffsetSeconds")) { const startTimestamp = extraContext?.startTimestamp; From f5d37fb5d22254845e19b99a6199184dff1c90e6 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 28 May 2022 18:44:30 +0200 Subject: [PATCH 237/314] Added decorations test --- .../recorded/decorations/chuckFine.yml | 38 +++++++++++++ .../recorded/decorations/chuckLineFine.yml | 40 ++++++++++++++ .../decorations/chuckLineFineBetweenRisk.yml | 53 +++++++++++++++++++ .../recorded/decorations/clearBlockFine.yml | 40 ++++++++++++++ .../recorded/decorations/clearFine.yml | 38 +++++++++++++ .../recorded/decorations/clearLineFine.yml | 41 ++++++++++++++ .../recorded/decorations/highlightFine.yml | 38 +++++++++++++ .../decorations/highlightLineFine.yml | 41 ++++++++++++++ 8 files changed, 329 insertions(+) create mode 100644 src/test/suite/fixtures/recorded/decorations/chuckFine.yml create mode 100644 src/test/suite/fixtures/recorded/decorations/chuckLineFine.yml create mode 100644 src/test/suite/fixtures/recorded/decorations/chuckLineFineBetweenRisk.yml create mode 100644 src/test/suite/fixtures/recorded/decorations/clearBlockFine.yml create mode 100644 src/test/suite/fixtures/recorded/decorations/clearFine.yml create mode 100644 src/test/suite/fixtures/recorded/decorations/clearLineFine.yml create mode 100644 src/test/suite/fixtures/recorded/decorations/highlightFine.yml create mode 100644 src/test/suite/fixtures/recorded/decorations/highlightLineFine.yml diff --git a/src/test/suite/fixtures/recorded/decorations/chuckFine.yml b/src/test/suite/fixtures/recorded/decorations/chuckFine.yml new file mode 100644 index 0000000000..43eb4ea759 --- /dev/null +++ b/src/test/suite/fixtures/recorded/decorations/chuckFine.yml @@ -0,0 +1,38 @@ +languageId: plaintext +command: + spokenForm: chuck fine + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: f} + usePrePhraseSnapshot: true + action: {name: remove} +initialState: + documentContents: |2 + + foo ooo + bar + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: + default.f: + start: {line: 1, character: 4} + end: {line: 1, character: 7} +finalState: + documentContents: |2 + + ooo + bar + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} +decorations: + - name: pendingDeleteBackground + type: token + start: {line: 1, character: 4} + end: {line: 1, character: 8} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: f}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/decorations/chuckLineFine.yml b/src/test/suite/fixtures/recorded/decorations/chuckLineFine.yml new file mode 100644 index 0000000000..4f8015c849 --- /dev/null +++ b/src/test/suite/fixtures/recorded/decorations/chuckLineFine.yml @@ -0,0 +1,40 @@ +languageId: plaintext +command: + spokenForm: chuck line fine + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: f} + modifiers: + - type: containingScope + scopeType: {type: line} + usePrePhraseSnapshot: true + action: {name: remove} +initialState: + documentContents: |2 + + foo ooo + bar + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: + default.f: + start: {line: 1, character: 4} + end: {line: 1, character: 7} +finalState: + documentContents: |2 + + bar + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} +decorations: + - name: pendingDeleteBackground + type: line + start: {line: 1, character: 4} + end: {line: 1, character: 11} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: f}, modifiers: [{type: containingScope, scopeType: {type: line}}]}] diff --git a/src/test/suite/fixtures/recorded/decorations/chuckLineFineBetweenRisk.yml b/src/test/suite/fixtures/recorded/decorations/chuckLineFineBetweenRisk.yml new file mode 100644 index 0000000000..4a964e5883 --- /dev/null +++ b/src/test/suite/fixtures/recorded/decorations/chuckLineFineBetweenRisk.yml @@ -0,0 +1,53 @@ +languageId: plaintext +command: + spokenForm: chuck line fine between risk + version: 2 + targets: + - type: range + anchor: + type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: f} + modifiers: + - type: containingScope + scopeType: {type: line} + active: + type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: r} + excludeAnchor: true + excludeActive: true + usePrePhraseSnapshot: true + action: {name: remove} +initialState: + documentContents: |2 + + foo ooo + aa + bb + bar + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: + default.f: + start: {line: 1, character: 4} + end: {line: 1, character: 7} + default.r: + start: {line: 4, character: 4} + end: {line: 4, character: 7} +finalState: + documentContents: |2 + + foo ooo + bar + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} +decorations: + - name: pendingDeleteBackground + type: line + start: {line: 2, character: 0} + end: {line: 3, character: 2} +fullTargets: [{type: range, excludeAnchor: true, excludeActive: true, rangeType: continuous, anchor: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: f}, modifiers: &ref_0 [{type: containingScope, scopeType: {type: line}}]}, active: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: r}, modifiers: *ref_0}}] diff --git a/src/test/suite/fixtures/recorded/decorations/clearBlockFine.yml b/src/test/suite/fixtures/recorded/decorations/clearBlockFine.yml new file mode 100644 index 0000000000..e8712165d2 --- /dev/null +++ b/src/test/suite/fixtures/recorded/decorations/clearBlockFine.yml @@ -0,0 +1,40 @@ +languageId: plaintext +command: + spokenForm: clear block fine + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: f} + modifiers: + - type: containingScope + scopeType: {type: paragraph} + usePrePhraseSnapshot: true + action: {name: clearAndSetSelection} +initialState: + documentContents: |2 + + foo ooo + bar + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: + default.f: + start: {line: 1, character: 4} + end: {line: 1, character: 7} +finalState: + documentContents: |2 + + + selections: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} + thatMark: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} +decorations: + - name: pendingDeleteBackground + type: token + start: {line: 1, character: 4} + end: {line: 2, character: 7} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: f}, modifiers: [{type: containingScope, scopeType: {type: paragraph}}]}] diff --git a/src/test/suite/fixtures/recorded/decorations/clearFine.yml b/src/test/suite/fixtures/recorded/decorations/clearFine.yml new file mode 100644 index 0000000000..b9e9934a2c --- /dev/null +++ b/src/test/suite/fixtures/recorded/decorations/clearFine.yml @@ -0,0 +1,38 @@ +languageId: plaintext +command: + spokenForm: clear fine + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: f} + usePrePhraseSnapshot: true + action: {name: clearAndSetSelection} +initialState: + documentContents: |2 + + foo ooo + bar + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: + default.f: + start: {line: 1, character: 4} + end: {line: 1, character: 7} +finalState: + documentContents: |2 + + ooo + bar + selections: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} + thatMark: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} +decorations: + - name: pendingDeleteBackground + type: token + start: {line: 1, character: 4} + end: {line: 1, character: 7} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: f}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/decorations/clearLineFine.yml b/src/test/suite/fixtures/recorded/decorations/clearLineFine.yml new file mode 100644 index 0000000000..ffd01ae9aa --- /dev/null +++ b/src/test/suite/fixtures/recorded/decorations/clearLineFine.yml @@ -0,0 +1,41 @@ +languageId: plaintext +command: + spokenForm: clear line fine + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: f} + modifiers: + - type: containingScope + scopeType: {type: line} + usePrePhraseSnapshot: true + action: {name: clearAndSetSelection} +initialState: + documentContents: |2 + + foo ooo + bar + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: + default.f: + start: {line: 1, character: 4} + end: {line: 1, character: 7} +finalState: + documentContents: |2 + + + bar + selections: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} + thatMark: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} +decorations: + - name: pendingDeleteBackground + type: token + start: {line: 1, character: 4} + end: {line: 1, character: 11} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: f}, modifiers: [{type: containingScope, scopeType: {type: line}}]}] diff --git a/src/test/suite/fixtures/recorded/decorations/highlightFine.yml b/src/test/suite/fixtures/recorded/decorations/highlightFine.yml new file mode 100644 index 0000000000..a8ddda9123 --- /dev/null +++ b/src/test/suite/fixtures/recorded/decorations/highlightFine.yml @@ -0,0 +1,38 @@ +languageId: plaintext +command: + spokenForm: highlight fine + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: f} + usePrePhraseSnapshot: true + action: {name: highlight} +initialState: + documentContents: |2 + + foo + bar + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: + default.f: + start: {line: 1, character: 4} + end: {line: 1, character: 7} +finalState: + documentContents: |2 + + foo + bar + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 7} +decorations: + - name: highlight0Background + type: token + start: {line: 1, character: 4} + end: {line: 1, character: 7} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: f}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/decorations/highlightLineFine.yml b/src/test/suite/fixtures/recorded/decorations/highlightLineFine.yml new file mode 100644 index 0000000000..21cb711515 --- /dev/null +++ b/src/test/suite/fixtures/recorded/decorations/highlightLineFine.yml @@ -0,0 +1,41 @@ +languageId: plaintext +command: + spokenForm: highlight line fine + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: f} + modifiers: + - type: containingScope + scopeType: {type: line} + usePrePhraseSnapshot: true + action: {name: highlight} +initialState: + documentContents: |2 + + foo + bar + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: + default.f: + start: {line: 1, character: 4} + end: {line: 1, character: 7} +finalState: + documentContents: |2 + + foo + bar + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 7} +decorations: + - name: highlight0Background + type: line + start: {line: 1, character: 4} + end: {line: 1, character: 7} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: f}, modifiers: [{type: containingScope, scopeType: {type: line}}]}] From 46390c0b13dd45374fceef65f634cf364102c1cf Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 28 May 2022 18:46:11 +0200 Subject: [PATCH 238/314] Added decorations test --- .../fixtures/recorded/decorations/cutFine.yml | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/test/suite/fixtures/recorded/decorations/cutFine.yml diff --git a/src/test/suite/fixtures/recorded/decorations/cutFine.yml b/src/test/suite/fixtures/recorded/decorations/cutFine.yml new file mode 100644 index 0000000000..8d9cd74e13 --- /dev/null +++ b/src/test/suite/fixtures/recorded/decorations/cutFine.yml @@ -0,0 +1,40 @@ +languageId: plaintext +command: + spokenForm: cut fine + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: f} + usePrePhraseSnapshot: true + action: {name: cutToClipboard} +initialState: + documentContents: |2 + + foo bar + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: + default.f: + start: {line: 1, character: 4} + end: {line: 1, character: 7} +finalState: + documentContents: |2 + + bar + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} +decorations: + - name: referencedBackground + type: token + start: {line: 1, character: 4} + end: {line: 1, character: 7} + - name: pendingDeleteBackground + type: token + start: {line: 1, character: 7} + end: {line: 1, character: 8} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: f}, modifiers: []}] From fdbc9a51363746900a45766acb49d95cc0d13c5d Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 29 May 2022 03:28:06 +0200 Subject: [PATCH 239/314] Added leading and trailing delimiters as separate stage and target --- package.json | 4 +- .../upgradeV1ToV2/upgradeV1ToV2.ts | 35 ++- src/processTargets/getModifierStage.ts | 18 +- .../modifiers/DelimiterRangeStage.ts | 39 +++ .../modifiers/ModifyIfWeakStage.ts | 5 +- .../modifiers/OrdinalRangeSubTokenStage.ts | 2 +- src/processTargets/modifiers/PositionStage.ts | 41 +++- .../modifiers/RawSelectionStage.ts | 2 +- .../modifiers/SurroundingPairStage.ts | 2 +- src/processTargets/processTargets.ts | 46 ++-- .../targetUtil/createContinuousRange.ts | 46 ++++ .../targetUtil/getLineDelimiters.ts | 12 + .../targetUtil/maybeAddDelimiter.ts | 18 -- src/processTargets/targets/BaseTarget.ts | 125 ++++------ .../targets/ContinuousRangeTarget.ts | 206 ---------------- .../targets/DelimiterRangeTarget.ts | 90 +++++++ src/processTargets/targets/DocumentTarget.ts | 65 ++++- src/processTargets/targets/LineTarget.ts | 69 ++++-- .../targets/NotebookCellTarget.ts | 61 ++++- src/processTargets/targets/ParagraphTarget.ts | 232 +++++++++--------- src/processTargets/targets/PositionTarget.ts | 97 ++++++++ .../targets/RawSelectionTarget.ts | 54 +++- src/processTargets/targets/ScopeTypeTarget.ts | 100 ++++++-- .../targets/SurroundingPairTarget.ts | 68 +++-- src/processTargets/targets/TokenTarget.ts | 53 +++- src/processTargets/targets/WeakTarget.ts | 58 ++++- .../recorded/decorations/chuckBlockAir.yml | 47 ++++ .../decorations/chuckBlockAirUntilBatt.yml | 56 +++++ .../recorded/decorations/chuckBlockBatt.yml | 47 ++++ .../recorded/decorations/chuckBlockBatt2.yml | 39 +++ .../decorations/chuckBlockBattUntilAir.yml | 56 +++++ ...PointToEndOfThisAndEndOfWhaleTakeWhale.yml | 2 - ...dHarpToEndOfThisAndEndOfWhaleTakeWhale.yml | 4 +- ...eBlockAir.yml => chuckLeadingBlockAir.yml} | 4 +- ...ockVest.yml => chuckTrailingBlockVest.yml} | 8 +- src/test/suite/recorded.test.ts | 4 +- src/testUtil/TestCase.ts | 9 +- src/testUtil/toPlainObject.ts | 10 + src/typings/target.types.ts | 60 +++-- 39 files changed, 1307 insertions(+), 587 deletions(-) create mode 100644 src/processTargets/modifiers/DelimiterRangeStage.ts create mode 100644 src/processTargets/targetUtil/createContinuousRange.ts delete mode 100644 src/processTargets/targetUtil/maybeAddDelimiter.ts delete mode 100644 src/processTargets/targets/ContinuousRangeTarget.ts create mode 100644 src/processTargets/targets/DelimiterRangeTarget.ts create mode 100644 src/processTargets/targets/PositionTarget.ts create mode 100644 src/test/suite/fixtures/recorded/decorations/chuckBlockAir.yml create mode 100644 src/test/suite/fixtures/recorded/decorations/chuckBlockAirUntilBatt.yml create mode 100644 src/test/suite/fixtures/recorded/decorations/chuckBlockBatt.yml create mode 100644 src/test/suite/fixtures/recorded/decorations/chuckBlockBatt2.yml create mode 100644 src/test/suite/fixtures/recorded/decorations/chuckBlockBattUntilAir.yml rename src/test/suite/fixtures/recorded/positions/{chuckBeforeBlockAir.yml => chuckLeadingBlockAir.yml} (92%) rename src/test/suite/fixtures/recorded/positions/{chuckAfterBlockVest.yml => chuckTrailingBlockVest.yml} (85%) diff --git a/package.json b/package.json index 0b9d0ca3ac..fb5f1b3a29 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "color": "#00001A", "theme": "dark" }, - "version": "0.25.0", + "version": "0.26.0-SNAPSHOT", "publisher": "pokey", "license": "MIT", "repository": { @@ -542,4 +542,4 @@ "immutability-helper": "^3.1.1", "lodash": "^4.17.21" } -} +} \ No newline at end of file diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts index 94cf77eb9b..96dac3d269 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts @@ -18,13 +18,14 @@ import { import { upgradeStrictHere } from "./upgradeStrictHere"; export function upgradeV1ToV2(command: CommandV1): CommandV2 { + const actionName = command.action as ActionType; return { spokenForm: command.spokenForm, action: { - name: command.action as ActionType, + name: actionName, args: command.extraArgs, }, - targets: upgradeTargets(command.targets), + targets: upgradeTargets(command.targets, actionName), usePrePhraseSnapshot: command.usePrePhraseSnapshot ?? false, version: 2, }; @@ -85,7 +86,8 @@ function upgradeModifier(modifier: ModifierV0V1): Modifier[] { } function upgradePrimitiveTarget( - target: PartialPrimitiveTargetV0V1 + target: PartialPrimitiveTargetV0V1, + action: ActionType ): PartialPrimitiveTargetDesc { const { type, @@ -102,12 +104,16 @@ function upgradePrimitiveTarget( if (position === "before") { if (insideOutsideType === "inside") { modifiers.push({ type: "position", position: "start" }); + } else if (action === "remove") { + modifiers.push({ type: "delimiterRange", direction: "leading" }); } else { modifiers.push({ type: "position", position: "before" }); } } else { if (insideOutsideType === "inside") { modifiers.push({ type: "position", position: "end" }); + } else if (action === "remove") { + modifiers.push({ type: "delimiterRange", direction: "trailing" }); } else { modifiers.push({ type: "position", position: "after" }); } @@ -146,14 +152,17 @@ function upgradePrimitiveTarget( }; } -function upgradeTarget(target: PartialTargetV0V1): PartialTargetDesc { +function upgradeTarget( + target: PartialTargetV0V1, + action: ActionType +): PartialTargetDesc { switch (target.type) { case "list": return { ...target, elements: target.elements.map( (target) => - upgradeTarget(target) as + upgradeTarget(target, action) as | PartialPrimitiveTargetDesc | PartialRangeTargetDesc ), @@ -163,19 +172,23 @@ function upgradeTarget(target: PartialTargetV0V1): PartialTargetDesc { return { type, rangeType, - anchor: upgradePrimitiveTarget(start), - active: upgradePrimitiveTarget(end), + anchor: upgradePrimitiveTarget(start, action), + active: upgradePrimitiveTarget(end, action), excludeAnchor: excludeStart ?? false, excludeActive: excludeEnd ?? false, }; case "primitive": - return upgradePrimitiveTarget(target); + return upgradePrimitiveTarget(target, action); } } -function upgradeTargets(partialTargets: PartialTargetV0V1[]) { - const partialTargetsV2: PartialTargetDesc[] = - partialTargets.map(upgradeTarget); +function upgradeTargets( + partialTargets: PartialTargetV0V1[], + action: ActionType +) { + const partialTargetsV2: PartialTargetDesc[] = partialTargets.map((target) => + upgradeTarget(target, action) + ); return transformPartialPrimitiveTargets( partialTargetsV2, flow(upgradeStrictHere) diff --git a/src/processTargets/getModifierStage.ts b/src/processTargets/getModifierStage.ts index d903f96618..e95951f140 100644 --- a/src/processTargets/getModifierStage.ts +++ b/src/processTargets/getModifierStage.ts @@ -4,6 +4,7 @@ import { EveryScopeModifier, Modifier, } from "../typings/target.types"; +import DelimiterRangeStage from "./modifiers/DelimiterRangeStage"; import { HeadStage, TailStage } from "./modifiers/HeadTailStage"; import { ExcludeInteriorStage, @@ -41,23 +42,24 @@ export default (modifier: Modifier): ModifierStage => { return new TailStage(modifier); case "toRawSelection": return new RawSelectionStage(modifier); + case "interiorOnly": + return new InteriorOnlyStage(modifier); + case "excludeInterior": + return new ExcludeInteriorStage(modifier); + case "delimiterRange": + return new DelimiterRangeStage(modifier); + case "containingScope": + case "everyScope": + return getContainingScopeStage(modifier); case "ordinalRange": if (!["word", "character"].includes(modifier.scopeType.type)) { throw Error( `Unsupported ordinal scope type ${modifier.scopeType.type}` ); } - return new OrdinalRangeSubTokenStage( modifier as OrdinalRangeSubTokenModifier ); - case "interiorOnly": - return new InteriorOnlyStage(modifier); - case "excludeInterior": - return new ExcludeInteriorStage(modifier); - case "containingScope": - case "everyScope": - return getContainingScopeStage(modifier); } }; diff --git a/src/processTargets/modifiers/DelimiterRangeStage.ts b/src/processTargets/modifiers/DelimiterRangeStage.ts new file mode 100644 index 0000000000..81bdae14da --- /dev/null +++ b/src/processTargets/modifiers/DelimiterRangeStage.ts @@ -0,0 +1,39 @@ +import { Range } from "vscode"; +import { DelimiterRangeModifier, Target } from "../../typings/target.types"; +import { ProcessedTargetsContext } from "../../typings/Types"; +import { ModifierStage } from "../PipelineStages.types"; +import DelimiterRangeTarget from "../targets/DelimiterRangeTarget"; + +export default class DelimiterRangeStage implements ModifierStage { + constructor(private modifier: DelimiterRangeModifier) {} + + run(context: ProcessedTargetsContext, target: Target): Target[] { + let contentRange: Range; + + switch (this.modifier.direction) { + case "leading": + const leading = target.getLeadingDelimiterRange(true); + if (leading == null) { + throw Error("No available leading range"); + } + contentRange = leading; + break; + + case "trailing": + const trailing = target.getTrailingDelimiterRange(true); + if (trailing == null) { + throw Error("No available trailing range"); + } + contentRange = trailing; + } + + return [ + new DelimiterRangeTarget({ + editor: target.editor, + isReversed: target.isReversed, + contentRange, + isLine: target.is("paragraph"), + }), + ]; + } +} diff --git a/src/processTargets/modifiers/ModifyIfWeakStage.ts b/src/processTargets/modifiers/ModifyIfWeakStage.ts index 449e8b163a..f92a8994f8 100644 --- a/src/processTargets/modifiers/ModifyIfWeakStage.ts +++ b/src/processTargets/modifiers/ModifyIfWeakStage.ts @@ -3,7 +3,7 @@ import { ProcessedTargetsContext } from "../../typings/Types"; import getModifierStage from "../getModifierStage"; import { ModifierStage } from "../PipelineStages.types"; -export default class implements ModifierStage { +export default class ModifyIfWeakStage implements ModifierStage { private nestedStage_?: ModifierStage; constructor(private nestedModifier: Modifier) {} @@ -17,7 +17,8 @@ export default class implements ModifierStage { } run(context: ProcessedTargetsContext, target: Target): Target[] { - if (target.isWeak) { + /** If true this target is of weak type and should use inference/upgrade when needed. See {@link WeakTarget} for more info */ + if (target.type === "weak") { return this.nestedStage .run(context, target) .map((newTarget) => newTarget.withThatTarget(target)); diff --git a/src/processTargets/modifiers/OrdinalRangeSubTokenStage.ts b/src/processTargets/modifiers/OrdinalRangeSubTokenStage.ts index 19e12938d4..7be4972fb3 100644 --- a/src/processTargets/modifiers/OrdinalRangeSubTokenStage.ts +++ b/src/processTargets/modifiers/OrdinalRangeSubTokenStage.ts @@ -19,7 +19,7 @@ export interface OrdinalRangeSubTokenModifier extends OrdinalRangeModifier { scopeType: OrdinalScopeType; } -export default class implements ModifierStage { +export default class OrdinalRangeSubTokenStage implements ModifierStage { constructor(private modifier: OrdinalRangeSubTokenModifier) {} run(context: ProcessedTargetsContext, target: Target): Target[] { diff --git a/src/processTargets/modifiers/PositionStage.ts b/src/processTargets/modifiers/PositionStage.ts index b9e6be6d73..f2cdd84192 100644 --- a/src/processTargets/modifiers/PositionStage.ts +++ b/src/processTargets/modifiers/PositionStage.ts @@ -1,11 +1,48 @@ +import { Range } from "vscode"; import { PositionModifier, Target } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; +import PositionTarget from "../targets/PositionTarget"; -export default class implements ModifierStage { +export default class PositionStage implements ModifierStage { constructor(private modifier: PositionModifier) {} run(context: ProcessedTargetsContext, target: Target): Target[] { - return [target.withPosition(this.modifier.position)]; + const { start, end } = target.contentRange; + let contentRange: Range; + let delimiter: string | undefined; + + switch (this.modifier.position) { + case "before": + contentRange = new Range(start, start); + delimiter = target.delimiter; + break; + + case "after": + contentRange = new Range(end, end); + delimiter = target.delimiter; + break; + + case "start": + contentRange = new Range(start, start); + // This it NOT a raw target. Joining with this should be done on empty delimiter. + delimiter = ""; + break; + + case "end": + contentRange = new Range(end, end); + delimiter = ""; + break; + } + + return [ + new PositionTarget({ + editor: target.editor, + isReversed: target.isReversed, + contentRange, + position: this.modifier.position, + delimiter, + }), + ]; } } diff --git a/src/processTargets/modifiers/RawSelectionStage.ts b/src/processTargets/modifiers/RawSelectionStage.ts index c95a0fdded..468fb8f23a 100644 --- a/src/processTargets/modifiers/RawSelectionStage.ts +++ b/src/processTargets/modifiers/RawSelectionStage.ts @@ -3,7 +3,7 @@ import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; import RawSelectionTarget from "../targets/RawSelectionTarget"; -export default class implements ModifierStage { +export default class RawSelectionStage implements ModifierStage { constructor(private modifier: RawSelectionModifier) {} run(context: ProcessedTargetsContext, target: Target): Target[] { diff --git a/src/processTargets/modifiers/SurroundingPairStage.ts b/src/processTargets/modifiers/SurroundingPairStage.ts index 0e12d6f64d..017aa01b8f 100644 --- a/src/processTargets/modifiers/SurroundingPairStage.ts +++ b/src/processTargets/modifiers/SurroundingPairStage.ts @@ -20,7 +20,7 @@ import { processSurroundingPair } from "./surroundingPair"; * @returns The new selection expanded to the containing surrounding pair or * `null` if none was found */ -export default class implements ModifierStage { +export default class SurroundingPairStage implements ModifierStage { constructor(private modifier: ContainingSurroundingPairModifier) {} run( diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index 9886eb8034..e66d0c621a 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -11,7 +11,7 @@ import { ensureSingleEditor } from "../util/targetUtils"; import uniqDeep from "../util/uniqDeep"; import getMarkStage from "./getMarkStage"; import getModifierStage from "./getModifierStage"; -import ContinuousRangeTarget from "./targets/ContinuousRangeTarget"; +import PositionTarget from "./targets/PositionTarget"; import WeakTarget from "./targets/WeakTarget"; /** @@ -100,14 +100,17 @@ function processContinuousRangeTarget( ): Target { ensureSingleEditor([anchorTarget, activeTarget]); const isReversed = calcIsReversed(anchorTarget, activeTarget); + const startTarget = isReversed ? activeTarget : anchorTarget; + const endTarget = isReversed ? anchorTarget : activeTarget; + const excludeStart = isReversed ? excludeActive : excludeAnchor; + const excludeEnd = isReversed ? excludeAnchor : excludeActive; - return new ContinuousRangeTarget({ - startTarget: isReversed ? activeTarget : anchorTarget, - endTarget: isReversed ? anchorTarget : activeTarget, - excludeStart: isReversed ? excludeActive : excludeAnchor, - excludeEnd: isReversed ? excludeAnchor : excludeActive, + return startTarget.createContinuousRangeTarget( isReversed, - }); + endTarget, + !excludeStart, + !excludeEnd + ); } export function targetsToContinuousTarget( @@ -143,14 +146,27 @@ function processVerticalRangeTarget( i, anchorTarget.contentRange.end.character ); - results.push( - new WeakTarget({ - editor: anchorTarget.editor, - isReversed: anchorTarget.isReversed, - contentRange, - position: anchorTarget.position, - }) - ); + + if (anchorTarget.position != null) { + results.push( + new PositionTarget({ + editor: anchorTarget.editor, + isReversed: anchorTarget.isReversed, + contentRange, + position: anchorTarget.position, + delimiter: anchorTarget.delimiter, + }) + ); + } else { + results.push( + new WeakTarget({ + editor: anchorTarget.editor, + isReversed: anchorTarget.isReversed, + contentRange, + }) + ); + } + if (i === activeLine) { return results; } diff --git a/src/processTargets/targetUtil/createContinuousRange.ts b/src/processTargets/targetUtil/createContinuousRange.ts new file mode 100644 index 0000000000..b85e65aedf --- /dev/null +++ b/src/processTargets/targetUtil/createContinuousRange.ts @@ -0,0 +1,46 @@ +import { Position, Range } from "vscode"; +import { Target } from "../../typings/target.types"; + +export function createContinuousRange( + startTarget: Target, + endTarget: Target, + includeStart: boolean, + includeEnd: boolean +) { + return createContinuousRangeFromRanges( + startTarget.contentRange, + endTarget.contentRange, + includeStart, + includeEnd + ); +} + +export function createContinuousRangeFromRanges( + startRange: Range, + endRange: Range, + includeStart: boolean, + includeEnd: boolean +) { + return new Range( + includeStart ? startRange.start : startRange.end, + includeEnd ? endRange.end : endRange.start + ); +} + +export function createContinuousLineRange( + startTarget: Target, + endTarget: Target, + includeStart: boolean, + includeEnd: boolean +) { + const start = includeStart + ? startTarget.contentRange.start + : new Position(startTarget.contentRange.end.line + 1, 0); + + const end = includeEnd + ? endTarget.contentRange.end + : endTarget.editor.document.lineAt(endTarget.contentRange.start.line - 1) + .range.end; + + return new Range(start, end); +} diff --git a/src/processTargets/targetUtil/getLineDelimiters.ts b/src/processTargets/targetUtil/getLineDelimiters.ts index 9976d92498..004fb56d46 100644 --- a/src/processTargets/targetUtil/getLineDelimiters.ts +++ b/src/processTargets/targetUtil/getLineDelimiters.ts @@ -16,3 +16,15 @@ export function getLineTrailingDelimiterRange( ? new Range(range.end, new Position(end.line + 1, 0)) : undefined; } + +export function addLineDelimiterRanges(editor: TextEditor, range: Range) { + const trailingDelimiterRange = getLineTrailingDelimiterRange(editor, range); + if (trailingDelimiterRange != null) { + return range.union(trailingDelimiterRange); + } + const leadingDelimiterRange = getLineLeadingDelimiterRange(editor, range); + if (leadingDelimiterRange != null) { + return range.union(leadingDelimiterRange); + } + return range; +} diff --git a/src/processTargets/targetUtil/maybeAddDelimiter.ts b/src/processTargets/targetUtil/maybeAddDelimiter.ts deleted file mode 100644 index 11f50c086e..0000000000 --- a/src/processTargets/targetUtil/maybeAddDelimiter.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Position } from "../../typings/target.types"; - -/** Possibly add delimiter for positions before/after */ -export function maybeAddDelimiter( - text: string, - delimiter?: string, - position?: Position -): string { - if (delimiter != null) { - if (position === "before") { - return text + delimiter; - } - if (position === "after") { - return delimiter + text; - } - } - return text; -} diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index 6558cd0b64..d687e407cb 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -1,70 +1,52 @@ import { Range, Selection, TextEditor } from "vscode"; -import { EditNewContext, Position, Target } from "../../typings/target.types"; +import { + EditNewContext, + Position, + Target, + TargetType, +} from "../../typings/target.types"; import { selectionFromRange } from "../../util/selectionUtils"; import { getTokenDelimiters } from "../targetUtil/getTokenDelimiters"; -import { maybeAddDelimiter } from "../targetUtil/maybeAddDelimiter"; - -export function extractCommonParameters(parameters: CommonTargetParameters) { - return { - editor: parameters.editor, - isReversed: parameters.isReversed, - contentRange: parameters.contentRange, - position: parameters.position, - thatTarget: parameters.thatTarget, - }; -} /** Parameters supported by all target classes */ export interface CommonTargetParameters { readonly editor: TextEditor; readonly isReversed: boolean; readonly contentRange: Range; - readonly position?: Position; readonly thatTarget?: Target; } export interface CloneWithParameters { - readonly position?: Position; readonly thatTarget?: Target; } -export interface BaseTargetParameters extends CommonTargetParameters { - readonly delimiter: string; -} - export default abstract class BaseTarget implements Target { - protected readonly state: BaseTargetParameters; + protected readonly state: CommonTargetParameters; - constructor(parameters: BaseTargetParameters) { + constructor(parameters: CommonTargetParameters) { this.state = { editor: parameters.editor, isReversed: parameters.isReversed, contentRange: parameters.contentRange, - position: parameters.position, - delimiter: parameters.delimiter, thatTarget: parameters.thatTarget, }; } - get position() { - return this.state.position; - } + abstract get type(): TargetType; + abstract get delimiter(): string | undefined; get editor() { return this.state.editor; } get isReversed() { return this.state.isReversed; } - get contentRemovalRange() { + protected get contentRemovalRange() { return this.contentRange; } - get isLine() { - return false; - } - get isParagraph() { - return false; + get position(): Position | undefined { + return undefined; } - get isWeak() { + get isLine() { return false; } @@ -83,91 +65,56 @@ export default abstract class BaseTarget implements Target { } get contentRange(): Range { - switch (this.position) { - case "start": - case "before": - return new Range( - this.state.contentRange.start, - this.state.contentRange.start - ); - case "end": - case "after": - return new Range( - this.state.contentRange.end, - this.state.contentRange.end - ); - default: - return this.state.contentRange; - } + return this.state.contentRange; } - get delimiter(): string | undefined { - switch (this.position) { - // This it NOT a raw target. Joining with this should be done on empty delimiter. - case "start": - case "end": - return ""; - default: - return this.state.delimiter; - } + is(type: TargetType): boolean { + return this.type === type; } - get leadingDelimiterRange() { + getLeadingDelimiterRange(force?: boolean) { const { includeDelimitersInRemoval, leadingDelimiterRange } = getTokenDelimiters(this.state.editor, this.state.contentRange); - return includeDelimitersInRemoval || this.position != null + return includeDelimitersInRemoval || force ? leadingDelimiterRange : undefined; } - get trailingDelimiterRange() { + getTrailingDelimiterRange(force?: boolean) { const { includeDelimitersInRemoval, trailingDelimiterRange } = getTokenDelimiters(this.state.editor, this.state.contentRange); - return includeDelimitersInRemoval || this.position != null + return includeDelimitersInRemoval || force ? trailingDelimiterRange : undefined; } maybeAddDelimiter(text: string): string { - return maybeAddDelimiter(text, this.delimiter, this.position); + return text; } getEditNewContext(isBefore: boolean): EditNewContext { - if (this.delimiter === "\n" && !isBefore) { + const delimiter = this.delimiter ?? ""; + if (delimiter === "\n" && !isBefore) { return { type: "command", command: "editor.action.insertLineAfter" }; } return { type: "delimiter", - delimiter: this.delimiter ?? "", + delimiter, }; } getRemovalRange(): Range { - switch (this.position) { - case "before": - return this.leadingDelimiterRange ?? this.contentRange; - case "after": - return this.trailingDelimiterRange ?? this.contentRange; - case "start": - case "end": - return this.contentRange; - default: - const delimiterRange = - this.trailingDelimiterRange ?? this.leadingDelimiterRange; - return delimiterRange != null - ? this.contentRemovalRange.union(delimiterRange) - : this.contentRemovalRange; - } + const delimiterRange = + this.getTrailingDelimiterRange() ?? this.getLeadingDelimiterRange(); + return delimiterRange != null + ? this.contentRemovalRange.union(delimiterRange) + : this.contentRemovalRange; } getRemovalHighlightRange(): Range | undefined { return this.getRemovalRange(); } - withPosition(position: Position): Target { - return this.cloneWith({ position }); - } - withThatTarget(thatTarget: Target): Target { return this.cloneWith({ thatTarget }); } @@ -180,4 +127,16 @@ export default abstract class BaseTarget implements Target { } abstract cloneWith(parameters: CloneWithParameters): Target; + protected abstract getCloneParameters(): unknown; + + abstract createContinuousRangeTarget( + isReversed: boolean, + endTarget: Target, + includeStart: boolean, + includeEnd: boolean + ): Target; + + protected isSameType(target: Target) { + return this.type === target.type; + } } diff --git a/src/processTargets/targets/ContinuousRangeTarget.ts b/src/processTargets/targets/ContinuousRangeTarget.ts deleted file mode 100644 index 23e48ad9fe..0000000000 --- a/src/processTargets/targets/ContinuousRangeTarget.ts +++ /dev/null @@ -1,206 +0,0 @@ -import { Range, Selection, Position as VS_Position } from "vscode"; -import { EditNewContext, Position, Target } from "../../typings/target.types"; -import { selectionFromRange } from "../../util/selectionUtils"; -import { - getLineLeadingDelimiterRange, - getLineTrailingDelimiterRange, -} from "../targetUtil/getLineDelimiters"; -import { maybeAddDelimiter } from "../targetUtil/maybeAddDelimiter"; - -interface ContinuousRangeTargetParameters { - readonly startTarget: Target; - readonly endTarget: Target; - readonly isReversed: boolean; - readonly excludeStart: boolean; - readonly excludeEnd: boolean; -} - -export default class ContinuousRangeTarget implements Target { - private startTarget_: Target; - private endTarget_: Target; - private isReversed_: boolean; - private excludeStart_: boolean; - private excludeEnd_: boolean; - - constructor(parameters: ContinuousRangeTargetParameters) { - this.startTarget_ = parameters.startTarget; - this.endTarget_ = parameters.endTarget; - this.isReversed_ = parameters.isReversed; - this.excludeStart_ = parameters.excludeStart; - this.excludeEnd_ = parameters.excludeEnd; - } - - get editor() { - return this.startTarget_.editor; - } - get isReversed() { - return this.isReversed_; - } - get position() { - return undefined; - } - get isLine() { - return this.startTarget_.isLine && this.endTarget_.isLine; - } - get isParagraph() { - return this.startTarget_.isParagraph && this.endTarget_.isParagraph; - } - get isWeak() { - return false; - } - get thatTarget() { - return this; - } - get contentText(): string { - return this.editor.document.getText(this.contentRange); - } - get contentSelection(): Selection { - return selectionFromRange(this.isReversed, this.contentRange); - } - - get delimiter() { - return ( - (this.startTarget_.delimiter === this.endTarget_.delimiter - ? this.startTarget_.delimiter - : null) ?? " " - ); - } - - get leadingDelimiterRange() { - const startTarget = this.startTarget_; - if (startTarget.position === "start") { - return undefined; - } - if (this.excludeStart_) { - if (startTarget.isLine) { - return getLineLeadingDelimiterRange(this.editor, this.contentRange); - } - return undefined; - } - return startTarget.leadingDelimiterRange; - } - - get trailingDelimiterRange() { - const endTarget = this.endTarget_; - if (endTarget.position === "end") { - return undefined; - } - if (this.excludeEnd_) { - if (endTarget.isLine) { - return getLineTrailingDelimiterRange(this.editor, this.contentRange); - } - return undefined; - } - return endTarget.trailingDelimiterRange; - } - - get leadingDelimiterHighlightRange() { - const leadingDelimiterRange = this.leadingDelimiterRange; - if (leadingDelimiterRange == null) { - return undefined; - } - const startTarget = this.startTarget_; - if (startTarget.isLine && !this.excludeStart_) { - return new Range(leadingDelimiterRange.end, this.contentRange.start); - } - return leadingDelimiterRange; - } - - get trailingDelimiterHighlightRange() { - const trailingDelimiterRange = this.trailingDelimiterRange; - if (trailingDelimiterRange == null) { - return undefined; - } - const endTarget = this.endTarget_; - if (endTarget.isLine) { - if (this.excludeEnd_) { - return new Range( - this.contentRange.end, - endTarget.leadingDelimiterRange!.start - ); - } - return new Range(this.contentRange.end, trailingDelimiterRange.start); - } - return trailingDelimiterRange; - } - - get contentRange() { - return this.processRanges( - this.startTarget_.contentRange, - this.endTarget_.contentRange - ); - } - - get contentRemovalRange() { - return this.processRanges( - this.startTarget_.contentRemovalRange, - this.endTarget_.contentRemovalRange - ); - } - - maybeAddDelimiter(text: string): string { - return maybeAddDelimiter(text, this.delimiter, this.position); - } - - getEditNewContext(_isBefore: boolean): EditNewContext { - return { - type: "delimiter", - delimiter: this.delimiter, - }; - } - - getRemovalRange(): Range { - const delimiterRange = - this.trailingDelimiterRange ?? this.leadingDelimiterRange; - return delimiterRange != null - ? this.contentRemovalRange.union(delimiterRange) - : this.contentRemovalRange; - } - - getRemovalHighlightRange(): Range | undefined { - const delimiterRange = - this.trailingDelimiterHighlightRange ?? - this.leadingDelimiterHighlightRange; - return delimiterRange != null - ? this.contentRemovalRange.union(delimiterRange) - : this.contentRemovalRange; - } - - getInteriorStrict(): Target[] { - throw Error("No available interior"); - } - getBoundaryStrict(): Target[] { - throw Error("No available boundaries"); - } - withPosition(_position: Position): Target { - throw new Error("Method not implemented"); - } - withThatTarget(_thatTarget: Target): Target { - throw new Error("Method not implemented"); - } - - private processRanges(startRange: Range, endRange: Range) { - const startTarget = this.startTarget_; - const endTarget = this.endTarget_; - const start = (() => { - if (this.excludeStart_) { - if (startTarget.isLine) { - return new VS_Position(startRange.end.line + 1, 0); - } - return startRange.end; - } - return startRange.start; - })(); - const end = (() => { - if (this.excludeEnd_) { - if (endTarget.isLine) { - const { lineAt } = this.editor.document; - return lineAt(endRange.start.line - 1).range.end; - } - return endRange.start; - } - return endRange.end; - })(); - return new Range(start, end); - } -} diff --git a/src/processTargets/targets/DelimiterRangeTarget.ts b/src/processTargets/targets/DelimiterRangeTarget.ts new file mode 100644 index 0000000000..cb680c5022 --- /dev/null +++ b/src/processTargets/targets/DelimiterRangeTarget.ts @@ -0,0 +1,90 @@ +import { Range } from "vscode"; +import { Target, TargetType } from "../../typings/target.types"; +import { createContinuousRange } from "../targetUtil/createContinuousRange"; +import { addLineDelimiterRanges } from "../targetUtil/getLineDelimiters"; +import BaseTarget, { + CloneWithParameters, + CommonTargetParameters, +} from "./BaseTarget"; +import { createContinuousRangeWeakTarget } from "./WeakTarget"; + +interface DelimiterRangeTargetParameters extends CommonTargetParameters { + readonly isLine: boolean; +} + +export default class DelimiterRangeTarget extends BaseTarget { + private isLine_: boolean; + + constructor(parameters: DelimiterRangeTargetParameters) { + super(parameters); + this.isLine_ = parameters.isLine; + } + + get type(): TargetType { + return "delimiterRange"; + } + get delimiter() { + return " "; + } + get isLine() { + return this.isLine_; + } + getLeadingDelimiterRange() { + return undefined; + } + getTrailingDelimiterRange() { + return undefined; + } + + getRemovalRange(): Range { + return this.isLine + ? addLineDelimiterRanges(this.editor, this.contentRange) + : this.contentRange; + } + + getRemovalHighlightRange(): Range { + return this.contentRange; + } + + cloneWith(parameters: CloneWithParameters) { + return new DelimiterRangeTarget({ + ...this.getCloneParameters(), + ...parameters, + }); + } + + createContinuousRangeTarget( + isReversed: boolean, + endTarget: Target, + includeStart: boolean, + includeEnd: boolean + ): Target { + if (this.isSameType(endTarget)) { + return new DelimiterRangeTarget({ + ...this.getCloneParameters(), + isReversed, + contentRange: createContinuousRange( + this, + endTarget, + includeStart, + includeEnd + ), + }); + } + + return createContinuousRangeWeakTarget( + isReversed, + this, + endTarget, + includeStart, + includeEnd + ); + } + + protected getCloneParameters() { + return { + ...this.state, + isLine: this.isLine_, + }; + } +} diff --git a/src/processTargets/targets/DocumentTarget.ts b/src/processTargets/targets/DocumentTarget.ts index 7fd5e3e9ea..3e43a18f2b 100644 --- a/src/processTargets/targets/DocumentTarget.ts +++ b/src/processTargets/targets/DocumentTarget.ts @@ -1,26 +1,36 @@ import { Range, TextEditor } from "vscode"; -import { Target } from "../../typings/target.types"; +import { Target, TargetType } from "../../typings/target.types"; import { fitRangeToLineContent } from "../modifiers/scopeTypeStages/LineStage"; +import { createContinuousRange } from "../targetUtil/createContinuousRange"; import BaseTarget, { CloneWithParameters, CommonTargetParameters, - extractCommonParameters, } from "./BaseTarget"; -import WeakTarget from "./WeakTarget"; +import WeakTarget, { createContinuousRangeWeakTarget } from "./WeakTarget"; export default class DocumentTarget extends BaseTarget { constructor(parameters: CommonTargetParameters) { - super({ - ...extractCommonParameters(parameters), - delimiter: "\n", - }); + super(parameters); } + get type(): TargetType { + return "document"; + } + get delimiter() { + return "\n"; + } get isLine() { return true; } - getInteriorStrict(): Target[] { + getLeadingDelimiterRange() { + return undefined; + } + getTrailingDelimiterRange() { + return undefined; + } + + getInteriorStrict() { return [ new WeakTarget({ editor: this.editor, @@ -30,8 +40,43 @@ export default class DocumentTarget extends BaseTarget { ]; } - cloneWith(parameters: CloneWithParameters): DocumentTarget { - return new DocumentTarget({ ...this.state, ...parameters }); + cloneWith(parameters: CloneWithParameters) { + return new DocumentTarget({ + ...this.getCloneParameters(), + ...parameters, + }); + } + + createContinuousRangeTarget( + isReversed: boolean, + endTarget: Target, + includeStart: boolean, + includeEnd: boolean + ): Target { + if (this.isSameType(endTarget)) { + return new DocumentTarget({ + ...this.getCloneParameters(), + isReversed, + contentRange: createContinuousRange( + this, + endTarget, + includeStart, + includeEnd + ), + }); + } + + return createContinuousRangeWeakTarget( + isReversed, + this, + endTarget, + includeStart, + includeEnd + ); + } + + protected getCloneParameters() { + return this.state; } } diff --git a/src/processTargets/targets/LineTarget.ts b/src/processTargets/targets/LineTarget.ts index 479dcc1ee3..72892eae02 100644 --- a/src/processTargets/targets/LineTarget.ts +++ b/src/processTargets/targets/LineTarget.ts @@ -1,4 +1,6 @@ import { Position, Range } from "vscode"; +import { Target, TargetType } from "../../typings/target.types"; +import { createContinuousLineRange } from "../targetUtil/createContinuousRange"; import { getLineLeadingDelimiterRange, getLineTrailingDelimiterRange, @@ -6,44 +8,79 @@ import { import BaseTarget, { CloneWithParameters, CommonTargetParameters, - extractCommonParameters, } from "./BaseTarget"; +import { createContinuousRangeWeakTarget } from "./WeakTarget"; export default class LineTarget extends BaseTarget { constructor(parameters: CommonTargetParameters) { - super({ - ...extractCommonParameters(parameters), - delimiter: "\n", - }); + super(parameters); } + get type(): TargetType { + return "line"; + } + get delimiter() { + return "\n"; + } get isLine() { return true; } - cloneWith(parameters: CloneWithParameters): LineTarget { - return new LineTarget({ ...this.state, ...parameters }); - } - - get contentRemovalRange() { + protected get contentRemovalRange() { return new Range( new Position(this.contentRange.start.line, 0), this.editor.document.lineAt(this.contentRange.end).range.end ); } - get leadingDelimiterRange() { + getLeadingDelimiterRange() { return getLineLeadingDelimiterRange(this.editor, this.contentRemovalRange); } - get trailingDelimiterRange() { + getTrailingDelimiterRange() { return getLineTrailingDelimiterRange(this.editor, this.contentRemovalRange); } - getRemovalHighlightRange(): Range | undefined { - if (this.position != null) { - return undefined; - } + getRemovalHighlightRange() { return this.contentRange; } + + cloneWith(parameters: CloneWithParameters) { + return new LineTarget({ + ...this.getCloneParameters(), + ...parameters, + }); + } + + createContinuousRangeTarget( + isReversed: boolean, + endTarget: Target, + includeStart: boolean, + includeEnd: boolean + ): Target { + if (this.isSameType(endTarget) || endTarget.is("paragraph")) { + return new LineTarget({ + ...this.getCloneParameters(), + isReversed, + contentRange: createContinuousLineRange( + this, + endTarget, + includeStart, + includeEnd + ), + }); + } + + return createContinuousRangeWeakTarget( + isReversed, + this, + endTarget, + includeStart, + includeEnd + ); + } + + protected getCloneParameters() { + return this.state; + } } diff --git a/src/processTargets/targets/NotebookCellTarget.ts b/src/processTargets/targets/NotebookCellTarget.ts index 0e52ff4cb6..14df51e1c4 100644 --- a/src/processTargets/targets/NotebookCellTarget.ts +++ b/src/processTargets/targets/NotebookCellTarget.ts @@ -1,17 +1,29 @@ import { TextEditor } from "vscode"; -import { EditNewContext } from "../../typings/target.types"; +import { EditNewContext, Target, TargetType } from "../../typings/target.types"; import { getNotebookFromCellDocument } from "../../util/notebook"; +import { createContinuousRange } from "../targetUtil/createContinuousRange"; import BaseTarget, { CloneWithParameters, CommonTargetParameters, } from "./BaseTarget"; +import { createContinuousRangeWeakTarget } from "./WeakTarget"; export default class NotebookCellTarget extends BaseTarget { constructor(parameters: CommonTargetParameters) { - super({ - ...parameters, - delimiter: "\n", - }); + super(parameters); + } + + get type(): TargetType { + return "notebookCell"; + } + get delimiter() { + return "\n"; + } + getLeadingDelimiterRange() { + return undefined; + } + getTrailingDelimiterRange() { + return undefined; } getEditNewContext(isBefore: boolean): EditNewContext { @@ -31,8 +43,43 @@ export default class NotebookCellTarget extends BaseTarget { }; } - cloneWith(parameters: CloneWithParameters): NotebookCellTarget { - return new NotebookCellTarget({ ...this.state, ...parameters }); + cloneWith(parameters: CloneWithParameters) { + return new NotebookCellTarget({ + ...this.getCloneParameters(), + ...parameters, + }); + } + + createContinuousRangeTarget( + isReversed: boolean, + endTarget: Target, + includeStart: boolean, + includeEnd: boolean + ): Target { + if (this.isSameType(endTarget)) { + return new NotebookCellTarget({ + ...this.getCloneParameters(), + isReversed, + contentRange: createContinuousRange( + this, + endTarget, + includeStart, + includeEnd + ), + }); + } + + return createContinuousRangeWeakTarget( + isReversed, + this, + endTarget, + includeStart, + includeEnd + ); + } + + protected getCloneParameters() { + return this.state; } private isNotebookEditor(editor: TextEditor) { diff --git a/src/processTargets/targets/ParagraphTarget.ts b/src/processTargets/targets/ParagraphTarget.ts index 3173bc27a5..bc6cacdc87 100644 --- a/src/processTargets/targets/ParagraphTarget.ts +++ b/src/processTargets/targets/ParagraphTarget.ts @@ -1,89 +1,55 @@ import { Position, Range, TextDocument, TextEditor, TextLine } from "vscode"; +import { Target, TargetType } from "../../typings/target.types"; +import { createContinuousLineRange } from "../targetUtil/createContinuousRange"; +import { addLineDelimiterRanges } from "../targetUtil/getLineDelimiters"; import BaseTarget, { CloneWithParameters, CommonTargetParameters, - extractCommonParameters, } from "./BaseTarget"; +import LineTarget from "./LineTarget"; +import { createContinuousRangeWeakTarget } from "./WeakTarget"; export default class ParagraphTarget extends BaseTarget { constructor(parameters: CommonTargetParameters) { - super({ - ...extractCommonParameters(parameters), - delimiter: "\n\n", - }); + super(parameters); } - get isLine() { - return true; + get type(): TargetType { + return "paragraph"; } - - get isParagraph() { + get delimiter() { + return "\n\n"; + } + get isLine() { return true; } - get contentRemovalRange() { + protected get contentRemovalRange() { return new Range( new Position(this.contentRange.start.line, 0), this.editor.document.lineAt(this.contentRange.end).range.end ); } - get leadingDelimiterRange() { - return getLeadingDelimiter( - this.editor, - this.contentRange, - this.position == null - )?.range; - } - get trailingDelimiterRange() { - return getTrailingDelimiter( - this.editor, - this.contentRange, - this.position == null - )?.range; - } - - get leadingDelimiterHighlightRange() { - return getLeadingDelimiter( - this.editor, - this.contentRange, - this.position == null - )?.highlight; - } - get trailingDelimiterHighlightRange() { - return getTrailingDelimiter( - this.editor, - this.contentRange, - this.position == null - )?.highlight; - } - - getRemovalRange(): Range { - switch (this.position) { - case "before": - return this.leadingDelimiterRange ?? this.contentRange; - case "after": - return this.trailingDelimiterRange ?? this.contentRange; - case "start": - case "end": - return this.contentRange; - } + getLeadingDelimiterRange() { + return getLeadingDelimiter(this.editor, this.contentRange); + } + getTrailingDelimiterRange() { + return getTrailingDelimiter(this.editor, this.contentRange); + } + private get leadingDelimiterHighlightRange() { + return getLeadingDelimiter(this.editor, this.contentRange); + } + private get trailingDelimiterHighlightRange() { + return getTrailingDelimiter(this.editor, this.contentRange); + } + + getRemovalRange() { const delimiterRange = (() => { - const leadingDelimiterRange = this.leadingDelimiterRange; - const trailingDelimiterRange = this.trailingDelimiterRange; + const leadingDelimiterRange = this.getLeadingDelimiterRange(); + let trailingDelimiterRange = this.getTrailingDelimiterRange(); if (trailingDelimiterRange != null) { - const { document } = this.editor; - // Trailing delimiter to end of file. Need to remove leading new line delimiter - if ( - trailingDelimiterRange.end.line === document.lineCount - 1 && - leadingDelimiterRange != null - ) { - return new Range( - document.lineAt(this.contentRange.start.line - 1).range.end, - trailingDelimiterRange.end - ); - } return trailingDelimiterRange; } if (leadingDelimiterRange) { @@ -92,12 +58,16 @@ export default class ParagraphTarget extends BaseTarget { return undefined; })(); - return delimiterRange != null - ? this.contentRemovalRange.union(delimiterRange) - : this.contentRemovalRange; + const removalRange = + delimiterRange != null + ? this.contentRemovalRange.union(delimiterRange) + : this.contentRemovalRange; + + // Check if there is a new line delimiter to remove as well + return addLineDelimiterRanges(this.editor, removalRange); } - getRemovalHighlightRange(): Range | undefined { + getRemovalHighlightRange() { const delimiterRange = this.trailingDelimiterHighlightRange ?? this.leadingDelimiterHighlightRange; @@ -106,74 +76,104 @@ export default class ParagraphTarget extends BaseTarget { : this.contentRemovalRange; } - cloneWith(parameters: CloneWithParameters): ParagraphTarget { - return new ParagraphTarget({ ...this.state, ...parameters }); + cloneWith(parameters: CloneWithParameters) { + return new ParagraphTarget({ + ...this.getCloneParameters(), + ...parameters, + }); + } + + createContinuousRangeTarget( + isReversed: boolean, + endTarget: Target, + includeStart: boolean, + includeEnd: boolean + ): Target { + if (this.isSameType(endTarget)) { + return new ParagraphTarget({ + ...this.getCloneParameters(), + isReversed, + contentRange: createContinuousLineRange( + this, + endTarget, + includeStart, + includeEnd + ), + }); + } + + if (endTarget.is("line")) { + return new LineTarget({ + editor: this.editor, + isReversed, + contentRange: createContinuousLineRange( + this, + endTarget, + includeStart, + includeEnd + ), + }); + } + + return createContinuousRangeWeakTarget( + isReversed, + this, + endTarget, + includeStart, + includeEnd + ); + } + + protected getCloneParameters() { + return this.state; } } -function getLeadingDelimiter( - editor: TextEditor, - removalRange: Range, - keepLastNewline: boolean -) { +function getLeadingDelimiter(editor: TextEditor, contentRange: Range) { const { document } = editor; const { lineAt } = document; - const startLine = lineAt(removalRange.start); + const startLine = lineAt(contentRange.start); const leadingLine = getPreviousNonEmptyLine(document, startLine); + // Lines are next to each other so they can be no delimiter range if (leadingLine != null) { - const startPosition = keepLastNewline - ? leadingLine.range.end - : leadingLine.range.end.translate({ lineDelta: 1 }); - return { - range: new Range(startPosition, startLine.range.start), - highlight: new Range( - lineAt(leadingLine.lineNumber + 1).range.start, - lineAt(startLine.lineNumber - 1).range.end - ), - }; + if (leadingLine.lineNumber + 1 === startLine.lineNumber) { + return undefined; + } + return new Range( + new Position(leadingLine.lineNumber + 1, 0), + lineAt(startLine.lineNumber - 1).range.end + ); } + // Leading delimiter to start of file if (startLine.lineNumber > 0) { - const { start } = lineAt(0).range; - return { - range: new Range(start, startLine.range.start), - highlight: new Range(start, lineAt(startLine.lineNumber - 1).range.end), - }; + return new Range( + new Position(0, 0), + lineAt(startLine.lineNumber - 1).range.end + ); } return undefined; } -function getTrailingDelimiter( - editor: TextEditor, - removalRange: Range, - keepLastNewline: boolean -) { +function getTrailingDelimiter(editor: TextEditor, contentRange: Range) { const { document } = editor; const { lineAt } = document; - const endLine = lineAt(removalRange.end); + const endLine = lineAt(contentRange.end); const trailingLine = getNextNonEmptyLine(document, endLine); if (trailingLine != null) { - const endPosition = keepLastNewline - ? trailingLine.range.start - : trailingLine.range.start.translate({ lineDelta: -1 }); - return { - range: new Range(endLine.range.end, endPosition), - highlight: new Range( - lineAt(endLine.lineNumber + 1).range.start, - lineAt(trailingLine.lineNumber - 1).range.end - ), - }; + if (trailingLine.lineNumber - 1 === endLine.lineNumber) { + return undefined; + } + return new Range( + new Position(endLine.lineNumber + 1, 0), + lineAt(trailingLine.lineNumber - 1).range.end + ); } + // Trailing delimiter to end of file if (endLine.lineNumber < document.lineCount - 1) { - const lastLine = lineAt(document.lineCount - 1); - // If true there is an empty line after this one that isn't the last/final one - const highlightStart = - endLine.lineNumber !== document.lineCount - 1 - ? lineAt(endLine.lineNumber + 1).range.end - : lastLine.range.start; - return { - range: new Range(endLine.range.end, lastLine.range.end), - highlight: new Range(highlightStart, lastLine.range.end), - }; + return new Range( + new Position(endLine.lineNumber + 1, 0), + lineAt(document.lineCount - 1).range.end + ); } return undefined; } diff --git a/src/processTargets/targets/PositionTarget.ts b/src/processTargets/targets/PositionTarget.ts new file mode 100644 index 0000000000..cc88c0fbec --- /dev/null +++ b/src/processTargets/targets/PositionTarget.ts @@ -0,0 +1,97 @@ +import { Position, Target, TargetType } from "../../typings/target.types"; +import { createContinuousRange } from "../targetUtil/createContinuousRange"; +import BaseTarget, { + CloneWithParameters, + CommonTargetParameters, +} from "./BaseTarget"; +import { createContinuousRangeWeakTarget } from "./WeakTarget"; + +interface PositionTargetParameters extends CommonTargetParameters { + readonly position: Position; + readonly delimiter?: string; +} + +export default class PositionTarget extends BaseTarget { + private position_: Position; + private delimiter_: string | undefined; + + constructor(parameters: PositionTargetParameters) { + super(parameters); + this.position_ = parameters.position; + this.delimiter_ = parameters.delimiter; + } + + get type(): TargetType { + return "position"; + } + get delimiter() { + return this.delimiter_; + } + get position() { + return this.position_; + } + + getLeadingDelimiterRange() { + return undefined; + } + getTrailingDelimiterRange() { + return undefined; + } + + maybeAddDelimiter(text: string): string { + if (this.delimiter == null) { + return text; + } + switch (this.position) { + case "before": + return text + this.delimiter; + case "after": + return this.delimiter + text; + default: + return text; + } + } + + cloneWith(parameters: CloneWithParameters) { + return new PositionTarget({ + ...this.getCloneParameters(), + ...parameters, + }); + } + + createContinuousRangeTarget( + isReversed: boolean, + endTarget: Target, + includeStart: boolean, + includeEnd: boolean + ): Target { + if (this.isSameType(endTarget)) { + return new PositionTarget({ + ...this.getCloneParameters(), + isReversed, + contentRange: createContinuousRange( + this, + endTarget, + includeStart, + includeEnd + ), + }); + } + + return createContinuousRangeWeakTarget( + isReversed, + this, + endTarget, + includeStart, + includeEnd + ); + } + + protected getCloneParameters() { + return { + ...this.state, + position: this.position_, + delimiter: this.delimiter_, + }; + } +} diff --git a/src/processTargets/targets/RawSelectionTarget.ts b/src/processTargets/targets/RawSelectionTarget.ts index 77b8b85aa9..7a53efe167 100644 --- a/src/processTargets/targets/RawSelectionTarget.ts +++ b/src/processTargets/targets/RawSelectionTarget.ts @@ -1,19 +1,65 @@ +import { Target, TargetType } from "../../typings/target.types"; +import { createContinuousRange } from "../targetUtil/createContinuousRange"; import BaseTarget, { CloneWithParameters, CommonTargetParameters, - extractCommonParameters, } from "./BaseTarget"; +import { createContinuousRangeWeakTarget } from "./WeakTarget"; export default class RawSelectionTarget extends BaseTarget { constructor(parameters: CommonTargetParameters) { - super({ ...extractCommonParameters(parameters), delimiter: "" }); + super(parameters); } + get type(): TargetType { + return "rawSelection"; + } get delimiter() { return undefined; } + getLeadingDelimiterRange() { + return undefined; + } + getTrailingDelimiterRange() { + return undefined; + } + + cloneWith(parameters: CloneWithParameters) { + return new RawSelectionTarget({ + ...this.getCloneParameters(), + ...parameters, + }); + } + + createContinuousRangeTarget( + isReversed: boolean, + endTarget: Target, + includeStart: boolean, + includeEnd: boolean + ): Target { + if (this.isSameType(endTarget)) { + return new RawSelectionTarget({ + ...this.getCloneParameters(), + isReversed, + contentRange: createContinuousRange( + this, + endTarget, + includeStart, + includeEnd + ), + }); + } + + return createContinuousRangeWeakTarget( + isReversed, + this, + endTarget, + includeStart, + includeEnd + ); + } - cloneWith(parameters: CloneWithParameters): RawSelectionTarget { - return new RawSelectionTarget({ ...this.state, ...parameters }); + protected getCloneParameters() { + return this.state; } } diff --git a/src/processTargets/targets/ScopeTypeTarget.ts b/src/processTargets/targets/ScopeTypeTarget.ts index e23696e7e6..aa118c03da 100644 --- a/src/processTargets/targets/ScopeTypeTarget.ts +++ b/src/processTargets/targets/ScopeTypeTarget.ts @@ -1,10 +1,18 @@ import { Range } from "vscode"; -import { SimpleScopeTypeType } from "../../typings/target.types"; +import { + SimpleScopeTypeType, + Target, + TargetType, +} from "../../typings/target.types"; +import { + createContinuousRange, + createContinuousRangeFromRanges, +} from "../targetUtil/createContinuousRange"; import BaseTarget, { CloneWithParameters, CommonTargetParameters, - extractCommonParameters, } from "./BaseTarget"; +import { createContinuousRangeWeakTarget } from "./WeakTarget"; export interface ScopeTypeTargetParameters extends CommonTargetParameters { readonly scopeTypeType: SimpleScopeTypeType; @@ -15,49 +23,109 @@ export interface ScopeTypeTargetParameters extends CommonTargetParameters { } export default class ScopeTypeTarget extends BaseTarget { + private scopeTypeType_: SimpleScopeTypeType; private contentRemovalRange_?: Range; private leadingDelimiterRange_?: Range; private trailingDelimiterRange_?: Range; private hasDelimiterRange_: boolean; + private delimiter_: string; constructor(parameters: ScopeTypeTargetParameters) { - super({ - ...extractCommonParameters(parameters), - delimiter: parameters.delimiter ?? getDelimiter(parameters.scopeTypeType), - }); + super(parameters); + this.scopeTypeType_ = parameters.scopeTypeType; this.contentRemovalRange_ = parameters.contentRemovalRange; this.leadingDelimiterRange_ = parameters.leadingDelimiterRange; this.trailingDelimiterRange_ = parameters.trailingDelimiterRange; + this.delimiter_ = + parameters.delimiter ?? getDelimiter(parameters.scopeTypeType); this.hasDelimiterRange_ = !!this.leadingDelimiterRange_ || !!this.trailingDelimiterRange_; } - get contentRemovalRange() { + get type(): TargetType { + return "scopeType"; + } + get delimiter() { + return this.delimiter_; + } + protected get contentRemovalRange() { return this.contentRemovalRange_ ?? this.contentRange; } - get leadingDelimiterRange() { + getLeadingDelimiterRange() { if (this.hasDelimiterRange_) { return this.leadingDelimiterRange_; } - return super.leadingDelimiterRange; + return super.getLeadingDelimiterRange(); } - get trailingDelimiterRange() { + getTrailingDelimiterRange() { if (this.hasDelimiterRange_) { return this.trailingDelimiterRange_; } - return super.trailingDelimiterRange; + return super.getTrailingDelimiterRange(); } - cloneWith(parameters: CloneWithParameters): ScopeTypeTarget { + cloneWith(parameters: CloneWithParameters) { return new ScopeTypeTarget({ - ...(this.state), + ...this.getCloneParameters(), + ...parameters, + }); + } + + createContinuousRangeTarget( + isReversed: boolean, + endTarget: Target, + includeStart: boolean, + includeEnd: boolean + ): Target { + if (this.isSameType(endTarget)) { + const scopeTarget = endTarget; + if (this.scopeTypeType_ === scopeTarget.scopeTypeType_) { + const contentRemovalRange = + this.contentRemovalRange_ != null || + scopeTarget.contentRemovalRange_ != null + ? createContinuousRangeFromRanges( + this.contentRemovalRange_ ?? this.contentRange, + scopeTarget.contentRemovalRange_ ?? scopeTarget.contentRange, + includeStart, + includeEnd + ) + : undefined; + + return new ScopeTypeTarget({ + ...this.getCloneParameters(), + isReversed, + leadingDelimiterRange: this.leadingDelimiterRange_, + trailingDelimiterRange: scopeTarget.trailingDelimiterRange_, + contentRemovalRange, + contentRange: createContinuousRange( + this, + endTarget, + includeStart, + includeEnd + ), + }); + } + } + + return createContinuousRangeWeakTarget( + isReversed, + this, + endTarget, + includeStart, + includeEnd + ); + } + + protected getCloneParameters() { + return { + ...this.state, + scopeTypeType: this.scopeTypeType_, contentRemovalRange: this.contentRemovalRange_, leadingDelimiterRange: this.leadingDelimiterRange_, trailingDelimiterRange: this.trailingDelimiterRange_, - ...parameters, - }); + }; } } @@ -67,8 +135,8 @@ function getDelimiter(scopeType: SimpleScopeTypeType): string { case "statement": case "ifStatement": return "\n"; - case "namedFunction": case "class": + case "namedFunction": return "\n\n"; default: return " "; diff --git a/src/processTargets/targets/SurroundingPairTarget.ts b/src/processTargets/targets/SurroundingPairTarget.ts index 08c0bbafcc..cb1db74489 100644 --- a/src/processTargets/targets/SurroundingPairTarget.ts +++ b/src/processTargets/targets/SurroundingPairTarget.ts @@ -1,11 +1,11 @@ import { Range } from "vscode"; -import { Target } from "../../typings/target.types"; +import { Target, TargetType } from "../../typings/target.types"; +import { createContinuousRange } from "../targetUtil/createContinuousRange"; import BaseTarget, { CloneWithParameters, CommonTargetParameters, - extractCommonParameters, } from "./BaseTarget"; -import WeakTarget from "./WeakTarget"; +import WeakTarget, { createContinuousRangeWeakTarget } from "./WeakTarget"; interface SurroundingPairTargetParameters extends CommonTargetParameters { /** @@ -28,18 +28,19 @@ export default class SurroundingPairTarget extends BaseTarget { private boundary_: [Range, Range]; constructor(parameters: SurroundingPairTargetParameters) { - super({ - ...extractCommonParameters(parameters), - delimiter: " ", - }); + super(parameters); this.boundary_ = parameters.boundary; this.interiorRange_ = parameters.interiorRange; } - getInteriorStrict(): Target[] { - if (this.interiorRange_ == null || this.position != null) { - super.getInteriorStrict(); - } + get type(): TargetType { + return "surroundingPair"; + } + get delimiter() { + return " "; + } + + getInteriorStrict() { return [ new WeakTarget({ editor: this.editor, @@ -49,10 +50,7 @@ export default class SurroundingPairTarget extends BaseTarget { ]; } - getBoundaryStrict(): Target[] { - if (this.boundary_ == null || this.position != null) { - throw Error("No available boundaries"); - } + getBoundaryStrict() { return this.boundary_.map( (contentRange) => new WeakTarget({ @@ -63,12 +61,46 @@ export default class SurroundingPairTarget extends BaseTarget { ); } - cloneWith(parameters: CloneWithParameters): SurroundingPairTarget { + cloneWith(parameters: CloneWithParameters) { return new SurroundingPairTarget({ + ...this.getCloneParameters(), + ...parameters, + }); + } + + createContinuousRangeTarget( + isReversed: boolean, + endTarget: Target, + includeStart: boolean, + includeEnd: boolean + ): Target { + if (this.isSameType(endTarget)) { + return new SurroundingPairTarget({ + ...this.getCloneParameters(), + isReversed, + contentRange: createContinuousRange( + this, + endTarget, + includeStart, + includeEnd + ), + }); + } + + return createContinuousRangeWeakTarget( + isReversed, + this, + endTarget, + includeStart, + includeEnd + ); + } + + protected getCloneParameters() { + return { ...this.state, interiorRange: this.interiorRange_, boundary: this.boundary_, - ...parameters, - }); + }; } } diff --git a/src/processTargets/targets/TokenTarget.ts b/src/processTargets/targets/TokenTarget.ts index a3da513ce1..4c8c7b8ae1 100644 --- a/src/processTargets/targets/TokenTarget.ts +++ b/src/processTargets/targets/TokenTarget.ts @@ -1,18 +1,59 @@ +import { Target, TargetType } from "../../typings/target.types"; +import { createContinuousRange } from "../targetUtil/createContinuousRange"; import BaseTarget, { CloneWithParameters, CommonTargetParameters, - extractCommonParameters, } from "./BaseTarget"; +import { createContinuousRangeWeakTarget } from "./WeakTarget"; export default class TokenTarget extends BaseTarget { constructor(parameters: CommonTargetParameters) { - super({ - ...extractCommonParameters(parameters), - delimiter: " ", + super(parameters); + } + + get type(): TargetType { + return "token"; + } + get delimiter() { + return " "; + } + + cloneWith(parameters: CloneWithParameters) { + return new TokenTarget({ + ...this.getCloneParameters(), + ...parameters, }); } - cloneWith(parameters: CloneWithParameters): TokenTarget { - return new TokenTarget({ ...this.state, ...parameters }); + createContinuousRangeTarget( + isReversed: boolean, + endTarget: Target, + includeStart: boolean, + includeEnd: boolean + ): Target { + if (this.isSameType(endTarget)) { + return new TokenTarget({ + ...this.getCloneParameters(), + isReversed, + contentRange: createContinuousRange( + this, + endTarget, + includeStart, + includeEnd + ), + }); + } + + return createContinuousRangeWeakTarget( + isReversed, + this, + endTarget, + includeStart, + includeEnd + ); + } + + protected getCloneParameters() { + return this.state; } } diff --git a/src/processTargets/targets/WeakTarget.ts b/src/processTargets/targets/WeakTarget.ts index b42da0240f..87a5626009 100644 --- a/src/processTargets/targets/WeakTarget.ts +++ b/src/processTargets/targets/WeakTarget.ts @@ -1,7 +1,8 @@ +import { Target, TargetType } from "../../typings/target.types"; +import { createContinuousRange } from "../targetUtil/createContinuousRange"; import BaseTarget, { CloneWithParameters, CommonTargetParameters, - extractCommonParameters, } from "./BaseTarget"; /** @@ -11,17 +12,58 @@ import BaseTarget, { */ export default class WeakTarget extends BaseTarget { constructor(parameters: CommonTargetParameters) { - super({ - ...extractCommonParameters(parameters), - delimiter: " ", + super(parameters); + } + + get type(): TargetType { + return "weak"; + } + get delimiter() { + return " "; + } + + cloneWith(parameters: CloneWithParameters) { + return new WeakTarget({ + ...this.getCloneParameters(), + ...parameters, }); } - get isWeak() { - return true; + createContinuousRangeTarget( + isReversed: boolean, + endTarget: Target, + includeStart: boolean, + includeEnd: boolean + ): Target { + return createContinuousRangeWeakTarget( + isReversed, + this, + endTarget, + includeStart, + includeEnd + ); } - cloneWith(parameters: CloneWithParameters): WeakTarget { - return new WeakTarget({ ...this.state, ...parameters }); + protected getCloneParameters() { + return this.state; } } + +export function createContinuousRangeWeakTarget( + isReversed: boolean, + startTarget: Target, + endTarget: Target, + includeStart: boolean, + includeEnd: boolean +): WeakTarget { + return new WeakTarget({ + editor: startTarget.editor, + isReversed, + contentRange: createContinuousRange( + startTarget, + endTarget, + includeStart, + includeEnd + ), + }); +} diff --git a/src/test/suite/fixtures/recorded/decorations/chuckBlockAir.yml b/src/test/suite/fixtures/recorded/decorations/chuckBlockAir.yml new file mode 100644 index 0000000000..17523b1b2d --- /dev/null +++ b/src/test/suite/fixtures/recorded/decorations/chuckBlockAir.yml @@ -0,0 +1,47 @@ +languageId: plaintext +command: + spokenForm: chuck block air + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: a} + modifiers: + - type: containingScope + scopeType: {type: paragraph} + usePrePhraseSnapshot: true + action: {name: remove} +initialState: + documentContents: | + + a + a + + + b c + d e + f g + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: + default.a: + start: {line: 1, character: 0} + end: {line: 1, character: 1} +finalState: + documentContents: | + + b c + d e + f g + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} +decorations: + - name: pendingDeleteBackground + type: line + start: {line: 1, character: 0} + end: {line: 4, character: 0} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: a}, modifiers: [{type: containingScope, scopeType: {type: paragraph}}]}] diff --git a/src/test/suite/fixtures/recorded/decorations/chuckBlockAirUntilBatt.yml b/src/test/suite/fixtures/recorded/decorations/chuckBlockAirUntilBatt.yml new file mode 100644 index 0000000000..6fcc5a49d4 --- /dev/null +++ b/src/test/suite/fixtures/recorded/decorations/chuckBlockAirUntilBatt.yml @@ -0,0 +1,56 @@ +languageId: plaintext +command: + spokenForm: chuck block air until batt + version: 2 + targets: + - type: range + anchor: + type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: a} + modifiers: + - type: containingScope + scopeType: {type: paragraph} + active: + type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: b} + excludeAnchor: false + excludeActive: true + usePrePhraseSnapshot: true + action: {name: remove} +initialState: + documentContents: | + + a + a + + + b c + d e + f g + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: + default.a: + start: {line: 1, character: 0} + end: {line: 1, character: 1} + default.b: + start: {line: 5, character: 0} + end: {line: 5, character: 1} +finalState: + documentContents: | + b c + d e + f g + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} +decorations: + - name: pendingDeleteBackground + type: line + start: {line: 0, character: 0} + end: {line: 4, character: 0} +fullTargets: [{type: range, excludeAnchor: false, excludeActive: true, rangeType: continuous, anchor: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: a}, modifiers: &ref_0 [{type: containingScope, scopeType: {type: paragraph}}]}, active: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: b}, modifiers: *ref_0}}] diff --git a/src/test/suite/fixtures/recorded/decorations/chuckBlockBatt.yml b/src/test/suite/fixtures/recorded/decorations/chuckBlockBatt.yml new file mode 100644 index 0000000000..62fb4e3e4a --- /dev/null +++ b/src/test/suite/fixtures/recorded/decorations/chuckBlockBatt.yml @@ -0,0 +1,47 @@ +languageId: plaintext +command: + spokenForm: chuck block batt + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: b} + modifiers: + - type: containingScope + scopeType: {type: paragraph} + usePrePhraseSnapshot: true + action: {name: remove} +initialState: + documentContents: | + + a + a + + + b c + d e + f g + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: + default.b: + start: {line: 5, character: 0} + end: {line: 5, character: 1} +finalState: + documentContents: |+ + + a + a + + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 4, character: 0} + active: {line: 4, character: 0} +decorations: + - name: pendingDeleteBackground + type: line + start: {line: 5, character: 0} + end: {line: 8, character: 0} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: b}, modifiers: [{type: containingScope, scopeType: {type: paragraph}}]}] diff --git a/src/test/suite/fixtures/recorded/decorations/chuckBlockBatt2.yml b/src/test/suite/fixtures/recorded/decorations/chuckBlockBatt2.yml new file mode 100644 index 0000000000..f5a16a3c1c --- /dev/null +++ b/src/test/suite/fixtures/recorded/decorations/chuckBlockBatt2.yml @@ -0,0 +1,39 @@ +languageId: plaintext +command: + spokenForm: chuck block batt + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: b} + modifiers: + - type: containingScope + scopeType: {type: paragraph} + usePrePhraseSnapshot: true + action: {name: remove} +initialState: + documentContents: |- + + b c + d e + f g + selections: + - anchor: {line: 3, character: 5} + active: {line: 3, character: 5} + marks: + default.b: + start: {line: 1, character: 0} + end: {line: 1, character: 1} +finalState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} +decorations: + - name: pendingDeleteBackground + type: line + start: {line: 0, character: 0} + end: {line: 3, character: 5} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: b}, modifiers: [{type: containingScope, scopeType: {type: paragraph}}]}] diff --git a/src/test/suite/fixtures/recorded/decorations/chuckBlockBattUntilAir.yml b/src/test/suite/fixtures/recorded/decorations/chuckBlockBattUntilAir.yml new file mode 100644 index 0000000000..f4ea08883f --- /dev/null +++ b/src/test/suite/fixtures/recorded/decorations/chuckBlockBattUntilAir.yml @@ -0,0 +1,56 @@ +languageId: plaintext +command: + spokenForm: chuck block batt until air + version: 2 + targets: + - type: range + anchor: + type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: b} + modifiers: + - type: containingScope + scopeType: {type: paragraph} + active: + type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: a} + excludeAnchor: false + excludeActive: true + usePrePhraseSnapshot: true + action: {name: remove} +initialState: + documentContents: | + + a + a + + + b c + d e + f g + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: + default.b: + start: {line: 5, character: 0} + end: {line: 5, character: 1} + default.a: + start: {line: 1, character: 0} + end: {line: 1, character: 1} +finalState: + documentContents: |- + + a + a + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 2, character: 1} + active: {line: 2, character: 1} +decorations: + - name: pendingDeleteBackground + type: line + start: {line: 3, character: 0} + end: {line: 8, character: 0} +fullTargets: [{type: range, excludeAnchor: false, excludeActive: true, rangeType: continuous, anchor: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: b}, modifiers: &ref_0 [{type: containingScope, scopeType: {type: paragraph}}]}, active: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: a}, modifiers: *ref_0}}] diff --git a/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToEndOfThisAndEndOfWhaleTakeWhale.yml b/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToEndOfThisAndEndOfWhaleTakeWhale.yml index 47adf5fb01..ba8dfd6fb6 100644 --- a/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToEndOfThisAndEndOfWhaleTakeWhale.yml +++ b/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToEndOfThisAndEndOfWhaleTakeWhale.yml @@ -54,8 +54,6 @@ finalState: thatMark: - anchor: {line: 0, character: 12} active: {line: 0, character: 18} - - anchor: {line: 0, character: 12} - active: {line: 0, character: 18} sourceMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 5} diff --git a/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhaleTakeWhale.yml b/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhaleTakeWhale.yml index a572792994..3d50804e9d 100644 --- a/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhaleTakeWhale.yml +++ b/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhaleTakeWhale.yml @@ -50,12 +50,10 @@ finalState: end: {line: 0, character: 5} default.w: start: {line: 0, character: 7} - end: {line: 0, character: 18} + end: {line: 0, character: 12} thatMark: - anchor: {line: 0, character: 12} active: {line: 0, character: 18} - - anchor: {line: 0, character: 12} - active: {line: 0, character: 18} sourceMark: - anchor: {line: 0, character: 5} active: {line: 0, character: 6} diff --git a/src/test/suite/fixtures/recorded/positions/chuckBeforeBlockAir.yml b/src/test/suite/fixtures/recorded/positions/chuckLeadingBlockAir.yml similarity index 92% rename from src/test/suite/fixtures/recorded/positions/chuckBeforeBlockAir.yml rename to src/test/suite/fixtures/recorded/positions/chuckLeadingBlockAir.yml index 3136f1fa2e..e806ead97b 100644 --- a/src/test/suite/fixtures/recorded/positions/chuckBeforeBlockAir.yml +++ b/src/test/suite/fixtures/recorded/positions/chuckLeadingBlockAir.yml @@ -1,12 +1,12 @@ languageId: plaintext command: - spokenForm: chuck before block air + spokenForm: chuck leading block air version: 2 targets: - type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: a} modifiers: - - {type: position, position: before} + - {type: delimiterRange, direction: leading} - type: containingScope scopeType: {type: paragraph} usePrePhraseSnapshot: true diff --git a/src/test/suite/fixtures/recorded/positions/chuckAfterBlockVest.yml b/src/test/suite/fixtures/recorded/positions/chuckTrailingBlockVest.yml similarity index 85% rename from src/test/suite/fixtures/recorded/positions/chuckAfterBlockVest.yml rename to src/test/suite/fixtures/recorded/positions/chuckTrailingBlockVest.yml index b88f3971c2..0b7a3665ed 100644 --- a/src/test/suite/fixtures/recorded/positions/chuckAfterBlockVest.yml +++ b/src/test/suite/fixtures/recorded/positions/chuckTrailingBlockVest.yml @@ -1,12 +1,12 @@ languageId: plaintext command: - spokenForm: chuck after block vest + spokenForm: chuck trailing block vest version: 2 targets: - type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: v} modifiers: - - {type: position, position: after} + - {type: delimiterRange, direction: trailing} - type: containingScope scopeType: {type: paragraph} usePrePhraseSnapshot: true @@ -33,6 +33,6 @@ finalState: - anchor: {line: 0, character: 0} active: {line: 0, character: 0} thatMark: - - anchor: {line: 1, character: 28} - active: {line: 1, character: 28} + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: v}, modifiers: [{type: position, position: after}, {type: containingScope, scopeType: {type: paragraph}}]}] diff --git a/src/test/suite/recorded.test.ts b/src/test/suite/recorded.test.ts index 56ee019cf7..90386c8fb4 100644 --- a/src/test/suite/recorded.test.ts +++ b/src/test/suite/recorded.test.ts @@ -18,6 +18,7 @@ import { rangeToPlainObject, SelectionPlainObject, SerializedMarks, + testDecorationsToPlainObject, } from "../../testUtil/toPlainObject"; import { Clipboard } from "../../util/Clipboard"; import { getCursorlessApi } from "../../util/getExtensionApi"; @@ -64,6 +65,7 @@ async function runTest(file: string) { const cursorlessApi = await getCursorlessApi(); const graph = cursorlessApi.graph!; + graph.editStyles.testDecorations = []; const editor = await openNewEditor( fixture.initialState.documentContents, @@ -155,7 +157,7 @@ async function runTest(file: string) { if (fixture.decorations != null) { assert.deepStrictEqual( - graph.editStyles.testDecorations, + testDecorationsToPlainObject(graph.editStyles.testDecorations), fixture.decorations, "Unexpected decorations" ); diff --git a/src/testUtil/TestCase.ts b/src/testUtil/TestCase.ts index ec8746b399..bafad84787 100644 --- a/src/testUtil/TestCase.ts +++ b/src/testUtil/TestCase.ts @@ -20,8 +20,8 @@ import { import { marksToPlainObject, PositionPlainObject, - positionToPlainObject, SerializedMarks, + testDecorationsToPlainObject, } from "./toPlainObject"; export type TestCaseCommand = CommandLatest; @@ -94,12 +94,7 @@ export class TestCase { recordDecorations() { const decorations = this.context.decorations; if (this.isDecorationsTest && decorations.length > 0) { - this.decorations = decorations.map(({ name, type, start, end }) => ({ - name, - type, - start: positionToPlainObject(start), - end: positionToPlainObject(end), - })); + this.decorations = testDecorationsToPlainObject(decorations); } } diff --git a/src/testUtil/toPlainObject.ts b/src/testUtil/toPlainObject.ts index 8d4ac974de..fe415bdb3f 100644 --- a/src/testUtil/toPlainObject.ts +++ b/src/testUtil/toPlainObject.ts @@ -1,4 +1,5 @@ import { Selection, Position, Range } from "vscode"; +import { TestDecoration } from "../core/editStyles"; import { Token } from "../typings/Types"; export type PositionPlainObject = { @@ -50,3 +51,12 @@ export function marksToPlainObject(marks: { ); return serializedMarks; } + +export function testDecorationsToPlainObject(decorations: TestDecoration[]) { + return decorations.map(({ name, type, start, end }) => ({ + name, + type, + start: positionToPlainObject(start), + end: positionToPlainObject(end), + })); +} diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 7b1f6ae4ec..221c1e2004 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -180,6 +180,13 @@ export interface PositionModifier { position: Position; } +export type DelimiterRangeDirection = "leading" | "trailing"; + +export interface DelimiterRangeModifier { + type: "delimiterRange"; + direction: DelimiterRangeDirection; +} + export interface PartialPrimitiveTargetDesc { type: "primitive"; mark?: Mark; @@ -196,7 +203,8 @@ export type Modifier = | OrdinalRangeModifier | HeadModifier | TailModifier - | RawSelectionModifier; + | RawSelectionModifier + | DelimiterRangeModifier; export interface PartialRangeTargetDesc { type: "range"; @@ -269,7 +277,23 @@ export interface EditNewDelimiterContext { export type EditNewContext = EditNewCommandContext | EditNewDelimiterContext; +export type TargetType = + | "delimiterRange" + | "document" + | "line" + | "notebookCell" + | "paragraph" + | "position" + | "rawSelection" + | "scopeType" + | "surroundingPair" + | "token" + | "weak"; + export interface Target { + /** The type of this target */ + readonly type: TargetType; + /** The text editor used for all ranges */ readonly editor: TextEditor; @@ -282,37 +306,39 @@ export interface Target { /** If this selection has a delimiter. For example, new line for a line or paragraph and comma for a list or argument */ readonly delimiter?: string; - /** The range to remove the content. This does not include any delimiters. */ - readonly contentRemovalRange: Range; - - /** The range of the delimiter before the content selection */ - readonly leadingDelimiterRange?: Range; - - /** The range of the delimiter after the content selection */ - readonly trailingDelimiterRange?: Range; - /** The current position */ readonly position?: Position; /** If true this target should be treated as a line */ readonly isLine: boolean; - /** If true this target should be treated as a paragraph */ - readonly isParagraph: boolean; - - /** If true this target is of weak type and should use inference/upgrade when needed. See {@link WeakTarget} for more info */ - readonly isWeak: boolean; - + /** The text contained in the content range */ readonly contentText: string; + + /** The content range and is reversed turned into a selection */ readonly contentSelection: Selection; + + /** Internal target that should be used for the that mark */ readonly thatTarget: Target; + /** Returns true if this target is of the given type */ + is(type: TargetType): boolean; getInteriorStrict(): Target[]; getBoundaryStrict(): Target[]; + /** Possibly add delimiter for positions before/after */ maybeAddDelimiter(text: string): string; + /** The range of the delimiter before the content selection */ + getLeadingDelimiterRange(force?: boolean): Range | undefined; + /** The range of the delimiter after the content selection */ + getTrailingDelimiterRange(force?: boolean): Range | undefined; getRemovalRange(): Range; getRemovalHighlightRange(): Range | undefined; getEditNewContext(isBefore: boolean): EditNewContext; - withPosition(position: Position): Target; withThatTarget(thatTarget: Target): Target; + createContinuousRangeTarget( + isReversed: boolean, + endTarget: Target, + includeStart: boolean, + includeEnd: boolean + ): Target; } From a815abf9798ac02003e36d4bef338cb82067bff5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 29 May 2022 01:28:33 +0000 Subject: [PATCH 240/314] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fb5f1b3a29..b7b49b92b8 100644 --- a/package.json +++ b/package.json @@ -542,4 +542,4 @@ "immutability-helper": "^3.1.1", "lodash": "^4.17.21" } -} \ No newline at end of file +} From 35f06f664749b1430209ca90e7ff4680efa0ea50 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 29 May 2022 05:59:05 +0200 Subject: [PATCH 241/314] Create edits in actual targets --- src/actions/BringMoveSwap.ts | 46 +++------ src/actions/Replace.ts | 5 +- src/processTargets/targets/BaseTarget.ts | 17 +++- src/processTargets/targets/PositionTarget.ts | 98 ++++++++++++++++--- .../bringAirAndBatAndCapToAfterDrum.yml | 2 +- src/typings/Types.ts | 4 + src/typings/target.types.ts | 7 +- 7 files changed, 130 insertions(+), 49 deletions(-) diff --git a/src/actions/BringMoveSwap.ts b/src/actions/BringMoveSwap.ts index f26c0f90b5..cc8935a4b9 100644 --- a/src/actions/BringMoveSwap.ts +++ b/src/actions/BringMoveSwap.ts @@ -5,7 +5,8 @@ import { performEditsAndUpdateFullSelectionInfos, } from "../core/updateSelections/updateSelections"; import { Target } from "../typings/target.types"; -import { Edit, Graph } from "../typings/Types"; +import { EditWithRangeUpdater, Graph } from "../typings/Types"; +import { selectionFromRange } from "../util/selectionUtils"; import { setSelectionsWithoutFocusingEditor } from "../util/setSelectionsAndFocusEditor"; import { getContentRange, @@ -17,7 +18,8 @@ import { Action, ActionReturnValue } from "./actions.types"; type ActionType = "bring" | "move" | "swap"; -interface ExtendedEdit extends Edit { +interface ExtendedEdit { + edit: EditWithRangeUpdater; editor: TextEditor; isSource: boolean; originalTarget: Target; @@ -101,27 +103,19 @@ class BringMoveSwap implements Action { text = sources .map((source, i) => { const text = source.contentText; - const containingListDelimiter = - destination.delimiter ?? source.delimiter; - return i > 0 && containingListDelimiter - ? containingListDelimiter + text - : text; + const delimiter = destination.delimiter ?? source.delimiter; + return i > 0 && delimiter != null ? delimiter + text : text; }) .join(""); - text = destination.maybeAddDelimiter(text); } else { - // Get text adjusting for destination position - text = getTextWithPossibleDelimiter(source, destination); + text = source.contentText; } // Add destination edit results.push({ - range: destination.contentRange, - text, + edit: destination.constructChangeEdit(text), editor: destination.editor, originalTarget: destination, isSource: false, - isReplace: - destination.position === "after" || destination.position === "end", }); } else { destination = destinations[0]; @@ -133,12 +127,10 @@ class BringMoveSwap implements Action { usedSources.push(source); if (this.type !== "move") { results.push({ - range: source.contentRange, - text: destination.contentText, + edit: source.constructChangeEdit(destination.contentText), editor: source.editor, originalTarget: source, isSource: true, - isReplace: false, }); } } @@ -148,12 +140,10 @@ class BringMoveSwap implements Action { // Unify overlapping targets. unifyRemovalTargets(usedSources).forEach((source) => { results.push({ - range: source.getRemovalRange(), - text: "", + edit: source.constructRemovalEdit(), editor: source.editor, originalTarget: source, isSource: true, - isReplace: false, }); }); } @@ -195,7 +185,7 @@ class BringMoveSwap implements Action { await performEditsAndUpdateFullSelectionInfos( this.graph.rangeUpdater, editor, - filteredEdits, + filteredEdits.map(({ edit }) => edit), [editSelectionInfos, cursorSelectionInfos] ); @@ -203,11 +193,13 @@ class BringMoveSwap implements Action { return edits.map((edit, index): MarkEntry => { const selection = updatedEditSelections[index]; + const range = edit.edit.updateRange(selection); + const target = edit.originalTarget; return { editor, - selection, - isSource: edit!.isSource, - target: edit!.originalTarget, + selection: selectionFromRange(target.isReversed, range), + isSource: edit.isSource, + target, }; }); } @@ -288,9 +280,3 @@ export class Swap extends BringMoveSwap { super(graph, "swap"); } } - -/** Get text from selection. Possibly add delimiter for positions before/after */ -function getTextWithPossibleDelimiter(source: Target, destination: Target) { - const sourceText = source.contentText; - return destination.maybeAddDelimiter(sourceText); -} diff --git a/src/actions/Replace.ts b/src/actions/Replace.ts index 256a0630ca..c96a306a77 100644 --- a/src/actions/Replace.ts +++ b/src/actions/Replace.ts @@ -46,9 +46,8 @@ export default class implements Action { } const edits = zip(targets, texts).map(([target, text]) => ({ + edit: target!.constructChangeEdit(text!), editor: target!.editor, - range: target!.contentRange, - text: target!.maybeAddDelimiter(text!), })); const thatMark = flatten( @@ -59,7 +58,7 @@ export default class implements Action { const [updatedSelections] = await performEditsAndUpdateSelections( this.graph.rangeUpdater, editor, - edits, + edits.map(({ edit }) => edit), [targets.map((target) => target.contentSelection)] ); diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index d687e407cb..7480ece387 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -5,6 +5,7 @@ import { Target, TargetType, } from "../../typings/target.types"; +import { EditWithRangeUpdater } from "../../typings/Types"; import { selectionFromRange } from "../../util/selectionUtils"; import { getTokenDelimiters } from "../targetUtil/getTokenDelimiters"; @@ -88,8 +89,20 @@ export default abstract class BaseTarget implements Target { : undefined; } - maybeAddDelimiter(text: string): string { - return text; + constructChangeEdit(text: string): EditWithRangeUpdater { + return { + range: this.contentRange, + text, + updateRange: (range) => range, + }; + } + + constructRemovalEdit(): EditWithRangeUpdater { + return { + range: this.contentRange, + text: "", + updateRange: (range) => range, + }; } getEditNewContext(isBefore: boolean): EditNewContext { diff --git a/src/processTargets/targets/PositionTarget.ts b/src/processTargets/targets/PositionTarget.ts index cc88c0fbec..8a65e09808 100644 --- a/src/processTargets/targets/PositionTarget.ts +++ b/src/processTargets/targets/PositionTarget.ts @@ -1,4 +1,6 @@ +import { Position as VS_Position, Range, TextEditor } from "vscode"; import { Position, Target, TargetType } from "../../typings/target.types"; +import { EditWithRangeUpdater } from "../../typings/Types"; import { createContinuousRange } from "../targetUtil/createContinuousRange"; import BaseTarget, { CloneWithParameters, @@ -38,18 +40,59 @@ export default class PositionTarget extends BaseTarget { return undefined; } - maybeAddDelimiter(text: string): string { - if (this.delimiter == null) { - return text; - } - switch (this.position) { - case "before": - return text + this.delimiter; - case "after": - return this.delimiter + text; - default: - return text; + private constructReplaceEdit(text: string): EditWithRangeUpdater { + return { + range: this.contentRange, + text, + updateRange: (range) => range, + }; + } + + private constructInsertionEdit(text: string): EditWithRangeUpdater { + const delimiter = this.delimiter!; + const isLine = delimiter.includes("\n"); + const isBefore = this.position === "before"; + + const range = getEditRange( + this.editor, + this.contentRange, + isLine, + isBefore + ); + const padding = isLine ? getLinePadding(this.editor, range, isBefore) : ""; + + const editText = isBefore + ? text + delimiter + padding + : delimiter + padding + text; + + const updateRange = (range: Range) => { + const startOffset = this.editor.document.offsetAt(range.start); + const startIndex = isBefore + ? startOffset + : startOffset + delimiter.length + padding.length; + const endIndex = startIndex + text.length; + return new Range( + this.editor.document.positionAt(startIndex), + this.editor.document.positionAt(endIndex) + ); + }; + + return { + range: this.contentRange, + text: editText, + isReplace: this.position === "after", + updateRange, + }; + } + + constructChangeEdit(text: string): EditWithRangeUpdater { + if ( + this.delimiter != null && + (this.position === "before" || this.position === "after") + ) { + return this.constructInsertionEdit(text); } + return this.constructReplaceEdit(text); } cloneWith(parameters: CloneWithParameters) { @@ -95,3 +138,36 @@ export default class PositionTarget extends BaseTarget { }; } } + +function getLinePadding(editor: TextEditor, range: Range, isBefore: boolean) { + const line = editor.document.lineAt(isBefore ? range.start : range.end); + const characterIndex = line.isEmptyOrWhitespace + ? range.start.character + : line.firstNonWhitespaceCharacterIndex; + return line.text.slice(0, characterIndex); +} + +function getEditRange( + editor: TextEditor, + range: Range, + isLine: boolean, + isBefore: boolean +) { + let position: VS_Position; + if (isLine) { + const line = editor.document.lineAt(isBefore ? range.start : range.end); + if (isBefore) { + position = line.isEmptyOrWhitespace + ? range.start + : new VS_Position( + line.lineNumber, + line.firstNonWhitespaceCharacterIndex + ); + } else { + position = line.range.end; + } + } else { + position = isBefore ? range.start : range.end; + } + return new Range(position, position); +} diff --git a/src/test/suite/fixtures/recorded/actions/bringAirAndBatAndCapToAfterDrum.yml b/src/test/suite/fixtures/recorded/actions/bringAirAndBatAndCapToAfterDrum.yml index 677b64079d..87e39a9618 100644 --- a/src/test/suite/fixtures/recorded/actions/bringAirAndBatAndCapToAfterDrum.yml +++ b/src/test/suite/fixtures/recorded/actions/bringAirAndBatAndCapToAfterDrum.yml @@ -49,7 +49,7 @@ finalState: - anchor: {line: 5, character: 0} active: {line: 5, character: 0} thatMark: - - anchor: {line: 4, character: 1} + - anchor: {line: 4, character: 2} active: {line: 4, character: 7} sourceMark: - anchor: {line: 0, character: 0} diff --git a/src/typings/Types.ts b/src/typings/Types.ts index e6a902261a..00cc00bcef 100644 --- a/src/typings/Types.ts +++ b/src/typings/Types.ts @@ -180,3 +180,7 @@ export interface Edit { */ isReplace?: boolean; } + +export interface EditWithRangeUpdater extends Edit { + updateRange: (range: vscode.Range) => vscode.Range; +} diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 221c1e2004..594882ed64 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -1,5 +1,6 @@ import { Range, Selection, TextEditor } from "vscode"; import { HatStyleName } from "../core/constants"; +import { EditWithRangeUpdater } from "./Types"; export interface CursorMark { type: "cursor"; @@ -325,8 +326,6 @@ export interface Target { is(type: TargetType): boolean; getInteriorStrict(): Target[]; getBoundaryStrict(): Target[]; - /** Possibly add delimiter for positions before/after */ - maybeAddDelimiter(text: string): string; /** The range of the delimiter before the content selection */ getLeadingDelimiterRange(force?: boolean): Range | undefined; /** The range of the delimiter after the content selection */ @@ -341,4 +340,8 @@ export interface Target { includeStart: boolean, includeEnd: boolean ): Target; + /** Constructs change/insertion edit. Adds delimiter before/after if needed */ + constructChangeEdit(text: string): EditWithRangeUpdater; + /** Constructs removal edit */ + constructRemovalEdit(): EditWithRangeUpdater; } From 3fc9dec700b5a6a7f0cc8af6f13afde0be80c086 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 29 May 2022 09:50:02 +0200 Subject: [PATCH 242/314] Use object oriented targets to construct edits --- src/actions/BringMoveSwap.ts | 10 +- src/actions/Clear.ts | 7 +- src/actions/EditNew.ts | 70 +++++++--- src/actions/InsertCopy.ts | 51 ++++--- src/actions/InsertEmptyLines.ts | 93 +++++++------ src/actions/Remove.ts | 28 +--- src/core/editStyles.ts | 57 ++++---- src/core/updateSelections/updateSelections.ts | 42 +++++- src/processTargets/modifiers/PositionStage.ts | 76 ++++++----- .../modifiers/RawSelectionStage.ts | 16 ++- .../modifiers/scopeTypeStages/LineStage.ts | 24 ++-- src/processTargets/targets/BaseTarget.ts | 7 +- src/typings/target.types.ts | 1 + src/util/targetUtils.ts | 4 - src/util/textInsertion.ts | 127 ------------------ src/util/unifyRanges.ts | 6 +- 16 files changed, 275 insertions(+), 344 deletions(-) delete mode 100644 src/util/textInsertion.ts diff --git a/src/actions/BringMoveSwap.ts b/src/actions/BringMoveSwap.ts index cc8935a4b9..4706fb0e37 100644 --- a/src/actions/BringMoveSwap.ts +++ b/src/actions/BringMoveSwap.ts @@ -8,11 +8,7 @@ import { Target } from "../typings/target.types"; import { EditWithRangeUpdater, Graph } from "../typings/Types"; import { selectionFromRange } from "../util/selectionUtils"; import { setSelectionsWithoutFocusingEditor } from "../util/setSelectionsAndFocusEditor"; -import { - getContentRange, - getRemovalRange, - runForEachEditor, -} from "../util/targetUtils"; +import { getContentRange, runForEachEditor } from "../util/targetUtils"; import { unifyRemovalTargets } from "../util/unifyRanges"; import { Action, ActionReturnValue } from "./actions.types"; @@ -280,3 +276,7 @@ export class Swap extends BringMoveSwap { super(graph, "swap"); } } + +function getRemovalRange(target: Target) { + return target.getRemovalRange(); +} diff --git a/src/actions/Clear.ts b/src/actions/Clear.ts index b3ae468327..ea0109fe87 100644 --- a/src/actions/Clear.ts +++ b/src/actions/Clear.ts @@ -1,3 +1,4 @@ +import { toRawTarget } from "../processTargets/modifiers/RawSelectionStage"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; import { setSelectionsAndFocusEditor } from "../util/setSelectionsAndFocusEditor"; @@ -11,11 +12,9 @@ export default class Clear implements Action { async run([targets]: [Target[]]): Promise { const editor = ensureSingleEditor(targets); + const rawTargets = targets.map(toRawTarget); - const { thatMark } = await this.graph.actions.remove.run([targets], { - showDecorations: true, - contentOnly: true, - }); + const { thatMark } = await this.graph.actions.remove.run([rawTargets]); if (thatMark != null) { await setSelectionsAndFocusEditor( diff --git a/src/actions/EditNew.ts b/src/actions/EditNew.ts index 7d60466d00..f81e8fedf8 100644 --- a/src/actions/EditNew.ts +++ b/src/actions/EditNew.ts @@ -1,13 +1,22 @@ import { zip } from "lodash"; -import { commands, Range, TextEditor } from "vscode"; -import { callFunctionAndUpdateRanges } from "../core/updateSelections/updateSelections"; +import { + commands, + DecorationRangeBehavior, + Range, + Selection, + TextEditor, +} from "vscode"; +import { + callFunctionAndUpdateRanges, + performEditsAndUpdateSelectionsWithBehavior, +} from "../core/updateSelections/updateSelections"; import { weakContainingLineStage } from "../processTargets/modifiers/commonWeakContainingScopeStages"; +import { toPositionTarget } from "../processTargets/modifiers/PositionStage"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; import { selectionFromRange } from "../util/selectionUtils"; import { setSelectionsAndFocusEditor } from "../util/setSelectionsAndFocusEditor"; import { createThatMark, ensureSingleEditor } from "../util/targetUtils"; -import { insertTextAfter, insertTextBefore } from "../util/textInsertion"; import { Action, ActionReturnValue } from "./actions.types"; class EditNew implements Action { @@ -24,7 +33,7 @@ class EditNew implements Action { const context = target.getEditNewContext(this.isBefore); const common = { target, - targetRange: target.thatTarget.contentRange, + // targetRange: target.thatTarget.contentRange, cursorRange: target.contentRange, }; switch (context.type) { @@ -67,10 +76,8 @@ class EditNew implements Action { await setSelectionsAndFocusEditor(editor, newSelections); } - const targetRanges = richTargets.map((target) => target.targetRange); - return { - thatMark: createThatMark(targets, targetRanges), + thatMark: createThatMark(richTargets.map(({ target }) => target)), }; } @@ -79,20 +86,40 @@ class EditNew implements Action { commandTargets: CommandTarget[], delimiterTargets: DelimiterTarget[] ) { - const textInsertions = delimiterTargets.map((target) => { - return { - range: target.targetRange, - delimiter: target.delimiter, - text: "", - }; - }); + const position = this.isBefore ? "before" : "after"; + const edits = delimiterTargets.flatMap((target) => + toPositionTarget(target.target, position).constructChangeEdit("") + ); + + const cursorSelections = { selections: editor.selections }; + const contentSelections = { + selections: delimiterTargets.map( + ({ target }) => target.thatTarget.contentSelection + ), + }; + const editSelections = { + selections: edits.map( + ({ range }) => new Selection(range.start, range.end) + ), + rangeBehavior: DecorationRangeBehavior.OpenOpen, + }; - const { updatedEditorSelections, updatedContentRanges, insertionRanges } = - this.isBefore - ? await insertTextBefore(this.graph, editor, textInsertions) - : await insertTextAfter(this.graph, editor, textInsertions); + const [ + updatedEditorSelections, + updatedContentSelections, + updatedEditSelections, + ]: Selection[][] = await performEditsAndUpdateSelectionsWithBehavior( + this.graph.rangeUpdater, + editor, + edits, + [cursorSelections, contentSelections, editSelections] + ); + + const insertionRanges = zip(edits, updatedEditSelections).map( + ([edit, selection]) => edit!.updateRange(selection!) + ); - updateTargets(delimiterTargets, updatedContentRanges, insertionRanges); + updateTargets(delimiterTargets, updatedContentSelections, insertionRanges); updateCommandTargets(commandTargets, updatedEditorSelections); } @@ -119,7 +146,7 @@ class EditNew implements Action { () => commands.executeCommand(command), editor.document, [ - targets.map(({ targetRange }) => targetRange), + targets.map(({ target }) => target.contentRange), targets.map(({ cursorRange }) => cursorRange), ] ); @@ -143,7 +170,6 @@ export class EditNewAfter extends EditNew { interface CommonTarget { target: Target; - targetRange: Range; cursorRange: Range; updateSelection: boolean; } @@ -181,7 +207,7 @@ function updateTargets( ) { zip(targets, updatedTargetRanges, updatedCursorRanges).forEach( ([target, updatedTargetRange, updatedCursorRange]) => { - target!.targetRange = updatedTargetRange!; + target!.target = target!.target.withContentRange(updatedTargetRange!); target!.cursorRange = updatedCursorRange!; } ); diff --git a/src/actions/InsertCopy.ts b/src/actions/InsertCopy.ts index 9677af1889..f8c42fe683 100644 --- a/src/actions/InsertCopy.ts +++ b/src/actions/InsertCopy.ts @@ -1,11 +1,12 @@ -import { flatten } from "lodash"; -import { TextEditor } from "vscode"; +import { flatten, zip } from "lodash"; +import { DecorationRangeBehavior, Selection, TextEditor } from "vscode"; +import { performEditsAndUpdateSelectionsWithBehavior } from "../core/updateSelections/updateSelections"; import { weakContainingLineStage } from "../processTargets/modifiers/commonWeakContainingScopeStages"; +import { toPositionTarget } from "../processTargets/modifiers/PositionStage"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; import { setSelectionsWithoutFocusingEditor } from "../util/setSelectionsAndFocusEditor"; import { createThatMark, runOnTargetsForEachEditor } from "../util/targetUtils"; -import { insertTextAfter, insertTextBefore } from "../util/textInsertion"; import { Action, ActionReturnValue } from "./actions.types"; class InsertCopy implements Action { @@ -39,26 +40,44 @@ class InsertCopy implements Action { } private async runForEditor(editor: TextEditor, targets: Target[]) { - const textInsertions = targets.map((target) => { - return { - range: target.contentRange, - text: target.contentText, - delimiter: target.delimiter ?? "", - }; - }); + // isBefore is inverted because we want the selections to stay with what is to the user the "copy" + const position = this.isBefore ? "after" : "before"; + const edits = targets.flatMap((target) => + toPositionTarget(target, position).constructChangeEdit(target.contentText) + ); + + const cursorSelections = { selections: editor.selections }; + const contentSelections = { + selections: targets.map(({ contentSelection }) => contentSelection), + }; + const editSelections = { + selections: edits.map( + ({ range }) => new Selection(range.start, range.end) + ), + rangeBehavior: DecorationRangeBehavior.OpenOpen, + }; + + const [ + updatedEditorSelections, + updatedContentSelections, + updatedEditSelections, + ]: Selection[][] = await performEditsAndUpdateSelectionsWithBehavior( + this.graph.rangeUpdater, + editor, + edits, + [cursorSelections, contentSelections, editSelections] + ); - const { updatedEditorSelections, updatedContentRanges, insertionRanges } = - // isBefore is inverted because we want the selections to stay with what is to the user the "copy" - this.isBefore - ? await insertTextAfter(this.graph, editor, textInsertions) - : await insertTextBefore(this.graph, editor, textInsertions); + const insertionRanges = zip(edits, updatedEditSelections).map( + ([edit, selection]) => edit!.updateRange(selection!) + ); setSelectionsWithoutFocusingEditor(editor, updatedEditorSelections); editor.revealRange(editor.selection); return { sourceMark: createThatMark(targets, insertionRanges), - thatMark: createThatMark(targets, updatedContentRanges), + thatMark: createThatMark(targets, updatedContentSelections), }; } } diff --git a/src/actions/InsertEmptyLines.ts b/src/actions/InsertEmptyLines.ts index e19705370b..5357d1a43f 100644 --- a/src/actions/InsertEmptyLines.ts +++ b/src/actions/InsertEmptyLines.ts @@ -1,8 +1,10 @@ -import { flatten } from "lodash"; -import { Range, Selection } from "vscode"; -import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; +import { flatten, zip } from "lodash"; +import { DecorationRangeBehavior, Selection } from "vscode"; +import { performEditsAndUpdateSelectionsWithBehavior } from "../core/updateSelections/updateSelections"; +import { toPositionTarget } from "../processTargets/modifiers/PositionStage"; +import { toLineTarget } from "../processTargets/modifiers/scopeTypeStages/LineStage"; import { Target } from "../typings/target.types"; -import { Graph } from "../typings/Types"; +import { EditWithRangeUpdater, Graph } from "../typings/Types"; import { setSelectionsWithoutFocusingEditor } from "../util/setSelectionsAndFocusEditor"; import { runOnTargetsForEachEditor } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; @@ -16,64 +18,67 @@ class InsertEmptyLines implements Action { this.run = this.run.bind(this); } - private getRanges(targets: Target[]) { - let lines = targets.flatMap((target) => { - const lines = []; + private getEdits(targets: Target[]) { + return targets.flatMap((target) => { + const lineTarget = toLineTarget(target); + const edits: EditWithRangeUpdater[] = []; if (this.insertAbove) { - lines.push(target.contentRange.start.line); + edits.push( + toPositionTarget(lineTarget, "before").constructChangeEdit("") + ); } if (this.insertBelow) { - lines.push(target.contentRange.end.line + 1); + edits.push( + toPositionTarget(lineTarget, "after").constructChangeEdit("") + ); } - return lines; + return edits; }); - // Remove duplicates - lines = [...new Set(lines)]; - - return lines.map((line) => new Range(line, 0, line, 0)); - } - - private getEdits(ranges: Range[]) { - return ranges.map((range) => ({ - range, - text: "\n", - })); } async run([targets]: [Target[]]): Promise { const results = flatten( await runOnTargetsForEachEditor(targets, async (editor, targets) => { - const ranges = this.getRanges(targets); - const edits = this.getEdits(ranges); + const edits = this.getEdits(targets); - const [updatedSelections, lineSelections, updatedOriginalSelections] = - await performEditsAndUpdateSelections( - this.graph.rangeUpdater, - editor, - edits, - [ - targets.map((target) => target.contentSelection), - ranges.map((range) => new Selection(range.start, range.end)), - editor.selections, - ] - ); + const cursorSelections = { selections: editor.selections }; + const contentSelections = { + selections: targets.map( + (target) => target.thatTarget.contentSelection + ), + }; + const editSelections = { + selections: edits.map( + ({ range }) => new Selection(range.start, range.end) + ), + rangeBehavior: DecorationRangeBehavior.OpenOpen, + }; + + const [ + updatedCursorSelections, + updatedContentSelections, + updatedEditSelections, + ]: Selection[][] = await performEditsAndUpdateSelectionsWithBehavior( + this.graph.rangeUpdater, + editor, + edits, + [cursorSelections, contentSelections, editSelections] + ); + + const insertionRanges = zip(edits, updatedEditSelections).map( + ([edit, selection]) => edit!.updateRange(selection!) + ); - setSelectionsWithoutFocusingEditor(editor, updatedOriginalSelections); + setSelectionsWithoutFocusingEditor(editor, updatedCursorSelections); return { - thatMark: updatedSelections.map((selection) => ({ + thatMark: updatedContentSelections.map((selection) => ({ editor, selection, })), - lineSelections: lineSelections.map((selection, index) => ({ + lineSelections: insertionRanges.map((range) => ({ editor, - range: - ranges[index].start.line < editor.document.lineCount - 1 - ? new Range( - selection.start.translate({ lineDelta: -1 }), - selection.end.translate({ lineDelta: -1 }) - ) - : selection, + range, })), }; }) diff --git a/src/actions/Remove.ts b/src/actions/Remove.ts index 44389181b6..a15f32103b 100644 --- a/src/actions/Remove.ts +++ b/src/actions/Remove.ts @@ -2,12 +2,7 @@ import { flatten } from "lodash"; import { performEditsAndUpdateRanges } from "../core/updateSelections/updateSelections"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; -import { - createThatMark, - getContentRange, - getRemovalRange, - runOnTargetsForEachEditor, -} from "../util/targetUtils"; +import { createThatMark, runOnTargetsForEachEditor } from "../util/targetUtils"; import { unifyRemovalTargets } from "../util/unifyRanges"; import { Action, ActionReturnValue } from "./actions.types"; @@ -18,31 +13,22 @@ export default class Delete implements Action { async run( [targets]: [Target[]], - { showDecorations = true, contentOnly = false } = {} + { showDecorations = true } = {} ): Promise { // Unify overlapping targets because of overlapping leading and trailing delimiters. - if (!contentOnly) { - targets = unifyRemovalTargets(targets); - } + targets = unifyRemovalTargets(targets); if (showDecorations) { await this.graph.editStyles.displayPendingEditDecorations( targets, this.graph.editStyles.pendingDelete, - contentOnly ? getContentRange : getRemovalHighlightRange, - contentOnly + (target) => target.getRemovalHighlightRange() ); } const thatMark = flatten( await runOnTargetsForEachEditor(targets, async (editor, targets) => { - const getRangeCallback = contentOnly - ? getContentRange - : getRemovalRange; - const edits = targets.map((target) => ({ - range: getRangeCallback(target), - text: "", - })); + const edits = targets.map((target) => target.constructRemovalEdit()); const ranges = edits.map((edit) => edit.range); const [updatedRanges] = await performEditsAndUpdateRanges( @@ -59,7 +45,3 @@ export default class Delete implements Action { return { thatMark }; } } - -function getRemovalHighlightRange(target: Target) { - return target.getRemovalHighlightRange(); -} diff --git a/src/core/editStyles.ts b/src/core/editStyles.ts index 9946ec34cd..f281afa4c7 100644 --- a/src/core/editStyles.ts +++ b/src/core/editStyles.ts @@ -88,10 +88,9 @@ export class EditStyles implements Record { async displayPendingEditDecorations( targets: Target[], style: EditStyle, - getRange: (target: Target) => Range | undefined = getContentRange, - contentOnly: boolean = false + getRange: (target: Target) => Range | undefined = getContentRange ) { - await this.setDecorations(targets, style, getRange, contentOnly); + await this.setDecorations(targets, style, getRange); await decorationSleep(); @@ -142,40 +141,30 @@ export class EditStyles implements Record { ); } - async setDecorations( + setDecorations( targets: Target[], style: EditStyle, - getRange: (target: Target) => Range | undefined = getContentRange, - contentOnly: boolean = false + getRange: (target: Target) => Range | undefined = getContentRange ) { - await runOnTargetsForEachEditor(targets, async (editor, targets) => { - if (contentOnly) { - this.setEditorDecorations( - editor, - style, - true, - targets.map(getRange).filter((range): range is Range => !!range) - ); - } else { - this.setEditorDecorations( - editor, - style, - true, - targets - .filter((target) => !target.isLine) - .map(getRange) - .filter((range): range is Range => !!range) - ); - this.setEditorDecorations( - editor, - style, - false, - targets - .filter((target) => target.isLine) - .map(getRange) - .filter((range): range is Range => !!range) - ); - } + return runOnTargetsForEachEditor(targets, async (editor, targets) => { + this.setEditorDecorations( + editor, + style, + true, + targets + .filter((target) => !target.isLine) + .map(getRange) + .filter((range): range is Range => !!range) + ); + this.setEditorDecorations( + editor, + style, + false, + targets + .filter((target) => target.isLine) + .map(getRange) + .filter((range): range is Range => !!range) + ); }); } diff --git a/src/core/updateSelections/updateSelections.ts b/src/core/updateSelections/updateSelections.ts index d5a4467c1b..0e09437996 100644 --- a/src/core/updateSelections/updateSelections.ts +++ b/src/core/updateSelections/updateSelections.ts @@ -15,6 +15,11 @@ import { performDocumentEdits } from "../../util/performDocumentEdits"; import { isForward } from "../../util/selectionUtils"; import { RangeUpdater } from "./RangeUpdater"; +interface SelectionsWithBehavior { + selections: readonly Selection[]; + rangeBehavior?: DecorationRangeBehavior; +} + /** * Given a selection, this function creates a `SelectionInfo` object that can * be passed in to any of the commands that update selections. @@ -230,6 +235,39 @@ export async function performEditsAndUpdateSelections( ); } +/** + * Performs a list of edits and returns the given selections updated based on + * the applied edits + * @param rangeUpdater A RangeUpdate instance that will perform actual range updating + * @param editor The editor containing the selections + * @param edits A list of edits to apply + * @param originalSelections The selections to update + * @param rangeBehavior How selections should behave with respect to insertions on either end + * @returns The updated selections + */ +export function performEditsAndUpdateSelectionsWithBehavior( + rangeUpdater: RangeUpdater, + editor: TextEditor, + edits: Edit[], + originalSelections: SelectionsWithBehavior[] +) { + return performEditsAndUpdateFullSelectionInfos( + rangeUpdater, + editor, + edits, + originalSelections.map((selectionsWithBehavior) => + selectionsWithBehavior.selections.map((selection) => + getSelectionInfo( + editor.document, + selection, + selectionsWithBehavior.rangeBehavior ?? + DecorationRangeBehavior.ClosedClosed + ) + ) + ) + ); +} + export async function performEditsAndUpdateRanges( rangeUpdater: RangeUpdater, editor: TextEditor, @@ -267,7 +305,7 @@ export async function performEditsAndUpdateSelectionInfos( editor: TextEditor, edits: Edit[], originalSelectionInfos: SelectionInfo[][] -) { +): Promise { fillOutSelectionInfos(editor.document, originalSelectionInfos); return await performEditsAndUpdateFullSelectionInfos( @@ -292,7 +330,7 @@ export async function performEditsAndUpdateFullSelectionInfos( editor: TextEditor, edits: Edit[], originalSelectionInfos: FullSelectionInfo[][] -) { +): Promise { // NB: We do everything using VSCode listeners. We can associate changes // with our changes just by looking at their offets / text in order to // recover isReplace. We need to do this because VSCode does some fancy diff --git a/src/processTargets/modifiers/PositionStage.ts b/src/processTargets/modifiers/PositionStage.ts index f2cdd84192..3c9ffaf8ed 100644 --- a/src/processTargets/modifiers/PositionStage.ts +++ b/src/processTargets/modifiers/PositionStage.ts @@ -1,5 +1,5 @@ import { Range } from "vscode"; -import { PositionModifier, Target } from "../../typings/target.types"; +import { Position, PositionModifier, Target } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; import PositionTarget from "../targets/PositionTarget"; @@ -8,41 +8,43 @@ export default class PositionStage implements ModifierStage { constructor(private modifier: PositionModifier) {} run(context: ProcessedTargetsContext, target: Target): Target[] { - const { start, end } = target.contentRange; - let contentRange: Range; - let delimiter: string | undefined; - - switch (this.modifier.position) { - case "before": - contentRange = new Range(start, start); - delimiter = target.delimiter; - break; - - case "after": - contentRange = new Range(end, end); - delimiter = target.delimiter; - break; - - case "start": - contentRange = new Range(start, start); - // This it NOT a raw target. Joining with this should be done on empty delimiter. - delimiter = ""; - break; - - case "end": - contentRange = new Range(end, end); - delimiter = ""; - break; - } - - return [ - new PositionTarget({ - editor: target.editor, - isReversed: target.isReversed, - contentRange, - position: this.modifier.position, - delimiter, - }), - ]; + return [toPositionTarget(target, this.modifier.position)]; } } + +export function toPositionTarget(target: Target, position: Position): Target { + const { start, end } = target.contentRange; + let contentRange: Range; + let delimiter: string | undefined; + + switch (position) { + case "before": + contentRange = new Range(start, start); + delimiter = target.delimiter; + break; + + case "after": + contentRange = new Range(end, end); + delimiter = target.delimiter; + break; + + case "start": + contentRange = new Range(start, start); + // This it NOT a raw target. Joining with this should be done on empty delimiter. + delimiter = ""; + break; + + case "end": + contentRange = new Range(end, end); + delimiter = ""; + break; + } + + return new PositionTarget({ + editor: target.editor, + isReversed: target.isReversed, + contentRange, + position, + delimiter, + }); +} diff --git a/src/processTargets/modifiers/RawSelectionStage.ts b/src/processTargets/modifiers/RawSelectionStage.ts index 468fb8f23a..e54772a3c9 100644 --- a/src/processTargets/modifiers/RawSelectionStage.ts +++ b/src/processTargets/modifiers/RawSelectionStage.ts @@ -7,12 +7,14 @@ export default class RawSelectionStage implements ModifierStage { constructor(private modifier: RawSelectionModifier) {} run(context: ProcessedTargetsContext, target: Target): Target[] { - return [ - new RawSelectionTarget({ - editor: target.editor, - contentRange: target.contentRange, - isReversed: target.isReversed, - }), - ]; + return [toRawTarget(target)]; } } + +export function toRawTarget(target: Target) { + return new RawSelectionTarget({ + editor: target.editor, + contentRange: target.contentRange, + isReversed: target.isReversed, + }); +} diff --git a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts index a97a2724c6..d0427670f2 100644 --- a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts @@ -15,7 +15,7 @@ export default class implements ModifierStage { if (this.modifier.type === "everyScope") { return this.getEveryTarget(target); } - return [this.getSingleTarget(target)]; + return [toLineTarget(target)]; } getEveryTarget(target: Target): LineTarget[] { @@ -30,7 +30,9 @@ export default class implements ModifierStage { for (let i = startLine; i <= endLine; ++i) { const line = editor.document.lineAt(i); if (!line.isEmptyOrWhitespace) { - targets.push(this.getTargetFromRange(target, line.range)); + targets.push( + createLineTarget(target.editor, line.range, target.isReversed) + ); } } @@ -42,18 +44,14 @@ export default class implements ModifierStage { return targets; } +} - getSingleTarget(target: Target): LineTarget { - return createLineTarget( - target.editor, - target.contentRange, - target.isReversed - ); - } - - getTargetFromRange(target: Target, range: Range): LineTarget { - return createLineTarget(target.editor, range, target.isReversed); - } +export function toLineTarget(target: Target): LineTarget { + return createLineTarget( + target.editor, + target.contentRange, + target.isReversed + ); } export function createLineTarget( diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index 7480ece387..55f5316bb6 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -19,6 +19,7 @@ export interface CommonTargetParameters { export interface CloneWithParameters { readonly thatTarget?: Target; + readonly contentRange?: Range; } export default abstract class BaseTarget implements Target { @@ -99,7 +100,7 @@ export default abstract class BaseTarget implements Target { constructRemovalEdit(): EditWithRangeUpdater { return { - range: this.contentRange, + range: this.getRemovalRange(), text: "", updateRange: (range) => range, }; @@ -132,6 +133,10 @@ export default abstract class BaseTarget implements Target { return this.cloneWith({ thatTarget }); } + withContentRange(contentRange: Range): Target { + return this.cloneWith({ contentRange }); + } + getInteriorStrict(): Target[] { throw Error("No available interior"); } diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 594882ed64..99f25ab04f 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -334,6 +334,7 @@ export interface Target { getRemovalHighlightRange(): Range | undefined; getEditNewContext(isBefore: boolean): EditNewContext; withThatTarget(thatTarget: Target): Target; + withContentRange(contentRange: Range): Target; createContinuousRangeTarget( isReversed: boolean, endTarget: Target, diff --git a/src/util/targetUtils.ts b/src/util/targetUtils.ts index 7f2ecd97cb..e0fff7ee76 100644 --- a/src/util/targetUtils.ts +++ b/src/util/targetUtils.ts @@ -103,7 +103,3 @@ export function createThatMark( })); return thatMark; } - -export function getRemovalRange(target: Target) { - return target.getRemovalRange(); -} diff --git a/src/util/textInsertion.ts b/src/util/textInsertion.ts deleted file mode 100644 index 12b0ec9e5f..0000000000 --- a/src/util/textInsertion.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { zip } from "lodash"; -import { Position, Range, Selection, TextEditor } from "vscode"; -import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; -import { Graph } from "../typings/Types"; - -interface TextInsertion { - range: Range; - text: string; - delimiter: string; -} - -export async function insertTextBefore( - graph: Graph, - editor: TextEditor, - textInsertions: TextInsertion[] -) { - return insertText(graph, editor, textInsertions, true); -} - -export async function insertTextAfter( - graph: Graph, - editor: TextEditor, - textInsertions: TextInsertion[] -) { - return insertText(graph, editor, textInsertions, false); -} - -async function insertText( - graph: Graph, - editor: TextEditor, - textInsertions: TextInsertion[], - isBefore: boolean -) { - const edits = createEdits(editor, textInsertions, isBefore); - const editSelections = edits.map( - ({ range }) => new Selection(range.start, range.end) - ); - const contentSelections = textInsertions.map( - ({ range }) => new Selection(range.start, range.end) - ); - - const [ - updatedEditorSelections, - updatedEditSelections, - updatedContentSelections, - ] = await performEditsAndUpdateSelections(graph.rangeUpdater, editor, edits, [ - editor.selections, - editSelections, - contentSelections, - ]); - - const insertionRanges = zip(edits, updatedEditSelections).map( - ([edit, selection]) => { - const startOffset = editor.document.offsetAt(selection!.start); - const startIndex = isBefore - ? startOffset - edit!.offset - edit!.length - : startOffset + edit!.offset; - const endIndex = startIndex + edit!.length; - return new Range( - editor.document.positionAt(startIndex), - editor.document.positionAt(endIndex) - ); - } - ); - - return { - updatedEditorSelections, - updatedContentRanges: updatedContentSelections as Range[], - insertionRanges, - }; -} - -function createEdits( - editor: TextEditor, - textInsertions: TextInsertion[], - isBefore: boolean -) { - return textInsertions.map((insertion) => { - const { range: contentRange, text, delimiter } = insertion; - const isLine = delimiter.includes("\n"); - - const range = getEditRange(editor, contentRange, isLine, isBefore); - const padding = isLine ? getLinePadding(editor, range, isBefore) : ""; - - const editText = isBefore - ? text + delimiter + padding - : delimiter + padding + text; - - return { - range, - isReplace: !isBefore, - text: editText, - offset: delimiter.length + padding.length, - length: text.length, - }; - }); -} - -function getLinePadding(editor: TextEditor, range: Range, isBefore: boolean) { - const line = editor.document.lineAt(isBefore ? range.start : range.end); - const characterIndex = line.isEmptyOrWhitespace - ? range.start.character - : line.firstNonWhitespaceCharacterIndex; - return line.text.slice(0, characterIndex); -} - -function getEditRange( - editor: TextEditor, - range: Range, - isLine: boolean, - isBefore: boolean -) { - let position: Position; - if (isLine) { - const line = editor.document.lineAt(isBefore ? range.start : range.end); - if (isBefore) { - position = line.isEmptyOrWhitespace - ? range.start - : new Position(line.lineNumber, line.firstNonWhitespaceCharacterIndex); - } else { - position = line.range.end; - } - } else { - position = isBefore ? range.start : range.end; - } - return new Range(position, position); -} diff --git a/src/util/unifyRanges.ts b/src/util/unifyRanges.ts index 21e94ee8e5..8324207cff 100644 --- a/src/util/unifyRanges.ts +++ b/src/util/unifyRanges.ts @@ -36,11 +36,7 @@ function unifyRangesOnePass(ranges: Range[]): [Range[], boolean] { return [result, madeChanges]; } -/** - * Unifies overlapping/intersecting targets - * FIXME This code probably needs to update once we have objected oriented targets - * https://github.com/cursorless-dev/cursorless/issues/210 - */ +/** Unifies overlapping/intersecting targets */ export function unifyRemovalTargets(targets: Target[]): Target[] { if (targets.length < 2) { return targets; From 4e08c904d8361906822cfdd875b497a393f94640 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 29 May 2022 11:57:30 +0200 Subject: [PATCH 243/314] Enabled bring before and after without to --- cursorless-talon/src/actions/actions.py | 3 +- .../src/actions/actions_simple.py | 11 +++- cursorless-talon/src/actions/call.py | 3 +- cursorless-talon/src/actions/move_bring.py | 17 ++---- cursorless-talon/src/compound_targets.py | 5 +- cursorless-talon/src/connective.py | 11 +++- cursorless-talon/src/cursorless.talon | 3 + .../src/modifiers/delimiter_range.py | 22 ++++++++ cursorless-talon/src/modifiers/position.py | 15 ++++- cursorless-talon/src/positional_target.py | 56 +++++++++++++++++++ cursorless-talon/src/primitive_target.py | 2 +- 11 files changed, 128 insertions(+), 20 deletions(-) create mode 100644 cursorless-talon/src/modifiers/delimiter_range.py create mode 100644 cursorless-talon/src/positional_target.py diff --git a/cursorless-talon/src/actions/actions.py b/cursorless-talon/src/actions/actions.py index ef9d8b71d5..94ebbb04bf 100644 --- a/cursorless-talon/src/actions/actions.py +++ b/cursorless-talon/src/actions/actions.py @@ -4,7 +4,7 @@ from .actions_callback import callback_action_defaults, callback_action_map from .actions_custom import custom_action_defaults from .actions_makeshift import makeshift_action_defaults, makeshift_action_map -from .actions_simple import simple_action_defaults +from .actions_simple import simple_action_defaults, positional_action_defaults mod = Module() @@ -79,6 +79,7 @@ def vscode_command_no_wait(command_id: str, target: dict, command_options: dict default_values = { "simple_action": simple_action_defaults, + "positional_action": positional_action_defaults, "callback_action": callback_action_defaults, "makeshift_action": makeshift_action_defaults, "custom_action": custom_action_defaults, diff --git a/cursorless-talon/src/actions/actions_simple.py b/cursorless-talon/src/actions/actions_simple.py index eabd90bbdc..fc1e20297c 100644 --- a/cursorless-talon/src/actions/actions_simple.py +++ b/cursorless-talon/src/actions/actions_simple.py @@ -24,7 +24,6 @@ "give": "deselect", "highlight": "highlight", "indent": "indentLine", - "paste to": "pasteFromClipboard", "post": "setSelectionAfter", "pour": "editNewLineAfter", "pre": "setSelectionBefore", @@ -37,8 +36,18 @@ "unfold": "unfoldRegion", } +# NOTE: Please do not change these dicts. Use the CSVs for customization. +# See https://www.cursorless.org/docs/user/customization/ +positional_action_defaults = { + "paste": "pasteFromClipboard", +} + mod = Module() mod.list( "cursorless_simple_action", desc="Supported simple actions for cursorless navigation", ) +mod.list( + "cursorless_positional_action", + desc="Supported actions for cursorless that expect a positional target", +) diff --git a/cursorless-talon/src/actions/call.py b/cursorless-talon/src/actions/call.py index f29e61fab1..753d7e0e84 100644 --- a/cursorless-talon/src/actions/call.py +++ b/cursorless-talon/src/actions/call.py @@ -1,10 +1,9 @@ from talon import Module, actions - from ..primitive_target import IMPLICIT_TARGET mod = Module() def run_call_action(target: dict): - targets = [target, IMPLICIT_TARGET] + targets = [target, IMPLICIT_TARGET.copy()] actions.user.cursorless_multiple_target_command("callAsFunction", targets) diff --git a/cursorless-talon/src/actions/move_bring.py b/cursorless-talon/src/actions/move_bring.py index 021fffa174..d38f94dd94 100644 --- a/cursorless-talon/src/actions/move_bring.py +++ b/cursorless-talon/src/actions/move_bring.py @@ -1,26 +1,19 @@ from talon import Module - from ..primitive_target import IMPLICIT_TARGET mod = Module() -mod.list( - "cursorless_source_destination_connective", - desc="The connective used to separate source and destination targets", -) mod.list("cursorless_move_bring_action", desc="Cursorless move or bring actions") -@mod.capture( - rule=( - " [{user.cursorless_source_destination_connective} ]" - ) -) +@mod.capture(rule=" []") def cursorless_move_bring_targets(m) -> list[dict]: target_list = m.cursorless_target_list - if len(target_list) == 1: - target_list = target_list + [IMPLICIT_TARGET] + try: + target_list += [m.cursorless_positional_target] + except AttributeError: + target_list += [IMPLICIT_TARGET.copy()] return target_list diff --git a/cursorless-talon/src/compound_targets.py b/cursorless-talon/src/compound_targets.py index 5257c2a1e8..63f8512fca 100644 --- a/cursorless-talon/src/compound_targets.py +++ b/cursorless-talon/src/compound_targets.py @@ -79,4 +79,7 @@ def is_active_included(range_connective: str): def cursorless_target(m) -> dict: if len(m.cursorless_range_list) == 1: return m.cursorless_range - return {"type": "list", "elements": m.cursorless_range_list} + return { + "type": "list", + "elements": m.cursorless_range_list, + } diff --git a/cursorless-talon/src/connective.py b/cursorless-talon/src/connective.py index 28e593e7de..05723e9cd6 100644 --- a/cursorless-talon/src/connective.py +++ b/cursorless-talon/src/connective.py @@ -1,7 +1,15 @@ -from talon import app +from talon import Module, app from .csv_overrides import init_csv_and_watch_changes +mod = Module() + +mod.list( + "cursorless_source_destination_connective", + desc="The connective used to separate source and destination targets", +) + + # NOTE: Please do not change these dicts. Use the CSVs for customization. # See https://www.cursorless.org/docs/user/customization/ range_connectives = { @@ -11,6 +19,7 @@ "until": "rangeExcludingEnd", } + default_range_connective = "rangeInclusive" diff --git a/cursorless-talon/src/cursorless.talon b/cursorless-talon/src/cursorless.talon index 1ebb807a85..52563585a8 100644 --- a/cursorless-talon/src/cursorless.talon +++ b/cursorless-talon/src/cursorless.talon @@ -4,6 +4,9 @@ app: vscode : user.cursorless_action_or_vscode_command(cursorless_action_or_vscode_command, cursorless_target) +{user.cursorless_positional_action} : + user.cursorless_single_target_command(cursorless_positional_action, cursorless_positional_target) + {user.cursorless_swap_action} : user.cursorless_multiple_target_command(cursorless_swap_action, cursorless_swap_targets) diff --git a/cursorless-talon/src/modifiers/delimiter_range.py b/cursorless-talon/src/modifiers/delimiter_range.py new file mode 100644 index 0000000000..6d5adee64d --- /dev/null +++ b/cursorless-talon/src/modifiers/delimiter_range.py @@ -0,0 +1,22 @@ +from typing import Any +from talon import Context, Module + +mod = Module() +ctx = Context() + + +delimiter_ranges = { + "leading": {"direction": "leading"}, + "trailing": {"direction": "trailing"}, +} + +mod.list("cursorless_delimiter_range", desc="Types of delimiter ranges") +ctx.lists["self.cursorless_delimiter_range"] = delimiter_ranges.keys() + + +@mod.capture(rule="{user.cursorless_delimiter_range}") +def cursorless_delimiter_range(m) -> dict[str, Any]: + return { + "type": "delimiterRange", + **delimiter_ranges[m.cursorless_delimiter_range], + } diff --git a/cursorless-talon/src/modifiers/position.py b/cursorless-talon/src/modifiers/position.py index b4f9da56a1..ba060826e6 100644 --- a/cursorless-talon/src/modifiers/position.py +++ b/cursorless-talon/src/modifiers/position.py @@ -5,6 +5,16 @@ mod = Module() ctx = Context() +POSITION_BEFORE = { + "before": { + "type": "position", + "position": "before", + } +} + +POSITION_AFTER = { + "after": {"type": "position", "position": "after"}, +} positions = { "before": {"position": "before"}, @@ -22,4 +32,7 @@ @mod.capture(rule="{user.cursorless_position}") def cursorless_position(m) -> dict[str, Any]: - return {"type": "position", **positions[m.cursorless_position]} + return { + "type": "position", + **positions[m.cursorless_position], + } diff --git a/cursorless-talon/src/positional_target.py b/cursorless-talon/src/positional_target.py new file mode 100644 index 0000000000..16de0e8847 --- /dev/null +++ b/cursorless-talon/src/positional_target.py @@ -0,0 +1,56 @@ +from talon import Module, Context + +from .modifiers.position import POSITION_BEFORE, POSITION_AFTER + +mod = Module() +ctx = Context() + +mod.list( + "cursorless_positional_connective", + desc="The connective used to separate source and destination targets", +) + +positional_connectives = { + **POSITION_BEFORE, + **POSITION_AFTER, +} + +print(positional_connectives) +ctx.lists["self.cursorless_positional_connective"] = positional_connectives.keys() + + +@mod.capture( + rule=( + "({user.cursorless_positional_connective} | {user.cursorless_source_destination_connective}) " + "" + ) +) +def cursorless_positional_target(m) -> list[dict]: + target = m.cursorless_target + try: + modifier = positional_connectives[m.cursorless_positional_connective] + return update_first_primitive_target(target, modifier) + except AttributeError: + return target + + +def update_first_primitive_target(target: dict, modifier: dict): + if target["type"] == "primitive": + if "modifies" not in target: + target["modifiers"] = [] + target["modifiers"].append(modifier) + return target + elif target["type"] == "range": + return { + **target, + "start": update_first_primitive_target(target["start"], modifier), + } + else: + elements = target["elements"] + return { + **target, + "elements": [ + update_first_primitive_target(elements[0], modifier), + *elements[1:], + ], + } diff --git a/cursorless-talon/src/primitive_target.py b/cursorless-talon/src/primitive_target.py index c1f5c9f590..75fb41985b 100644 --- a/cursorless-talon/src/primitive_target.py +++ b/cursorless-talon/src/primitive_target.py @@ -16,7 +16,7 @@ "", # matching/pair [curly, round] "", # just "", # inside, bounds - # "", # matching + "", # leading, trailing ] From 65bf87f6e46fd4fe33de0013f7f323e36c62f54b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 29 May 2022 09:57:57 +0000 Subject: [PATCH 244/314] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- cursorless-talon/src/actions/actions.py | 2 +- cursorless-talon/src/actions/call.py | 1 + cursorless-talon/src/actions/move_bring.py | 1 + cursorless-talon/src/modifiers/delimiter_range.py | 1 + cursorless-talon/src/positional_target.py | 4 ++-- 5 files changed, 6 insertions(+), 3 deletions(-) diff --git a/cursorless-talon/src/actions/actions.py b/cursorless-talon/src/actions/actions.py index 94ebbb04bf..56bdeb0192 100644 --- a/cursorless-talon/src/actions/actions.py +++ b/cursorless-talon/src/actions/actions.py @@ -4,7 +4,7 @@ from .actions_callback import callback_action_defaults, callback_action_map from .actions_custom import custom_action_defaults from .actions_makeshift import makeshift_action_defaults, makeshift_action_map -from .actions_simple import simple_action_defaults, positional_action_defaults +from .actions_simple import positional_action_defaults, simple_action_defaults mod = Module() diff --git a/cursorless-talon/src/actions/call.py b/cursorless-talon/src/actions/call.py index 753d7e0e84..d12aff0172 100644 --- a/cursorless-talon/src/actions/call.py +++ b/cursorless-talon/src/actions/call.py @@ -1,4 +1,5 @@ from talon import Module, actions + from ..primitive_target import IMPLICIT_TARGET mod = Module() diff --git a/cursorless-talon/src/actions/move_bring.py b/cursorless-talon/src/actions/move_bring.py index d38f94dd94..30c7241452 100644 --- a/cursorless-talon/src/actions/move_bring.py +++ b/cursorless-talon/src/actions/move_bring.py @@ -1,4 +1,5 @@ from talon import Module + from ..primitive_target import IMPLICIT_TARGET mod = Module() diff --git a/cursorless-talon/src/modifiers/delimiter_range.py b/cursorless-talon/src/modifiers/delimiter_range.py index 6d5adee64d..1a20e9c43a 100644 --- a/cursorless-talon/src/modifiers/delimiter_range.py +++ b/cursorless-talon/src/modifiers/delimiter_range.py @@ -1,4 +1,5 @@ from typing import Any + from talon import Context, Module mod = Module() diff --git a/cursorless-talon/src/positional_target.py b/cursorless-talon/src/positional_target.py index 16de0e8847..013d24cbee 100644 --- a/cursorless-talon/src/positional_target.py +++ b/cursorless-talon/src/positional_target.py @@ -1,6 +1,6 @@ -from talon import Module, Context +from talon import Context, Module -from .modifiers.position import POSITION_BEFORE, POSITION_AFTER +from .modifiers.position import POSITION_AFTER, POSITION_BEFORE mod = Module() ctx = Context() From b6891465c97aa5427a58209a97a2379030eb0927 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 29 May 2022 12:14:13 +0200 Subject: [PATCH 245/314] Fix --- cursorless-talon/src/positional_target.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cursorless-talon/src/positional_target.py b/cursorless-talon/src/positional_target.py index 013d24cbee..3681b1309a 100644 --- a/cursorless-talon/src/positional_target.py +++ b/cursorless-talon/src/positional_target.py @@ -36,9 +36,9 @@ def cursorless_positional_target(m) -> list[dict]: def update_first_primitive_target(target: dict, modifier: dict): if target["type"] == "primitive": - if "modifies" not in target: + if "modifiers" not in target: target["modifiers"] = [] - target["modifiers"].append(modifier) + target["modifiers"].insert(0, modifier) return target elif target["type"] == "range": return { From cd651eca649a7fbb6a721acd7eee64846b1561f9 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Sun, 29 May 2022 16:52:30 +0100 Subject: [PATCH 246/314] Support fully compositional modifiers Fixes #69 --- src/processTargets/targets/BaseTarget.ts | 41 +++++++++++++-- .../targets/DelimiterRangeTarget.ts | 44 +--------------- src/processTargets/targets/DocumentTarget.ts | 45 ++-------------- src/processTargets/targets/LineTarget.ts | 12 +---- .../targets/NotebookCellTarget.ts | 44 +--------------- src/processTargets/targets/ParagraphTarget.ts | 12 +---- src/processTargets/targets/PositionTarget.ts | 51 +++---------------- .../targets/RawSelectionTarget.ts | 44 +--------------- src/processTargets/targets/ScopeTypeTarget.ts | 12 +---- .../targets/SurroundingPairTarget.ts | 45 ++-------------- src/processTargets/targets/TokenTarget.ts | 44 +--------------- 11 files changed, 60 insertions(+), 334 deletions(-) diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index 55f5316bb6..d71c2dddcf 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -7,7 +7,9 @@ import { } from "../../typings/target.types"; import { EditWithRangeUpdater } from "../../typings/Types"; import { selectionFromRange } from "../../util/selectionUtils"; +import { createContinuousRange } from "../targetUtil/createContinuousRange"; import { getTokenDelimiters } from "../targetUtil/getTokenDelimiters"; +import { createContinuousRangeWeakTarget } from "./WeakTarget"; /** Parameters supported by all target classes */ export interface CommonTargetParameters { @@ -144,15 +146,46 @@ export default abstract class BaseTarget implements Target { throw Error("No available boundaries"); } - abstract cloneWith(parameters: CloneWithParameters): Target; - protected abstract getCloneParameters(): unknown; + readonly cloneWith = (parameters: CloneWithParameters) => { + const constructor = Object.getPrototypeOf(this).constructor; - abstract createContinuousRangeTarget( + return new constructor({ + ...this.getCloneParameters(), + ...parameters, + }); + }; + + protected abstract getCloneParameters(): object; + + createContinuousRangeTarget( isReversed: boolean, endTarget: Target, includeStart: boolean, includeEnd: boolean - ): Target; + ): Target { + if (this.isSameType(endTarget)) { + const constructor = Object.getPrototypeOf(this).constructor; + + return new constructor({ + ...this.getCloneParameters(), + isReversed, + contentRange: createContinuousRange( + this, + endTarget, + includeStart, + includeEnd + ), + }); + } + + return createContinuousRangeWeakTarget( + isReversed, + this, + endTarget, + includeStart, + includeEnd + ); + } protected isSameType(target: Target) { return this.type === target.type; diff --git a/src/processTargets/targets/DelimiterRangeTarget.ts b/src/processTargets/targets/DelimiterRangeTarget.ts index cb680c5022..85a1e069f2 100644 --- a/src/processTargets/targets/DelimiterRangeTarget.ts +++ b/src/processTargets/targets/DelimiterRangeTarget.ts @@ -1,12 +1,7 @@ import { Range } from "vscode"; -import { Target, TargetType } from "../../typings/target.types"; -import { createContinuousRange } from "../targetUtil/createContinuousRange"; +import { TargetType } from "../../typings/target.types"; import { addLineDelimiterRanges } from "../targetUtil/getLineDelimiters"; -import BaseTarget, { - CloneWithParameters, - CommonTargetParameters, -} from "./BaseTarget"; -import { createContinuousRangeWeakTarget } from "./WeakTarget"; +import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; interface DelimiterRangeTargetParameters extends CommonTargetParameters { readonly isLine: boolean; @@ -46,41 +41,6 @@ export default class DelimiterRangeTarget extends BaseTarget { return this.contentRange; } - cloneWith(parameters: CloneWithParameters) { - return new DelimiterRangeTarget({ - ...this.getCloneParameters(), - ...parameters, - }); - } - - createContinuousRangeTarget( - isReversed: boolean, - endTarget: Target, - includeStart: boolean, - includeEnd: boolean - ): Target { - if (this.isSameType(endTarget)) { - return new DelimiterRangeTarget({ - ...this.getCloneParameters(), - isReversed, - contentRange: createContinuousRange( - this, - endTarget, - includeStart, - includeEnd - ), - }); - } - - return createContinuousRangeWeakTarget( - isReversed, - this, - endTarget, - includeStart, - includeEnd - ); - } - protected getCloneParameters() { return { ...this.state, diff --git a/src/processTargets/targets/DocumentTarget.ts b/src/processTargets/targets/DocumentTarget.ts index 3e43a18f2b..91647cc3a8 100644 --- a/src/processTargets/targets/DocumentTarget.ts +++ b/src/processTargets/targets/DocumentTarget.ts @@ -1,12 +1,8 @@ import { Range, TextEditor } from "vscode"; -import { Target, TargetType } from "../../typings/target.types"; +import { TargetType } from "../../typings/target.types"; import { fitRangeToLineContent } from "../modifiers/scopeTypeStages/LineStage"; -import { createContinuousRange } from "../targetUtil/createContinuousRange"; -import BaseTarget, { - CloneWithParameters, - CommonTargetParameters, -} from "./BaseTarget"; -import WeakTarget, { createContinuousRangeWeakTarget } from "./WeakTarget"; +import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; +import WeakTarget from "./WeakTarget"; export default class DocumentTarget extends BaseTarget { constructor(parameters: CommonTargetParameters) { @@ -40,41 +36,6 @@ export default class DocumentTarget extends BaseTarget { ]; } - cloneWith(parameters: CloneWithParameters) { - return new DocumentTarget({ - ...this.getCloneParameters(), - ...parameters, - }); - } - - createContinuousRangeTarget( - isReversed: boolean, - endTarget: Target, - includeStart: boolean, - includeEnd: boolean - ): Target { - if (this.isSameType(endTarget)) { - return new DocumentTarget({ - ...this.getCloneParameters(), - isReversed, - contentRange: createContinuousRange( - this, - endTarget, - includeStart, - includeEnd - ), - }); - } - - return createContinuousRangeWeakTarget( - isReversed, - this, - endTarget, - includeStart, - includeEnd - ); - } - protected getCloneParameters() { return this.state; } diff --git a/src/processTargets/targets/LineTarget.ts b/src/processTargets/targets/LineTarget.ts index 72892eae02..d951aaa770 100644 --- a/src/processTargets/targets/LineTarget.ts +++ b/src/processTargets/targets/LineTarget.ts @@ -5,10 +5,7 @@ import { getLineLeadingDelimiterRange, getLineTrailingDelimiterRange, } from "../targetUtil/getLineDelimiters"; -import BaseTarget, { - CloneWithParameters, - CommonTargetParameters, -} from "./BaseTarget"; +import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; import { createContinuousRangeWeakTarget } from "./WeakTarget"; export default class LineTarget extends BaseTarget { @@ -45,13 +42,6 @@ export default class LineTarget extends BaseTarget { return this.contentRange; } - cloneWith(parameters: CloneWithParameters) { - return new LineTarget({ - ...this.getCloneParameters(), - ...parameters, - }); - } - createContinuousRangeTarget( isReversed: boolean, endTarget: Target, diff --git a/src/processTargets/targets/NotebookCellTarget.ts b/src/processTargets/targets/NotebookCellTarget.ts index 14df51e1c4..878325bc5b 100644 --- a/src/processTargets/targets/NotebookCellTarget.ts +++ b/src/processTargets/targets/NotebookCellTarget.ts @@ -1,12 +1,7 @@ import { TextEditor } from "vscode"; -import { EditNewContext, Target, TargetType } from "../../typings/target.types"; +import { EditNewContext, TargetType } from "../../typings/target.types"; import { getNotebookFromCellDocument } from "../../util/notebook"; -import { createContinuousRange } from "../targetUtil/createContinuousRange"; -import BaseTarget, { - CloneWithParameters, - CommonTargetParameters, -} from "./BaseTarget"; -import { createContinuousRangeWeakTarget } from "./WeakTarget"; +import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; export default class NotebookCellTarget extends BaseTarget { constructor(parameters: CommonTargetParameters) { @@ -43,41 +38,6 @@ export default class NotebookCellTarget extends BaseTarget { }; } - cloneWith(parameters: CloneWithParameters) { - return new NotebookCellTarget({ - ...this.getCloneParameters(), - ...parameters, - }); - } - - createContinuousRangeTarget( - isReversed: boolean, - endTarget: Target, - includeStart: boolean, - includeEnd: boolean - ): Target { - if (this.isSameType(endTarget)) { - return new NotebookCellTarget({ - ...this.getCloneParameters(), - isReversed, - contentRange: createContinuousRange( - this, - endTarget, - includeStart, - includeEnd - ), - }); - } - - return createContinuousRangeWeakTarget( - isReversed, - this, - endTarget, - includeStart, - includeEnd - ); - } - protected getCloneParameters() { return this.state; } diff --git a/src/processTargets/targets/ParagraphTarget.ts b/src/processTargets/targets/ParagraphTarget.ts index bc6cacdc87..24a95d3e30 100644 --- a/src/processTargets/targets/ParagraphTarget.ts +++ b/src/processTargets/targets/ParagraphTarget.ts @@ -2,10 +2,7 @@ import { Position, Range, TextDocument, TextEditor, TextLine } from "vscode"; import { Target, TargetType } from "../../typings/target.types"; import { createContinuousLineRange } from "../targetUtil/createContinuousRange"; import { addLineDelimiterRanges } from "../targetUtil/getLineDelimiters"; -import BaseTarget, { - CloneWithParameters, - CommonTargetParameters, -} from "./BaseTarget"; +import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; import LineTarget from "./LineTarget"; import { createContinuousRangeWeakTarget } from "./WeakTarget"; @@ -76,13 +73,6 @@ export default class ParagraphTarget extends BaseTarget { : this.contentRemovalRange; } - cloneWith(parameters: CloneWithParameters) { - return new ParagraphTarget({ - ...this.getCloneParameters(), - ...parameters, - }); - } - createContinuousRangeTarget( isReversed: boolean, endTarget: Target, diff --git a/src/processTargets/targets/PositionTarget.ts b/src/processTargets/targets/PositionTarget.ts index 8a65e09808..559d6eca01 100644 --- a/src/processTargets/targets/PositionTarget.ts +++ b/src/processTargets/targets/PositionTarget.ts @@ -1,12 +1,8 @@ -import { Position as VS_Position, Range, TextEditor } from "vscode"; -import { Position, Target, TargetType } from "../../typings/target.types"; +import { Range, TextEditor } from "vscode"; +import * as vscode from "vscode"; +import { Position, TargetType } from "../../typings/target.types"; import { EditWithRangeUpdater } from "../../typings/Types"; -import { createContinuousRange } from "../targetUtil/createContinuousRange"; -import BaseTarget, { - CloneWithParameters, - CommonTargetParameters, -} from "./BaseTarget"; -import { createContinuousRangeWeakTarget } from "./WeakTarget"; +import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; interface PositionTargetParameters extends CommonTargetParameters { readonly position: Position; @@ -95,41 +91,6 @@ export default class PositionTarget extends BaseTarget { return this.constructReplaceEdit(text); } - cloneWith(parameters: CloneWithParameters) { - return new PositionTarget({ - ...this.getCloneParameters(), - ...parameters, - }); - } - - createContinuousRangeTarget( - isReversed: boolean, - endTarget: Target, - includeStart: boolean, - includeEnd: boolean - ): Target { - if (this.isSameType(endTarget)) { - return new PositionTarget({ - ...this.getCloneParameters(), - isReversed, - contentRange: createContinuousRange( - this, - endTarget, - includeStart, - includeEnd - ), - }); - } - - return createContinuousRangeWeakTarget( - isReversed, - this, - endTarget, - includeStart, - includeEnd - ); - } - protected getCloneParameters() { return { ...this.state, @@ -153,13 +114,13 @@ function getEditRange( isLine: boolean, isBefore: boolean ) { - let position: VS_Position; + let position: vscode.Position; if (isLine) { const line = editor.document.lineAt(isBefore ? range.start : range.end); if (isBefore) { position = line.isEmptyOrWhitespace ? range.start - : new VS_Position( + : new vscode.Position( line.lineNumber, line.firstNonWhitespaceCharacterIndex ); diff --git a/src/processTargets/targets/RawSelectionTarget.ts b/src/processTargets/targets/RawSelectionTarget.ts index 7a53efe167..a4bd1d92f5 100644 --- a/src/processTargets/targets/RawSelectionTarget.ts +++ b/src/processTargets/targets/RawSelectionTarget.ts @@ -1,10 +1,5 @@ -import { Target, TargetType } from "../../typings/target.types"; -import { createContinuousRange } from "../targetUtil/createContinuousRange"; -import BaseTarget, { - CloneWithParameters, - CommonTargetParameters, -} from "./BaseTarget"; -import { createContinuousRangeWeakTarget } from "./WeakTarget"; +import { TargetType } from "../../typings/target.types"; +import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; export default class RawSelectionTarget extends BaseTarget { constructor(parameters: CommonTargetParameters) { @@ -24,41 +19,6 @@ export default class RawSelectionTarget extends BaseTarget { return undefined; } - cloneWith(parameters: CloneWithParameters) { - return new RawSelectionTarget({ - ...this.getCloneParameters(), - ...parameters, - }); - } - - createContinuousRangeTarget( - isReversed: boolean, - endTarget: Target, - includeStart: boolean, - includeEnd: boolean - ): Target { - if (this.isSameType(endTarget)) { - return new RawSelectionTarget({ - ...this.getCloneParameters(), - isReversed, - contentRange: createContinuousRange( - this, - endTarget, - includeStart, - includeEnd - ), - }); - } - - return createContinuousRangeWeakTarget( - isReversed, - this, - endTarget, - includeStart, - includeEnd - ); - } - protected getCloneParameters() { return this.state; } diff --git a/src/processTargets/targets/ScopeTypeTarget.ts b/src/processTargets/targets/ScopeTypeTarget.ts index aa118c03da..3e2dc48dac 100644 --- a/src/processTargets/targets/ScopeTypeTarget.ts +++ b/src/processTargets/targets/ScopeTypeTarget.ts @@ -8,10 +8,7 @@ import { createContinuousRange, createContinuousRangeFromRanges, } from "../targetUtil/createContinuousRange"; -import BaseTarget, { - CloneWithParameters, - CommonTargetParameters, -} from "./BaseTarget"; +import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; import { createContinuousRangeWeakTarget } from "./WeakTarget"; export interface ScopeTypeTargetParameters extends CommonTargetParameters { @@ -66,13 +63,6 @@ export default class ScopeTypeTarget extends BaseTarget { return super.getTrailingDelimiterRange(); } - cloneWith(parameters: CloneWithParameters) { - return new ScopeTypeTarget({ - ...this.getCloneParameters(), - ...parameters, - }); - } - createContinuousRangeTarget( isReversed: boolean, endTarget: Target, diff --git a/src/processTargets/targets/SurroundingPairTarget.ts b/src/processTargets/targets/SurroundingPairTarget.ts index cb1db74489..be2a8ce5a2 100644 --- a/src/processTargets/targets/SurroundingPairTarget.ts +++ b/src/processTargets/targets/SurroundingPairTarget.ts @@ -1,11 +1,7 @@ import { Range } from "vscode"; -import { Target, TargetType } from "../../typings/target.types"; -import { createContinuousRange } from "../targetUtil/createContinuousRange"; -import BaseTarget, { - CloneWithParameters, - CommonTargetParameters, -} from "./BaseTarget"; -import WeakTarget, { createContinuousRangeWeakTarget } from "./WeakTarget"; +import { TargetType } from "../../typings/target.types"; +import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; +import WeakTarget from "./WeakTarget"; interface SurroundingPairTargetParameters extends CommonTargetParameters { /** @@ -61,41 +57,6 @@ export default class SurroundingPairTarget extends BaseTarget { ); } - cloneWith(parameters: CloneWithParameters) { - return new SurroundingPairTarget({ - ...this.getCloneParameters(), - ...parameters, - }); - } - - createContinuousRangeTarget( - isReversed: boolean, - endTarget: Target, - includeStart: boolean, - includeEnd: boolean - ): Target { - if (this.isSameType(endTarget)) { - return new SurroundingPairTarget({ - ...this.getCloneParameters(), - isReversed, - contentRange: createContinuousRange( - this, - endTarget, - includeStart, - includeEnd - ), - }); - } - - return createContinuousRangeWeakTarget( - isReversed, - this, - endTarget, - includeStart, - includeEnd - ); - } - protected getCloneParameters() { return { ...this.state, diff --git a/src/processTargets/targets/TokenTarget.ts b/src/processTargets/targets/TokenTarget.ts index 4c8c7b8ae1..913fb7b4bf 100644 --- a/src/processTargets/targets/TokenTarget.ts +++ b/src/processTargets/targets/TokenTarget.ts @@ -1,10 +1,5 @@ -import { Target, TargetType } from "../../typings/target.types"; -import { createContinuousRange } from "../targetUtil/createContinuousRange"; -import BaseTarget, { - CloneWithParameters, - CommonTargetParameters, -} from "./BaseTarget"; -import { createContinuousRangeWeakTarget } from "./WeakTarget"; +import { TargetType } from "../../typings/target.types"; +import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; export default class TokenTarget extends BaseTarget { constructor(parameters: CommonTargetParameters) { @@ -18,41 +13,6 @@ export default class TokenTarget extends BaseTarget { return " "; } - cloneWith(parameters: CloneWithParameters) { - return new TokenTarget({ - ...this.getCloneParameters(), - ...parameters, - }); - } - - createContinuousRangeTarget( - isReversed: boolean, - endTarget: Target, - includeStart: boolean, - includeEnd: boolean - ): Target { - if (this.isSameType(endTarget)) { - return new TokenTarget({ - ...this.getCloneParameters(), - isReversed, - contentRange: createContinuousRange( - this, - endTarget, - includeStart, - includeEnd - ), - }); - } - - return createContinuousRangeWeakTarget( - isReversed, - this, - endTarget, - includeStart, - includeEnd - ); - } - protected getCloneParameters() { return this.state; } From 3bb09393117878b66fa3ccb5b3e922ed1f3add74 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Sun, 29 May 2022 22:30:23 +0100 Subject: [PATCH 247/314] Getting started --- .../modifiers/DelimiterRangeStage.ts | 4 +-- src/processTargets/targets/BaseTarget.ts | 25 +++++-------------- .../targets/DelimiterRangeTarget.ts | 4 +-- src/processTargets/targets/DocumentTarget.ts | 4 +-- src/processTargets/targets/LineTarget.ts | 4 +-- .../targets/NotebookCellTarget.ts | 4 +-- src/processTargets/targets/ParagraphTarget.ts | 13 +++++----- src/processTargets/targets/PositionTarget.ts | 4 +-- .../targets/RawSelectionTarget.ts | 4 +-- src/processTargets/targets/ScopeTypeTarget.ts | 15 +++++------ src/typings/target.types.ts | 22 ++-------------- src/util/typeUtils.ts | 13 ++++++++++ 12 files changed, 50 insertions(+), 66 deletions(-) create mode 100644 src/util/typeUtils.ts diff --git a/src/processTargets/modifiers/DelimiterRangeStage.ts b/src/processTargets/modifiers/DelimiterRangeStage.ts index 81bdae14da..3eabdd730e 100644 --- a/src/processTargets/modifiers/DelimiterRangeStage.ts +++ b/src/processTargets/modifiers/DelimiterRangeStage.ts @@ -12,7 +12,7 @@ export default class DelimiterRangeStage implements ModifierStage { switch (this.modifier.direction) { case "leading": - const leading = target.getLeadingDelimiterRange(true); + const leading = target.getLeadingDelimiterTarget(true); if (leading == null) { throw Error("No available leading range"); } @@ -20,7 +20,7 @@ export default class DelimiterRangeStage implements ModifierStage { break; case "trailing": - const trailing = target.getTrailingDelimiterRange(true); + const trailing = target.getTrailingDelimiterTarget(true); if (trailing == null) { throw Error("No available trailing range"); } diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index d71c2dddcf..bd73530cd2 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -1,12 +1,8 @@ import { Range, Selection, TextEditor } from "vscode"; -import { - EditNewContext, - Position, - Target, - TargetType, -} from "../../typings/target.types"; +import { EditNewContext, Position, Target } from "../../typings/target.types"; import { EditWithRangeUpdater } from "../../typings/Types"; import { selectionFromRange } from "../../util/selectionUtils"; +import { isSameType } from "../../util/typeUtils"; import { createContinuousRange } from "../targetUtil/createContinuousRange"; import { getTokenDelimiters } from "../targetUtil/getTokenDelimiters"; import { createContinuousRangeWeakTarget } from "./WeakTarget"; @@ -36,7 +32,6 @@ export default abstract class BaseTarget implements Target { }; } - abstract get type(): TargetType; abstract get delimiter(): string | undefined; get editor() { return this.state.editor; @@ -72,11 +67,7 @@ export default abstract class BaseTarget implements Target { return this.state.contentRange; } - is(type: TargetType): boolean { - return this.type === type; - } - - getLeadingDelimiterRange(force?: boolean) { + getLeadingDelimiterTarget() { const { includeDelimitersInRemoval, leadingDelimiterRange } = getTokenDelimiters(this.state.editor, this.state.contentRange); return includeDelimitersInRemoval || force @@ -84,7 +75,7 @@ export default abstract class BaseTarget implements Target { : undefined; } - getTrailingDelimiterRange(force?: boolean) { + getTrailingDelimiterTarget() { const { includeDelimitersInRemoval, trailingDelimiterRange } = getTokenDelimiters(this.state.editor, this.state.contentRange); return includeDelimitersInRemoval || force @@ -121,7 +112,7 @@ export default abstract class BaseTarget implements Target { getRemovalRange(): Range { const delimiterRange = - this.getTrailingDelimiterRange() ?? this.getLeadingDelimiterRange(); + this.getTrailingDelimiterTarget() ?? this.getLeadingDelimiterTarget(); return delimiterRange != null ? this.contentRemovalRange.union(delimiterRange) : this.contentRemovalRange; @@ -163,7 +154,7 @@ export default abstract class BaseTarget implements Target { includeStart: boolean, includeEnd: boolean ): Target { - if (this.isSameType(endTarget)) { + if (isSameType(this, endTarget)) { const constructor = Object.getPrototypeOf(this).constructor; return new constructor({ @@ -186,8 +177,4 @@ export default abstract class BaseTarget implements Target { includeEnd ); } - - protected isSameType(target: Target) { - return this.type === target.type; - } } diff --git a/src/processTargets/targets/DelimiterRangeTarget.ts b/src/processTargets/targets/DelimiterRangeTarget.ts index 85a1e069f2..c0d6ea8376 100644 --- a/src/processTargets/targets/DelimiterRangeTarget.ts +++ b/src/processTargets/targets/DelimiterRangeTarget.ts @@ -24,10 +24,10 @@ export default class DelimiterRangeTarget extends BaseTarget { get isLine() { return this.isLine_; } - getLeadingDelimiterRange() { + getLeadingDelimiterTarget() { return undefined; } - getTrailingDelimiterRange() { + getTrailingDelimiterTarget() { return undefined; } diff --git a/src/processTargets/targets/DocumentTarget.ts b/src/processTargets/targets/DocumentTarget.ts index 91647cc3a8..8bf9a586d0 100644 --- a/src/processTargets/targets/DocumentTarget.ts +++ b/src/processTargets/targets/DocumentTarget.ts @@ -19,10 +19,10 @@ export default class DocumentTarget extends BaseTarget { return true; } - getLeadingDelimiterRange() { + getLeadingDelimiterTarget() { return undefined; } - getTrailingDelimiterRange() { + getTrailingDelimiterTarget() { return undefined; } diff --git a/src/processTargets/targets/LineTarget.ts b/src/processTargets/targets/LineTarget.ts index d951aaa770..481952c5dd 100644 --- a/src/processTargets/targets/LineTarget.ts +++ b/src/processTargets/targets/LineTarget.ts @@ -30,11 +30,11 @@ export default class LineTarget extends BaseTarget { ); } - getLeadingDelimiterRange() { + getLeadingDelimiterTarget() { return getLineLeadingDelimiterRange(this.editor, this.contentRemovalRange); } - getTrailingDelimiterRange() { + getTrailingDelimiterTarget() { return getLineTrailingDelimiterRange(this.editor, this.contentRemovalRange); } diff --git a/src/processTargets/targets/NotebookCellTarget.ts b/src/processTargets/targets/NotebookCellTarget.ts index 878325bc5b..aaf4c0234e 100644 --- a/src/processTargets/targets/NotebookCellTarget.ts +++ b/src/processTargets/targets/NotebookCellTarget.ts @@ -14,10 +14,10 @@ export default class NotebookCellTarget extends BaseTarget { get delimiter() { return "\n"; } - getLeadingDelimiterRange() { + getLeadingDelimiterTarget() { return undefined; } - getTrailingDelimiterRange() { + getTrailingDelimiterTarget() { return undefined; } diff --git a/src/processTargets/targets/ParagraphTarget.ts b/src/processTargets/targets/ParagraphTarget.ts index 24a95d3e30..1bdfc8b5b2 100644 --- a/src/processTargets/targets/ParagraphTarget.ts +++ b/src/processTargets/targets/ParagraphTarget.ts @@ -1,5 +1,6 @@ import { Position, Range, TextDocument, TextEditor, TextLine } from "vscode"; import { Target, TargetType } from "../../typings/target.types"; +import { isSameType } from "../../util/typeUtils"; import { createContinuousLineRange } from "../targetUtil/createContinuousRange"; import { addLineDelimiterRanges } from "../targetUtil/getLineDelimiters"; import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; @@ -28,10 +29,10 @@ export default class ParagraphTarget extends BaseTarget { ); } - getLeadingDelimiterRange() { + getLeadingDelimiterTarget() { return getLeadingDelimiter(this.editor, this.contentRange); } - getTrailingDelimiterRange() { + getTrailingDelimiterTarget() { return getTrailingDelimiter(this.editor, this.contentRange); } @@ -44,8 +45,8 @@ export default class ParagraphTarget extends BaseTarget { getRemovalRange() { const delimiterRange = (() => { - const leadingDelimiterRange = this.getLeadingDelimiterRange(); - let trailingDelimiterRange = this.getTrailingDelimiterRange(); + const leadingDelimiterRange = this.getLeadingDelimiterTarget(); + let trailingDelimiterRange = this.getTrailingDelimiterTarget(); if (trailingDelimiterRange != null) { return trailingDelimiterRange; } @@ -79,7 +80,7 @@ export default class ParagraphTarget extends BaseTarget { includeStart: boolean, includeEnd: boolean ): Target { - if (this.isSameType(endTarget)) { + if (isSameType(this, endTarget)) { return new ParagraphTarget({ ...this.getCloneParameters(), isReversed, @@ -92,7 +93,7 @@ export default class ParagraphTarget extends BaseTarget { }); } - if (endTarget.is("line")) { + if (endTarget.isLine) { return new LineTarget({ editor: this.editor, isReversed, diff --git a/src/processTargets/targets/PositionTarget.ts b/src/processTargets/targets/PositionTarget.ts index 559d6eca01..027b9a74f7 100644 --- a/src/processTargets/targets/PositionTarget.ts +++ b/src/processTargets/targets/PositionTarget.ts @@ -29,10 +29,10 @@ export default class PositionTarget extends BaseTarget { return this.position_; } - getLeadingDelimiterRange() { + getLeadingDelimiterTarget() { return undefined; } - getTrailingDelimiterRange() { + getTrailingDelimiterTarget() { return undefined; } diff --git a/src/processTargets/targets/RawSelectionTarget.ts b/src/processTargets/targets/RawSelectionTarget.ts index a4bd1d92f5..749325c793 100644 --- a/src/processTargets/targets/RawSelectionTarget.ts +++ b/src/processTargets/targets/RawSelectionTarget.ts @@ -12,10 +12,10 @@ export default class RawSelectionTarget extends BaseTarget { get delimiter() { return undefined; } - getLeadingDelimiterRange() { + getLeadingDelimiterTarget() { return undefined; } - getTrailingDelimiterRange() { + getTrailingDelimiterTarget() { return undefined; } diff --git a/src/processTargets/targets/ScopeTypeTarget.ts b/src/processTargets/targets/ScopeTypeTarget.ts index 3e2dc48dac..f7e34a0ac7 100644 --- a/src/processTargets/targets/ScopeTypeTarget.ts +++ b/src/processTargets/targets/ScopeTypeTarget.ts @@ -2,11 +2,12 @@ import { Range } from "vscode"; import { SimpleScopeTypeType, Target, - TargetType, + TargetType } from "../../typings/target.types"; +import { isSameType } from "../../util/typeUtils"; import { createContinuousRange, - createContinuousRangeFromRanges, + createContinuousRangeFromRanges } from "../targetUtil/createContinuousRange"; import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; import { createContinuousRangeWeakTarget } from "./WeakTarget"; @@ -49,18 +50,18 @@ export default class ScopeTypeTarget extends BaseTarget { return this.contentRemovalRange_ ?? this.contentRange; } - getLeadingDelimiterRange() { + getLeadingDelimiterTarget() { if (this.hasDelimiterRange_) { return this.leadingDelimiterRange_; } - return super.getLeadingDelimiterRange(); + return super.getLeadingDelimiterTarget(); } - getTrailingDelimiterRange() { + getTrailingDelimiterTarget() { if (this.hasDelimiterRange_) { return this.trailingDelimiterRange_; } - return super.getTrailingDelimiterRange(); + return super.getTrailingDelimiterTarget(); } createContinuousRangeTarget( @@ -69,7 +70,7 @@ export default class ScopeTypeTarget extends BaseTarget { includeStart: boolean, includeEnd: boolean ): Target { - if (this.isSameType(endTarget)) { + if (isSameType(this, endTarget)) { const scopeTarget = endTarget; if (this.scopeTypeType_ === scopeTarget.scopeTypeType_) { const contentRemovalRange = diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 99f25ab04f..2e411811c4 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -278,23 +278,7 @@ export interface EditNewDelimiterContext { export type EditNewContext = EditNewCommandContext | EditNewDelimiterContext; -export type TargetType = - | "delimiterRange" - | "document" - | "line" - | "notebookCell" - | "paragraph" - | "position" - | "rawSelection" - | "scopeType" - | "surroundingPair" - | "token" - | "weak"; - export interface Target { - /** The type of this target */ - readonly type: TargetType; - /** The text editor used for all ranges */ readonly editor: TextEditor; @@ -322,14 +306,12 @@ export interface Target { /** Internal target that should be used for the that mark */ readonly thatTarget: Target; - /** Returns true if this target is of the given type */ - is(type: TargetType): boolean; getInteriorStrict(): Target[]; getBoundaryStrict(): Target[]; /** The range of the delimiter before the content selection */ - getLeadingDelimiterRange(force?: boolean): Range | undefined; + getLeadingDelimiterTarget(force?: boolean): Range | undefined; /** The range of the delimiter after the content selection */ - getTrailingDelimiterRange(force?: boolean): Range | undefined; + getTrailingDelimiterTarget(force?: boolean): Range | undefined; getRemovalRange(): Range; getRemovalHighlightRange(): Range | undefined; getEditNewContext(isBefore: boolean): EditNewContext; diff --git a/src/util/typeUtils.ts b/src/util/typeUtils.ts new file mode 100644 index 0000000000..da390ba0b3 --- /dev/null +++ b/src/util/typeUtils.ts @@ -0,0 +1,13 @@ +/** + * Determines whether two objects have the same constructor. + * + * @param a The first object + * @param b The second object + * @returns True if `a` and `b` have the same constructor + */ +export function isSameType(a: unknown, b: unknown): boolean { + return ( + Object.getPrototypeOf(a).constructor === + Object.getPrototypeOf(b).constructor + ); +} From 6a3b20854ffcd6a6d601ea1b4b5d62b352ce2adf Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 29 May 2022 21:30:48 +0000 Subject: [PATCH 248/314] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/processTargets/targets/ScopeTypeTarget.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/processTargets/targets/ScopeTypeTarget.ts b/src/processTargets/targets/ScopeTypeTarget.ts index f7e34a0ac7..0b4ad9f3ff 100644 --- a/src/processTargets/targets/ScopeTypeTarget.ts +++ b/src/processTargets/targets/ScopeTypeTarget.ts @@ -2,12 +2,12 @@ import { Range } from "vscode"; import { SimpleScopeTypeType, Target, - TargetType + TargetType, } from "../../typings/target.types"; import { isSameType } from "../../util/typeUtils"; import { createContinuousRange, - createContinuousRangeFromRanges + createContinuousRangeFromRanges, } from "../targetUtil/createContinuousRange"; import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; import { createContinuousRangeWeakTarget } from "./WeakTarget"; From 36c9f5f74edf2d40c885c1107c084c82aca806ba Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Mon, 30 May 2022 21:36:12 +0100 Subject: [PATCH 249/314] Start using InsertionRemovalBehavior --- src/actions/BringMoveSwap.ts | 2 +- .../insertionRemovalBehavior.types.ts | 9 ++ src/processTargets/modifiers/PositionStage.ts | 4 +- ...limitedSequenceInsertionRemovalBehavior.ts | 28 ++++++ .../TokenInsertionRemovalBehavior.ts | 90 +++++++++++++++++++ .../insertionRemovalBehavior.types.ts | 9 ++ src/processTargets/processTargets.ts | 20 +---- src/processTargets/targets/BaseTarget.ts | 54 +++++------ .../targets/DelimiterRangeTarget.ts | 2 +- src/processTargets/targets/DocumentTarget.ts | 2 +- src/processTargets/targets/LineTarget.ts | 17 ++-- .../targets/NotebookCellTarget.ts | 2 +- src/processTargets/targets/ParagraphTarget.ts | 2 +- src/processTargets/targets/PositionTarget.ts | 30 ++----- .../targets/RawSelectionTarget.ts | 2 +- src/processTargets/targets/ScopeTypeTarget.ts | 2 +- .../targets/SurroundingPairTarget.ts | 2 +- src/processTargets/targets/TokenTarget.ts | 6 +- src/processTargets/targets/WeakTarget.ts | 2 +- src/typings/target.types.ts | 9 +- 20 files changed, 182 insertions(+), 112 deletions(-) create mode 100644 src/processTargets/insertionRemovalBehavior.types.ts create mode 100644 src/processTargets/modifiers/insertionRemovalBehaviors/DelimitedSequenceInsertionRemovalBehavior.ts create mode 100644 src/processTargets/modifiers/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts create mode 100644 src/processTargets/modifiers/insertionRemovalBehaviors/insertionRemovalBehavior.types.ts diff --git a/src/actions/BringMoveSwap.ts b/src/actions/BringMoveSwap.ts index 4706fb0e37..97a24c845a 100644 --- a/src/actions/BringMoveSwap.ts +++ b/src/actions/BringMoveSwap.ts @@ -99,7 +99,7 @@ class BringMoveSwap implements Action { text = sources .map((source, i) => { const text = source.contentText; - const delimiter = destination.delimiter ?? source.delimiter; + const delimiter = destination.delimiterString ?? source.delimiterString; return i > 0 && delimiter != null ? delimiter + text : text; }) .join(""); diff --git a/src/processTargets/insertionRemovalBehavior.types.ts b/src/processTargets/insertionRemovalBehavior.types.ts new file mode 100644 index 0000000000..ca2874d41c --- /dev/null +++ b/src/processTargets/insertionRemovalBehavior.types.ts @@ -0,0 +1,9 @@ +import { Range } from "vscode"; +import { Target } from "../typings/target.types"; + +export default interface InsertionRemovalBehavior { + getLeadingDelimiterTarget(): Target | undefined; + getTrailingDelimiterTarget(): Target | undefined; + getRemovalRange(): Range; + delimiterString: string | undefined; +} diff --git a/src/processTargets/modifiers/PositionStage.ts b/src/processTargets/modifiers/PositionStage.ts index 3c9ffaf8ed..230cb47ec2 100644 --- a/src/processTargets/modifiers/PositionStage.ts +++ b/src/processTargets/modifiers/PositionStage.ts @@ -20,12 +20,12 @@ export function toPositionTarget(target: Target, position: Position): Target { switch (position) { case "before": contentRange = new Range(start, start); - delimiter = target.delimiter; + delimiter = target.delimiterString; break; case "after": contentRange = new Range(end, end); - delimiter = target.delimiter; + delimiter = target.delimiterString; break; case "start": diff --git a/src/processTargets/modifiers/insertionRemovalBehaviors/DelimitedSequenceInsertionRemovalBehavior.ts b/src/processTargets/modifiers/insertionRemovalBehaviors/DelimitedSequenceInsertionRemovalBehavior.ts new file mode 100644 index 0000000000..f078c25a71 --- /dev/null +++ b/src/processTargets/modifiers/insertionRemovalBehaviors/DelimitedSequenceInsertionRemovalBehavior.ts @@ -0,0 +1,28 @@ +import { Range } from "vscode"; +import { Target } from "../../../typings/target.types"; +import InsertionRemovalBehavior from "./insertionRemovalBehavior.types"; + +interface Config { + getLeadingDelimiterTarget(): Target | undefined; + getTrailingDelimiterTarget(): Target | undefined; + delimiterString: string; +} + +export default class DelimitedSequenceInsertionRemovalBehavior + implements InsertionRemovalBehavior +{ + constructor(private target: Target, private config: Config) {} + + delimiterString = this.config.delimiterString; + getLeadingDelimiterTarget = this.config.getLeadingDelimiterTarget; + getTrailingDelimiterTarget = this.config.getTrailingDelimiterTarget; + + getRemovalRange(): Range { + const delimiterTarget = + this.getTrailingDelimiterTarget() ?? this.getLeadingDelimiterTarget(); + + return delimiterTarget != null + ? this.target.contentRange.union(delimiterTarget.getRemovalRange()) + : this.target.contentRange; + } +} diff --git a/src/processTargets/modifiers/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts b/src/processTargets/modifiers/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts new file mode 100644 index 0000000000..f21b7aae57 --- /dev/null +++ b/src/processTargets/modifiers/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts @@ -0,0 +1,90 @@ +import { Range } from "vscode"; +import { Target } from "../../../typings/target.types"; +import RawSelectionTarget from "../../targets/RawSelectionTarget"; +import DelimitedSequenceInsertionRemovalBehavior from "./DelimitedSequenceInsertionRemovalBehavior"; +import InsertionRemovalBehavior from "./insertionRemovalBehavior.types"; + +export default class TokenInsertionRemovalBehavior + implements InsertionRemovalBehavior +{ + private delimitedSequenceInsertionRemovalBehavior: DelimitedSequenceInsertionRemovalBehavior; + + delimiterString = " "; + + constructor(private target: Target) { + this.delimitedSequenceInsertionRemovalBehavior = + new DelimitedSequenceInsertionRemovalBehavior(target, { + delimiterString: this.delimiterString, + getLeadingDelimiterTarget: () => this.getLeadingDelimiterTarget(), + getTrailingDelimiterTarget: () => this.getTrailingDelimiterTarget(), + }); + } + + getLeadingDelimiterTarget() { + const { editor } = this.target; + const { start } = this.target.contentRange; + + const startLine = editor.document.lineAt(start); + const leadingText = startLine.text.slice(0, start.character); + const leadingDelimiters = leadingText.match(/\s+$/); + + return leadingDelimiters == null + ? undefined + : new RawSelectionTarget({ + contentRange: new Range( + start.line, + start.character - leadingDelimiters[0].length, + start.line, + start.character + ), + editor, + isReversed: false, + }); + } + + getTrailingDelimiterTarget() { + const { editor } = this.target; + const { end } = this.target.contentRange; + + const endLine = editor.document.lineAt(end); + const trailingText = endLine.text.slice(end.character); + const trailingDelimiters = trailingText.match(/^\s+/); + + return trailingDelimiters == null + ? undefined + : new RawSelectionTarget({ + contentRange: new Range( + end.line, + end.character, + end.line, + end.character + trailingDelimiters[0].length + ), + editor, + isReversed: false, + }); + } + + getRemovalRange(): Range { + const { start, end } = this.target.contentRange; + const endLine = this.target.editor.document.lineAt(end); + + const leadingDelimiterTarget = this.getLeadingDelimiterTarget(); + const trailingDelimiterTarget = this.getTrailingDelimiterTarget(); + + // If there is a token directly to the left or right of us with no + // separating white space, then we might join two tokens if we try to clean + // up whitespace space. In this case we just remove the content range + // without attempting to clean up white space. + // + // In the future, we might get more sophisticated and to clean up white space if we can detect that it won't cause two tokens be merged + if ( + (leadingDelimiterTarget == null && start.character !== 0) || + (trailingDelimiterTarget == null && !end.isEqual(endLine.range.end)) + ) { + return this.target.contentRange; + } + + // Otherwise, behave like a whitespace delimited sequence + return this.delimitedSequenceInsertionRemovalBehavior.getRemovalRange(); + } +} diff --git a/src/processTargets/modifiers/insertionRemovalBehaviors/insertionRemovalBehavior.types.ts b/src/processTargets/modifiers/insertionRemovalBehaviors/insertionRemovalBehavior.types.ts new file mode 100644 index 0000000000..3441ebb19c --- /dev/null +++ b/src/processTargets/modifiers/insertionRemovalBehaviors/insertionRemovalBehavior.types.ts @@ -0,0 +1,9 @@ +import { Range } from "vscode"; +import { Target } from "../../../typings/target.types"; + +export default interface InsertionRemovalBehavior { + getLeadingDelimiterTarget(): Target | undefined; + getTrailingDelimiterTarget(): Target | undefined; + getRemovalRange(): Range; + delimiterString: string | undefined; +} diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index e66d0c621a..8d4a073c85 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -147,25 +147,7 @@ function processVerticalRangeTarget( anchorTarget.contentRange.end.character ); - if (anchorTarget.position != null) { - results.push( - new PositionTarget({ - editor: anchorTarget.editor, - isReversed: anchorTarget.isReversed, - contentRange, - position: anchorTarget.position, - delimiter: anchorTarget.delimiter, - }) - ); - } else { - results.push( - new WeakTarget({ - editor: anchorTarget.editor, - isReversed: anchorTarget.isReversed, - contentRange, - }) - ); - } + results.push(anchorTarget.withContentRange(contentRange)); if (i === activeLine) { return results; diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index bd73530cd2..fe5f9bd282 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -3,8 +3,8 @@ import { EditNewContext, Position, Target } from "../../typings/target.types"; import { EditWithRangeUpdater } from "../../typings/Types"; import { selectionFromRange } from "../../util/selectionUtils"; import { isSameType } from "../../util/typeUtils"; +import InsertionRemovalBehavior from "../insertionRemovalBehavior.types"; import { createContinuousRange } from "../targetUtil/createContinuousRange"; -import { getTokenDelimiters } from "../targetUtil/getTokenDelimiters"; import { createContinuousRangeWeakTarget } from "./WeakTarget"; /** Parameters supported by all target classes */ @@ -23,7 +23,10 @@ export interface CloneWithParameters { export default abstract class BaseTarget implements Target { protected readonly state: CommonTargetParameters; - constructor(parameters: CommonTargetParameters) { + constructor( + parameters: CommonTargetParameters, + private insertionRemovalBehavior: InsertionRemovalBehavior + ) { this.state = { editor: parameters.editor, isReversed: parameters.isReversed, @@ -32,19 +35,13 @@ export default abstract class BaseTarget implements Target { }; } - abstract get delimiter(): string | undefined; get editor() { return this.state.editor; } get isReversed() { return this.state.isReversed; } - protected get contentRemovalRange() { - return this.contentRange; - } - get position(): Position | undefined { - return undefined; - } + get isLine() { return false; } @@ -67,22 +64,6 @@ export default abstract class BaseTarget implements Target { return this.state.contentRange; } - getLeadingDelimiterTarget() { - const { includeDelimitersInRemoval, leadingDelimiterRange } = - getTokenDelimiters(this.state.editor, this.state.contentRange); - return includeDelimitersInRemoval || force - ? leadingDelimiterRange - : undefined; - } - - getTrailingDelimiterTarget() { - const { includeDelimitersInRemoval, trailingDelimiterRange } = - getTokenDelimiters(this.state.editor, this.state.contentRange); - return includeDelimitersInRemoval || force - ? trailingDelimiterRange - : undefined; - } - constructChangeEdit(text: string): EditWithRangeUpdater { return { range: this.contentRange, @@ -100,7 +81,7 @@ export default abstract class BaseTarget implements Target { } getEditNewContext(isBefore: boolean): EditNewContext { - const delimiter = this.delimiter ?? ""; + const delimiter = this.delimiterString ?? ""; if (delimiter === "\n" && !isBefore) { return { type: "command", command: "editor.action.insertLineAfter" }; } @@ -110,14 +91,6 @@ export default abstract class BaseTarget implements Target { }; } - getRemovalRange(): Range { - const delimiterRange = - this.getTrailingDelimiterTarget() ?? this.getLeadingDelimiterTarget(); - return delimiterRange != null - ? this.contentRemovalRange.union(delimiterRange) - : this.contentRemovalRange; - } - getRemovalHighlightRange(): Range | undefined { return this.getRemovalRange(); } @@ -177,4 +150,17 @@ export default abstract class BaseTarget implements Target { includeEnd ); } + + get delimiterString() { + return this.insertionRemovalBehavior.delimiterString; + } + getLeadingDelimiterTarget() { + return this.insertionRemovalBehavior.getLeadingDelimiterTarget(); + } + getTrailingDelimiterTarget() { + return this.insertionRemovalBehavior.getTrailingDelimiterTarget(); + } + getRemovalRange() { + return this.insertionRemovalBehavior.getRemovalRange(); + } } diff --git a/src/processTargets/targets/DelimiterRangeTarget.ts b/src/processTargets/targets/DelimiterRangeTarget.ts index c0d6ea8376..5e3424cead 100644 --- a/src/processTargets/targets/DelimiterRangeTarget.ts +++ b/src/processTargets/targets/DelimiterRangeTarget.ts @@ -18,7 +18,7 @@ export default class DelimiterRangeTarget extends BaseTarget { get type(): TargetType { return "delimiterRange"; } - get delimiter() { + get delimiterString() { return " "; } get isLine() { diff --git a/src/processTargets/targets/DocumentTarget.ts b/src/processTargets/targets/DocumentTarget.ts index 8bf9a586d0..056cb84e09 100644 --- a/src/processTargets/targets/DocumentTarget.ts +++ b/src/processTargets/targets/DocumentTarget.ts @@ -12,7 +12,7 @@ export default class DocumentTarget extends BaseTarget { get type(): TargetType { return "document"; } - get delimiter() { + get delimiterString() { return "\n"; } get isLine() { diff --git a/src/processTargets/targets/LineTarget.ts b/src/processTargets/targets/LineTarget.ts index 481952c5dd..d5ce2a8587 100644 --- a/src/processTargets/targets/LineTarget.ts +++ b/src/processTargets/targets/LineTarget.ts @@ -16,7 +16,7 @@ export default class LineTarget extends BaseTarget { get type(): TargetType { return "line"; } - get delimiter() { + get delimiterString() { return "\n"; } get isLine() { @@ -48,17 +48,10 @@ export default class LineTarget extends BaseTarget { includeStart: boolean, includeEnd: boolean ): Target { - if (this.isSameType(endTarget) || endTarget.is("paragraph")) { - return new LineTarget({ - ...this.getCloneParameters(), - isReversed, - contentRange: createContinuousLineRange( - this, - endTarget, - includeStart, - includeEnd - ), - }); + if (endTarget.isLine) { + return this.withContentRange( + createContinuousLineRange(this, endTarget, includeStart, includeEnd) + ); } return createContinuousRangeWeakTarget( diff --git a/src/processTargets/targets/NotebookCellTarget.ts b/src/processTargets/targets/NotebookCellTarget.ts index aaf4c0234e..ca6f55bc42 100644 --- a/src/processTargets/targets/NotebookCellTarget.ts +++ b/src/processTargets/targets/NotebookCellTarget.ts @@ -11,7 +11,7 @@ export default class NotebookCellTarget extends BaseTarget { get type(): TargetType { return "notebookCell"; } - get delimiter() { + get delimiterString() { return "\n"; } getLeadingDelimiterTarget() { diff --git a/src/processTargets/targets/ParagraphTarget.ts b/src/processTargets/targets/ParagraphTarget.ts index 1bdfc8b5b2..cb3759d7a8 100644 --- a/src/processTargets/targets/ParagraphTarget.ts +++ b/src/processTargets/targets/ParagraphTarget.ts @@ -15,7 +15,7 @@ export default class ParagraphTarget extends BaseTarget { get type(): TargetType { return "paragraph"; } - get delimiter() { + get delimiterString() { return "\n\n"; } get isLine() { diff --git a/src/processTargets/targets/PositionTarget.ts b/src/processTargets/targets/PositionTarget.ts index 027b9a74f7..fddc47c4cc 100644 --- a/src/processTargets/targets/PositionTarget.ts +++ b/src/processTargets/targets/PositionTarget.ts @@ -10,30 +10,11 @@ interface PositionTargetParameters extends CommonTargetParameters { } export default class PositionTarget extends BaseTarget { - private position_: Position; - private delimiter_: string | undefined; + private position: Position; constructor(parameters: PositionTargetParameters) { super(parameters); - this.position_ = parameters.position; - this.delimiter_ = parameters.delimiter; - } - - get type(): TargetType { - return "position"; - } - get delimiter() { - return this.delimiter_; - } - get position() { - return this.position_; - } - - getLeadingDelimiterTarget() { - return undefined; - } - getTrailingDelimiterTarget() { - return undefined; + this.position = parameters.position; } private constructReplaceEdit(text: string): EditWithRangeUpdater { @@ -45,7 +26,7 @@ export default class PositionTarget extends BaseTarget { } private constructInsertionEdit(text: string): EditWithRangeUpdater { - const delimiter = this.delimiter!; + const delimiter = this.delimiterString!; const isLine = delimiter.includes("\n"); const isBefore = this.position === "before"; @@ -83,7 +64,7 @@ export default class PositionTarget extends BaseTarget { constructChangeEdit(text: string): EditWithRangeUpdater { if ( - this.delimiter != null && + this.delimiterString != null && (this.position === "before" || this.position === "after") ) { return this.constructInsertionEdit(text); @@ -94,8 +75,7 @@ export default class PositionTarget extends BaseTarget { protected getCloneParameters() { return { ...this.state, - position: this.position_, - delimiter: this.delimiter_, + position: this.position, }; } } diff --git a/src/processTargets/targets/RawSelectionTarget.ts b/src/processTargets/targets/RawSelectionTarget.ts index 749325c793..c810b3b769 100644 --- a/src/processTargets/targets/RawSelectionTarget.ts +++ b/src/processTargets/targets/RawSelectionTarget.ts @@ -9,7 +9,7 @@ export default class RawSelectionTarget extends BaseTarget { get type(): TargetType { return "rawSelection"; } - get delimiter() { + get delimiterString() { return undefined; } getLeadingDelimiterTarget() { diff --git a/src/processTargets/targets/ScopeTypeTarget.ts b/src/processTargets/targets/ScopeTypeTarget.ts index 0b4ad9f3ff..7dbd6acf9a 100644 --- a/src/processTargets/targets/ScopeTypeTarget.ts +++ b/src/processTargets/targets/ScopeTypeTarget.ts @@ -43,7 +43,7 @@ export default class ScopeTypeTarget extends BaseTarget { get type(): TargetType { return "scopeType"; } - get delimiter() { + get delimiterString() { return this.delimiter_; } protected get contentRemovalRange() { diff --git a/src/processTargets/targets/SurroundingPairTarget.ts b/src/processTargets/targets/SurroundingPairTarget.ts index be2a8ce5a2..a69f862b4a 100644 --- a/src/processTargets/targets/SurroundingPairTarget.ts +++ b/src/processTargets/targets/SurroundingPairTarget.ts @@ -32,7 +32,7 @@ export default class SurroundingPairTarget extends BaseTarget { get type(): TargetType { return "surroundingPair"; } - get delimiter() { + get delimiterString() { return " "; } diff --git a/src/processTargets/targets/TokenTarget.ts b/src/processTargets/targets/TokenTarget.ts index 913fb7b4bf..6b9687868e 100644 --- a/src/processTargets/targets/TokenTarget.ts +++ b/src/processTargets/targets/TokenTarget.ts @@ -1,4 +1,3 @@ -import { TargetType } from "../../typings/target.types"; import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; export default class TokenTarget extends BaseTarget { @@ -6,10 +5,7 @@ export default class TokenTarget extends BaseTarget { super(parameters); } - get type(): TargetType { - return "token"; - } - get delimiter() { + get delimiterString() { return " "; } diff --git a/src/processTargets/targets/WeakTarget.ts b/src/processTargets/targets/WeakTarget.ts index 87a5626009..4420d4a13e 100644 --- a/src/processTargets/targets/WeakTarget.ts +++ b/src/processTargets/targets/WeakTarget.ts @@ -18,7 +18,7 @@ export default class WeakTarget extends BaseTarget { get type(): TargetType { return "weak"; } - get delimiter() { + get delimiterString() { return " "; } diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 2e411811c4..5d63a73159 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -289,10 +289,7 @@ export interface Target { readonly contentRange: Range; /** If this selection has a delimiter. For example, new line for a line or paragraph and comma for a list or argument */ - readonly delimiter?: string; - - /** The current position */ - readonly position?: Position; + readonly delimiterString?: string; /** If true this target should be treated as a line */ readonly isLine: boolean; @@ -309,9 +306,9 @@ export interface Target { getInteriorStrict(): Target[]; getBoundaryStrict(): Target[]; /** The range of the delimiter before the content selection */ - getLeadingDelimiterTarget(force?: boolean): Range | undefined; + getLeadingDelimiterTarget(): Target | undefined; /** The range of the delimiter after the content selection */ - getTrailingDelimiterTarget(force?: boolean): Range | undefined; + getTrailingDelimiterTarget(): Target | undefined; getRemovalRange(): Range; getRemovalHighlightRange(): Range | undefined; getEditNewContext(isBefore: boolean): EditNewContext; From ccd03d6d029554e9bb5ccf9cf403a8b76c750721 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 30 May 2022 20:36:49 +0000 Subject: [PATCH 250/314] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/actions/BringMoveSwap.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/actions/BringMoveSwap.ts b/src/actions/BringMoveSwap.ts index 97a24c845a..d46253bc00 100644 --- a/src/actions/BringMoveSwap.ts +++ b/src/actions/BringMoveSwap.ts @@ -99,7 +99,8 @@ class BringMoveSwap implements Action { text = sources .map((source, i) => { const text = source.contentText; - const delimiter = destination.delimiterString ?? source.delimiterString; + const delimiter = + destination.delimiterString ?? source.delimiterString; return i > 0 && delimiter != null ? delimiter + text : text; }) .join(""); From a2cce40ef62e37099730880e852f159148479463 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Mon, 30 May 2022 21:57:54 +0100 Subject: [PATCH 251/314] Cleanup --- .../TokenInsertionRemovalBehavior.ts | 8 +++++--- src/util/rangeUtils.ts | 11 +++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 src/util/rangeUtils.ts diff --git a/src/processTargets/modifiers/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts b/src/processTargets/modifiers/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts index f21b7aae57..f824aba09e 100644 --- a/src/processTargets/modifiers/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts +++ b/src/processTargets/modifiers/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts @@ -1,5 +1,6 @@ import { Range } from "vscode"; import { Target } from "../../../typings/target.types"; +import { isAtEndOfLine, isAtStartOfLine } from "../../../util/rangeUtils"; import RawSelectionTarget from "../../targets/RawSelectionTarget"; import DelimitedSequenceInsertionRemovalBehavior from "./DelimitedSequenceInsertionRemovalBehavior"; import InsertionRemovalBehavior from "./insertionRemovalBehavior.types"; @@ -66,7 +67,6 @@ export default class TokenInsertionRemovalBehavior getRemovalRange(): Range { const { start, end } = this.target.contentRange; - const endLine = this.target.editor.document.lineAt(end); const leadingDelimiterTarget = this.getLeadingDelimiterTarget(); const trailingDelimiterTarget = this.getTrailingDelimiterTarget(); @@ -78,8 +78,10 @@ export default class TokenInsertionRemovalBehavior // // In the future, we might get more sophisticated and to clean up white space if we can detect that it won't cause two tokens be merged if ( - (leadingDelimiterTarget == null && start.character !== 0) || - (trailingDelimiterTarget == null && !end.isEqual(endLine.range.end)) + (leadingDelimiterTarget == null && + !isAtStartOfLine(this.target.editor, start)) || + (trailingDelimiterTarget == null && + !isAtEndOfLine(this.target.editor, end)) ) { return this.target.contentRange; } diff --git a/src/util/rangeUtils.ts b/src/util/rangeUtils.ts new file mode 100644 index 0000000000..f56dada96e --- /dev/null +++ b/src/util/rangeUtils.ts @@ -0,0 +1,11 @@ +import { Position, TextEditor } from "vscode"; + +export function isAtEndOfLine(editor: TextEditor, position: Position) { + const endLine = editor.document.lineAt(position); + + return position.isEqual(endLine.range.end); +} + +export function isAtStartOfLine(editor: TextEditor, position: Position) { + return position.character === 0; +} From 98ff662fb572f6f1cbcab7a9fa50fe77c2e43877 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Mon, 30 May 2022 21:59:09 +0100 Subject: [PATCH 252/314] Tweak --- src/util/rangeUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/rangeUtils.ts b/src/util/rangeUtils.ts index f56dada96e..782f8e28cd 100644 --- a/src/util/rangeUtils.ts +++ b/src/util/rangeUtils.ts @@ -6,6 +6,6 @@ export function isAtEndOfLine(editor: TextEditor, position: Position) { return position.isEqual(endLine.range.end); } -export function isAtStartOfLine(editor: TextEditor, position: Position) { +export function isAtStartOfLine(_editor: TextEditor, position: Position) { return position.character === 0; } From 39064568cb25e7a9e09c90f3acaa50603cd5891a Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Mon, 30 May 2022 22:05:26 +0100 Subject: [PATCH 253/314] More cleanup --- .../insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts | 3 +-- src/util/rangeUtils.ts | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/processTargets/modifiers/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts b/src/processTargets/modifiers/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts index f824aba09e..406e7d1368 100644 --- a/src/processTargets/modifiers/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts +++ b/src/processTargets/modifiers/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts @@ -78,8 +78,7 @@ export default class TokenInsertionRemovalBehavior // // In the future, we might get more sophisticated and to clean up white space if we can detect that it won't cause two tokens be merged if ( - (leadingDelimiterTarget == null && - !isAtStartOfLine(this.target.editor, start)) || + (leadingDelimiterTarget == null && !isAtStartOfLine(start)) || (trailingDelimiterTarget == null && !isAtEndOfLine(this.target.editor, end)) ) { diff --git a/src/util/rangeUtils.ts b/src/util/rangeUtils.ts index 782f8e28cd..641c5e3b9d 100644 --- a/src/util/rangeUtils.ts +++ b/src/util/rangeUtils.ts @@ -6,6 +6,6 @@ export function isAtEndOfLine(editor: TextEditor, position: Position) { return position.isEqual(endLine.range.end); } -export function isAtStartOfLine(_editor: TextEditor, position: Position) { +export function isAtStartOfLine(position: Position) { return position.character === 0; } From ee95e0f42aab4078b8294e2f47e827278558385f Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Tue, 31 May 2022 20:01:36 +0100 Subject: [PATCH 254/314] More tweaks --- src/actions/CutCopyPaste.ts | 4 +- ...limitedSequenceInsertionRemovalBehavior.ts | 29 +--- .../TokenInsertionRemovalBehavior.ts | 131 ++++++++---------- src/processTargets/targets/BaseTarget.ts | 23 +-- src/processTargets/targets/LineTarget.ts | 3 - src/processTargets/targets/ParagraphTarget.ts | 52 +++++-- src/processTargets/targets/PlainTarget.ts | 14 ++ .../targets/RawSelectionTarget.ts | 32 ++--- 8 files changed, 132 insertions(+), 156 deletions(-) create mode 100644 src/processTargets/targets/PlainTarget.ts diff --git a/src/actions/CutCopyPaste.ts b/src/actions/CutCopyPaste.ts index 50c243c44e..b0e70739cc 100644 --- a/src/actions/CutCopyPaste.ts +++ b/src/actions/CutCopyPaste.ts @@ -1,4 +1,4 @@ -import RawSelectionTarget from "../processTargets/targets/RawSelectionTarget"; +import PlainTarget from "../processTargets/targets/PlainTarget"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; import { getOutsideOverflow } from "../util/targetUtils"; @@ -19,7 +19,7 @@ export class Cut implements Action { return getOutsideOverflow(target.editor, target.contentRange, range).map( (overflow): Target => // TODO Instead of creating a new target display decorations by range - new RawSelectionTarget({ + new PlainTarget({ editor: target.editor, contentRange: overflow, isReversed: false, diff --git a/src/processTargets/modifiers/insertionRemovalBehaviors/DelimitedSequenceInsertionRemovalBehavior.ts b/src/processTargets/modifiers/insertionRemovalBehaviors/DelimitedSequenceInsertionRemovalBehavior.ts index f078c25a71..abe9abc87f 100644 --- a/src/processTargets/modifiers/insertionRemovalBehaviors/DelimitedSequenceInsertionRemovalBehavior.ts +++ b/src/processTargets/modifiers/insertionRemovalBehaviors/DelimitedSequenceInsertionRemovalBehavior.ts @@ -1,28 +1,11 @@ import { Range } from "vscode"; import { Target } from "../../../typings/target.types"; -import InsertionRemovalBehavior from "./insertionRemovalBehavior.types"; -interface Config { - getLeadingDelimiterTarget(): Target | undefined; - getTrailingDelimiterTarget(): Target | undefined; - delimiterString: string; -} - -export default class DelimitedSequenceInsertionRemovalBehavior - implements InsertionRemovalBehavior -{ - constructor(private target: Target, private config: Config) {} - - delimiterString = this.config.delimiterString; - getLeadingDelimiterTarget = this.config.getLeadingDelimiterTarget; - getTrailingDelimiterTarget = this.config.getTrailingDelimiterTarget; - - getRemovalRange(): Range { - const delimiterTarget = - this.getTrailingDelimiterTarget() ?? this.getLeadingDelimiterTarget(); +export function getDelimitedSequenceRemovalRange(target: Target): Range { + const delimiterTarget = + target.getTrailingDelimiterTarget() ?? target.getLeadingDelimiterTarget(); - return delimiterTarget != null - ? this.target.contentRange.union(delimiterTarget.getRemovalRange()) - : this.target.contentRange; - } + return delimiterTarget != null + ? target.contentRange.union(delimiterTarget.contentRange) + : target.contentRange; } diff --git a/src/processTargets/modifiers/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts b/src/processTargets/modifiers/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts index 406e7d1368..bbb2c3410c 100644 --- a/src/processTargets/modifiers/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts +++ b/src/processTargets/modifiers/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts @@ -1,91 +1,72 @@ import { Range } from "vscode"; import { Target } from "../../../typings/target.types"; import { isAtEndOfLine, isAtStartOfLine } from "../../../util/rangeUtils"; -import RawSelectionTarget from "../../targets/RawSelectionTarget"; -import DelimitedSequenceInsertionRemovalBehavior from "./DelimitedSequenceInsertionRemovalBehavior"; -import InsertionRemovalBehavior from "./insertionRemovalBehavior.types"; +import PlainTarget from "../../targets/PlainTarget"; +import { getDelimitedSequenceRemovalRange } from "./DelimitedSequenceInsertionRemovalBehavior"; -export default class TokenInsertionRemovalBehavior - implements InsertionRemovalBehavior -{ - private delimitedSequenceInsertionRemovalBehavior: DelimitedSequenceInsertionRemovalBehavior; +export function getTokenLeadingDelimiterTarget(target: Target) { + const { editor } = target; + const { start } = target.contentRange; - delimiterString = " "; + const startLine = editor.document.lineAt(start); + const leadingText = startLine.text.slice(0, start.character); + const leadingDelimiters = leadingText.match(/\s+$/); - constructor(private target: Target) { - this.delimitedSequenceInsertionRemovalBehavior = - new DelimitedSequenceInsertionRemovalBehavior(target, { - delimiterString: this.delimiterString, - getLeadingDelimiterTarget: () => this.getLeadingDelimiterTarget(), - getTrailingDelimiterTarget: () => this.getTrailingDelimiterTarget(), + return leadingDelimiters == null + ? undefined + : new PlainTarget({ + contentRange: new Range( + start.line, + start.character - leadingDelimiters[0].length, + start.line, + start.character + ), + editor, + isReversed: false, }); - } +} - getLeadingDelimiterTarget() { - const { editor } = this.target; - const { start } = this.target.contentRange; +export function getTokenTrailingDelimiterTarget(target: Target) { + const { editor } = target; + const { end } = target.contentRange; - const startLine = editor.document.lineAt(start); - const leadingText = startLine.text.slice(0, start.character); - const leadingDelimiters = leadingText.match(/\s+$/); + const endLine = editor.document.lineAt(end); + const trailingText = endLine.text.slice(end.character); + const trailingDelimiters = trailingText.match(/^\s+/); - return leadingDelimiters == null - ? undefined - : new RawSelectionTarget({ - contentRange: new Range( - start.line, - start.character - leadingDelimiters[0].length, - start.line, - start.character - ), - editor, - isReversed: false, - }); - } + return trailingDelimiters == null + ? undefined + : new PlainTarget({ + contentRange: new Range( + end.line, + end.character, + end.line, + end.character + trailingDelimiters[0].length + ), + editor, + isReversed: false, + }); +} - getTrailingDelimiterTarget() { - const { editor } = this.target; - const { end } = this.target.contentRange; +export function getTokenRemovalRange(target: Target): Range { + const { start, end } = target.contentRange; - const endLine = editor.document.lineAt(end); - const trailingText = endLine.text.slice(end.character); - const trailingDelimiters = trailingText.match(/^\s+/); + const leadingDelimiterTarget = getTokenLeadingDelimiterTarget(target); + const trailingDelimiterTarget = getTokenTrailingDelimiterTarget(target); - return trailingDelimiters == null - ? undefined - : new RawSelectionTarget({ - contentRange: new Range( - end.line, - end.character, - end.line, - end.character + trailingDelimiters[0].length - ), - editor, - isReversed: false, - }); + // If there is a token directly to the left or right of us with no + // separating white space, then we might join two tokens if we try to clean + // up whitespace space. In this case we just remove the content range + // without attempting to clean up white space. + // + // In the future, we might get more sophisticated and to clean up white space if we can detect that it won't cause two tokens be merged + if ( + (leadingDelimiterTarget == null && !isAtStartOfLine(start)) || + (trailingDelimiterTarget == null && !isAtEndOfLine(target.editor, end)) + ) { + return target.contentRange; } - getRemovalRange(): Range { - const { start, end } = this.target.contentRange; - - const leadingDelimiterTarget = this.getLeadingDelimiterTarget(); - const trailingDelimiterTarget = this.getTrailingDelimiterTarget(); - - // If there is a token directly to the left or right of us with no - // separating white space, then we might join two tokens if we try to clean - // up whitespace space. In this case we just remove the content range - // without attempting to clean up white space. - // - // In the future, we might get more sophisticated and to clean up white space if we can detect that it won't cause two tokens be merged - if ( - (leadingDelimiterTarget == null && !isAtStartOfLine(start)) || - (trailingDelimiterTarget == null && - !isAtEndOfLine(this.target.editor, end)) - ) { - return this.target.contentRange; - } - - // Otherwise, behave like a whitespace delimited sequence - return this.delimitedSequenceInsertionRemovalBehavior.getRemovalRange(); - } + // Otherwise, behave like a whitespace delimited sequence + return getDelimitedSequenceRemovalRange(target); } diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index fe5f9bd282..2c6c45b94f 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -1,5 +1,5 @@ import { Range, Selection, TextEditor } from "vscode"; -import { EditNewContext, Position, Target } from "../../typings/target.types"; +import { EditNewContext, Target } from "../../typings/target.types"; import { EditWithRangeUpdater } from "../../typings/Types"; import { selectionFromRange } from "../../util/selectionUtils"; import { isSameType } from "../../util/typeUtils"; @@ -23,10 +23,7 @@ export interface CloneWithParameters { export default abstract class BaseTarget implements Target { protected readonly state: CommonTargetParameters; - constructor( - parameters: CommonTargetParameters, - private insertionRemovalBehavior: InsertionRemovalBehavior - ) { + constructor(parameters: CommonTargetParameters) { this.state = { editor: parameters.editor, isReversed: parameters.isReversed, @@ -151,16 +148,8 @@ export default abstract class BaseTarget implements Target { ); } - get delimiterString() { - return this.insertionRemovalBehavior.delimiterString; - } - getLeadingDelimiterTarget() { - return this.insertionRemovalBehavior.getLeadingDelimiterTarget(); - } - getTrailingDelimiterTarget() { - return this.insertionRemovalBehavior.getTrailingDelimiterTarget(); - } - getRemovalRange() { - return this.insertionRemovalBehavior.getRemovalRange(); - } + abstract get delimiterString(): string | undefined; + abstract getLeadingDelimiterTarget(): Target | undefined; + abstract getTrailingDelimiterTarget(): Target | undefined; + abstract getRemovalRange(): Range; } diff --git a/src/processTargets/targets/LineTarget.ts b/src/processTargets/targets/LineTarget.ts index d5ce2a8587..2b76842842 100644 --- a/src/processTargets/targets/LineTarget.ts +++ b/src/processTargets/targets/LineTarget.ts @@ -13,9 +13,6 @@ export default class LineTarget extends BaseTarget { super(parameters); } - get type(): TargetType { - return "line"; - } get delimiterString() { return "\n"; } diff --git a/src/processTargets/targets/ParagraphTarget.ts b/src/processTargets/targets/ParagraphTarget.ts index cb3759d7a8..9d1d5495c6 100644 --- a/src/processTargets/targets/ParagraphTarget.ts +++ b/src/processTargets/targets/ParagraphTarget.ts @@ -22,18 +22,28 @@ export default class ParagraphTarget extends BaseTarget { return true; } - protected get contentRemovalRange() { - return new Range( - new Position(this.contentRange.start.line, 0), - this.editor.document.lineAt(this.contentRange.end).range.end - ); - } - getLeadingDelimiterTarget() { - return getLeadingDelimiter(this.editor, this.contentRange); + const contentRange = getLeadingDelimiter(this.editor, this.contentRange); + + return contentRange == null + ? undefined + : new LineTarget({ + editor: this.editor, + isReversed: false, + contentRange, + }); } + getTrailingDelimiterTarget() { - return getTrailingDelimiter(this.editor, this.contentRange); + const contentRange = getTrailingDelimiter(this.editor, this.contentRange); + + return contentRange == null + ? undefined + : new LineTarget({ + editor: this.editor, + isReversed: false, + contentRange, + }); } private get leadingDelimiterHighlightRange() { @@ -44,34 +54,46 @@ export default class ParagraphTarget extends BaseTarget { } getRemovalRange() { + // TODO: In the future we could get rid of this function if {@link + // getDelimitedSequenceRemovalRange} made a continuous range from the target + // past its delimiter target and then used the removal range of that. const delimiterRange = (() => { const leadingDelimiterRange = this.getLeadingDelimiterTarget(); let trailingDelimiterRange = this.getTrailingDelimiterTarget(); if (trailingDelimiterRange != null) { - return trailingDelimiterRange; + return trailingDelimiterRange.contentRange; } if (leadingDelimiterRange) { - return leadingDelimiterRange; + return leadingDelimiterRange.contentRange; } return undefined; })(); + const contentRemovalRange = this.fullLineContentRange; + const removalRange = delimiterRange != null - ? this.contentRemovalRange.union(delimiterRange) - : this.contentRemovalRange; + ? contentRemovalRange.union(delimiterRange) + : contentRemovalRange; // Check if there is a new line delimiter to remove as well return addLineDelimiterRanges(this.editor, removalRange); } + private get fullLineContentRange() { + return new Range( + new Position(this.contentRange.start.line, 0), + this.editor.document.lineAt(this.contentRange.end).range.end + ); + } + getRemovalHighlightRange() { const delimiterRange = this.trailingDelimiterHighlightRange ?? this.leadingDelimiterHighlightRange; return delimiterRange != null - ? this.contentRemovalRange.union(delimiterRange) - : this.contentRemovalRange; + ? this.fullLineContentRange.union(delimiterRange) + : this.fullLineContentRange; } createContinuousRangeTarget( diff --git a/src/processTargets/targets/PlainTarget.ts b/src/processTargets/targets/PlainTarget.ts new file mode 100644 index 0000000000..8ec42a9bf6 --- /dev/null +++ b/src/processTargets/targets/PlainTarget.ts @@ -0,0 +1,14 @@ +import BaseTarget from "./BaseTarget"; + +/** + * A target that has no leading or trailing delimiters so it's removal range + * just consists of the content itself. Its insertion delimiter is empty string. + */ +export default class PlainTarget extends BaseTarget { + delimiterString = ""; + getLeadingDelimiterTarget = () => undefined; + getTrailingDelimiterTarget = () => undefined; + getRemovalRange = () => this.contentRange; + + protected getCloneParameters = () => this.state; +} diff --git a/src/processTargets/targets/RawSelectionTarget.ts b/src/processTargets/targets/RawSelectionTarget.ts index c810b3b769..20b3405f60 100644 --- a/src/processTargets/targets/RawSelectionTarget.ts +++ b/src/processTargets/targets/RawSelectionTarget.ts @@ -1,25 +1,15 @@ -import { TargetType } from "../../typings/target.types"; -import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; +import BaseTarget from "./BaseTarget"; +/** + * A target that has no leading or trailing delimiters so it's removal range + * just consists of the content itself. Its insertion delimiter will be + * inherited from the source in the case of a bring after a bring before + */ export default class RawSelectionTarget extends BaseTarget { - constructor(parameters: CommonTargetParameters) { - super(parameters); - } + delimiterString = undefined; + getLeadingDelimiterTarget = () => undefined; + getTrailingDelimiterTarget = () => undefined; + getRemovalRange = () => this.contentRange; - get type(): TargetType { - return "rawSelection"; - } - get delimiterString() { - return undefined; - } - getLeadingDelimiterTarget() { - return undefined; - } - getTrailingDelimiterTarget() { - return undefined; - } - - protected getCloneParameters() { - return this.state; - } + protected getCloneParameters = () => this.state; } From 58a78dd9514f213bee52c169dc355a5c1b00d616 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Tue, 31 May 2022 20:03:22 +0100 Subject: [PATCH 255/314] Tweaks --- src/processTargets/targets/PlainTarget.ts | 1 + src/processTargets/targets/RawSelectionTarget.ts | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/src/processTargets/targets/PlainTarget.ts b/src/processTargets/targets/PlainTarget.ts index 8ec42a9bf6..182f9bea3b 100644 --- a/src/processTargets/targets/PlainTarget.ts +++ b/src/processTargets/targets/PlainTarget.ts @@ -6,6 +6,7 @@ import BaseTarget from "./BaseTarget"; */ export default class PlainTarget extends BaseTarget { delimiterString = ""; + getLeadingDelimiterTarget = () => undefined; getTrailingDelimiterTarget = () => undefined; getRemovalRange = () => this.contentRange; diff --git a/src/processTargets/targets/RawSelectionTarget.ts b/src/processTargets/targets/RawSelectionTarget.ts index 20b3405f60..0dd2bbfbe0 100644 --- a/src/processTargets/targets/RawSelectionTarget.ts +++ b/src/processTargets/targets/RawSelectionTarget.ts @@ -6,7 +6,12 @@ import BaseTarget from "./BaseTarget"; * inherited from the source in the case of a bring after a bring before */ export default class RawSelectionTarget extends BaseTarget { + /** + * Note that we use an `undefined` value for `delimiterString` so that + * "bring" will use the source delimiterString + * */ delimiterString = undefined; + getLeadingDelimiterTarget = () => undefined; getTrailingDelimiterTarget = () => undefined; getRemovalRange = () => this.contentRange; From da08ed255e28aedf4bf7e7e4031bed18fa9cd2e5 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Tue, 31 May 2022 22:19:24 +0100 Subject: [PATCH 256/314] More cleanup --- .../modifiers/DelimiterRangeStage.ts | 22 +--- .../targetUtil/createContinuousRange.ts | 21 ++++ .../targetUtil/getLineDelimiters.ts | 30 ----- src/processTargets/targets/BaseTarget.ts | 4 +- .../targets/DelimiterRangeTarget.ts | 50 -------- src/processTargets/targets/LineTarget.ts | 83 ++++++++----- src/processTargets/targets/ParagraphTarget.ts | 114 +++++++----------- src/processTargets/targets/ScopeTypeTarget.ts | 3 - src/util/rangeUtils.ts | 17 ++- src/util/wrapRangeWithTarget.ts | 36 ++++++ 10 files changed, 175 insertions(+), 205 deletions(-) delete mode 100644 src/processTargets/targetUtil/getLineDelimiters.ts delete mode 100644 src/processTargets/targets/DelimiterRangeTarget.ts create mode 100644 src/util/wrapRangeWithTarget.ts diff --git a/src/processTargets/modifiers/DelimiterRangeStage.ts b/src/processTargets/modifiers/DelimiterRangeStage.ts index 3eabdd730e..4aa2990e3b 100644 --- a/src/processTargets/modifiers/DelimiterRangeStage.ts +++ b/src/processTargets/modifiers/DelimiterRangeStage.ts @@ -1,39 +1,25 @@ -import { Range } from "vscode"; import { DelimiterRangeModifier, Target } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; -import DelimiterRangeTarget from "../targets/DelimiterRangeTarget"; export default class DelimiterRangeStage implements ModifierStage { constructor(private modifier: DelimiterRangeModifier) {} run(context: ProcessedTargetsContext, target: Target): Target[] { - let contentRange: Range; - switch (this.modifier.direction) { case "leading": - const leading = target.getLeadingDelimiterTarget(true); + const leading = target.getLeadingDelimiterTarget(); if (leading == null) { throw Error("No available leading range"); } - contentRange = leading; - break; + return [leading]; case "trailing": - const trailing = target.getTrailingDelimiterTarget(true); + const trailing = target.getTrailingDelimiterTarget(); if (trailing == null) { throw Error("No available trailing range"); } - contentRange = trailing; + return [trailing]; } - - return [ - new DelimiterRangeTarget({ - editor: target.editor, - isReversed: target.isReversed, - contentRange, - isLine: target.is("paragraph"), - }), - ]; } } diff --git a/src/processTargets/targetUtil/createContinuousRange.ts b/src/processTargets/targetUtil/createContinuousRange.ts index b85e65aedf..2f21737b0c 100644 --- a/src/processTargets/targetUtil/createContinuousRange.ts +++ b/src/processTargets/targetUtil/createContinuousRange.ts @@ -44,3 +44,24 @@ export function createContinuousLineRange( return new Range(start, end); } + +export function createSimpleContinuousRangeTarget( + target1: Target, + target2: Target, + isReversed: boolean = false, + includeStart: boolean = true, + includeEnd: boolean = true +) { + const isForward = target1.contentRange.start.isBefore( + target2.contentRange.start + ); + const anchorTarget = isForward ? target1 : target2; + const activeTarget = isForward ? target2 : target1; + + return anchorTarget.createContinuousRangeTarget( + isReversed, + activeTarget, + includeStart, + includeEnd + ); +} diff --git a/src/processTargets/targetUtil/getLineDelimiters.ts b/src/processTargets/targetUtil/getLineDelimiters.ts deleted file mode 100644 index 004fb56d46..0000000000 --- a/src/processTargets/targetUtil/getLineDelimiters.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { TextEditor, Range, Position } from "vscode"; - -export function getLineLeadingDelimiterRange(editor: TextEditor, range: Range) { - const { start } = range; - return start.line > 0 - ? new Range(editor.document.lineAt(start.line - 1).range.end, range.start) - : undefined; -} - -export function getLineTrailingDelimiterRange( - editor: TextEditor, - range: Range -) { - const { end } = range; - return end.line + 1 < editor.document.lineCount - ? new Range(range.end, new Position(end.line + 1, 0)) - : undefined; -} - -export function addLineDelimiterRanges(editor: TextEditor, range: Range) { - const trailingDelimiterRange = getLineTrailingDelimiterRange(editor, range); - if (trailingDelimiterRange != null) { - return range.union(trailingDelimiterRange); - } - const leadingDelimiterRange = getLineLeadingDelimiterRange(editor, range); - if (leadingDelimiterRange != null) { - return range.union(leadingDelimiterRange); - } - return range; -} diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index 2c6c45b94f..532ac46049 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -39,9 +39,7 @@ export default abstract class BaseTarget implements Target { return this.state.isReversed; } - get isLine() { - return false; - } + isLine = false; get thatTarget(): Target { return this.state.thatTarget != null diff --git a/src/processTargets/targets/DelimiterRangeTarget.ts b/src/processTargets/targets/DelimiterRangeTarget.ts deleted file mode 100644 index 5e3424cead..0000000000 --- a/src/processTargets/targets/DelimiterRangeTarget.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { Range } from "vscode"; -import { TargetType } from "../../typings/target.types"; -import { addLineDelimiterRanges } from "../targetUtil/getLineDelimiters"; -import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; - -interface DelimiterRangeTargetParameters extends CommonTargetParameters { - readonly isLine: boolean; -} - -export default class DelimiterRangeTarget extends BaseTarget { - private isLine_: boolean; - - constructor(parameters: DelimiterRangeTargetParameters) { - super(parameters); - this.isLine_ = parameters.isLine; - } - - get type(): TargetType { - return "delimiterRange"; - } - get delimiterString() { - return " "; - } - get isLine() { - return this.isLine_; - } - getLeadingDelimiterTarget() { - return undefined; - } - getTrailingDelimiterTarget() { - return undefined; - } - - getRemovalRange(): Range { - return this.isLine - ? addLineDelimiterRanges(this.editor, this.contentRange) - : this.contentRange; - } - - getRemovalHighlightRange(): Range { - return this.contentRange; - } - - protected getCloneParameters() { - return { - ...this.state, - isLine: this.isLine_, - }; - } -} diff --git a/src/processTargets/targets/LineTarget.ts b/src/processTargets/targets/LineTarget.ts index 2b76842842..0abc3f4a1e 100644 --- a/src/processTargets/targets/LineTarget.ts +++ b/src/processTargets/targets/LineTarget.ts @@ -1,44 +1,52 @@ -import { Position, Range } from "vscode"; -import { Target, TargetType } from "../../typings/target.types"; +import { Position, Range, TextEditor } from "vscode"; +import { Target } from "../../typings/target.types"; +import { expandToFullLine } from "../../util/rangeUtils"; +import { wrapRangeWithTarget } from "../../util/wrapRangeWithTarget"; import { createContinuousLineRange } from "../targetUtil/createContinuousRange"; import { - getLineLeadingDelimiterRange, - getLineTrailingDelimiterRange, + getLineLeadingDelimiterRange as getLeadingDelimiterRange, + getLineTrailingDelimiterRange as getTrailingDelimiterRange, } from "../targetUtil/getLineDelimiters"; -import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; +import BaseTarget from "./BaseTarget"; +import PlainTarget from "./PlainTarget"; import { createContinuousRangeWeakTarget } from "./WeakTarget"; export default class LineTarget extends BaseTarget { - constructor(parameters: CommonTargetParameters) { - super(parameters); - } + delimiterString = "\n"; + isLine = true; - get delimiterString() { - return "\n"; - } - get isLine() { - return true; - } - - protected get contentRemovalRange() { - return new Range( - new Position(this.contentRange.start.line, 0), - this.editor.document.lineAt(this.contentRange.end).range.end - ); + private get fullLineContentRange() { + return expandToFullLine(this.editor, this.contentRange); } getLeadingDelimiterTarget() { - return getLineLeadingDelimiterRange(this.editor, this.contentRemovalRange); + return wrapRangeWithTarget( + PlainTarget, + this.editor, + getLeadingDelimiterRange(this.editor, this.fullLineContentRange) + ); } getTrailingDelimiterTarget() { - return getLineTrailingDelimiterRange(this.editor, this.contentRemovalRange); + return wrapRangeWithTarget( + PlainTarget, + this.editor, + getTrailingDelimiterRange(this.editor, this.fullLineContentRange) + ); } - getRemovalHighlightRange() { - return this.contentRange; + getRemovalRange() { + const contentRemovalRange = this.fullLineContentRange; + const delimiterTarget = + this.getTrailingDelimiterTarget() ?? this.getLeadingDelimiterTarget(); + + return delimiterTarget == null + ? contentRemovalRange + : contentRemovalRange.union(delimiterTarget.contentRange); } + getRemovalHighlightRange = () => this.fullLineContentRange; + createContinuousRangeTarget( isReversed: boolean, endTarget: Target, @@ -46,9 +54,16 @@ export default class LineTarget extends BaseTarget { includeEnd: boolean ): Target { if (endTarget.isLine) { - return this.withContentRange( - createContinuousLineRange(this, endTarget, includeStart, includeEnd) - ); + return new LineTarget({ + editor: this.editor, + isReversed, + contentRange: createContinuousLineRange( + this, + endTarget, + includeStart, + includeEnd + ), + }); } return createContinuousRangeWeakTarget( @@ -64,3 +79,17 @@ export default class LineTarget extends BaseTarget { return this.state; } } + +function getLeadingDelimiterRange(editor: TextEditor, range: Range) { + const { start } = range; + return start.line > 0 + ? new Range(editor.document.lineAt(start.line - 1).range.end, range.start) + : undefined; +} + +function getTrailingDelimiterRange(editor: TextEditor, range: Range) { + const { end } = range; + return end.line + 1 < editor.document.lineCount + ? new Range(range.end, new Position(end.line + 1, 0)) + : undefined; +} diff --git a/src/processTargets/targets/ParagraphTarget.ts b/src/processTargets/targets/ParagraphTarget.ts index 9d1d5495c6..8d10bfdf79 100644 --- a/src/processTargets/targets/ParagraphTarget.ts +++ b/src/processTargets/targets/ParagraphTarget.ts @@ -1,98 +1,66 @@ import { Position, Range, TextDocument, TextEditor, TextLine } from "vscode"; -import { Target, TargetType } from "../../typings/target.types"; +import { Target } from "../../typings/target.types"; +import { expandToFullLine } from "../../util/rangeUtils"; import { isSameType } from "../../util/typeUtils"; -import { createContinuousLineRange } from "../targetUtil/createContinuousRange"; -import { addLineDelimiterRanges } from "../targetUtil/getLineDelimiters"; -import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; +import { wrapRangeWithTarget } from "../../util/wrapRangeWithTarget"; +import { + createContinuousLineRange, + createSimpleContinuousRangeTarget, +} from "../targetUtil/createContinuousRange"; +import BaseTarget from "./BaseTarget"; import LineTarget from "./LineTarget"; import { createContinuousRangeWeakTarget } from "./WeakTarget"; export default class ParagraphTarget extends BaseTarget { - constructor(parameters: CommonTargetParameters) { - super(parameters); - } - - get type(): TargetType { - return "paragraph"; - } - get delimiterString() { - return "\n\n"; - } - get isLine() { - return true; - } + delimiterString = "\n\n"; + isLine = true; getLeadingDelimiterTarget() { - const contentRange = getLeadingDelimiter(this.editor, this.contentRange); - - return contentRange == null - ? undefined - : new LineTarget({ - editor: this.editor, - isReversed: false, - contentRange, - }); + return wrapRangeWithTarget( + LineTarget, + this.editor, + getLeadingDelimiterRange(this.editor, this.contentRange) + ); } getTrailingDelimiterTarget() { - const contentRange = getTrailingDelimiter(this.editor, this.contentRange); - - return contentRange == null - ? undefined - : new LineTarget({ - editor: this.editor, - isReversed: false, - contentRange, - }); - } - - private get leadingDelimiterHighlightRange() { - return getLeadingDelimiter(this.editor, this.contentRange); - } - private get trailingDelimiterHighlightRange() { - return getTrailingDelimiter(this.editor, this.contentRange); + return wrapRangeWithTarget( + LineTarget, + this.editor, + getTrailingDelimiterRange(this.editor, this.contentRange) + ); } getRemovalRange() { // TODO: In the future we could get rid of this function if {@link // getDelimitedSequenceRemovalRange} made a continuous range from the target // past its delimiter target and then used the removal range of that. - const delimiterRange = (() => { - const leadingDelimiterRange = this.getLeadingDelimiterTarget(); - let trailingDelimiterRange = this.getTrailingDelimiterTarget(); - if (trailingDelimiterRange != null) { - return trailingDelimiterRange.contentRange; - } - if (leadingDelimiterRange) { - return leadingDelimiterRange.contentRange; - } - return undefined; - })(); - const contentRemovalRange = this.fullLineContentRange; - - const removalRange = - delimiterRange != null - ? contentRemovalRange.union(delimiterRange) - : contentRemovalRange; - - // Check if there is a new line delimiter to remove as well - return addLineDelimiterRanges(this.editor, removalRange); + const delimiterTarget = + this.getTrailingDelimiterTarget() ?? this.getLeadingDelimiterTarget(); + + // If there is a delimiter, it will be a line target, so we join it with + // ourself to create a line target containing ourself and the delimiter + // line. We then allow the line target removal range code to cleanup any + // extra leading or trailing newline + return delimiterTarget == null + ? contentRemovalRange + : createSimpleContinuousRangeTarget( + this, + delimiterTarget + ).getRemovalRange(); } private get fullLineContentRange() { - return new Range( - new Position(this.contentRange.start.line, 0), - this.editor.document.lineAt(this.contentRange.end).range.end - ); + return expandToFullLine(this.editor, this.contentRange); } getRemovalHighlightRange() { - const delimiterRange = - this.trailingDelimiterHighlightRange ?? - this.leadingDelimiterHighlightRange; - return delimiterRange != null - ? this.fullLineContentRange.union(delimiterRange) + const delimiterTarget = + this.getTrailingDelimiterTarget() ?? this.getLeadingDelimiterTarget(); + + return delimiterTarget != null + ? this.fullLineContentRange.union(delimiterTarget.contentRange) : this.fullLineContentRange; } @@ -142,7 +110,7 @@ export default class ParagraphTarget extends BaseTarget { } } -function getLeadingDelimiter(editor: TextEditor, contentRange: Range) { +function getLeadingDelimiterRange(editor: TextEditor, contentRange: Range) { const { document } = editor; const { lineAt } = document; const startLine = lineAt(contentRange.start); @@ -167,7 +135,7 @@ function getLeadingDelimiter(editor: TextEditor, contentRange: Range) { return undefined; } -function getTrailingDelimiter(editor: TextEditor, contentRange: Range) { +function getTrailingDelimiterRange(editor: TextEditor, contentRange: Range) { const { document } = editor; const { lineAt } = document; const endLine = lineAt(contentRange.end); diff --git a/src/processTargets/targets/ScopeTypeTarget.ts b/src/processTargets/targets/ScopeTypeTarget.ts index 7dbd6acf9a..1bbe6f4cfc 100644 --- a/src/processTargets/targets/ScopeTypeTarget.ts +++ b/src/processTargets/targets/ScopeTypeTarget.ts @@ -40,9 +40,6 @@ export default class ScopeTypeTarget extends BaseTarget { !!this.leadingDelimiterRange_ || !!this.trailingDelimiterRange_; } - get type(): TargetType { - return "scopeType"; - } get delimiterString() { return this.delimiter_; } diff --git a/src/util/rangeUtils.ts b/src/util/rangeUtils.ts index 641c5e3b9d..e05aa0e190 100644 --- a/src/util/rangeUtils.ts +++ b/src/util/rangeUtils.ts @@ -1,4 +1,4 @@ -import { Position, TextEditor } from "vscode"; +import { Position, Range, TextEditor } from "vscode"; export function isAtEndOfLine(editor: TextEditor, position: Position) { const endLine = editor.document.lineAt(position); @@ -9,3 +9,18 @@ export function isAtEndOfLine(editor: TextEditor, position: Position) { export function isAtStartOfLine(position: Position) { return position.character === 0; } + +/** + * Expands the given range to in the full line(s) containing it, including + * leading and trailing white space. + * + * @param editor The editor + * @param range The range to expand + * @returns The expanded range + */ +export function expandToFullLine(editor: TextEditor, range: Range) { + return new Range( + new Position(range.start.line, 0), + editor.document.lineAt(range.end).range.end + ); +} diff --git a/src/util/wrapRangeWithTarget.ts b/src/util/wrapRangeWithTarget.ts new file mode 100644 index 0000000000..31ab80c296 --- /dev/null +++ b/src/util/wrapRangeWithTarget.ts @@ -0,0 +1,36 @@ +import { Range, TextEditor } from "vscode"; +import { CommonTargetParameters } from "../processTargets/targets/BaseTarget"; +import { Target } from "../typings/target.types"; + +type TargetConstructor = new ( + parameters: CommonTargetParameters +) => T; + +export function wrapRangeWithTarget( + constructor: TargetConstructor, + editor: TextEditor, + range: undefined +): undefined; +export function wrapRangeWithTarget( + constructor: TargetConstructor, + editor: TextEditor, + range: Range +): T; +export function wrapRangeWithTarget( + constructor: TargetConstructor, + editor: TextEditor, + range: Range | undefined +): T | undefined; +export function wrapRangeWithTarget( + constructor: TargetConstructor, + editor: TextEditor, + range: Range | undefined +): T | undefined { + return range == null + ? undefined + : new constructor({ + editor, + isReversed: false, + contentRange: range, + }); +} From 430183618e6506c5a35a0a0f800b53803649ef9b Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 1 Jun 2022 13:55:58 +0200 Subject: [PATCH 257/314] Cleanup --- .../insertionRemovalBehavior.types.ts | 9 --- .../modifiers/ModifyIfWeakStage.ts | 2 +- .../targetUtil/getTokenDelimiters.ts | 43 -------------- ...limitedSequenceInsertionRemovalBehavior.ts | 0 .../TokenInsertionRemovalBehavior.ts | 8 ++- .../insertionRemovalBehavior.types.ts | 0 src/processTargets/targets/BaseTarget.ts | 5 +- src/processTargets/targets/DocumentTarget.ts | 17 ++---- src/processTargets/targets/LineTarget.ts | 4 -- .../targets/NotebookCellTarget.ts | 19 ++---- src/processTargets/targets/ParagraphTarget.ts | 2 +- src/processTargets/targets/PositionTarget.ts | 10 +++- src/processTargets/targets/ScopeTypeTarget.ts | 59 ++++++++++++------- .../targets/SurroundingPairTarget.ts | 19 ++++-- src/processTargets/targets/TokenTarget.ts | 19 +++++- src/processTargets/targets/WeakTarget.ts | 32 +++++----- src/typings/target.types.ts | 3 + 17 files changed, 119 insertions(+), 132 deletions(-) delete mode 100644 src/processTargets/insertionRemovalBehavior.types.ts delete mode 100644 src/processTargets/targetUtil/getTokenDelimiters.ts rename src/processTargets/{modifiers => targetUtil}/insertionRemovalBehaviors/DelimitedSequenceInsertionRemovalBehavior.ts (100%) rename src/processTargets/{modifiers => targetUtil}/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts (92%) rename src/processTargets/{modifiers => targetUtil}/insertionRemovalBehaviors/insertionRemovalBehavior.types.ts (100%) diff --git a/src/processTargets/insertionRemovalBehavior.types.ts b/src/processTargets/insertionRemovalBehavior.types.ts deleted file mode 100644 index ca2874d41c..0000000000 --- a/src/processTargets/insertionRemovalBehavior.types.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Range } from "vscode"; -import { Target } from "../typings/target.types"; - -export default interface InsertionRemovalBehavior { - getLeadingDelimiterTarget(): Target | undefined; - getTrailingDelimiterTarget(): Target | undefined; - getRemovalRange(): Range; - delimiterString: string | undefined; -} diff --git a/src/processTargets/modifiers/ModifyIfWeakStage.ts b/src/processTargets/modifiers/ModifyIfWeakStage.ts index f92a8994f8..344923b359 100644 --- a/src/processTargets/modifiers/ModifyIfWeakStage.ts +++ b/src/processTargets/modifiers/ModifyIfWeakStage.ts @@ -18,7 +18,7 @@ export default class ModifyIfWeakStage implements ModifierStage { run(context: ProcessedTargetsContext, target: Target): Target[] { /** If true this target is of weak type and should use inference/upgrade when needed. See {@link WeakTarget} for more info */ - if (target.type === "weak") { + if (target.isWeak) { return this.nestedStage .run(context, target) .map((newTarget) => newTarget.withThatTarget(target)); diff --git a/src/processTargets/targetUtil/getTokenDelimiters.ts b/src/processTargets/targetUtil/getTokenDelimiters.ts deleted file mode 100644 index b8259ebd24..0000000000 --- a/src/processTargets/targetUtil/getTokenDelimiters.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { Range, TextEditor } from "vscode"; - -export function getTokenDelimiters(editor: TextEditor, contentRange: Range) { - const { document } = editor; - const { start, end } = contentRange; - const endLine = document.lineAt(end); - - const startLine = document.lineAt(start); - const leadingText = startLine.text.slice(0, start.character); - const leadingDelimiters = leadingText.match(/\s+$/); - const leadingDelimiterRange = - leadingDelimiters != null - ? new Range( - start.line, - start.character - leadingDelimiters[0].length, - start.line, - start.character - ) - : undefined; - - const trailingText = endLine.text.slice(end.character); - const trailingDelimiters = trailingText.match(/^\s+/); - const trailingDelimiterRange = - trailingDelimiters != null - ? new Range( - end.line, - end.character, - end.line, - end.character + trailingDelimiters[0].length - ) - : undefined; - - const includeDelimitersInRemoval = - (leadingDelimiterRange != null || trailingDelimiterRange != null) && - (leadingDelimiterRange != null || start.character === 0) && - (trailingDelimiterRange != null || end.isEqual(endLine.range.end)); - - return { - includeDelimitersInRemoval, - leadingDelimiterRange, - trailingDelimiterRange, - }; -} diff --git a/src/processTargets/modifiers/insertionRemovalBehaviors/DelimitedSequenceInsertionRemovalBehavior.ts b/src/processTargets/targetUtil/insertionRemovalBehaviors/DelimitedSequenceInsertionRemovalBehavior.ts similarity index 100% rename from src/processTargets/modifiers/insertionRemovalBehaviors/DelimitedSequenceInsertionRemovalBehavior.ts rename to src/processTargets/targetUtil/insertionRemovalBehaviors/DelimitedSequenceInsertionRemovalBehavior.ts diff --git a/src/processTargets/modifiers/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts b/src/processTargets/targetUtil/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts similarity index 92% rename from src/processTargets/modifiers/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts rename to src/processTargets/targetUtil/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts index bbb2c3410c..6b308a8853 100644 --- a/src/processTargets/modifiers/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts +++ b/src/processTargets/targetUtil/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts @@ -4,7 +4,9 @@ import { isAtEndOfLine, isAtStartOfLine } from "../../../util/rangeUtils"; import PlainTarget from "../../targets/PlainTarget"; import { getDelimitedSequenceRemovalRange } from "./DelimitedSequenceInsertionRemovalBehavior"; -export function getTokenLeadingDelimiterTarget(target: Target) { +export function getTokenLeadingDelimiterTarget( + target: Target +): Target | undefined { const { editor } = target; const { start } = target.contentRange; @@ -26,7 +28,9 @@ export function getTokenLeadingDelimiterTarget(target: Target) { }); } -export function getTokenTrailingDelimiterTarget(target: Target) { +export function getTokenTrailingDelimiterTarget( + target: Target +): Target | undefined { const { editor } = target; const { end } = target.contentRange; diff --git a/src/processTargets/modifiers/insertionRemovalBehaviors/insertionRemovalBehavior.types.ts b/src/processTargets/targetUtil/insertionRemovalBehaviors/insertionRemovalBehavior.types.ts similarity index 100% rename from src/processTargets/modifiers/insertionRemovalBehaviors/insertionRemovalBehavior.types.ts rename to src/processTargets/targetUtil/insertionRemovalBehaviors/insertionRemovalBehavior.types.ts diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index 532ac46049..ed5fcd0cc1 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -3,7 +3,6 @@ import { EditNewContext, Target } from "../../typings/target.types"; import { EditWithRangeUpdater } from "../../typings/Types"; import { selectionFromRange } from "../../util/selectionUtils"; import { isSameType } from "../../util/typeUtils"; -import InsertionRemovalBehavior from "../insertionRemovalBehavior.types"; import { createContinuousRange } from "../targetUtil/createContinuousRange"; import { createContinuousRangeWeakTarget } from "./WeakTarget"; @@ -22,6 +21,8 @@ export interface CloneWithParameters { export default abstract class BaseTarget implements Target { protected readonly state: CommonTargetParameters; + isLine = false; + isWeak = false; constructor(parameters: CommonTargetParameters) { this.state = { @@ -39,8 +40,6 @@ export default abstract class BaseTarget implements Target { return this.state.isReversed; } - isLine = false; - get thatTarget(): Target { return this.state.thatTarget != null ? this.state.thatTarget.thatTarget diff --git a/src/processTargets/targets/DocumentTarget.ts b/src/processTargets/targets/DocumentTarget.ts index 056cb84e09..5bb41fdf15 100644 --- a/src/processTargets/targets/DocumentTarget.ts +++ b/src/processTargets/targets/DocumentTarget.ts @@ -1,30 +1,25 @@ import { Range, TextEditor } from "vscode"; -import { TargetType } from "../../typings/target.types"; import { fitRangeToLineContent } from "../modifiers/scopeTypeStages/LineStage"; import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; import WeakTarget from "./WeakTarget"; export default class DocumentTarget extends BaseTarget { + delimiterString = "\n"; + isLine = true; + constructor(parameters: CommonTargetParameters) { super(parameters); } - get type(): TargetType { - return "document"; - } - get delimiterString() { - return "\n"; - } - get isLine() { - return true; - } - getLeadingDelimiterTarget() { return undefined; } getTrailingDelimiterTarget() { return undefined; } + getRemovalRange(): Range { + return this.contentRange; + } getInteriorStrict() { return [ diff --git a/src/processTargets/targets/LineTarget.ts b/src/processTargets/targets/LineTarget.ts index 0abc3f4a1e..60a9efee40 100644 --- a/src/processTargets/targets/LineTarget.ts +++ b/src/processTargets/targets/LineTarget.ts @@ -3,10 +3,6 @@ import { Target } from "../../typings/target.types"; import { expandToFullLine } from "../../util/rangeUtils"; import { wrapRangeWithTarget } from "../../util/wrapRangeWithTarget"; import { createContinuousLineRange } from "../targetUtil/createContinuousRange"; -import { - getLineLeadingDelimiterRange as getLeadingDelimiterRange, - getLineTrailingDelimiterRange as getTrailingDelimiterRange, -} from "../targetUtil/getLineDelimiters"; import BaseTarget from "./BaseTarget"; import PlainTarget from "./PlainTarget"; import { createContinuousRangeWeakTarget } from "./WeakTarget"; diff --git a/src/processTargets/targets/NotebookCellTarget.ts b/src/processTargets/targets/NotebookCellTarget.ts index ca6f55bc42..8ae3c10686 100644 --- a/src/processTargets/targets/NotebookCellTarget.ts +++ b/src/processTargets/targets/NotebookCellTarget.ts @@ -1,25 +1,18 @@ import { TextEditor } from "vscode"; -import { EditNewContext, TargetType } from "../../typings/target.types"; +import { EditNewContext } from "../../typings/target.types"; import { getNotebookFromCellDocument } from "../../util/notebook"; import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; export default class NotebookCellTarget extends BaseTarget { + delimiterString = "\n"; + constructor(parameters: CommonTargetParameters) { super(parameters); } - get type(): TargetType { - return "notebookCell"; - } - get delimiterString() { - return "\n"; - } - getLeadingDelimiterTarget() { - return undefined; - } - getTrailingDelimiterTarget() { - return undefined; - } + getLeadingDelimiterTarget = () => undefined; + getTrailingDelimiterTarget = () => undefined; + getRemovalRange = () => this.contentRange; getEditNewContext(isBefore: boolean): EditNewContext { if (this.isNotebookEditor(this.editor)) { diff --git a/src/processTargets/targets/ParagraphTarget.ts b/src/processTargets/targets/ParagraphTarget.ts index 8d10bfdf79..1f13b35889 100644 --- a/src/processTargets/targets/ParagraphTarget.ts +++ b/src/processTargets/targets/ParagraphTarget.ts @@ -31,7 +31,7 @@ export default class ParagraphTarget extends BaseTarget { ); } - getRemovalRange() { + getRemovalRange(): Range { // TODO: In the future we could get rid of this function if {@link // getDelimitedSequenceRemovalRange} made a continuous range from the target // past its delimiter target and then used the removal range of that. diff --git a/src/processTargets/targets/PositionTarget.ts b/src/processTargets/targets/PositionTarget.ts index fddc47c4cc..5d1a4204ce 100644 --- a/src/processTargets/targets/PositionTarget.ts +++ b/src/processTargets/targets/PositionTarget.ts @@ -1,6 +1,6 @@ -import { Range, TextEditor } from "vscode"; import * as vscode from "vscode"; -import { Position, TargetType } from "../../typings/target.types"; +import { Range, TextEditor } from "vscode"; +import { Position } from "../../typings/target.types"; import { EditWithRangeUpdater } from "../../typings/Types"; import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; @@ -10,13 +10,19 @@ interface PositionTargetParameters extends CommonTargetParameters { } export default class PositionTarget extends BaseTarget { + delimiterString: string; private position: Position; constructor(parameters: PositionTargetParameters) { super(parameters); this.position = parameters.position; + this.delimiterString = parameters.delimiter ?? ""; } + getLeadingDelimiterTarget = () => undefined; + getTrailingDelimiterTarget = () => undefined; + getRemovalRange = () => this.contentRange; + private constructReplaceEdit(text: string): EditWithRangeUpdater { return { range: this.contentRange, diff --git a/src/processTargets/targets/ScopeTypeTarget.ts b/src/processTargets/targets/ScopeTypeTarget.ts index 1bbe6f4cfc..b16496cbf7 100644 --- a/src/processTargets/targets/ScopeTypeTarget.ts +++ b/src/processTargets/targets/ScopeTypeTarget.ts @@ -1,15 +1,16 @@ import { Range } from "vscode"; -import { - SimpleScopeTypeType, - Target, - TargetType, -} from "../../typings/target.types"; +import { SimpleScopeTypeType, Target } from "../../typings/target.types"; import { isSameType } from "../../util/typeUtils"; import { createContinuousRange, createContinuousRangeFromRanges, } from "../targetUtil/createContinuousRange"; +import { + getTokenLeadingDelimiterTarget, + getTokenTrailingDelimiterTarget, +} from "../targetUtil/insertionRemovalBehaviors/TokenInsertionRemovalBehavior"; import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; +import PlainTarget from "./PlainTarget"; import { createContinuousRangeWeakTarget } from "./WeakTarget"; export interface ScopeTypeTargetParameters extends CommonTargetParameters { @@ -26,7 +27,7 @@ export default class ScopeTypeTarget extends BaseTarget { private leadingDelimiterRange_?: Range; private trailingDelimiterRange_?: Range; private hasDelimiterRange_: boolean; - private delimiter_: string; + delimiterString: string; constructor(parameters: ScopeTypeTargetParameters) { super(parameters); @@ -34,31 +35,47 @@ export default class ScopeTypeTarget extends BaseTarget { this.contentRemovalRange_ = parameters.contentRemovalRange; this.leadingDelimiterRange_ = parameters.leadingDelimiterRange; this.trailingDelimiterRange_ = parameters.trailingDelimiterRange; - this.delimiter_ = + this.delimiterString = parameters.delimiter ?? getDelimiter(parameters.scopeTypeType); this.hasDelimiterRange_ = !!this.leadingDelimiterRange_ || !!this.trailingDelimiterRange_; } - get delimiterString() { - return this.delimiter_; - } - protected get contentRemovalRange() { - return this.contentRemovalRange_ ?? this.contentRange; + getLeadingDelimiterTarget(): Target | undefined { + if (this.leadingDelimiterRange_ != null) { + return new PlainTarget({ + editor: this.editor, + isReversed: this.isReversed, + contentRange: this.leadingDelimiterRange_, + }); + } + if (!this.hasDelimiterRange_) { + return getTokenLeadingDelimiterTarget(this); + } + return undefined; } - getLeadingDelimiterTarget() { - if (this.hasDelimiterRange_) { - return this.leadingDelimiterRange_; + getTrailingDelimiterTarget(): Target | undefined { + if (this.trailingDelimiterRange_ != null) { + return new PlainTarget({ + editor: this.editor, + isReversed: this.isReversed, + contentRange: this.trailingDelimiterRange_, + }); + } + if (!this.hasDelimiterRange_) { + return getTokenTrailingDelimiterTarget(this); } - return super.getLeadingDelimiterTarget(); + return undefined; } - getTrailingDelimiterTarget() { - if (this.hasDelimiterRange_) { - return this.trailingDelimiterRange_; - } - return super.getTrailingDelimiterTarget(); + getRemovalRange(): Range { + const delimiterTarget = + this.getTrailingDelimiterTarget() ?? this.getLeadingDelimiterTarget(); + const contentRemovalRange_ = this.contentRemovalRange_ ?? this.contentRange; + return delimiterTarget != null + ? contentRemovalRange_.union(delimiterTarget.contentRange) + : contentRemovalRange_; } createContinuousRangeTarget( diff --git a/src/processTargets/targets/SurroundingPairTarget.ts b/src/processTargets/targets/SurroundingPairTarget.ts index a69f862b4a..ea9bc89461 100644 --- a/src/processTargets/targets/SurroundingPairTarget.ts +++ b/src/processTargets/targets/SurroundingPairTarget.ts @@ -1,5 +1,10 @@ import { Range } from "vscode"; -import { TargetType } from "../../typings/target.types"; +import { Target } from "../../typings/target.types"; +import { + getTokenLeadingDelimiterTarget, + getTokenRemovalRange, + getTokenTrailingDelimiterTarget, +} from "../targetUtil/insertionRemovalBehaviors/TokenInsertionRemovalBehavior"; import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; import WeakTarget from "./WeakTarget"; @@ -20,6 +25,7 @@ interface SurroundingPairTargetParameters extends CommonTargetParameters { } export default class SurroundingPairTarget extends BaseTarget { + delimiterString = " "; private interiorRange_: Range; private boundary_: [Range, Range]; @@ -29,11 +35,14 @@ export default class SurroundingPairTarget extends BaseTarget { this.interiorRange_ = parameters.interiorRange; } - get type(): TargetType { - return "surroundingPair"; + getLeadingDelimiterTarget(): Target | undefined { + return getTokenLeadingDelimiterTarget(this); } - get delimiterString() { - return " "; + getTrailingDelimiterTarget(): Target | undefined { + return getTokenTrailingDelimiterTarget(this); + } + getRemovalRange(): Range { + return getTokenRemovalRange(this); } getInteriorStrict() { diff --git a/src/processTargets/targets/TokenTarget.ts b/src/processTargets/targets/TokenTarget.ts index 6b9687868e..b41217655e 100644 --- a/src/processTargets/targets/TokenTarget.ts +++ b/src/processTargets/targets/TokenTarget.ts @@ -1,12 +1,27 @@ +import { Range } from "vscode"; +import { Target } from "../../typings/target.types"; +import { + getTokenLeadingDelimiterTarget, + getTokenTrailingDelimiterTarget, + getTokenRemovalRange, +} from "../targetUtil/insertionRemovalBehaviors/TokenInsertionRemovalBehavior"; import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; export default class TokenTarget extends BaseTarget { + delimiterString = " "; + constructor(parameters: CommonTargetParameters) { super(parameters); } - get delimiterString() { - return " "; + getLeadingDelimiterTarget(): Target | undefined { + return getTokenLeadingDelimiterTarget(this); + } + getTrailingDelimiterTarget(): Target | undefined { + return getTokenTrailingDelimiterTarget(this); + } + getRemovalRange(): Range { + return getTokenRemovalRange(this); } protected getCloneParameters() { diff --git a/src/processTargets/targets/WeakTarget.ts b/src/processTargets/targets/WeakTarget.ts index 4420d4a13e..e19e853dc3 100644 --- a/src/processTargets/targets/WeakTarget.ts +++ b/src/processTargets/targets/WeakTarget.ts @@ -1,9 +1,12 @@ -import { Target, TargetType } from "../../typings/target.types"; +import { Range } from "vscode"; +import { Target } from "../../typings/target.types"; import { createContinuousRange } from "../targetUtil/createContinuousRange"; -import BaseTarget, { - CloneWithParameters, - CommonTargetParameters, -} from "./BaseTarget"; +import { + getTokenLeadingDelimiterTarget, + getTokenRemovalRange, + getTokenTrailingDelimiterTarget, +} from "../targetUtil/insertionRemovalBehaviors/TokenInsertionRemovalBehavior"; +import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; /** * - Treated as "line" for "pour", "clone", and "breakpoint" @@ -11,22 +14,21 @@ import BaseTarget, { * - Expand to nearest containing pair when asked for boundary or interior */ export default class WeakTarget extends BaseTarget { + delimiterString = " "; + isWeak = true; + constructor(parameters: CommonTargetParameters) { super(parameters); } - get type(): TargetType { - return "weak"; + getLeadingDelimiterTarget(): Target | undefined { + return getTokenLeadingDelimiterTarget(this); } - get delimiterString() { - return " "; + getTrailingDelimiterTarget(): Target | undefined { + return getTokenTrailingDelimiterTarget(this); } - - cloneWith(parameters: CloneWithParameters) { - return new WeakTarget({ - ...this.getCloneParameters(), - ...parameters, - }); + getRemovalRange(): Range { + return getTokenRemovalRange(this); } createContinuousRangeTarget( diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 5d63a73159..4262aa38e4 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -294,6 +294,9 @@ export interface Target { /** If true this target should be treated as a line */ readonly isLine: boolean; + /** If true this target is weak and can be transformed/upgraded */ + readonly isWeak: boolean; + /** The text contained in the content range */ readonly contentText: string; From 7c1d1226654999eae1db4341659f013e7b0b2d53 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 1 Jun 2022 14:21:34 +0200 Subject: [PATCH 258/314] Removed padding from float and drop --- src/actions/InsertEmptyLines.ts | 4 +- src/processTargets/targets/BaseTarget.ts | 4 ++ src/processTargets/targets/PositionTarget.ts | 73 +++++++++++++------- src/typings/target.types.ts | 2 + 4 files changed, 55 insertions(+), 28 deletions(-) diff --git a/src/actions/InsertEmptyLines.ts b/src/actions/InsertEmptyLines.ts index 5357d1a43f..09cc7aefc2 100644 --- a/src/actions/InsertEmptyLines.ts +++ b/src/actions/InsertEmptyLines.ts @@ -24,12 +24,12 @@ class InsertEmptyLines implements Action { const edits: EditWithRangeUpdater[] = []; if (this.insertAbove) { edits.push( - toPositionTarget(lineTarget, "before").constructChangeEdit("") + toPositionTarget(lineTarget, "before").constructEmptyChangeEdit() ); } if (this.insertBelow) { edits.push( - toPositionTarget(lineTarget, "after").constructChangeEdit("") + toPositionTarget(lineTarget, "after").constructEmptyChangeEdit() ); } return edits; diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index ed5fcd0cc1..25185bd6a5 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -66,6 +66,10 @@ export default abstract class BaseTarget implements Target { }; } + constructEmptyChangeEdit(): EditWithRangeUpdater { + return this.constructChangeEdit(""); + } + constructRemovalEdit(): EditWithRangeUpdater { return { range: this.getRemovalRange(), diff --git a/src/processTargets/targets/PositionTarget.ts b/src/processTargets/targets/PositionTarget.ts index 5d1a4204ce..68000dc367 100644 --- a/src/processTargets/targets/PositionTarget.ts +++ b/src/processTargets/targets/PositionTarget.ts @@ -23,15 +23,31 @@ export default class PositionTarget extends BaseTarget { getTrailingDelimiterTarget = () => undefined; getRemovalRange = () => this.contentRange; - private constructReplaceEdit(text: string): EditWithRangeUpdater { + constructChangeEdit(text: string): EditWithRangeUpdater { + if (this.isInsertion()) { + return this.constructInsertionEdit(text, true); + } + return this.constructReplaceEdit(text); + } + + constructEmptyChangeEdit(): EditWithRangeUpdater { + if (this.isInsertion()) { + return this.constructInsertionEdit("", false); + } + return this.constructReplaceEdit(""); + } + + protected getCloneParameters() { return { - range: this.contentRange, - text, - updateRange: (range) => range, + ...this.state, + position: this.position, }; } - private constructInsertionEdit(text: string): EditWithRangeUpdater { + private constructInsertionEdit( + text: string, + useLinePadding: boolean + ): EditWithRangeUpdater { const delimiter = this.delimiterString!; const isLine = delimiter.includes("\n"); const isBefore = this.position === "before"; @@ -40,9 +56,13 @@ export default class PositionTarget extends BaseTarget { this.editor, this.contentRange, isLine, + useLinePadding, isBefore ); - const padding = isLine ? getLinePadding(this.editor, range, isBefore) : ""; + const padding = + isLine && useLinePadding + ? getLinePadding(this.editor, range, isBefore) + : ""; const editText = isBefore ? text + delimiter + padding @@ -61,29 +81,27 @@ export default class PositionTarget extends BaseTarget { }; return { - range: this.contentRange, + range: range, text: editText, isReplace: this.position === "after", updateRange, }; } - constructChangeEdit(text: string): EditWithRangeUpdater { - if ( - this.delimiterString != null && - (this.position === "before" || this.position === "after") - ) { - return this.constructInsertionEdit(text); - } - return this.constructReplaceEdit(text); - } - - protected getCloneParameters() { + private constructReplaceEdit(text: string): EditWithRangeUpdater { return { - ...this.state, - position: this.position, + range: this.contentRange, + text, + updateRange: (range) => range, }; } + + private isInsertion() { + return ( + this.delimiterString != null && + (this.position === "before" || this.position === "after") + ); + } } function getLinePadding(editor: TextEditor, range: Range, isBefore: boolean) { @@ -98,18 +116,21 @@ function getEditRange( editor: TextEditor, range: Range, isLine: boolean, + useLinePadding: boolean, isBefore: boolean ) { let position: vscode.Position; if (isLine) { const line = editor.document.lineAt(isBefore ? range.start : range.end); if (isBefore) { - position = line.isEmptyOrWhitespace - ? range.start - : new vscode.Position( - line.lineNumber, - line.firstNonWhitespaceCharacterIndex - ); + position = useLinePadding + ? line.isEmptyOrWhitespace + ? range.start + : new vscode.Position( + line.lineNumber, + line.firstNonWhitespaceCharacterIndex + ) + : line.range.start; } else { position = line.range.end; } diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 4262aa38e4..8e4374eb27 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -325,6 +325,8 @@ export interface Target { ): Target; /** Constructs change/insertion edit. Adds delimiter before/after if needed */ constructChangeEdit(text: string): EditWithRangeUpdater; + /** Constructs change/insertion edit. Differs from constructChangeEdit in that it does not add padding on insertion */ + constructEmptyChangeEdit(): EditWithRangeUpdater; /** Constructs removal edit */ constructRemovalEdit(): EditWithRangeUpdater; } From 1d3f0c941b214f39d11c7b088eabf34073dc1ea8 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 1 Jun 2022 14:33:44 +0200 Subject: [PATCH 259/314] Updated that mark on pour action --- src/actions/EditNew.ts | 3 +- .../actions/bringFineAfterLineVest.yml | 44 ++++++++++++++++++ .../actions/bringFineBeforeLineVest.yml | 46 +++++++++++++++++++ .../fixtures/recorded/actions/drinkVest2.yml | 32 +++++++++++++ .../fixtures/recorded/actions/dropVest2.yml | 32 +++++++++++++ .../fixtures/recorded/actions/floatVest2.yml | 32 +++++++++++++ .../fixtures/recorded/actions/pourVest2.yml | 32 +++++++++++++ .../fixtures/recorded/actions/puffVest2.yml | 33 +++++++++++++ 8 files changed, 252 insertions(+), 2 deletions(-) create mode 100644 src/test/suite/fixtures/recorded/actions/bringFineAfterLineVest.yml create mode 100644 src/test/suite/fixtures/recorded/actions/bringFineBeforeLineVest.yml create mode 100644 src/test/suite/fixtures/recorded/actions/drinkVest2.yml create mode 100644 src/test/suite/fixtures/recorded/actions/dropVest2.yml create mode 100644 src/test/suite/fixtures/recorded/actions/floatVest2.yml create mode 100644 src/test/suite/fixtures/recorded/actions/pourVest2.yml create mode 100644 src/test/suite/fixtures/recorded/actions/puffVest2.yml diff --git a/src/actions/EditNew.ts b/src/actions/EditNew.ts index f81e8fedf8..6b9b7f9e3d 100644 --- a/src/actions/EditNew.ts +++ b/src/actions/EditNew.ts @@ -33,7 +33,6 @@ class EditNew implements Action { const context = target.getEditNewContext(this.isBefore); const common = { target, - // targetRange: target.thatTarget.contentRange, cursorRange: target.contentRange, }; switch (context.type) { @@ -146,7 +145,7 @@ class EditNew implements Action { () => commands.executeCommand(command), editor.document, [ - targets.map(({ target }) => target.contentRange), + targets.map(({ target }) => target.thatTarget.contentRange), targets.map(({ cursorRange }) => cursorRange), ] ); diff --git a/src/test/suite/fixtures/recorded/actions/bringFineAfterLineVest.yml b/src/test/suite/fixtures/recorded/actions/bringFineAfterLineVest.yml new file mode 100644 index 0000000000..5234563536 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/bringFineAfterLineVest.yml @@ -0,0 +1,44 @@ +languageId: plaintext +command: + spokenForm: bring fine after line vest + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: f} + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: v} + modifiers: + - {type: position, position: after} + - type: containingScope + scopeType: {type: line} + usePrePhraseSnapshot: true + action: {name: replaceWithTarget} +initialState: + documentContents: | + foo + const value = "Hello world"; + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: + default.f: + start: {line: 0, character: 0} + end: {line: 0, character: 3} + default.v: + start: {line: 1, character: 10} + end: {line: 1, character: 15} +finalState: + documentContents: | + foo + const value = "Hello world"; + foo + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 2, character: 4} + active: {line: 2, character: 7} + sourceMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 3} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: f}, modifiers: []}, {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: v}, modifiers: [{type: position, position: after}, {type: containingScope, scopeType: {type: line}}]}] diff --git a/src/test/suite/fixtures/recorded/actions/bringFineBeforeLineVest.yml b/src/test/suite/fixtures/recorded/actions/bringFineBeforeLineVest.yml new file mode 100644 index 0000000000..905ddd611f --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/bringFineBeforeLineVest.yml @@ -0,0 +1,46 @@ +languageId: plaintext +command: + spokenForm: bring fine before line vest + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: f} + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: v} + modifiers: + - {type: position, position: before} + - type: containingScope + scopeType: {type: line} + usePrePhraseSnapshot: true + action: {name: replaceWithTarget} +initialState: + documentContents: |2 + + const value = "Hello world"; + foo + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: + default.f: + start: {line: 2, character: 0} + end: {line: 2, character: 3} + default.v: + start: {line: 1, character: 10} + end: {line: 1, character: 15} +finalState: + documentContents: |2 + + foo + const value = "Hello world"; + foo + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 7} + sourceMark: + - anchor: {line: 3, character: 0} + active: {line: 3, character: 3} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: f}, modifiers: []}, {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: v}, modifiers: [{type: position, position: before}, {type: containingScope, scopeType: {type: line}}]}] diff --git a/src/test/suite/fixtures/recorded/actions/drinkVest2.yml b/src/test/suite/fixtures/recorded/actions/drinkVest2.yml new file mode 100644 index 0000000000..24a73772cb --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/drinkVest2.yml @@ -0,0 +1,32 @@ +languageId: plaintext +command: + spokenForm: drink vest + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: v} + usePrePhraseSnapshot: true + action: {name: editNewLineBefore} +initialState: + documentContents: |2 + + const value = "Hello world"; + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: + default.v: + start: {line: 1, character: 10} + end: {line: 1, character: 15} +finalState: + documentContents: |2 + + + const value = "Hello world"; + selections: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} + thatMark: + - anchor: {line: 2, character: 10} + active: {line: 2, character: 15} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: v}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/dropVest2.yml b/src/test/suite/fixtures/recorded/actions/dropVest2.yml new file mode 100644 index 0000000000..2c0d0b5372 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/dropVest2.yml @@ -0,0 +1,32 @@ +languageId: plaintext +command: + spokenForm: drop vest + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: v} + usePrePhraseSnapshot: true + action: {name: insertEmptyLineBefore} +initialState: + documentContents: |2 + + const value = "Hello world"; + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: + default.v: + start: {line: 1, character: 10} + end: {line: 1, character: 15} +finalState: + documentContents: |2 + + + const value = "Hello world"; + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 2, character: 10} + active: {line: 2, character: 15} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: v}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/floatVest2.yml b/src/test/suite/fixtures/recorded/actions/floatVest2.yml new file mode 100644 index 0000000000..7a96fb4a2f --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/floatVest2.yml @@ -0,0 +1,32 @@ +languageId: plaintext +command: + spokenForm: float vest + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: v} + usePrePhraseSnapshot: true + action: {name: insertEmptyLineAfter} +initialState: + documentContents: |2 + + const value = "Hello world"; + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: + default.v: + start: {line: 1, character: 10} + end: {line: 1, character: 15} +finalState: + documentContents: |2+ + + const value = "Hello world"; + + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 1, character: 10} + active: {line: 1, character: 15} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: v}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/pourVest2.yml b/src/test/suite/fixtures/recorded/actions/pourVest2.yml new file mode 100644 index 0000000000..4ea51e852d --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/pourVest2.yml @@ -0,0 +1,32 @@ +languageId: plaintext +command: + spokenForm: pour vest + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: v} + usePrePhraseSnapshot: true + action: {name: editNewLineAfter} +initialState: + documentContents: |2 + + const value = "Hello world"; + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: + default.v: + start: {line: 1, character: 10} + end: {line: 1, character: 15} +finalState: + documentContents: |2 + + const value = "Hello world"; + + selections: + - anchor: {line: 2, character: 4} + active: {line: 2, character: 4} + thatMark: + - anchor: {line: 1, character: 10} + active: {line: 1, character: 15} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: v}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/puffVest2.yml b/src/test/suite/fixtures/recorded/actions/puffVest2.yml new file mode 100644 index 0000000000..9c4f98fe06 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/puffVest2.yml @@ -0,0 +1,33 @@ +languageId: plaintext +command: + spokenForm: puff vest + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: v} + usePrePhraseSnapshot: true + action: {name: insertEmptyLinesAround} +initialState: + documentContents: |2 + + const value = "Hello world"; + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: + default.v: + start: {line: 1, character: 10} + end: {line: 1, character: 15} +finalState: + documentContents: |2+ + + + const value = "Hello world"; + + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 2, character: 10} + active: {line: 2, character: 15} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: v}, modifiers: []}] From b9749c1686560df10af969e12259d7ebcc8d5e29 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Wed, 1 Jun 2022 16:32:07 +0100 Subject: [PATCH 260/314] Lots of stuff --- .../ContainingSyntaxScopeStage.ts | 12 ++- src/processTargets/processTargets.ts | 2 - .../targetUtil/createContinuousRange.ts | 22 +++- src/processTargets/targets/LineTarget.ts | 19 ++-- src/processTargets/targets/ParagraphTarget.ts | 18 ++-- src/processTargets/targets/ScopeTypeTarget.ts | 23 ++-- src/processTargets/targets/SubTokenTarget.ts | 102 ++++++++++++++++++ .../targets/SurroundingPairTarget.ts | 3 +- src/processTargets/targets/TokenTarget.ts | 8 +- src/processTargets/targets/WeakTarget.ts | 41 +------ src/util/wrapRangeWithTarget.ts | 40 +++---- 11 files changed, 187 insertions(+), 103 deletions(-) create mode 100644 src/processTargets/targets/SubTokenTarget.ts diff --git a/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts b/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts index ca2643b2e6..443ab59e4b 100644 --- a/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts @@ -62,6 +62,16 @@ export default class implements ModifierStage { trailingDelimiterRange, removalRange, } = scope.context; + + if ( + removalRange != null && + (leadingDelimiterRange != null || trailingDelimiterRange != null) + ) { + throw Error( + "Removal range is mutually exclusive with leading or trailing delimiter range" + ); + } + const { editor, selection: contentSelection } = scope.selection; return new ScopeTypeTarget({ @@ -69,7 +79,7 @@ export default class implements ModifierStage { editor, isReversed: target.isReversed, contentRange: contentSelection, - contentRemovalRange: removalRange, + removalRange: removalRange, delimiter: containingListDelimiter, leadingDelimiterRange, trailingDelimiterRange, diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index 8d4a073c85..7c9f54b3d0 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -11,8 +11,6 @@ import { ensureSingleEditor } from "../util/targetUtils"; import uniqDeep from "../util/uniqDeep"; import getMarkStage from "./getMarkStage"; import getModifierStage from "./getModifierStage"; -import PositionTarget from "./targets/PositionTarget"; -import WeakTarget from "./targets/WeakTarget"; /** * Converts the abstract target descriptions provided by the user to a concrete diff --git a/src/processTargets/targetUtil/createContinuousRange.ts b/src/processTargets/targetUtil/createContinuousRange.ts index 2f21737b0c..001282db93 100644 --- a/src/processTargets/targetUtil/createContinuousRange.ts +++ b/src/processTargets/targetUtil/createContinuousRange.ts @@ -1,5 +1,6 @@ import { Position, Range } from "vscode"; import { Target } from "../../typings/target.types"; +import WeakTarget from "../targets/WeakTarget"; export function createContinuousRange( startTarget: Target, @@ -48,7 +49,7 @@ export function createContinuousLineRange( export function createSimpleContinuousRangeTarget( target1: Target, target2: Target, - isReversed: boolean = false, + isReversed: boolean, includeStart: boolean = true, includeEnd: boolean = true ) { @@ -65,3 +66,22 @@ export function createSimpleContinuousRangeTarget( includeEnd ); } + +export function createContinuousRangeWeakTarget( + isReversed: boolean, + startTarget: Target, + endTarget: Target, + includeStart: boolean, + includeEnd: boolean +): WeakTarget { + return new WeakTarget({ + editor: startTarget.editor, + isReversed, + contentRange: createContinuousRange( + startTarget, + endTarget, + includeStart, + includeEnd + ), + }); +} diff --git a/src/processTargets/targets/LineTarget.ts b/src/processTargets/targets/LineTarget.ts index 60a9efee40..48625dfb32 100644 --- a/src/processTargets/targets/LineTarget.ts +++ b/src/processTargets/targets/LineTarget.ts @@ -1,11 +1,9 @@ import { Position, Range, TextEditor } from "vscode"; import { Target } from "../../typings/target.types"; import { expandToFullLine } from "../../util/rangeUtils"; -import { wrapRangeWithTarget } from "../../util/wrapRangeWithTarget"; +import { constructPlainTarget } from "../../util/wrapRangeWithTarget"; import { createContinuousLineRange } from "../targetUtil/createContinuousRange"; import BaseTarget from "./BaseTarget"; -import PlainTarget from "./PlainTarget"; -import { createContinuousRangeWeakTarget } from "./WeakTarget"; export default class LineTarget extends BaseTarget { delimiterString = "\n"; @@ -16,18 +14,18 @@ export default class LineTarget extends BaseTarget { } getLeadingDelimiterTarget() { - return wrapRangeWithTarget( - PlainTarget, + return constructPlainTarget( this.editor, - getLeadingDelimiterRange(this.editor, this.fullLineContentRange) + getLeadingDelimiterRange(this.editor, this.fullLineContentRange), + this.isReversed ); } getTrailingDelimiterTarget() { - return wrapRangeWithTarget( - PlainTarget, + return constructPlainTarget( this.editor, - getTrailingDelimiterRange(this.editor, this.fullLineContentRange) + getTrailingDelimiterRange(this.editor, this.fullLineContentRange), + this.isReversed ); } @@ -62,9 +60,8 @@ export default class LineTarget extends BaseTarget { }); } - return createContinuousRangeWeakTarget( + return super.createContinuousRangeTarget( isReversed, - this, endTarget, includeStart, includeEnd diff --git a/src/processTargets/targets/ParagraphTarget.ts b/src/processTargets/targets/ParagraphTarget.ts index 1f13b35889..058bbdf126 100644 --- a/src/processTargets/targets/ParagraphTarget.ts +++ b/src/processTargets/targets/ParagraphTarget.ts @@ -2,32 +2,31 @@ import { Position, Range, TextDocument, TextEditor, TextLine } from "vscode"; import { Target } from "../../typings/target.types"; import { expandToFullLine } from "../../util/rangeUtils"; import { isSameType } from "../../util/typeUtils"; -import { wrapRangeWithTarget } from "../../util/wrapRangeWithTarget"; +import { constructLineTarget } from "../../util/wrapRangeWithTarget"; import { createContinuousLineRange, createSimpleContinuousRangeTarget, } from "../targetUtil/createContinuousRange"; import BaseTarget from "./BaseTarget"; import LineTarget from "./LineTarget"; -import { createContinuousRangeWeakTarget } from "./WeakTarget"; export default class ParagraphTarget extends BaseTarget { delimiterString = "\n\n"; isLine = true; getLeadingDelimiterTarget() { - return wrapRangeWithTarget( - LineTarget, + return constructLineTarget( this.editor, - getLeadingDelimiterRange(this.editor, this.contentRange) + getLeadingDelimiterRange(this.editor, this.fullLineContentRange), + this.isReversed ); } getTrailingDelimiterTarget() { - return wrapRangeWithTarget( - LineTarget, + return constructLineTarget( this.editor, - getTrailingDelimiterRange(this.editor, this.contentRange) + getTrailingDelimiterRange(this.editor, this.fullLineContentRange), + this.isReversed ); } @@ -96,9 +95,8 @@ export default class ParagraphTarget extends BaseTarget { }); } - return createContinuousRangeWeakTarget( + return super.createContinuousRangeTarget( isReversed, - this, endTarget, includeStart, includeEnd diff --git a/src/processTargets/targets/ScopeTypeTarget.ts b/src/processTargets/targets/ScopeTypeTarget.ts index b16496cbf7..304c42f9e2 100644 --- a/src/processTargets/targets/ScopeTypeTarget.ts +++ b/src/processTargets/targets/ScopeTypeTarget.ts @@ -11,19 +11,18 @@ import { } from "../targetUtil/insertionRemovalBehaviors/TokenInsertionRemovalBehavior"; import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; import PlainTarget from "./PlainTarget"; -import { createContinuousRangeWeakTarget } from "./WeakTarget"; export interface ScopeTypeTargetParameters extends CommonTargetParameters { readonly scopeTypeType: SimpleScopeTypeType; readonly delimiter?: string; - readonly contentRemovalRange?: Range; + readonly removalRange?: Range; readonly leadingDelimiterRange?: Range; readonly trailingDelimiterRange?: Range; } export default class ScopeTypeTarget extends BaseTarget { private scopeTypeType_: SimpleScopeTypeType; - private contentRemovalRange_?: Range; + private removalRange_?: Range; private leadingDelimiterRange_?: Range; private trailingDelimiterRange_?: Range; private hasDelimiterRange_: boolean; @@ -32,7 +31,7 @@ export default class ScopeTypeTarget extends BaseTarget { constructor(parameters: ScopeTypeTargetParameters) { super(parameters); this.scopeTypeType_ = parameters.scopeTypeType; - this.contentRemovalRange_ = parameters.contentRemovalRange; + this.removalRange_ = parameters.removalRange; this.leadingDelimiterRange_ = parameters.leadingDelimiterRange; this.trailingDelimiterRange_ = parameters.trailingDelimiterRange; this.delimiterString = @@ -72,7 +71,7 @@ export default class ScopeTypeTarget extends BaseTarget { getRemovalRange(): Range { const delimiterTarget = this.getTrailingDelimiterTarget() ?? this.getLeadingDelimiterTarget(); - const contentRemovalRange_ = this.contentRemovalRange_ ?? this.contentRange; + const contentRemovalRange_ = this.removalRange_ ?? this.contentRange; return delimiterTarget != null ? contentRemovalRange_.union(delimiterTarget.contentRange) : contentRemovalRange_; @@ -88,11 +87,10 @@ export default class ScopeTypeTarget extends BaseTarget { const scopeTarget = endTarget; if (this.scopeTypeType_ === scopeTarget.scopeTypeType_) { const contentRemovalRange = - this.contentRemovalRange_ != null || - scopeTarget.contentRemovalRange_ != null + this.removalRange_ != null || scopeTarget.removalRange_ != null ? createContinuousRangeFromRanges( - this.contentRemovalRange_ ?? this.contentRange, - scopeTarget.contentRemovalRange_ ?? scopeTarget.contentRange, + this.removalRange_ ?? this.contentRange, + scopeTarget.removalRange_ ?? scopeTarget.contentRange, includeStart, includeEnd ) @@ -103,7 +101,7 @@ export default class ScopeTypeTarget extends BaseTarget { isReversed, leadingDelimiterRange: this.leadingDelimiterRange_, trailingDelimiterRange: scopeTarget.trailingDelimiterRange_, - contentRemovalRange, + removalRange: contentRemovalRange, contentRange: createContinuousRange( this, endTarget, @@ -114,9 +112,8 @@ export default class ScopeTypeTarget extends BaseTarget { } } - return createContinuousRangeWeakTarget( + return super.createContinuousRangeTarget( isReversed, - this, endTarget, includeStart, includeEnd @@ -127,7 +124,7 @@ export default class ScopeTypeTarget extends BaseTarget { return { ...this.state, scopeTypeType: this.scopeTypeType_, - contentRemovalRange: this.contentRemovalRange_, + contentRemovalRange: this.removalRange_, leadingDelimiterRange: this.leadingDelimiterRange_, trailingDelimiterRange: this.trailingDelimiterRange_, }; diff --git a/src/processTargets/targets/SubTokenTarget.ts b/src/processTargets/targets/SubTokenTarget.ts new file mode 100644 index 0000000000..ad22f7cfc2 --- /dev/null +++ b/src/processTargets/targets/SubTokenTarget.ts @@ -0,0 +1,102 @@ +import { Range } from "vscode"; +import { Target } from "../../typings/target.types"; +import { isSameType } from "../../util/typeUtils"; +import { constructPlainTarget } from "../../util/wrapRangeWithTarget"; +import { + createContinuousRange, + createContinuousRangeFromRanges, +} from "../targetUtil/createContinuousRange"; +import { getDelimitedSequenceRemovalRange } from "../targetUtil/insertionRemovalBehaviors/DelimitedSequenceInsertionRemovalBehavior"; +import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; +import ScopeTypeTarget from "./ScopeTypeTarget"; + +export interface SubTokenTargetParameters extends CommonTargetParameters { + readonly delimiterString: string; + readonly leadingDelimiterRange?: Range; + readonly trailingDelimiterRange?: Range; +} + +export default class SubTokenTarget extends BaseTarget { + private leadingDelimiterRange_?: Range; + private trailingDelimiterRange_?: Range; + delimiterString: string; + + constructor(parameters: SubTokenTargetParameters) { + super(parameters); + this.leadingDelimiterRange_ = parameters.leadingDelimiterRange; + this.trailingDelimiterRange_ = parameters.trailingDelimiterRange; + this.delimiterString = parameters.delimiterString; + } + + getLeadingDelimiterTarget() { + return constructPlainTarget( + this.editor, + this.leadingDelimiterRange_, + this.isReversed + ); + } + + getTrailingDelimiterTarget() { + return constructPlainTarget( + this.editor, + this.trailingDelimiterRange_, + this.isReversed + ); + } + + getRemovalRange(): Range { + return getDelimitedSequenceRemovalRange(this); + } + + createContinuousRangeTarget( + isReversed: boolean, + endTarget: Target, + includeStart: boolean, + includeEnd: boolean + ): Target { + if (isSameType(this, endTarget)) { + const scopeTarget = endTarget; + if (this.scopeTypeType_ === scopeTarget.scopeTypeType_) { + const contentRemovalRange = + this.contentRemovalRange_ != null || + scopeTarget.contentRemovalRange_ != null + ? createContinuousRangeFromRanges( + this.contentRemovalRange_ ?? this.contentRange, + scopeTarget.contentRemovalRange_ ?? scopeTarget.contentRange, + includeStart, + includeEnd + ) + : undefined; + + return new ScopeTypeTarget({ + ...this.getCloneParameters(), + isReversed, + leadingDelimiterRange: this.leadingDelimiterRange_, + trailingDelimiterRange: scopeTarget.trailingDelimiterRange_, + removalRange: contentRemovalRange, + contentRange: createContinuousRange( + this, + endTarget, + includeStart, + includeEnd + ), + }); + } + } + + return super.createContinuousRangeTarget( + isReversed, + endTarget, + includeStart, + includeEnd + ); + } + + protected getCloneParameters() { + return { + ...this.state, + leadingDelimiterRange: this.leadingDelimiterRange_, + trailingDelimiterRange: this.trailingDelimiterRange_, + }; + } +} diff --git a/src/processTargets/targets/SurroundingPairTarget.ts b/src/processTargets/targets/SurroundingPairTarget.ts index ea9bc89461..23db19b78a 100644 --- a/src/processTargets/targets/SurroundingPairTarget.ts +++ b/src/processTargets/targets/SurroundingPairTarget.ts @@ -6,6 +6,7 @@ import { getTokenTrailingDelimiterTarget, } from "../targetUtil/insertionRemovalBehaviors/TokenInsertionRemovalBehavior"; import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; +import TokenTarget from "./TokenTarget"; import WeakTarget from "./WeakTarget"; interface SurroundingPairTargetParameters extends CommonTargetParameters { @@ -58,7 +59,7 @@ export default class SurroundingPairTarget extends BaseTarget { getBoundaryStrict() { return this.boundary_.map( (contentRange) => - new WeakTarget({ + new TokenTarget({ editor: this.editor, isReversed: this.isReversed, contentRange, diff --git a/src/processTargets/targets/TokenTarget.ts b/src/processTargets/targets/TokenTarget.ts index b41217655e..d66d5ddd5b 100644 --- a/src/processTargets/targets/TokenTarget.ts +++ b/src/processTargets/targets/TokenTarget.ts @@ -2,18 +2,14 @@ import { Range } from "vscode"; import { Target } from "../../typings/target.types"; import { getTokenLeadingDelimiterTarget, - getTokenTrailingDelimiterTarget, getTokenRemovalRange, + getTokenTrailingDelimiterTarget, } from "../targetUtil/insertionRemovalBehaviors/TokenInsertionRemovalBehavior"; -import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; +import BaseTarget from "./BaseTarget"; export default class TokenTarget extends BaseTarget { delimiterString = " "; - constructor(parameters: CommonTargetParameters) { - super(parameters); - } - getLeadingDelimiterTarget(): Target | undefined { return getTokenLeadingDelimiterTarget(this); } diff --git a/src/processTargets/targets/WeakTarget.ts b/src/processTargets/targets/WeakTarget.ts index e19e853dc3..b3bcbe1aba 100644 --- a/src/processTargets/targets/WeakTarget.ts +++ b/src/processTargets/targets/WeakTarget.ts @@ -1,12 +1,11 @@ import { Range } from "vscode"; import { Target } from "../../typings/target.types"; -import { createContinuousRange } from "../targetUtil/createContinuousRange"; import { getTokenLeadingDelimiterTarget, getTokenRemovalRange, getTokenTrailingDelimiterTarget, } from "../targetUtil/insertionRemovalBehaviors/TokenInsertionRemovalBehavior"; -import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; +import BaseTarget from "./BaseTarget"; /** * - Treated as "line" for "pour", "clone", and "breakpoint" @@ -17,10 +16,6 @@ export default class WeakTarget extends BaseTarget { delimiterString = " "; isWeak = true; - constructor(parameters: CommonTargetParameters) { - super(parameters); - } - getLeadingDelimiterTarget(): Target | undefined { return getTokenLeadingDelimiterTarget(this); } @@ -31,41 +26,7 @@ export default class WeakTarget extends BaseTarget { return getTokenRemovalRange(this); } - createContinuousRangeTarget( - isReversed: boolean, - endTarget: Target, - includeStart: boolean, - includeEnd: boolean - ): Target { - return createContinuousRangeWeakTarget( - isReversed, - this, - endTarget, - includeStart, - includeEnd - ); - } - protected getCloneParameters() { return this.state; } } - -export function createContinuousRangeWeakTarget( - isReversed: boolean, - startTarget: Target, - endTarget: Target, - includeStart: boolean, - includeEnd: boolean -): WeakTarget { - return new WeakTarget({ - editor: startTarget.editor, - isReversed, - contentRange: createContinuousRange( - startTarget, - endTarget, - includeStart, - includeEnd - ), - }); -} diff --git a/src/util/wrapRangeWithTarget.ts b/src/util/wrapRangeWithTarget.ts index 31ab80c296..bf04d1b32b 100644 --- a/src/util/wrapRangeWithTarget.ts +++ b/src/util/wrapRangeWithTarget.ts @@ -1,36 +1,40 @@ import { Range, TextEditor } from "vscode"; import { CommonTargetParameters } from "../processTargets/targets/BaseTarget"; +import LineTarget from "../processTargets/targets/LineTarget"; +import PlainTarget from "../processTargets/targets/PlainTarget"; import { Target } from "../typings/target.types"; type TargetConstructor = new ( parameters: CommonTargetParameters ) => T; -export function wrapRangeWithTarget( +export function constructTarget( constructor: TargetConstructor, editor: TextEditor, - range: undefined -): undefined; -export function wrapRangeWithTarget( - constructor: TargetConstructor, - editor: TextEditor, - range: Range -): T; -export function wrapRangeWithTarget( - constructor: TargetConstructor, - editor: TextEditor, - range: Range | undefined -): T | undefined; -export function wrapRangeWithTarget( - constructor: TargetConstructor, - editor: TextEditor, - range: Range | undefined + range: Range | undefined, + isReversed: boolean ): T | undefined { return range == null ? undefined : new constructor({ editor, - isReversed: false, + isReversed, contentRange: range, }); } + +export function constructPlainTarget( + editor: TextEditor, + range: Range | undefined, + isReversed: boolean +): PlainTarget | undefined { + return constructTarget(PlainTarget, editor, range, isReversed); +} + +export function constructLineTarget( + editor: TextEditor, + range: Range | undefined, + isReversed: boolean +): LineTarget | undefined { + return constructTarget(LineTarget, editor, range, isReversed); +} From 50031db5c09c48d75e292e96bb89bfd68b1d65ed Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 1 Jun 2022 17:43:29 +0200 Subject: [PATCH 261/314] Fixed removal behavior on scope type target --- src/actions/CutCopyPaste.ts | 2 +- .../TokenInsertionRemovalBehavior.ts | 4 +- src/processTargets/targets/BaseTarget.ts | 6 +- src/processTargets/targets/ParagraphTarget.ts | 3 +- src/processTargets/targets/ScopeTypeTarget.ts | 10 +- src/processTargets/targets/SubTokenTarget.ts | 102 ------------------ 6 files changed, 13 insertions(+), 114 deletions(-) delete mode 100644 src/processTargets/targets/SubTokenTarget.ts diff --git a/src/actions/CutCopyPaste.ts b/src/actions/CutCopyPaste.ts index b0e70739cc..3847b6de4b 100644 --- a/src/actions/CutCopyPaste.ts +++ b/src/actions/CutCopyPaste.ts @@ -22,7 +22,7 @@ export class Cut implements Action { new PlainTarget({ editor: target.editor, contentRange: overflow, - isReversed: false, + isReversed: target.isReversed, }) ); }); diff --git a/src/processTargets/targetUtil/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts b/src/processTargets/targetUtil/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts index 6b308a8853..19ebdd7a3b 100644 --- a/src/processTargets/targetUtil/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts +++ b/src/processTargets/targetUtil/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts @@ -24,7 +24,7 @@ export function getTokenLeadingDelimiterTarget( start.character ), editor, - isReversed: false, + isReversed: target.isReversed, }); } @@ -48,7 +48,7 @@ export function getTokenTrailingDelimiterTarget( end.character + trailingDelimiters[0].length ), editor, - isReversed: false, + isReversed: target.isReversed, }); } diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index 25185bd6a5..de77adbd03 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -3,8 +3,10 @@ import { EditNewContext, Target } from "../../typings/target.types"; import { EditWithRangeUpdater } from "../../typings/Types"; import { selectionFromRange } from "../../util/selectionUtils"; import { isSameType } from "../../util/typeUtils"; -import { createContinuousRange } from "../targetUtil/createContinuousRange"; -import { createContinuousRangeWeakTarget } from "./WeakTarget"; +import { + createContinuousRange, + createContinuousRangeWeakTarget, +} from "../targetUtil/createContinuousRange"; /** Parameters supported by all target classes */ export interface CommonTargetParameters { diff --git a/src/processTargets/targets/ParagraphTarget.ts b/src/processTargets/targets/ParagraphTarget.ts index 058bbdf126..2225691cbe 100644 --- a/src/processTargets/targets/ParagraphTarget.ts +++ b/src/processTargets/targets/ParagraphTarget.ts @@ -46,7 +46,8 @@ export default class ParagraphTarget extends BaseTarget { ? contentRemovalRange : createSimpleContinuousRangeTarget( this, - delimiterTarget + delimiterTarget, + this.isReversed ).getRemovalRange(); } diff --git a/src/processTargets/targets/ScopeTypeTarget.ts b/src/processTargets/targets/ScopeTypeTarget.ts index 304c42f9e2..060e26f7f9 100644 --- a/src/processTargets/targets/ScopeTypeTarget.ts +++ b/src/processTargets/targets/ScopeTypeTarget.ts @@ -7,6 +7,7 @@ import { } from "../targetUtil/createContinuousRange"; import { getTokenLeadingDelimiterTarget, + getTokenRemovalRange, getTokenTrailingDelimiterTarget, } from "../targetUtil/insertionRemovalBehaviors/TokenInsertionRemovalBehavior"; import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; @@ -69,12 +70,9 @@ export default class ScopeTypeTarget extends BaseTarget { } getRemovalRange(): Range { - const delimiterTarget = - this.getTrailingDelimiterTarget() ?? this.getLeadingDelimiterTarget(); - const contentRemovalRange_ = this.removalRange_ ?? this.contentRange; - return delimiterTarget != null - ? contentRemovalRange_.union(delimiterTarget.contentRange) - : contentRemovalRange_; + return this.removalRange_ != null + ? this.removalRange_ + : getTokenRemovalRange(this); } createContinuousRangeTarget( diff --git a/src/processTargets/targets/SubTokenTarget.ts b/src/processTargets/targets/SubTokenTarget.ts deleted file mode 100644 index ad22f7cfc2..0000000000 --- a/src/processTargets/targets/SubTokenTarget.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { Range } from "vscode"; -import { Target } from "../../typings/target.types"; -import { isSameType } from "../../util/typeUtils"; -import { constructPlainTarget } from "../../util/wrapRangeWithTarget"; -import { - createContinuousRange, - createContinuousRangeFromRanges, -} from "../targetUtil/createContinuousRange"; -import { getDelimitedSequenceRemovalRange } from "../targetUtil/insertionRemovalBehaviors/DelimitedSequenceInsertionRemovalBehavior"; -import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; -import ScopeTypeTarget from "./ScopeTypeTarget"; - -export interface SubTokenTargetParameters extends CommonTargetParameters { - readonly delimiterString: string; - readonly leadingDelimiterRange?: Range; - readonly trailingDelimiterRange?: Range; -} - -export default class SubTokenTarget extends BaseTarget { - private leadingDelimiterRange_?: Range; - private trailingDelimiterRange_?: Range; - delimiterString: string; - - constructor(parameters: SubTokenTargetParameters) { - super(parameters); - this.leadingDelimiterRange_ = parameters.leadingDelimiterRange; - this.trailingDelimiterRange_ = parameters.trailingDelimiterRange; - this.delimiterString = parameters.delimiterString; - } - - getLeadingDelimiterTarget() { - return constructPlainTarget( - this.editor, - this.leadingDelimiterRange_, - this.isReversed - ); - } - - getTrailingDelimiterTarget() { - return constructPlainTarget( - this.editor, - this.trailingDelimiterRange_, - this.isReversed - ); - } - - getRemovalRange(): Range { - return getDelimitedSequenceRemovalRange(this); - } - - createContinuousRangeTarget( - isReversed: boolean, - endTarget: Target, - includeStart: boolean, - includeEnd: boolean - ): Target { - if (isSameType(this, endTarget)) { - const scopeTarget = endTarget; - if (this.scopeTypeType_ === scopeTarget.scopeTypeType_) { - const contentRemovalRange = - this.contentRemovalRange_ != null || - scopeTarget.contentRemovalRange_ != null - ? createContinuousRangeFromRanges( - this.contentRemovalRange_ ?? this.contentRange, - scopeTarget.contentRemovalRange_ ?? scopeTarget.contentRange, - includeStart, - includeEnd - ) - : undefined; - - return new ScopeTypeTarget({ - ...this.getCloneParameters(), - isReversed, - leadingDelimiterRange: this.leadingDelimiterRange_, - trailingDelimiterRange: scopeTarget.trailingDelimiterRange_, - removalRange: contentRemovalRange, - contentRange: createContinuousRange( - this, - endTarget, - includeStart, - includeEnd - ), - }); - } - } - - return super.createContinuousRangeTarget( - isReversed, - endTarget, - includeStart, - includeEnd - ); - } - - protected getCloneParameters() { - return { - ...this.state, - leadingDelimiterRange: this.leadingDelimiterRange_, - trailingDelimiterRange: this.trailingDelimiterRange_, - }; - } -} From 368619990862a7ce4bf044dcf7f68bd28691110c Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 1 Jun 2022 18:15:48 +0200 Subject: [PATCH 262/314] Hide panel on recorded test sweet startup --- src/test/suite/recorded.test.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/test/suite/recorded.test.ts b/src/test/suite/recorded.test.ts index 90386c8fb4..c2580eeae5 100644 --- a/src/test/suite/recorded.test.ts +++ b/src/test/suite/recorded.test.ts @@ -46,6 +46,11 @@ suite("recorded test cases", async function () { sinon.restore(); }); + suiteSetup(async () => { + // Necessary because opening a notebook opens the panel for some reason + await vscode.commands.executeCommand("workbench.action.closePanel"); + }); + getRecordedTestPaths().forEach((path) => test( path.split(".")[0], From 567210a488593ad925a44a78f3338c7e3246b6de Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Wed, 1 Jun 2022 19:46:11 +0100 Subject: [PATCH 263/314] More stuff --- src/processTargets/targets/SubTokenTarget.ts | 102 +++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 src/processTargets/targets/SubTokenTarget.ts diff --git a/src/processTargets/targets/SubTokenTarget.ts b/src/processTargets/targets/SubTokenTarget.ts new file mode 100644 index 0000000000..ad22f7cfc2 --- /dev/null +++ b/src/processTargets/targets/SubTokenTarget.ts @@ -0,0 +1,102 @@ +import { Range } from "vscode"; +import { Target } from "../../typings/target.types"; +import { isSameType } from "../../util/typeUtils"; +import { constructPlainTarget } from "../../util/wrapRangeWithTarget"; +import { + createContinuousRange, + createContinuousRangeFromRanges, +} from "../targetUtil/createContinuousRange"; +import { getDelimitedSequenceRemovalRange } from "../targetUtil/insertionRemovalBehaviors/DelimitedSequenceInsertionRemovalBehavior"; +import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; +import ScopeTypeTarget from "./ScopeTypeTarget"; + +export interface SubTokenTargetParameters extends CommonTargetParameters { + readonly delimiterString: string; + readonly leadingDelimiterRange?: Range; + readonly trailingDelimiterRange?: Range; +} + +export default class SubTokenTarget extends BaseTarget { + private leadingDelimiterRange_?: Range; + private trailingDelimiterRange_?: Range; + delimiterString: string; + + constructor(parameters: SubTokenTargetParameters) { + super(parameters); + this.leadingDelimiterRange_ = parameters.leadingDelimiterRange; + this.trailingDelimiterRange_ = parameters.trailingDelimiterRange; + this.delimiterString = parameters.delimiterString; + } + + getLeadingDelimiterTarget() { + return constructPlainTarget( + this.editor, + this.leadingDelimiterRange_, + this.isReversed + ); + } + + getTrailingDelimiterTarget() { + return constructPlainTarget( + this.editor, + this.trailingDelimiterRange_, + this.isReversed + ); + } + + getRemovalRange(): Range { + return getDelimitedSequenceRemovalRange(this); + } + + createContinuousRangeTarget( + isReversed: boolean, + endTarget: Target, + includeStart: boolean, + includeEnd: boolean + ): Target { + if (isSameType(this, endTarget)) { + const scopeTarget = endTarget; + if (this.scopeTypeType_ === scopeTarget.scopeTypeType_) { + const contentRemovalRange = + this.contentRemovalRange_ != null || + scopeTarget.contentRemovalRange_ != null + ? createContinuousRangeFromRanges( + this.contentRemovalRange_ ?? this.contentRange, + scopeTarget.contentRemovalRange_ ?? scopeTarget.contentRange, + includeStart, + includeEnd + ) + : undefined; + + return new ScopeTypeTarget({ + ...this.getCloneParameters(), + isReversed, + leadingDelimiterRange: this.leadingDelimiterRange_, + trailingDelimiterRange: scopeTarget.trailingDelimiterRange_, + removalRange: contentRemovalRange, + contentRange: createContinuousRange( + this, + endTarget, + includeStart, + includeEnd + ), + }); + } + } + + return super.createContinuousRangeTarget( + isReversed, + endTarget, + includeStart, + includeEnd + ); + } + + protected getCloneParameters() { + return { + ...this.state, + leadingDelimiterRange: this.leadingDelimiterRange_, + trailingDelimiterRange: this.trailingDelimiterRange_, + }; + } +} From ab699b2c8707cbf24cf3a14c41072dd551c36c66 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Wed, 1 Jun 2022 19:46:18 +0100 Subject: [PATCH 264/314] More stuff --- .../src/actions/actions_makeshift.py | 2 +- .../modifiers/OrdinalRangeSubTokenStage.ts | 46 +++++--- ...limitedSequenceInsertionRemovalBehavior.ts | 19 +++- .../TokenInsertionRemovalBehavior.ts | 19 +++- src/processTargets/targets/LineTarget.ts | 6 +- src/processTargets/targets/ParagraphTarget.ts | 24 +++-- src/processTargets/targets/ScopeTypeTarget.ts | 5 +- src/processTargets/targets/SubTokenTarget.ts | 102 ------------------ .../targets/SubTokenWordTarget.ts | 51 +++++++++ src/util/rangeUtils.ts | 4 + src/util/tryConstructTarget.ts | 68 ++++++++++++ src/util/wrapRangeWithTarget.ts | 40 ------- 12 files changed, 207 insertions(+), 179 deletions(-) delete mode 100644 src/processTargets/targets/SubTokenTarget.ts create mode 100644 src/processTargets/targets/SubTokenWordTarget.ts create mode 100644 src/util/tryConstructTarget.ts delete mode 100644 src/util/wrapRangeWithTarget.ts diff --git a/cursorless-talon/src/actions/actions_makeshift.py b/cursorless-talon/src/actions/actions_makeshift.py index f1f84075c4..06c40569bb 100644 --- a/cursorless-talon/src/actions/actions_makeshift.py +++ b/cursorless-talon/src/actions/actions_makeshift.py @@ -39,7 +39,7 @@ class MakeshiftAction: "editor.action.rename", restore_selection=True, await_command=False, - post_command_sleep_ms=150, + post_command_sleep_ms=200, ), ] diff --git a/src/processTargets/modifiers/OrdinalRangeSubTokenStage.ts b/src/processTargets/modifiers/OrdinalRangeSubTokenStage.ts index 7be4972fb3..36ab67d239 100644 --- a/src/processTargets/modifiers/OrdinalRangeSubTokenStage.ts +++ b/src/processTargets/modifiers/OrdinalRangeSubTokenStage.ts @@ -8,7 +8,8 @@ import { } from "../../typings/target.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; -import ScopeTypeTarget from "../targets/ScopeTypeTarget"; +import PlainTarget from "../targets/PlainTarget"; +import SubTokenWordTarget from "../targets/SubTokenWordTarget"; import { getTokenRangeForSelection } from "./scopeTypeStages/TokenStage"; interface OrdinalScopeType extends SimpleScopeType { @@ -24,11 +25,11 @@ export default class OrdinalRangeSubTokenStage implements ModifierStage { run(context: ProcessedTargetsContext, target: Target): Target[] { const { editor } = target; - const contentRange = target.contentRange.isEmpty + const tokenContentRange = target.contentRange.isEmpty ? getTokenRangeForSelection(target.editor, target.contentRange) : target.contentRange; - const token = editor.document.getText(contentRange); + const tokenText = editor.document.getText(tokenContentRange); let pieces: { start: number; end: number }[] = []; if (this.modifier.excludeActive || this.modifier.excludeAnchor) { @@ -36,12 +37,12 @@ export default class OrdinalRangeSubTokenStage implements ModifierStage { } if (this.modifier.scopeType.type === "word") { - pieces = [...token.matchAll(SUBWORD_MATCHER)].map((match) => ({ + pieces = [...tokenText.matchAll(SUBWORD_MATCHER)].map((match) => ({ start: match.index!, end: match.index! + match[0].length, })); } else if (this.modifier.scopeType.type === "character") { - pieces = range(token.length).map((index) => ({ + pieces = range(tokenText.length).map((index) => ({ start: index, end: index + 1, })); @@ -67,24 +68,36 @@ export default class OrdinalRangeSubTokenStage implements ModifierStage { const isReversed = activeIndex < anchorIndex; - const anchor = contentRange.start.translate( + const anchor = tokenContentRange.start.translate( undefined, isReversed ? pieces[anchorIndex].end : pieces[anchorIndex].start ); - const active = contentRange.start.translate( + const active = tokenContentRange.start.translate( undefined, isReversed ? pieces[activeIndex].start : pieces[activeIndex].end ); + const contentRange = new Range(anchor, active); + + if (this.modifier.scopeType.type === "character") { + return [ + new PlainTarget({ + editor, + isReversed, + contentRange, + }), + ]; + } + const startIndex = Math.min(anchorIndex, activeIndex); const endIndex = Math.max(anchorIndex, activeIndex); const leadingDelimiterRange = startIndex > 0 && pieces[startIndex - 1].end < pieces[startIndex].start ? new Range( - contentRange.start.translate({ + tokenContentRange.start.translate({ characterDelta: pieces[startIndex - 1].end, }), - contentRange.start.translate({ + tokenContentRange.start.translate({ characterDelta: pieces[startIndex].start, }) ) @@ -93,29 +106,28 @@ export default class OrdinalRangeSubTokenStage implements ModifierStage { endIndex + 1 < pieces.length && pieces[endIndex].end < pieces[endIndex + 1].start ? new Range( - contentRange.start.translate({ + tokenContentRange.start.translate({ characterDelta: pieces[endIndex].end, }), - contentRange.start.translate({ + tokenContentRange.start.translate({ characterDelta: pieces[endIndex + 1].start, }) ) : undefined; const isInDelimitedList = leadingDelimiterRange != null || trailingDelimiterRange != null; - const containingListDelimiter = isInDelimitedList + const delimiterString = isInDelimitedList ? editor.document.getText( (leadingDelimiterRange ?? trailingDelimiterRange)! ) - : undefined; + : ""; return [ - new ScopeTypeTarget({ + new SubTokenWordTarget({ editor, isReversed, - contentRange: new Range(anchor, active), - scopeTypeType: this.modifier.scopeType.type, - delimiter: containingListDelimiter ?? "", + contentRange, + delimiterString, leadingDelimiterRange, trailingDelimiterRange, }), diff --git a/src/processTargets/targetUtil/insertionRemovalBehaviors/DelimitedSequenceInsertionRemovalBehavior.ts b/src/processTargets/targetUtil/insertionRemovalBehaviors/DelimitedSequenceInsertionRemovalBehavior.ts index abe9abc87f..b26b7d2c4f 100644 --- a/src/processTargets/targetUtil/insertionRemovalBehaviors/DelimitedSequenceInsertionRemovalBehavior.ts +++ b/src/processTargets/targetUtil/insertionRemovalBehaviors/DelimitedSequenceInsertionRemovalBehavior.ts @@ -1,11 +1,24 @@ import { Range } from "vscode"; import { Target } from "../../../typings/target.types"; -export function getDelimitedSequenceRemovalRange(target: Target): Range { +/** + * Constructs a removal range for the given target that includes either the + * trailing or leading delimiter + * @param target The target to get the removal range for + * @param contentRange Can be used to override the content range instead of + * using the one on the target + * @returns The removal range for the given target + */ +export function getDelimitedSequenceRemovalRange( + target: Target, + contentRange?: Range +): Range { + contentRange = contentRange ?? target.contentRange; + const delimiterTarget = target.getTrailingDelimiterTarget() ?? target.getLeadingDelimiterTarget(); return delimiterTarget != null - ? target.contentRange.union(delimiterTarget.contentRange) - : target.contentRange; + ? contentRange.union(delimiterTarget.contentRange) + : contentRange; } diff --git a/src/processTargets/targetUtil/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts b/src/processTargets/targetUtil/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts index 19ebdd7a3b..8e0951bfda 100644 --- a/src/processTargets/targetUtil/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts +++ b/src/processTargets/targetUtil/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts @@ -52,8 +52,21 @@ export function getTokenTrailingDelimiterTarget( }); } -export function getTokenRemovalRange(target: Target): Range { - const { start, end } = target.contentRange; +/** + * Constructs a removal range for the given target that will clean up a json + * whitespace on one side unless it will cause two tokens to be merged. This + * removal range is designed to be used with things that should clean themselves + * up as if they're a range of tokens. + * @param target The target to get the token removal range for + * @param contentRange Can be used to override the content range instead of + * using the one on the target + * @returns The removal range for the given target + */ +export function getTokenRemovalRange( + target: Target, + contentRange?: Range +): Range { + const { start, end } = contentRange ?? target.contentRange; const leadingDelimiterTarget = getTokenLeadingDelimiterTarget(target); const trailingDelimiterTarget = getTokenTrailingDelimiterTarget(target); @@ -72,5 +85,5 @@ export function getTokenRemovalRange(target: Target): Range { } // Otherwise, behave like a whitespace delimited sequence - return getDelimitedSequenceRemovalRange(target); + return getDelimitedSequenceRemovalRange(target, contentRange); } diff --git a/src/processTargets/targets/LineTarget.ts b/src/processTargets/targets/LineTarget.ts index 48625dfb32..1fe7d4328b 100644 --- a/src/processTargets/targets/LineTarget.ts +++ b/src/processTargets/targets/LineTarget.ts @@ -1,7 +1,7 @@ import { Position, Range, TextEditor } from "vscode"; import { Target } from "../../typings/target.types"; import { expandToFullLine } from "../../util/rangeUtils"; -import { constructPlainTarget } from "../../util/wrapRangeWithTarget"; +import { tryConstructPlainTarget } from "../../util/tryConstructTarget"; import { createContinuousLineRange } from "../targetUtil/createContinuousRange"; import BaseTarget from "./BaseTarget"; @@ -14,7 +14,7 @@ export default class LineTarget extends BaseTarget { } getLeadingDelimiterTarget() { - return constructPlainTarget( + return tryConstructPlainTarget( this.editor, getLeadingDelimiterRange(this.editor, this.fullLineContentRange), this.isReversed @@ -22,7 +22,7 @@ export default class LineTarget extends BaseTarget { } getTrailingDelimiterTarget() { - return constructPlainTarget( + return tryConstructPlainTarget( this.editor, getTrailingDelimiterRange(this.editor, this.fullLineContentRange), this.isReversed diff --git a/src/processTargets/targets/ParagraphTarget.ts b/src/processTargets/targets/ParagraphTarget.ts index 2225691cbe..36dae1e326 100644 --- a/src/processTargets/targets/ParagraphTarget.ts +++ b/src/processTargets/targets/ParagraphTarget.ts @@ -2,7 +2,7 @@ import { Position, Range, TextDocument, TextEditor, TextLine } from "vscode"; import { Target } from "../../typings/target.types"; import { expandToFullLine } from "../../util/rangeUtils"; import { isSameType } from "../../util/typeUtils"; -import { constructLineTarget } from "../../util/wrapRangeWithTarget"; +import { constructLineTarget } from "../../util/tryConstructTarget"; import { createContinuousLineRange, createSimpleContinuousRangeTarget, @@ -34,21 +34,27 @@ export default class ParagraphTarget extends BaseTarget { // TODO: In the future we could get rid of this function if {@link // getDelimitedSequenceRemovalRange} made a continuous range from the target // past its delimiter target and then used the removal range of that. - const contentRemovalRange = this.fullLineContentRange; const delimiterTarget = this.getTrailingDelimiterTarget() ?? this.getLeadingDelimiterTarget(); + const removalContentRange = + delimiterTarget != null + ? this.contentRange.union(delimiterTarget.contentRange) + : this.contentRange; + // If there is a delimiter, it will be a line target, so we join it with // ourself to create a line target containing ourself and the delimiter // line. We then allow the line target removal range code to cleanup any // extra leading or trailing newline - return delimiterTarget == null - ? contentRemovalRange - : createSimpleContinuousRangeTarget( - this, - delimiterTarget, - this.isReversed - ).getRemovalRange(); + // + // If there is no delimiter, we just use the line content range, + // converting it to a line target so that it cleans up leading or trailing + // newline as necessary + return new LineTarget({ + contentRange: removalContentRange, + editor: this.editor, + isReversed: this.isReversed, + }).getRemovalRange(); } private get fullLineContentRange() { diff --git a/src/processTargets/targets/ScopeTypeTarget.ts b/src/processTargets/targets/ScopeTypeTarget.ts index 060e26f7f9..746ec0d9c0 100644 --- a/src/processTargets/targets/ScopeTypeTarget.ts +++ b/src/processTargets/targets/ScopeTypeTarget.ts @@ -5,6 +5,7 @@ import { createContinuousRange, createContinuousRangeFromRanges, } from "../targetUtil/createContinuousRange"; +import { getDelimitedSequenceRemovalRange } from "../targetUtil/insertionRemovalBehaviors/DelimitedSequenceInsertionRemovalBehavior"; import { getTokenLeadingDelimiterTarget, getTokenRemovalRange, @@ -71,7 +72,9 @@ export default class ScopeTypeTarget extends BaseTarget { getRemovalRange(): Range { return this.removalRange_ != null - ? this.removalRange_ + ? getTokenRemovalRange(this, this.removalRange_) + : this.hasDelimiterRange_ + ? getDelimitedSequenceRemovalRange(this) : getTokenRemovalRange(this); } diff --git a/src/processTargets/targets/SubTokenTarget.ts b/src/processTargets/targets/SubTokenTarget.ts deleted file mode 100644 index ad22f7cfc2..0000000000 --- a/src/processTargets/targets/SubTokenTarget.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { Range } from "vscode"; -import { Target } from "../../typings/target.types"; -import { isSameType } from "../../util/typeUtils"; -import { constructPlainTarget } from "../../util/wrapRangeWithTarget"; -import { - createContinuousRange, - createContinuousRangeFromRanges, -} from "../targetUtil/createContinuousRange"; -import { getDelimitedSequenceRemovalRange } from "../targetUtil/insertionRemovalBehaviors/DelimitedSequenceInsertionRemovalBehavior"; -import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; -import ScopeTypeTarget from "./ScopeTypeTarget"; - -export interface SubTokenTargetParameters extends CommonTargetParameters { - readonly delimiterString: string; - readonly leadingDelimiterRange?: Range; - readonly trailingDelimiterRange?: Range; -} - -export default class SubTokenTarget extends BaseTarget { - private leadingDelimiterRange_?: Range; - private trailingDelimiterRange_?: Range; - delimiterString: string; - - constructor(parameters: SubTokenTargetParameters) { - super(parameters); - this.leadingDelimiterRange_ = parameters.leadingDelimiterRange; - this.trailingDelimiterRange_ = parameters.trailingDelimiterRange; - this.delimiterString = parameters.delimiterString; - } - - getLeadingDelimiterTarget() { - return constructPlainTarget( - this.editor, - this.leadingDelimiterRange_, - this.isReversed - ); - } - - getTrailingDelimiterTarget() { - return constructPlainTarget( - this.editor, - this.trailingDelimiterRange_, - this.isReversed - ); - } - - getRemovalRange(): Range { - return getDelimitedSequenceRemovalRange(this); - } - - createContinuousRangeTarget( - isReversed: boolean, - endTarget: Target, - includeStart: boolean, - includeEnd: boolean - ): Target { - if (isSameType(this, endTarget)) { - const scopeTarget = endTarget; - if (this.scopeTypeType_ === scopeTarget.scopeTypeType_) { - const contentRemovalRange = - this.contentRemovalRange_ != null || - scopeTarget.contentRemovalRange_ != null - ? createContinuousRangeFromRanges( - this.contentRemovalRange_ ?? this.contentRange, - scopeTarget.contentRemovalRange_ ?? scopeTarget.contentRange, - includeStart, - includeEnd - ) - : undefined; - - return new ScopeTypeTarget({ - ...this.getCloneParameters(), - isReversed, - leadingDelimiterRange: this.leadingDelimiterRange_, - trailingDelimiterRange: scopeTarget.trailingDelimiterRange_, - removalRange: contentRemovalRange, - contentRange: createContinuousRange( - this, - endTarget, - includeStart, - includeEnd - ), - }); - } - } - - return super.createContinuousRangeTarget( - isReversed, - endTarget, - includeStart, - includeEnd - ); - } - - protected getCloneParameters() { - return { - ...this.state, - leadingDelimiterRange: this.leadingDelimiterRange_, - trailingDelimiterRange: this.trailingDelimiterRange_, - }; - } -} diff --git a/src/processTargets/targets/SubTokenWordTarget.ts b/src/processTargets/targets/SubTokenWordTarget.ts new file mode 100644 index 0000000000..a606437f29 --- /dev/null +++ b/src/processTargets/targets/SubTokenWordTarget.ts @@ -0,0 +1,51 @@ +import { Range } from "vscode"; +import { tryConstructPlainTarget as tryConstructPlainTarget } from "../../util/tryConstructTarget"; +import { getDelimitedSequenceRemovalRange } from "../targetUtil/insertionRemovalBehaviors/DelimitedSequenceInsertionRemovalBehavior"; +import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; + +export interface SubTokenTargetParameters extends CommonTargetParameters { + readonly delimiterString: string; + readonly leadingDelimiterRange?: Range; + readonly trailingDelimiterRange?: Range; +} + +export default class SubTokenWordTarget extends BaseTarget { + private leadingDelimiterRange_?: Range; + private trailingDelimiterRange_?: Range; + delimiterString: string; + + constructor(parameters: SubTokenTargetParameters) { + super(parameters); + this.leadingDelimiterRange_ = parameters.leadingDelimiterRange; + this.trailingDelimiterRange_ = parameters.trailingDelimiterRange; + this.delimiterString = parameters.delimiterString; + } + + getLeadingDelimiterTarget() { + return tryConstructPlainTarget( + this.editor, + this.leadingDelimiterRange_, + this.isReversed + ); + } + + getTrailingDelimiterTarget() { + return tryConstructPlainTarget( + this.editor, + this.trailingDelimiterRange_, + this.isReversed + ); + } + + getRemovalRange(): Range { + return getDelimitedSequenceRemovalRange(this); + } + + protected getCloneParameters() { + return { + ...this.state, + leadingDelimiterRange: this.leadingDelimiterRange_, + trailingDelimiterRange: this.trailingDelimiterRange_, + }; + } +} diff --git a/src/util/rangeUtils.ts b/src/util/rangeUtils.ts index e05aa0e190..a812180221 100644 --- a/src/util/rangeUtils.ts +++ b/src/util/rangeUtils.ts @@ -24,3 +24,7 @@ export function expandToFullLine(editor: TextEditor, range: Range) { editor.document.lineAt(range.end).range.end ); } + +export function makeEmptyRange(position: Position) { + return new Range(position, position); +} diff --git a/src/util/tryConstructTarget.ts b/src/util/tryConstructTarget.ts new file mode 100644 index 0000000000..220489f7c2 --- /dev/null +++ b/src/util/tryConstructTarget.ts @@ -0,0 +1,68 @@ +import { Range, TextEditor } from "vscode"; +import { CommonTargetParameters } from "../processTargets/targets/BaseTarget"; +import LineTarget from "../processTargets/targets/LineTarget"; +import PlainTarget from "../processTargets/targets/PlainTarget"; +import { Target } from "../typings/target.types"; + +type TargetConstructor = new ( + parameters: CommonTargetParameters +) => T; + +/** + * Constructs a target from the given range or returns undefined if the range is + * undefined + * @param constructor The type of target to construct + * @param editor The editor containing the range + * @param range The range to convert into a target + * @param isReversed Whether the rain should be backward + * @returns A new target constructed from the given range, or null if the range + * is undefined + */ +export function tryConstructTarget( + constructor: TargetConstructor, + editor: TextEditor, + range: Range | undefined, + isReversed: boolean +): T | undefined { + return range == null + ? undefined + : new constructor({ + editor, + isReversed, + contentRange: range, + }); +} + +/** + * Constructs a {@link PlainTarget} from the given range, or returns undefined + * if the range is undefined + * @param editor The editor containing the range + * @param range The range to convert into a target + * @param isReversed Whether the rain should be backward + * @returns A new {@link PlainTarget} constructed from the given range, or null + * if the range is undefined + */ +export function tryConstructPlainTarget( + editor: TextEditor, + range: Range | undefined, + isReversed: boolean +): PlainTarget | undefined { + return tryConstructTarget(PlainTarget, editor, range, isReversed); +} + +/** + * Constructs a {@link LineTarget} from the given range, or returns undefined + * if the range is undefined + * @param editor The editor containing the range + * @param range The range to convert into a target + * @param isReversed Whether the rain should be backward + * @returns A new {@link LineTarget} constructed from the given range, or null + * if the range is undefined + */ +export function constructLineTarget( + editor: TextEditor, + range: Range | undefined, + isReversed: boolean +): LineTarget | undefined { + return tryConstructTarget(LineTarget, editor, range, isReversed); +} diff --git a/src/util/wrapRangeWithTarget.ts b/src/util/wrapRangeWithTarget.ts deleted file mode 100644 index bf04d1b32b..0000000000 --- a/src/util/wrapRangeWithTarget.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Range, TextEditor } from "vscode"; -import { CommonTargetParameters } from "../processTargets/targets/BaseTarget"; -import LineTarget from "../processTargets/targets/LineTarget"; -import PlainTarget from "../processTargets/targets/PlainTarget"; -import { Target } from "../typings/target.types"; - -type TargetConstructor = new ( - parameters: CommonTargetParameters -) => T; - -export function constructTarget( - constructor: TargetConstructor, - editor: TextEditor, - range: Range | undefined, - isReversed: boolean -): T | undefined { - return range == null - ? undefined - : new constructor({ - editor, - isReversed, - contentRange: range, - }); -} - -export function constructPlainTarget( - editor: TextEditor, - range: Range | undefined, - isReversed: boolean -): PlainTarget | undefined { - return constructTarget(PlainTarget, editor, range, isReversed); -} - -export function constructLineTarget( - editor: TextEditor, - range: Range | undefined, - isReversed: boolean -): LineTarget | undefined { - return constructTarget(LineTarget, editor, range, isReversed); -} From 8c35a53fc3cf5916c4b810afdd7dae6c443e272b Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 1 Jun 2022 20:51:36 +0200 Subject: [PATCH 265/314] Cleanup --- src/processTargets/targets/ParagraphTarget.ts | 5 +---- src/processTargets/targets/TokenTarget.ts | 1 + 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/processTargets/targets/ParagraphTarget.ts b/src/processTargets/targets/ParagraphTarget.ts index 36dae1e326..63a0427eab 100644 --- a/src/processTargets/targets/ParagraphTarget.ts +++ b/src/processTargets/targets/ParagraphTarget.ts @@ -3,10 +3,7 @@ import { Target } from "../../typings/target.types"; import { expandToFullLine } from "../../util/rangeUtils"; import { isSameType } from "../../util/typeUtils"; import { constructLineTarget } from "../../util/tryConstructTarget"; -import { - createContinuousLineRange, - createSimpleContinuousRangeTarget, -} from "../targetUtil/createContinuousRange"; +import { createContinuousLineRange } from "../targetUtil/createContinuousRange"; import BaseTarget from "./BaseTarget"; import LineTarget from "./LineTarget"; diff --git a/src/processTargets/targets/TokenTarget.ts b/src/processTargets/targets/TokenTarget.ts index d66d5ddd5b..e0a6b2d60e 100644 --- a/src/processTargets/targets/TokenTarget.ts +++ b/src/processTargets/targets/TokenTarget.ts @@ -10,6 +10,7 @@ import BaseTarget from "./BaseTarget"; export default class TokenTarget extends BaseTarget { delimiterString = " "; + /** */ getLeadingDelimiterTarget(): Target | undefined { return getTokenLeadingDelimiterTarget(this); } From 2d627a641ca650d51244c5b6aa57d04e804b2a12 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 1 Jun 2022 21:30:28 +0200 Subject: [PATCH 266/314] Some stuff clean up whatever don't care --- src/processTargets/modifiers/PositionStage.ts | 5 ++--- .../TokenInsertionRemovalBehavior.ts | 2 +- src/processTargets/targets/PositionTarget.ts | 10 +++++++--- src/processTargets/targets/TokenTarget.ts | 1 - .../fixtures/recorded/decorations/chuckLineFine.yml | 4 ++-- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/processTargets/modifiers/PositionStage.ts b/src/processTargets/modifiers/PositionStage.ts index 230cb47ec2..3dc473a447 100644 --- a/src/processTargets/modifiers/PositionStage.ts +++ b/src/processTargets/modifiers/PositionStage.ts @@ -30,13 +30,12 @@ export function toPositionTarget(target: Target, position: Position): Target { case "start": contentRange = new Range(start, start); - // This it NOT a raw target. Joining with this should be done on empty delimiter. - delimiter = ""; + delimiter = target.delimiterString != null ? "" : undefined; break; case "end": contentRange = new Range(end, end); - delimiter = ""; + delimiter = target.delimiterString != null ? "" : undefined; break; } diff --git a/src/processTargets/targetUtil/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts b/src/processTargets/targetUtil/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts index 8e0951bfda..253aaf566a 100644 --- a/src/processTargets/targetUtil/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts +++ b/src/processTargets/targetUtil/insertionRemovalBehaviors/TokenInsertionRemovalBehavior.ts @@ -81,7 +81,7 @@ export function getTokenRemovalRange( (leadingDelimiterTarget == null && !isAtStartOfLine(start)) || (trailingDelimiterTarget == null && !isAtEndOfLine(target.editor, end)) ) { - return target.contentRange; + return contentRange ?? target.contentRange; } // Otherwise, behave like a whitespace delimited sequence diff --git a/src/processTargets/targets/PositionTarget.ts b/src/processTargets/targets/PositionTarget.ts index 68000dc367..0b8caa0af1 100644 --- a/src/processTargets/targets/PositionTarget.ts +++ b/src/processTargets/targets/PositionTarget.ts @@ -10,13 +10,17 @@ interface PositionTargetParameters extends CommonTargetParameters { } export default class PositionTarget extends BaseTarget { - delimiterString: string; + private delimiterString_?: string; private position: Position; constructor(parameters: PositionTargetParameters) { super(parameters); this.position = parameters.position; - this.delimiterString = parameters.delimiter ?? ""; + this.delimiterString_ = parameters.delimiter; + } + + get delimiterString() { + return this.delimiterString_; } getLeadingDelimiterTarget = () => undefined; @@ -48,7 +52,7 @@ export default class PositionTarget extends BaseTarget { text: string, useLinePadding: boolean ): EditWithRangeUpdater { - const delimiter = this.delimiterString!; + const delimiter = this.delimiterString ?? ""; const isLine = delimiter.includes("\n"); const isBefore = this.position === "before"; diff --git a/src/processTargets/targets/TokenTarget.ts b/src/processTargets/targets/TokenTarget.ts index e0a6b2d60e..d66d5ddd5b 100644 --- a/src/processTargets/targets/TokenTarget.ts +++ b/src/processTargets/targets/TokenTarget.ts @@ -10,7 +10,6 @@ import BaseTarget from "./BaseTarget"; export default class TokenTarget extends BaseTarget { delimiterString = " "; - /** */ getLeadingDelimiterTarget(): Target | undefined { return getTokenLeadingDelimiterTarget(this); } diff --git a/src/test/suite/fixtures/recorded/decorations/chuckLineFine.yml b/src/test/suite/fixtures/recorded/decorations/chuckLineFine.yml index 4f8015c849..c6d1c6d155 100644 --- a/src/test/suite/fixtures/recorded/decorations/chuckLineFine.yml +++ b/src/test/suite/fixtures/recorded/decorations/chuckLineFine.yml @@ -35,6 +35,6 @@ finalState: decorations: - name: pendingDeleteBackground type: line - start: {line: 1, character: 4} - end: {line: 1, character: 11} + start: {line: 1, character: 0} + end: {line: 1, character: 15} fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: f}, modifiers: [{type: containingScope, scopeType: {type: line}}]}] From 7e5278c6fdc744bf14b9039c9f7fd3d383633927 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 1 Jun 2022 22:56:26 +0200 Subject: [PATCH 267/314] Committed some stuff --- src/actions/BringMoveSwap.ts | 3 +- .../modifiers/OrdinalRangeSubTokenStage.ts | 4 +- src/processTargets/modifiers/PositionStage.ts | 14 ++--- src/processTargets/processTargets.ts | 9 ++-- .../insertionRemovalBehavior.types.ts | 2 +- src/processTargets/targets/BaseTarget.ts | 13 ++++- src/processTargets/targets/DocumentTarget.ts | 2 +- src/processTargets/targets/LineTarget.ts | 2 +- .../targets/NotebookCellTarget.ts | 2 +- src/processTargets/targets/ParagraphTarget.ts | 2 +- src/processTargets/targets/PlainTarget.ts | 2 +- src/processTargets/targets/PositionTarget.ts | 24 ++++----- .../targets/RawSelectionTarget.ts | 7 +-- src/processTargets/targets/ScopeTypeTarget.ts | 4 +- .../targets/SubTokenWordTarget.ts | 6 +-- .../targets/SurroundingPairTarget.ts | 2 +- src/processTargets/targets/TokenTarget.ts | 2 +- src/processTargets/targets/WeakTarget.ts | 2 +- .../bringArgMadeAndGustToEndOfJustThis.yml | 53 +++++++++++++++++++ src/typings/target.types.ts | 8 ++- 20 files changed, 115 insertions(+), 48 deletions(-) create mode 100644 src/test/suite/fixtures/recorded/positions/bringArgMadeAndGustToEndOfJustThis.yml diff --git a/src/actions/BringMoveSwap.ts b/src/actions/BringMoveSwap.ts index d46253bc00..79f98ae179 100644 --- a/src/actions/BringMoveSwap.ts +++ b/src/actions/BringMoveSwap.ts @@ -100,7 +100,8 @@ class BringMoveSwap implements Action { .map((source, i) => { const text = source.contentText; const delimiter = - destination.delimiterString ?? source.delimiterString; + (destination.isRaw ? null : destination.insertionDelimiter) ?? + (source.isRaw ? null : source.insertionDelimiter); return i > 0 && delimiter != null ? delimiter + text : text; }) .join(""); diff --git a/src/processTargets/modifiers/OrdinalRangeSubTokenStage.ts b/src/processTargets/modifiers/OrdinalRangeSubTokenStage.ts index 36ab67d239..b711a1583a 100644 --- a/src/processTargets/modifiers/OrdinalRangeSubTokenStage.ts +++ b/src/processTargets/modifiers/OrdinalRangeSubTokenStage.ts @@ -116,7 +116,7 @@ export default class OrdinalRangeSubTokenStage implements ModifierStage { : undefined; const isInDelimitedList = leadingDelimiterRange != null || trailingDelimiterRange != null; - const delimiterString = isInDelimitedList + const insertionDelimiter = isInDelimitedList ? editor.document.getText( (leadingDelimiterRange ?? trailingDelimiterRange)! ) @@ -127,7 +127,7 @@ export default class OrdinalRangeSubTokenStage implements ModifierStage { editor, isReversed, contentRange, - delimiterString, + insertionDelimiter, leadingDelimiterRange, trailingDelimiterRange, }), diff --git a/src/processTargets/modifiers/PositionStage.ts b/src/processTargets/modifiers/PositionStage.ts index 3dc473a447..5527b74589 100644 --- a/src/processTargets/modifiers/PositionStage.ts +++ b/src/processTargets/modifiers/PositionStage.ts @@ -15,27 +15,28 @@ export default class PositionStage implements ModifierStage { export function toPositionTarget(target: Target, position: Position): Target { const { start, end } = target.contentRange; let contentRange: Range; - let delimiter: string | undefined; + let insertionDelimiter: string; switch (position) { case "before": contentRange = new Range(start, start); - delimiter = target.delimiterString; + insertionDelimiter = target.insertionDelimiter; break; case "after": contentRange = new Range(end, end); - delimiter = target.delimiterString; + insertionDelimiter = target.insertionDelimiter; break; case "start": contentRange = new Range(start, start); - delimiter = target.delimiterString != null ? "" : undefined; + // This it NOT a raw target. Joining with this should be done on empty delimiter. + insertionDelimiter = ""; break; case "end": contentRange = new Range(end, end); - delimiter = target.delimiterString != null ? "" : undefined; + insertionDelimiter = ""; break; } @@ -44,6 +45,7 @@ export function toPositionTarget(target: Target, position: Position): Target { isReversed: target.isReversed, contentRange, position, - delimiter, + insertionDelimiter, + isRaw: target.isRaw, }); } diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index 7c9f54b3d0..c021e3fcc6 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -1,4 +1,4 @@ -import { zip } from "lodash"; +import { uniqWith, zip } from "lodash"; import { Range } from "vscode"; import { PrimitiveTargetDescriptor, @@ -8,7 +8,6 @@ import { } from "../typings/target.types"; import { ProcessedTargetsContext } from "../typings/Types"; import { ensureSingleEditor } from "../util/targetUtils"; -import uniqDeep from "../util/uniqDeep"; import getMarkStage from "./getMarkStage"; import getModifierStage from "./getModifierStage"; @@ -30,7 +29,7 @@ export default function ( context: ProcessedTargetsContext, targets: TargetDescriptor[] ): Target[][] { - return targets.map((target) => uniqDeep(processTarget(context, target))); + return targets.map((target) => uniqTargets(processTarget(context, target))); } function processTarget( @@ -214,3 +213,7 @@ function processPrimitiveTarget( function calcIsReversed(anchor: Target, active: Target) { return anchor.contentRange.start.isAfter(active.contentRange.start); } + +function uniqTargets(array: Target[]): Target[] { + return uniqWith(array, (a, b) => a.isEqual(b)); +} diff --git a/src/processTargets/targetUtil/insertionRemovalBehaviors/insertionRemovalBehavior.types.ts b/src/processTargets/targetUtil/insertionRemovalBehaviors/insertionRemovalBehavior.types.ts index 3441ebb19c..5a4c89d1eb 100644 --- a/src/processTargets/targetUtil/insertionRemovalBehaviors/insertionRemovalBehavior.types.ts +++ b/src/processTargets/targetUtil/insertionRemovalBehaviors/insertionRemovalBehavior.types.ts @@ -5,5 +5,5 @@ export default interface InsertionRemovalBehavior { getLeadingDelimiterTarget(): Target | undefined; getTrailingDelimiterTarget(): Target | undefined; getRemovalRange(): Range; - delimiterString: string | undefined; + insertionDelimiter: string | undefined; } diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index de77adbd03..1a8c388e36 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -1,3 +1,4 @@ +import { isEqual } from "lodash"; import { Range, Selection, TextEditor } from "vscode"; import { EditNewContext, Target } from "../../typings/target.types"; import { EditWithRangeUpdater } from "../../typings/Types"; @@ -25,6 +26,7 @@ export default abstract class BaseTarget implements Target { protected readonly state: CommonTargetParameters; isLine = false; isWeak = false; + isRaw = false; constructor(parameters: CommonTargetParameters) { this.state = { @@ -81,7 +83,7 @@ export default abstract class BaseTarget implements Target { } getEditNewContext(isBefore: boolean): EditNewContext { - const delimiter = this.delimiterString ?? ""; + const delimiter = this.insertionDelimiter ?? ""; if (delimiter === "\n" && !isBefore) { return { type: "command", command: "editor.action.insertLineAfter" }; } @@ -151,7 +153,14 @@ export default abstract class BaseTarget implements Target { ); } - abstract get delimiterString(): string | undefined; + isEqual(target: Target): boolean { + return ( + target instanceof BaseTarget && + isEqual(this.getCloneParameters(), target.getCloneParameters()) + ); + } + + abstract get insertionDelimiter(): string; abstract getLeadingDelimiterTarget(): Target | undefined; abstract getTrailingDelimiterTarget(): Target | undefined; abstract getRemovalRange(): Range; diff --git a/src/processTargets/targets/DocumentTarget.ts b/src/processTargets/targets/DocumentTarget.ts index 5bb41fdf15..7df946566c 100644 --- a/src/processTargets/targets/DocumentTarget.ts +++ b/src/processTargets/targets/DocumentTarget.ts @@ -4,7 +4,7 @@ import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; import WeakTarget from "./WeakTarget"; export default class DocumentTarget extends BaseTarget { - delimiterString = "\n"; + insertionDelimiter = "\n"; isLine = true; constructor(parameters: CommonTargetParameters) { diff --git a/src/processTargets/targets/LineTarget.ts b/src/processTargets/targets/LineTarget.ts index 1fe7d4328b..4b074cf0ec 100644 --- a/src/processTargets/targets/LineTarget.ts +++ b/src/processTargets/targets/LineTarget.ts @@ -6,7 +6,7 @@ import { createContinuousLineRange } from "../targetUtil/createContinuousRange"; import BaseTarget from "./BaseTarget"; export default class LineTarget extends BaseTarget { - delimiterString = "\n"; + insertionDelimiter = "\n"; isLine = true; private get fullLineContentRange() { diff --git a/src/processTargets/targets/NotebookCellTarget.ts b/src/processTargets/targets/NotebookCellTarget.ts index 8ae3c10686..ddfa09dcfb 100644 --- a/src/processTargets/targets/NotebookCellTarget.ts +++ b/src/processTargets/targets/NotebookCellTarget.ts @@ -4,7 +4,7 @@ import { getNotebookFromCellDocument } from "../../util/notebook"; import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; export default class NotebookCellTarget extends BaseTarget { - delimiterString = "\n"; + insertionDelimiter = "\n"; constructor(parameters: CommonTargetParameters) { super(parameters); diff --git a/src/processTargets/targets/ParagraphTarget.ts b/src/processTargets/targets/ParagraphTarget.ts index 63a0427eab..89e098f2c4 100644 --- a/src/processTargets/targets/ParagraphTarget.ts +++ b/src/processTargets/targets/ParagraphTarget.ts @@ -8,7 +8,7 @@ import BaseTarget from "./BaseTarget"; import LineTarget from "./LineTarget"; export default class ParagraphTarget extends BaseTarget { - delimiterString = "\n\n"; + insertionDelimiter = "\n\n"; isLine = true; getLeadingDelimiterTarget() { diff --git a/src/processTargets/targets/PlainTarget.ts b/src/processTargets/targets/PlainTarget.ts index 182f9bea3b..ffb542846b 100644 --- a/src/processTargets/targets/PlainTarget.ts +++ b/src/processTargets/targets/PlainTarget.ts @@ -5,7 +5,7 @@ import BaseTarget from "./BaseTarget"; * just consists of the content itself. Its insertion delimiter is empty string. */ export default class PlainTarget extends BaseTarget { - delimiterString = ""; + insertionDelimiter = ""; getLeadingDelimiterTarget = () => undefined; getTrailingDelimiterTarget = () => undefined; diff --git a/src/processTargets/targets/PositionTarget.ts b/src/processTargets/targets/PositionTarget.ts index 0b8caa0af1..755fb84f9a 100644 --- a/src/processTargets/targets/PositionTarget.ts +++ b/src/processTargets/targets/PositionTarget.ts @@ -6,21 +6,20 @@ import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; interface PositionTargetParameters extends CommonTargetParameters { readonly position: Position; - readonly delimiter?: string; + readonly insertionDelimiter: string; + readonly isRaw: boolean; } export default class PositionTarget extends BaseTarget { - private delimiterString_?: string; + insertionDelimiter: string; + isRaw: boolean; private position: Position; constructor(parameters: PositionTargetParameters) { super(parameters); this.position = parameters.position; - this.delimiterString_ = parameters.delimiter; - } - - get delimiterString() { - return this.delimiterString_; + this.insertionDelimiter = parameters.insertionDelimiter; + this.isRaw = parameters.isRaw; } getLeadingDelimiterTarget = () => undefined; @@ -41,10 +40,12 @@ export default class PositionTarget extends BaseTarget { return this.constructReplaceEdit(""); } - protected getCloneParameters() { + protected getCloneParameters(): PositionTargetParameters { return { ...this.state, position: this.position, + insertionDelimiter: this.insertionDelimiter, + isRaw: this.isRaw, }; } @@ -52,7 +53,7 @@ export default class PositionTarget extends BaseTarget { text: string, useLinePadding: boolean ): EditWithRangeUpdater { - const delimiter = this.delimiterString ?? ""; + const delimiter = this.insertionDelimiter; const isLine = delimiter.includes("\n"); const isBefore = this.position === "before"; @@ -101,10 +102,7 @@ export default class PositionTarget extends BaseTarget { } private isInsertion() { - return ( - this.delimiterString != null && - (this.position === "before" || this.position === "after") - ); + return this.position === "before" || this.position === "after"; } } diff --git a/src/processTargets/targets/RawSelectionTarget.ts b/src/processTargets/targets/RawSelectionTarget.ts index 0dd2bbfbe0..8a2c2cfd9d 100644 --- a/src/processTargets/targets/RawSelectionTarget.ts +++ b/src/processTargets/targets/RawSelectionTarget.ts @@ -6,11 +6,8 @@ import BaseTarget from "./BaseTarget"; * inherited from the source in the case of a bring after a bring before */ export default class RawSelectionTarget extends BaseTarget { - /** - * Note that we use an `undefined` value for `delimiterString` so that - * "bring" will use the source delimiterString - * */ - delimiterString = undefined; + insertionDelimiter = ""; + isRaw = true; getLeadingDelimiterTarget = () => undefined; getTrailingDelimiterTarget = () => undefined; diff --git a/src/processTargets/targets/ScopeTypeTarget.ts b/src/processTargets/targets/ScopeTypeTarget.ts index 746ec0d9c0..dcd1b1d838 100644 --- a/src/processTargets/targets/ScopeTypeTarget.ts +++ b/src/processTargets/targets/ScopeTypeTarget.ts @@ -28,7 +28,7 @@ export default class ScopeTypeTarget extends BaseTarget { private leadingDelimiterRange_?: Range; private trailingDelimiterRange_?: Range; private hasDelimiterRange_: boolean; - delimiterString: string; + insertionDelimiter: string; constructor(parameters: ScopeTypeTargetParameters) { super(parameters); @@ -36,7 +36,7 @@ export default class ScopeTypeTarget extends BaseTarget { this.removalRange_ = parameters.removalRange; this.leadingDelimiterRange_ = parameters.leadingDelimiterRange; this.trailingDelimiterRange_ = parameters.trailingDelimiterRange; - this.delimiterString = + this.insertionDelimiter = parameters.delimiter ?? getDelimiter(parameters.scopeTypeType); this.hasDelimiterRange_ = !!this.leadingDelimiterRange_ || !!this.trailingDelimiterRange_; diff --git a/src/processTargets/targets/SubTokenWordTarget.ts b/src/processTargets/targets/SubTokenWordTarget.ts index a606437f29..9fa37354b2 100644 --- a/src/processTargets/targets/SubTokenWordTarget.ts +++ b/src/processTargets/targets/SubTokenWordTarget.ts @@ -4,7 +4,7 @@ import { getDelimitedSequenceRemovalRange } from "../targetUtil/insertionRemoval import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; export interface SubTokenTargetParameters extends CommonTargetParameters { - readonly delimiterString: string; + readonly insertionDelimiter: string; readonly leadingDelimiterRange?: Range; readonly trailingDelimiterRange?: Range; } @@ -12,13 +12,13 @@ export interface SubTokenTargetParameters extends CommonTargetParameters { export default class SubTokenWordTarget extends BaseTarget { private leadingDelimiterRange_?: Range; private trailingDelimiterRange_?: Range; - delimiterString: string; + insertionDelimiter: string; constructor(parameters: SubTokenTargetParameters) { super(parameters); this.leadingDelimiterRange_ = parameters.leadingDelimiterRange; this.trailingDelimiterRange_ = parameters.trailingDelimiterRange; - this.delimiterString = parameters.delimiterString; + this.insertionDelimiter = parameters.insertionDelimiter; } getLeadingDelimiterTarget() { diff --git a/src/processTargets/targets/SurroundingPairTarget.ts b/src/processTargets/targets/SurroundingPairTarget.ts index 23db19b78a..c3bc151d74 100644 --- a/src/processTargets/targets/SurroundingPairTarget.ts +++ b/src/processTargets/targets/SurroundingPairTarget.ts @@ -26,7 +26,7 @@ interface SurroundingPairTargetParameters extends CommonTargetParameters { } export default class SurroundingPairTarget extends BaseTarget { - delimiterString = " "; + insertionDelimiter = " "; private interiorRange_: Range; private boundary_: [Range, Range]; diff --git a/src/processTargets/targets/TokenTarget.ts b/src/processTargets/targets/TokenTarget.ts index d66d5ddd5b..c19c77f175 100644 --- a/src/processTargets/targets/TokenTarget.ts +++ b/src/processTargets/targets/TokenTarget.ts @@ -8,7 +8,7 @@ import { import BaseTarget from "./BaseTarget"; export default class TokenTarget extends BaseTarget { - delimiterString = " "; + insertionDelimiter = " "; getLeadingDelimiterTarget(): Target | undefined { return getTokenLeadingDelimiterTarget(this); diff --git a/src/processTargets/targets/WeakTarget.ts b/src/processTargets/targets/WeakTarget.ts index b3bcbe1aba..4186756517 100644 --- a/src/processTargets/targets/WeakTarget.ts +++ b/src/processTargets/targets/WeakTarget.ts @@ -13,7 +13,7 @@ import BaseTarget from "./BaseTarget"; * - Expand to nearest containing pair when asked for boundary or interior */ export default class WeakTarget extends BaseTarget { - delimiterString = " "; + insertionDelimiter = " "; isWeak = true; getLeadingDelimiterTarget(): Target | undefined { diff --git a/src/test/suite/fixtures/recorded/positions/bringArgMadeAndGustToEndOfJustThis.yml b/src/test/suite/fixtures/recorded/positions/bringArgMadeAndGustToEndOfJustThis.yml new file mode 100644 index 0000000000..1dcffff209 --- /dev/null +++ b/src/test/suite/fixtures/recorded/positions/bringArgMadeAndGustToEndOfJustThis.yml @@ -0,0 +1,53 @@ +languageId: typescript +command: + spokenForm: bring arg made and gust to end of just this + version: 2 + targets: + - type: list + elements: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: m} + modifiers: + - type: containingScope + scopeType: {type: argumentOrParameter} + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: g} + - type: primitive + mark: {type: cursor} + modifiers: + - {type: position, position: end} + - {type: toRawSelection} + usePrePhraseSnapshot: true + action: {name: replaceWithTarget} +initialState: + documentContents: |- + function whatever(name: string, age: number, inclose: boolean) { + + } + selections: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} + marks: + default.m: + start: {line: 0, character: 18} + end: {line: 0, character: 22} + default.g: + start: {line: 0, character: 32} + end: {line: 0, character: 35} +finalState: + documentContents: |- + function whatever(name: string, age: number, inclose: boolean) { + name: string, age: number + } + selections: + - anchor: {line: 1, character: 29} + active: {line: 1, character: 29} + thatMark: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 29} + sourceMark: + - anchor: {line: 0, character: 18} + active: {line: 0, character: 30} + - anchor: {line: 0, character: 32} + active: {line: 0, character: 43} +fullTargets: [{type: list, elements: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: m}, modifiers: &ref_0 [{type: containingScope, scopeType: {type: argumentOrParameter}}]}, {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: g}, modifiers: *ref_0}]}, {type: primitive, mark: {type: cursor}, modifiers: [{type: position, position: end}, {type: toRawSelection}]}] diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 8e4374eb27..c788db2ec0 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -288,8 +288,8 @@ export interface Target { /** The range of the content */ readonly contentRange: Range; - /** If this selection has a delimiter. For example, new line for a line or paragraph and comma for a list or argument */ - readonly delimiterString?: string; + /** If this selection has a delimiter use it for inserting before or after the target. For example, new line for a line or paragraph and comma for a list or argument */ + readonly insertionDelimiter: string; /** If true this target should be treated as a line */ readonly isLine: boolean; @@ -297,6 +297,9 @@ export interface Target { /** If true this target is weak and can be transformed/upgraded */ readonly isWeak: boolean; + /** If true this target is a raw selection and its insertion delimiter should not be used on bring action */ + readonly isRaw: boolean; + /** The text contained in the content range */ readonly contentText: string; @@ -329,4 +332,5 @@ export interface Target { constructEmptyChangeEdit(): EditWithRangeUpdater; /** Constructs removal edit */ constructRemovalEdit(): EditWithRangeUpdater; + isEqual(target: Target): boolean; } From dbe081e3fc6e2a52dd3e6fb7c69d2a71f0e23f71 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 1 Jun 2022 23:10:04 +0200 Subject: [PATCH 268/314] Stuff --- src/test/suite/recorded.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/suite/recorded.test.ts b/src/test/suite/recorded.test.ts index c2580eeae5..b70fcb1599 100644 --- a/src/test/suite/recorded.test.ts +++ b/src/test/suite/recorded.test.ts @@ -66,7 +66,7 @@ async function runTest(file: string) { // TODO The snapshot gets messed up with timing issues when running the recorded tests // "Couldn't find token default.a" - fixture.command.usePrePhraseSnapshot = false; + const usePrePhraseSnapshot = false; const cursorlessApi = await getCursorlessApi(); const graph = cursorlessApi.graph!; @@ -119,7 +119,7 @@ async function runTest(file: string) { await graph.hatTokenMap.addDecorations(); const readableHatMap = await graph.hatTokenMap.getReadableMap( - fixture.command.usePrePhraseSnapshot + usePrePhraseSnapshot ); // Assert that recorded decorations are present @@ -127,7 +127,7 @@ async function runTest(file: string) { const returnValue = await vscode.commands.executeCommand( "cursorless.command", - fixture.command + { ...fixture.command, usePrePhraseSnapshot } ); const marks = From e9403a209b67ebbc2bcfa34a1caa77daea53e48d Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Wed, 1 Jun 2022 23:17:56 +0200 Subject: [PATCH 269/314] Updated tests --- .../actions/bringAirAndBatAndCapToAfterItemEach.yml | 2 +- .../recorded/actions/bringAirAndBatAndCapToBeforeDrum.yml | 2 +- .../actions/bringAirAndBatAndCapToBeforeItemEach.yml | 2 +- .../actions/bringLineAirAndBatAndCapToAfterDrum.yml | 2 +- .../actions/bringLineAirAndBatAndCapToBeforeDrum.yml | 2 +- .../suite/fixtures/recorded/actions/curlyRepackRound.yml | 4 ++-- src/test/suite/fixtures/recorded/actions/roundWrapThis.yml | 6 +++--- src/test/suite/fixtures/recorded/actions/roundWrapVest.yml | 6 +++--- src/test/suite/fixtures/recorded/actions/roundWrapVest2.yml | 6 +++--- .../suite/fixtures/recorded/actions/squareRepackHarp.yml | 6 +++--- .../suite/fixtures/recorded/actions/squareRepackLeper.yml | 6 +++--- .../suite/fixtures/recorded/actions/squareRepackPair.yml | 4 ++-- .../suite/fixtures/recorded/actions/squareRepackThis.yml | 6 +++--- .../compoundTargets/bringAirToAfterBatVerticalPastFine.yml | 6 +++--- .../compoundTargets/bringAirToBeforeBatVerticalPastFine.yml | 6 +++--- .../recorded/hatTokenMap/bringHarpAfterWhaleTakeWhale.yml | 2 +- .../bringHarpAndPointToEndOfThisAndEndOfWhaleTakeWhale.yml | 4 ++-- .../recorded/hatTokenMap/bringHarpBeforeWhaleTakeWhale.yml | 2 +- ...ntAndHarpToEndOfSecondCarWhaleAndEndOfWhaleTakeWhale.yml | 4 ++-- .../bringPointAndHarpToEndOfThisAndEndOfWhaleTakeWhale.yml | 4 ++-- ...tAndPointToEndOfSecondCarWhaleAndEndOfWhaleTakeWhale.yml | 4 ++-- .../fixtures/recorded/positions/bringHarpToAfterFile.yml | 2 +- .../recorded/positions/bringStateFineToAfterBatt.yml | 2 +- .../fixtures/recorded/positions/bringWhaleToBeforeFile.yml | 2 +- .../recorded/positions/replaceAfterVestWithHallo.yml | 4 ++-- .../recorded/selectionTypes/bringHarpToAfterFile.yml | 2 +- .../recorded/selectionTypes/bringWhaleToBeforeFile.yml | 2 +- .../fixtures/recorded/selectionTypes/chuckBlockAir.yml | 2 +- .../surroundingPair/parseTreeParity/clearBoundsDouble.yml | 2 -- .../surroundingPair/parseTreeParity/clearBoundsRound.yml | 2 -- .../recorded/surroundingPair/textual/clearBoundsDouble.yml | 2 -- .../recorded/surroundingPair/textual/clearBoundsRound.yml | 2 -- .../recorded/updateSelections/bringFineAfterThis.yml | 2 +- .../recorded/updateSelections/bringFineAfterThis2.yml | 2 +- .../recorded/updateSelections/bringFineBeforeThis.yml | 2 +- .../recorded/updateSelections/bringWhaleAfterFine.yml | 2 +- .../recorded/updateSelections/bringWhaleAfterThis.yml | 2 +- .../recorded/updateSelections/bringWhaleAfterThis2.yml | 2 +- .../recorded/updateSelections/bringWhaleBeforeThis.yml | 2 +- .../recorded/updateSelections/bringWhaleToEndOfFine.yml | 4 ++-- 40 files changed, 60 insertions(+), 68 deletions(-) diff --git a/src/test/suite/fixtures/recorded/actions/bringAirAndBatAndCapToAfterItemEach.yml b/src/test/suite/fixtures/recorded/actions/bringAirAndBatAndCapToAfterItemEach.yml index 5e350fe8ae..cc689a2093 100644 --- a/src/test/suite/fixtures/recorded/actions/bringAirAndBatAndCapToAfterItemEach.yml +++ b/src/test/suite/fixtures/recorded/actions/bringAirAndBatAndCapToAfterItemEach.yml @@ -50,7 +50,7 @@ finalState: - anchor: {line: 5, character: 0} active: {line: 5, character: 0} thatMark: - - anchor: {line: 4, character: 17} + - anchor: {line: 4, character: 19} active: {line: 4, character: 26} sourceMark: - anchor: {line: 0, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/bringAirAndBatAndCapToBeforeDrum.yml b/src/test/suite/fixtures/recorded/actions/bringAirAndBatAndCapToBeforeDrum.yml index ffaf9567ea..c34166fe21 100644 --- a/src/test/suite/fixtures/recorded/actions/bringAirAndBatAndCapToBeforeDrum.yml +++ b/src/test/suite/fixtures/recorded/actions/bringAirAndBatAndCapToBeforeDrum.yml @@ -50,7 +50,7 @@ finalState: active: {line: 5, character: 0} thatMark: - anchor: {line: 4, character: 0} - active: {line: 4, character: 6} + active: {line: 4, character: 5} sourceMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 1} diff --git a/src/test/suite/fixtures/recorded/actions/bringAirAndBatAndCapToBeforeItemEach.yml b/src/test/suite/fixtures/recorded/actions/bringAirAndBatAndCapToBeforeItemEach.yml index 59a4395e1b..f2d5fdc282 100644 --- a/src/test/suite/fixtures/recorded/actions/bringAirAndBatAndCapToBeforeItemEach.yml +++ b/src/test/suite/fixtures/recorded/actions/bringAirAndBatAndCapToBeforeItemEach.yml @@ -51,7 +51,7 @@ finalState: active: {line: 5, character: 0} thatMark: - anchor: {line: 4, character: 16} - active: {line: 4, character: 25} + active: {line: 4, character: 23} sourceMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 1} diff --git a/src/test/suite/fixtures/recorded/actions/bringLineAirAndBatAndCapToAfterDrum.yml b/src/test/suite/fixtures/recorded/actions/bringLineAirAndBatAndCapToAfterDrum.yml index 93166911b7..e01f78946a 100644 --- a/src/test/suite/fixtures/recorded/actions/bringLineAirAndBatAndCapToAfterDrum.yml +++ b/src/test/suite/fixtures/recorded/actions/bringLineAirAndBatAndCapToAfterDrum.yml @@ -53,7 +53,7 @@ finalState: - anchor: {line: 8, character: 0} active: {line: 8, character: 0} thatMark: - - anchor: {line: 4, character: 1} + - anchor: {line: 5, character: 0} active: {line: 7, character: 1} sourceMark: - anchor: {line: 0, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/bringLineAirAndBatAndCapToBeforeDrum.yml b/src/test/suite/fixtures/recorded/actions/bringLineAirAndBatAndCapToBeforeDrum.yml index 9811e5e7f0..2db341fbc0 100644 --- a/src/test/suite/fixtures/recorded/actions/bringLineAirAndBatAndCapToBeforeDrum.yml +++ b/src/test/suite/fixtures/recorded/actions/bringLineAirAndBatAndCapToBeforeDrum.yml @@ -54,7 +54,7 @@ finalState: active: {line: 8, character: 0} thatMark: - anchor: {line: 4, character: 0} - active: {line: 7, character: 0} + active: {line: 6, character: 1} sourceMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 1} diff --git a/src/test/suite/fixtures/recorded/actions/curlyRepackRound.yml b/src/test/suite/fixtures/recorded/actions/curlyRepackRound.yml index 53f7a16533..1ebafe1783 100644 --- a/src/test/suite/fixtures/recorded/actions/curlyRepackRound.yml +++ b/src/test/suite/fixtures/recorded/actions/curlyRepackRound.yml @@ -26,12 +26,12 @@ finalState: active: {line: 0, character: 5} - anchor: {line: 1, character: 5} active: {line: 1, character: 5} - sourceMark: + thatMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 9} - anchor: {line: 1, character: 0} active: {line: 1, character: 7} - thatMark: + sourceMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 9} - anchor: {line: 1, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/roundWrapThis.yml b/src/test/suite/fixtures/recorded/actions/roundWrapThis.yml index 6660d51b60..d5b5fc7dd1 100644 --- a/src/test/suite/fixtures/recorded/actions/roundWrapThis.yml +++ b/src/test/suite/fixtures/recorded/actions/roundWrapThis.yml @@ -22,10 +22,10 @@ finalState: selections: - anchor: {line: 0, character: 1} active: {line: 0, character: 1} - sourceMark: - - anchor: {line: 0, character: 1} - active: {line: 0, character: 1} thatMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 2} + sourceMark: + - anchor: {line: 0, character: 1} + active: {line: 0, character: 1} fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, modifier: {type: identity}, insideOutsideType: inside}] diff --git a/src/test/suite/fixtures/recorded/actions/roundWrapVest.yml b/src/test/suite/fixtures/recorded/actions/roundWrapVest.yml index 71f842c403..ce79366ac9 100644 --- a/src/test/suite/fixtures/recorded/actions/roundWrapVest.yml +++ b/src/test/suite/fixtures/recorded/actions/roundWrapVest.yml @@ -25,10 +25,10 @@ finalState: selections: - anchor: {line: 1, character: 12} active: {line: 1, character: 12} - sourceMark: - - anchor: {line: 1, character: 7} - active: {line: 1, character: 12} thatMark: - anchor: {line: 1, character: 6} active: {line: 1, character: 13} + sourceMark: + - anchor: {line: 1, character: 7} + active: {line: 1, character: 12} fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: v}, selectionType: token, position: contents, modifier: {type: identity}, insideOutsideType: inside}] diff --git a/src/test/suite/fixtures/recorded/actions/roundWrapVest2.yml b/src/test/suite/fixtures/recorded/actions/roundWrapVest2.yml index 51bae071e6..3e35851b63 100644 --- a/src/test/suite/fixtures/recorded/actions/roundWrapVest2.yml +++ b/src/test/suite/fixtures/recorded/actions/roundWrapVest2.yml @@ -25,10 +25,10 @@ finalState: selections: - anchor: {line: 1, character: 14} active: {line: 1, character: 14} - sourceMark: - - anchor: {line: 1, character: 7} - active: {line: 1, character: 12} thatMark: - anchor: {line: 1, character: 6} active: {line: 1, character: 13} + sourceMark: + - anchor: {line: 1, character: 7} + active: {line: 1, character: 12} fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: v}, selectionType: token, position: contents, modifier: {type: identity}, insideOutsideType: inside}] diff --git a/src/test/suite/fixtures/recorded/actions/squareRepackHarp.yml b/src/test/suite/fixtures/recorded/actions/squareRepackHarp.yml index d72406534f..63209009b0 100644 --- a/src/test/suite/fixtures/recorded/actions/squareRepackHarp.yml +++ b/src/test/suite/fixtures/recorded/actions/squareRepackHarp.yml @@ -23,10 +23,10 @@ finalState: selections: - anchor: {line: 1, character: 0} active: {line: 1, character: 0} - sourceMark: - - anchor: {line: 0, character: 1} - active: {line: 0, character: 6} thatMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 7} + sourceMark: + - anchor: {line: 0, character: 1} + active: {line: 0, character: 6} fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: h}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: surroundingPair, delimiter: any}}] diff --git a/src/test/suite/fixtures/recorded/actions/squareRepackLeper.yml b/src/test/suite/fixtures/recorded/actions/squareRepackLeper.yml index bd5846a0a8..9ca91f51ae 100644 --- a/src/test/suite/fixtures/recorded/actions/squareRepackLeper.yml +++ b/src/test/suite/fixtures/recorded/actions/squareRepackLeper.yml @@ -23,10 +23,10 @@ finalState: selections: - anchor: {line: 1, character: 0} active: {line: 1, character: 0} - sourceMark: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 1} thatMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 7} + sourceMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 1} fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: (}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: surroundingPair, delimiter: any}}] diff --git a/src/test/suite/fixtures/recorded/actions/squareRepackPair.yml b/src/test/suite/fixtures/recorded/actions/squareRepackPair.yml index 492adeed1f..a45641b3a3 100644 --- a/src/test/suite/fixtures/recorded/actions/squareRepackPair.yml +++ b/src/test/suite/fixtures/recorded/actions/squareRepackPair.yml @@ -20,10 +20,10 @@ finalState: selections: - anchor: {line: 0, character: 2} active: {line: 0, character: 2} - sourceMark: + thatMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 7} - thatMark: + sourceMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 7} fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: surroundingPair, delimiter: any}}] diff --git a/src/test/suite/fixtures/recorded/actions/squareRepackThis.yml b/src/test/suite/fixtures/recorded/actions/squareRepackThis.yml index 7a43a285e9..23666fd530 100644 --- a/src/test/suite/fixtures/recorded/actions/squareRepackThis.yml +++ b/src/test/suite/fixtures/recorded/actions/squareRepackThis.yml @@ -18,10 +18,10 @@ finalState: selections: - anchor: {line: 0, character: 4} active: {line: 0, character: 4} - sourceMark: - - anchor: {line: 0, character: 4} - active: {line: 0, character: 4} thatMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 7} + sourceMark: + - anchor: {line: 0, character: 4} + active: {line: 0, character: 4} fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: surroundingPair, delimiter: any}}] diff --git a/src/test/suite/fixtures/recorded/compoundTargets/bringAirToAfterBatVerticalPastFine.yml b/src/test/suite/fixtures/recorded/compoundTargets/bringAirToAfterBatVerticalPastFine.yml index 2a20533e7b..d58d27857c 100644 --- a/src/test/suite/fixtures/recorded/compoundTargets/bringAirToAfterBatVerticalPastFine.yml +++ b/src/test/suite/fixtures/recorded/compoundTargets/bringAirToAfterBatVerticalPastFine.yml @@ -48,11 +48,11 @@ finalState: - anchor: {line: 5, character: 0} active: {line: 5, character: 0} thatMark: - - anchor: {line: 2, character: 1} + - anchor: {line: 2, character: 2} active: {line: 2, character: 3} - - anchor: {line: 3, character: 1} + - anchor: {line: 3, character: 2} active: {line: 3, character: 3} - - anchor: {line: 4, character: 1} + - anchor: {line: 4, character: 2} active: {line: 4, character: 3} sourceMark: - anchor: {line: 0, character: 0} diff --git a/src/test/suite/fixtures/recorded/compoundTargets/bringAirToBeforeBatVerticalPastFine.yml b/src/test/suite/fixtures/recorded/compoundTargets/bringAirToBeforeBatVerticalPastFine.yml index 2a8b817e95..48e3d66a42 100644 --- a/src/test/suite/fixtures/recorded/compoundTargets/bringAirToBeforeBatVerticalPastFine.yml +++ b/src/test/suite/fixtures/recorded/compoundTargets/bringAirToBeforeBatVerticalPastFine.yml @@ -49,11 +49,11 @@ finalState: active: {line: 5, character: 0} thatMark: - anchor: {line: 2, character: 0} - active: {line: 2, character: 2} + active: {line: 2, character: 1} - anchor: {line: 3, character: 0} - active: {line: 3, character: 2} + active: {line: 3, character: 1} - anchor: {line: 4, character: 0} - active: {line: 4, character: 2} + active: {line: 4, character: 1} sourceMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 1} diff --git a/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAfterWhaleTakeWhale.yml b/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAfterWhaleTakeWhale.yml index 30dc8f8444..7a66d00b90 100644 --- a/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAfterWhaleTakeWhale.yml +++ b/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAfterWhaleTakeWhale.yml @@ -35,7 +35,7 @@ finalState: start: {line: 0, character: 6} end: {line: 0, character: 11} thatMark: - - anchor: {line: 0, character: 11} + - anchor: {line: 0, character: 12} active: {line: 0, character: 17} sourceMark: - anchor: {line: 0, character: 0} diff --git a/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToEndOfThisAndEndOfWhaleTakeWhale.yml b/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToEndOfThisAndEndOfWhaleTakeWhale.yml index ba8dfd6fb6..27113b5834 100644 --- a/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToEndOfThisAndEndOfWhaleTakeWhale.yml +++ b/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpAndPointToEndOfThisAndEndOfWhaleTakeWhale.yml @@ -39,8 +39,8 @@ initialState: finalState: documentContents: hello. worldhello. selections: - - anchor: {line: 0, character: 12} - active: {line: 0, character: 12} + - anchor: {line: 0, character: 18} + active: {line: 0, character: 18} marks: default.h: start: {line: 0, character: 0} diff --git a/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpBeforeWhaleTakeWhale.yml b/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpBeforeWhaleTakeWhale.yml index 455efe3062..a12af1bd2e 100644 --- a/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpBeforeWhaleTakeWhale.yml +++ b/src/test/suite/fixtures/recorded/hatTokenMap/bringHarpBeforeWhaleTakeWhale.yml @@ -36,7 +36,7 @@ finalState: end: {line: 0, character: 18} thatMark: - anchor: {line: 0, character: 7} - active: {line: 0, character: 13} + active: {line: 0, character: 12} sourceMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 5} diff --git a/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfSecondCarWhaleAndEndOfWhaleTakeWhale.yml b/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfSecondCarWhaleAndEndOfWhaleTakeWhale.yml index f31659fb46..2f1eb9460b 100644 --- a/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfSecondCarWhaleAndEndOfWhaleTakeWhale.yml +++ b/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfSecondCarWhaleAndEndOfWhaleTakeWhale.yml @@ -41,8 +41,8 @@ initialState: finalState: documentContents: hello. wo.rldhello selections: - - anchor: {line: 0, character: 13} - active: {line: 0, character: 13} + - anchor: {line: 0, character: 18} + active: {line: 0, character: 18} marks: default..: start: {line: 0, character: 5} diff --git a/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhaleTakeWhale.yml b/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhaleTakeWhale.yml index 3d50804e9d..f6ec4c6345 100644 --- a/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhaleTakeWhale.yml +++ b/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndHarpToEndOfThisAndEndOfWhaleTakeWhale.yml @@ -39,8 +39,8 @@ initialState: finalState: documentContents: hello. world.hello selections: - - anchor: {line: 0, character: 12} - active: {line: 0, character: 12} + - anchor: {line: 0, character: 18} + active: {line: 0, character: 18} marks: default..: start: {line: 0, character: 5} diff --git a/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndPointToEndOfSecondCarWhaleAndEndOfWhaleTakeWhale.yml b/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndPointToEndOfSecondCarWhaleAndEndOfWhaleTakeWhale.yml index ab7bc37076..6202f6bb19 100644 --- a/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndPointToEndOfSecondCarWhaleAndEndOfWhaleTakeWhale.yml +++ b/src/test/suite/fixtures/recorded/hatTokenMap/bringPointAndPointToEndOfSecondCarWhaleAndEndOfWhaleTakeWhale.yml @@ -38,8 +38,8 @@ initialState: finalState: documentContents: hello. wo.rld. selections: - - anchor: {line: 0, character: 13} - active: {line: 0, character: 13} + - anchor: {line: 0, character: 14} + active: {line: 0, character: 14} marks: default..: start: {line: 0, character: 5} diff --git a/src/test/suite/fixtures/recorded/positions/bringHarpToAfterFile.yml b/src/test/suite/fixtures/recorded/positions/bringHarpToAfterFile.yml index 71d9781961..7475840bb4 100644 --- a/src/test/suite/fixtures/recorded/positions/bringHarpToAfterFile.yml +++ b/src/test/suite/fixtures/recorded/positions/bringHarpToAfterFile.yml @@ -29,7 +29,7 @@ finalState: - anchor: {line: 0, character: 0} active: {line: 0, character: 0} thatMark: - - anchor: {line: 0, character: 11} + - anchor: {line: 1, character: 0} active: {line: 1, character: 5} sourceMark: - anchor: {line: 0, character: 0} diff --git a/src/test/suite/fixtures/recorded/positions/bringStateFineToAfterBatt.yml b/src/test/suite/fixtures/recorded/positions/bringStateFineToAfterBatt.yml index 3f0fc86688..a7a3313118 100644 --- a/src/test/suite/fixtures/recorded/positions/bringStateFineToAfterBatt.yml +++ b/src/test/suite/fixtures/recorded/positions/bringStateFineToAfterBatt.yml @@ -39,7 +39,7 @@ finalState: - anchor: {line: 0, character: 0} active: {line: 0, character: 0} thatMark: - - anchor: {line: 1, character: 8} + - anchor: {line: 2, character: 0} active: {line: 2, character: 8} sourceMark: - anchor: {line: 0, character: 0} diff --git a/src/test/suite/fixtures/recorded/positions/bringWhaleToBeforeFile.yml b/src/test/suite/fixtures/recorded/positions/bringWhaleToBeforeFile.yml index 0ffcbf02cf..7fa7920693 100644 --- a/src/test/suite/fixtures/recorded/positions/bringWhaleToBeforeFile.yml +++ b/src/test/suite/fixtures/recorded/positions/bringWhaleToBeforeFile.yml @@ -30,7 +30,7 @@ finalState: active: {line: 1, character: 0} thatMark: - anchor: {line: 0, character: 0} - active: {line: 1, character: 0} + active: {line: 0, character: 5} sourceMark: - anchor: {line: 1, character: 6} active: {line: 1, character: 11} diff --git a/src/test/suite/fixtures/recorded/positions/replaceAfterVestWithHallo.yml b/src/test/suite/fixtures/recorded/positions/replaceAfterVestWithHallo.yml index e88678cefe..e1b1396232 100644 --- a/src/test/suite/fixtures/recorded/positions/replaceAfterVestWithHallo.yml +++ b/src/test/suite/fixtures/recorded/positions/replaceAfterVestWithHallo.yml @@ -28,6 +28,6 @@ finalState: - anchor: {line: 0, character: 0} active: {line: 0, character: 0} thatMark: - - anchor: {line: 1, character: 17} - active: {line: 1, character: 17} + - anchor: {line: 1, character: 11} + active: {line: 1, character: 11} fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: v}, selectionType: token, position: after, modifier: {type: identity}, insideOutsideType: null}] diff --git a/src/test/suite/fixtures/recorded/selectionTypes/bringHarpToAfterFile.yml b/src/test/suite/fixtures/recorded/selectionTypes/bringHarpToAfterFile.yml index 9f63ae9bfa..a5640e4535 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/bringHarpToAfterFile.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/bringHarpToAfterFile.yml @@ -30,7 +30,7 @@ finalState: - anchor: {line: 0, character: 11} active: {line: 0, character: 11} thatMark: - - anchor: {line: 0, character: 11} + - anchor: {line: 1, character: 0} active: {line: 1, character: 5} sourceMark: - anchor: {line: 0, character: 0} diff --git a/src/test/suite/fixtures/recorded/selectionTypes/bringWhaleToBeforeFile.yml b/src/test/suite/fixtures/recorded/selectionTypes/bringWhaleToBeforeFile.yml index 2ac23a4d52..e2ee67f1e6 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/bringWhaleToBeforeFile.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/bringWhaleToBeforeFile.yml @@ -31,7 +31,7 @@ finalState: active: {line: 1, character: 11} thatMark: - anchor: {line: 0, character: 0} - active: {line: 1, character: 0} + active: {line: 0, character: 5} sourceMark: - anchor: {line: 1, character: 6} active: {line: 1, character: 11} diff --git a/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockAir.yml b/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockAir.yml index 4a85bceb85..27f2d0c7c2 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockAir.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/chuckBlockAir.yml @@ -22,7 +22,7 @@ initialState: start: {line: 3, character: 6} end: {line: 3, character: 11} finalState: - documentContents: |+ + documentContents: | const value = "Hello world"; selections: diff --git a/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/clearBoundsDouble.yml b/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/clearBoundsDouble.yml index 8c0835de11..4f1f3520bc 100644 --- a/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/clearBoundsDouble.yml +++ b/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/clearBoundsDouble.yml @@ -20,6 +20,4 @@ finalState: thatMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 0} - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: '"'}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: surroundingPair, delimiter: null, delimiterInclusion: delimitersOnly}}] diff --git a/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/clearBoundsRound.yml b/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/clearBoundsRound.yml index c9e4396ed4..384343be9d 100644 --- a/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/clearBoundsRound.yml +++ b/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/clearBoundsRound.yml @@ -19,6 +19,4 @@ finalState: thatMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 0} - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: surroundingPair, delimiter: parentheses, delimiterInclusion: delimitersOnly}}] diff --git a/src/test/suite/fixtures/recorded/surroundingPair/textual/clearBoundsDouble.yml b/src/test/suite/fixtures/recorded/surroundingPair/textual/clearBoundsDouble.yml index 88702f4831..d58ca06205 100644 --- a/src/test/suite/fixtures/recorded/surroundingPair/textual/clearBoundsDouble.yml +++ b/src/test/suite/fixtures/recorded/surroundingPair/textual/clearBoundsDouble.yml @@ -20,6 +20,4 @@ finalState: thatMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 0} - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: '"'}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: surroundingPair, delimiter: null, delimiterInclusion: delimitersOnly}}] diff --git a/src/test/suite/fixtures/recorded/surroundingPair/textual/clearBoundsRound.yml b/src/test/suite/fixtures/recorded/surroundingPair/textual/clearBoundsRound.yml index 4c53f678c0..1226f21476 100644 --- a/src/test/suite/fixtures/recorded/surroundingPair/textual/clearBoundsRound.yml +++ b/src/test/suite/fixtures/recorded/surroundingPair/textual/clearBoundsRound.yml @@ -19,6 +19,4 @@ finalState: thatMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 0} - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: surroundingPair, delimiter: parentheses, delimiterInclusion: delimitersOnly}}] diff --git a/src/test/suite/fixtures/recorded/updateSelections/bringFineAfterThis.yml b/src/test/suite/fixtures/recorded/updateSelections/bringFineAfterThis.yml index 10f6234510..1263de63de 100644 --- a/src/test/suite/fixtures/recorded/updateSelections/bringFineAfterThis.yml +++ b/src/test/suite/fixtures/recorded/updateSelections/bringFineAfterThis.yml @@ -24,7 +24,7 @@ finalState: - anchor: {line: 0, character: 4} active: {line: 0, character: 4} thatMark: - - anchor: {line: 0, character: 4} + - anchor: {line: 0, character: 5} active: {line: 0, character: 8} sourceMark: - anchor: {line: 0, character: 0} diff --git a/src/test/suite/fixtures/recorded/updateSelections/bringFineAfterThis2.yml b/src/test/suite/fixtures/recorded/updateSelections/bringFineAfterThis2.yml index 1267f27294..0a8ea09faf 100644 --- a/src/test/suite/fixtures/recorded/updateSelections/bringFineAfterThis2.yml +++ b/src/test/suite/fixtures/recorded/updateSelections/bringFineAfterThis2.yml @@ -24,7 +24,7 @@ finalState: - anchor: {line: 0, character: 9} active: {line: 0, character: 9} thatMark: - - anchor: {line: 0, character: 9} + - anchor: {line: 0, character: 10} active: {line: 0, character: 13} sourceMark: - anchor: {line: 0, character: 0} diff --git a/src/test/suite/fixtures/recorded/updateSelections/bringFineBeforeThis.yml b/src/test/suite/fixtures/recorded/updateSelections/bringFineBeforeThis.yml index bce7f981d2..c8e880d6fd 100644 --- a/src/test/suite/fixtures/recorded/updateSelections/bringFineBeforeThis.yml +++ b/src/test/suite/fixtures/recorded/updateSelections/bringFineBeforeThis.yml @@ -25,7 +25,7 @@ finalState: active: {line: 0, character: 8} thatMark: - anchor: {line: 0, character: 4} - active: {line: 0, character: 8} + active: {line: 0, character: 7} sourceMark: - anchor: {line: 0, character: 0} active: {line: 0, character: 3} diff --git a/src/test/suite/fixtures/recorded/updateSelections/bringWhaleAfterFine.yml b/src/test/suite/fixtures/recorded/updateSelections/bringWhaleAfterFine.yml index 94b44d205b..12a3be2b2b 100644 --- a/src/test/suite/fixtures/recorded/updateSelections/bringWhaleAfterFine.yml +++ b/src/test/suite/fixtures/recorded/updateSelections/bringWhaleAfterFine.yml @@ -27,7 +27,7 @@ finalState: - anchor: {line: 0, character: 3} active: {line: 0, character: 3} thatMark: - - anchor: {line: 0, character: 3} + - anchor: {line: 0, character: 4} active: {line: 0, character: 9} sourceMark: - anchor: {line: 0, character: 10} diff --git a/src/test/suite/fixtures/recorded/updateSelections/bringWhaleAfterThis.yml b/src/test/suite/fixtures/recorded/updateSelections/bringWhaleAfterThis.yml index e96ae1b561..381bbd053f 100644 --- a/src/test/suite/fixtures/recorded/updateSelections/bringWhaleAfterThis.yml +++ b/src/test/suite/fixtures/recorded/updateSelections/bringWhaleAfterThis.yml @@ -24,7 +24,7 @@ finalState: - anchor: {line: 0, character: 3} active: {line: 0, character: 3} thatMark: - - anchor: {line: 0, character: 3} + - anchor: {line: 0, character: 4} active: {line: 0, character: 9} sourceMark: - anchor: {line: 0, character: 10} diff --git a/src/test/suite/fixtures/recorded/updateSelections/bringWhaleAfterThis2.yml b/src/test/suite/fixtures/recorded/updateSelections/bringWhaleAfterThis2.yml index e96ae1b561..381bbd053f 100644 --- a/src/test/suite/fixtures/recorded/updateSelections/bringWhaleAfterThis2.yml +++ b/src/test/suite/fixtures/recorded/updateSelections/bringWhaleAfterThis2.yml @@ -24,7 +24,7 @@ finalState: - anchor: {line: 0, character: 3} active: {line: 0, character: 3} thatMark: - - anchor: {line: 0, character: 3} + - anchor: {line: 0, character: 4} active: {line: 0, character: 9} sourceMark: - anchor: {line: 0, character: 10} diff --git a/src/test/suite/fixtures/recorded/updateSelections/bringWhaleBeforeThis.yml b/src/test/suite/fixtures/recorded/updateSelections/bringWhaleBeforeThis.yml index dbd2c11525..3170e30f05 100644 --- a/src/test/suite/fixtures/recorded/updateSelections/bringWhaleBeforeThis.yml +++ b/src/test/suite/fixtures/recorded/updateSelections/bringWhaleBeforeThis.yml @@ -25,7 +25,7 @@ finalState: active: {line: 0, character: 9} thatMark: - anchor: {line: 0, character: 3} - active: {line: 0, character: 9} + active: {line: 0, character: 8} sourceMark: - anchor: {line: 0, character: 10} active: {line: 0, character: 15} diff --git a/src/test/suite/fixtures/recorded/updateSelections/bringWhaleToEndOfFine.yml b/src/test/suite/fixtures/recorded/updateSelections/bringWhaleToEndOfFine.yml index 6447d9784f..df49740867 100644 --- a/src/test/suite/fixtures/recorded/updateSelections/bringWhaleToEndOfFine.yml +++ b/src/test/suite/fixtures/recorded/updateSelections/bringWhaleToEndOfFine.yml @@ -25,8 +25,8 @@ initialState: finalState: documentContents: fooworld world selections: - - anchor: {line: 0, character: 3} - active: {line: 0, character: 3} + - anchor: {line: 0, character: 8} + active: {line: 0, character: 8} thatMark: - anchor: {line: 0, character: 3} active: {line: 0, character: 8} From fa613736b2c09ec515c072733c76618461e112b0 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Wed, 1 Jun 2022 23:36:07 +0100 Subject: [PATCH 270/314] Support chuck after and chuck before --- src/processTargets/modifiers/PositionStage.ts | 12 ++++++++ src/processTargets/targets/PositionTarget.ts | 9 ++++-- .../recorded/positions/chuckAfterWhale.yml | 29 +++++++++++++++++++ .../recorded/positions/chuckBeforeWhale.yml | 29 +++++++++++++++++++ .../recorded/positions/chuckEndOfWhale.yml | 29 +++++++++++++++++++ .../recorded/positions/chuckStartOfWhale.yml | 29 +++++++++++++++++++ .../recorded/positions/takeAfterWhale.yml | 29 +++++++++++++++++++ .../recorded/positions/takeBeforeWhale.yml | 29 +++++++++++++++++++ .../recorded/positions/takeEndOfWhale.yml | 29 +++++++++++++++++++ .../recorded/positions/takeStartOfWhale.yml | 29 +++++++++++++++++++ 10 files changed, 251 insertions(+), 2 deletions(-) create mode 100644 src/test/suite/fixtures/recorded/positions/chuckAfterWhale.yml create mode 100644 src/test/suite/fixtures/recorded/positions/chuckBeforeWhale.yml create mode 100644 src/test/suite/fixtures/recorded/positions/chuckEndOfWhale.yml create mode 100644 src/test/suite/fixtures/recorded/positions/chuckStartOfWhale.yml create mode 100644 src/test/suite/fixtures/recorded/positions/takeAfterWhale.yml create mode 100644 src/test/suite/fixtures/recorded/positions/takeBeforeWhale.yml create mode 100644 src/test/suite/fixtures/recorded/positions/takeEndOfWhale.yml create mode 100644 src/test/suite/fixtures/recorded/positions/takeStartOfWhale.yml diff --git a/src/processTargets/modifiers/PositionStage.ts b/src/processTargets/modifiers/PositionStage.ts index 5527b74589..6019163869 100644 --- a/src/processTargets/modifiers/PositionStage.ts +++ b/src/processTargets/modifiers/PositionStage.ts @@ -17,15 +17,26 @@ export function toPositionTarget(target: Target, position: Position): Target { let contentRange: Range; let insertionDelimiter: string; + /** + * We give "after" and "before" targets a removal range for backwards + * compatibility. This allows user to continue saying "chuck before" and + * "chuck after" to remove leading or trailing delimiter. We prefer that users + * use leading and trailing instead, but "before" and "after" are sometimes + * easier to think of, so we're keeping them for now + */ + let removalTarget: Target | undefined = undefined; + switch (position) { case "before": contentRange = new Range(start, start); insertionDelimiter = target.insertionDelimiter; + removalTarget = target.getLeadingDelimiterTarget(); break; case "after": contentRange = new Range(end, end); insertionDelimiter = target.insertionDelimiter; + removalTarget = target.getTrailingDelimiterTarget(); break; case "start": @@ -47,5 +58,6 @@ export function toPositionTarget(target: Target, position: Position): Target { position, insertionDelimiter, isRaw: target.isRaw, + removalTarget, }); } diff --git a/src/processTargets/targets/PositionTarget.ts b/src/processTargets/targets/PositionTarget.ts index 755fb84f9a..996305ad8c 100644 --- a/src/processTargets/targets/PositionTarget.ts +++ b/src/processTargets/targets/PositionTarget.ts @@ -1,6 +1,6 @@ import * as vscode from "vscode"; import { Range, TextEditor } from "vscode"; -import { Position } from "../../typings/target.types"; +import { Position, Target } from "../../typings/target.types"; import { EditWithRangeUpdater } from "../../typings/Types"; import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; @@ -8,23 +8,27 @@ interface PositionTargetParameters extends CommonTargetParameters { readonly position: Position; readonly insertionDelimiter: string; readonly isRaw: boolean; + readonly removalTarget: Target | undefined; } export default class PositionTarget extends BaseTarget { insertionDelimiter: string; isRaw: boolean; private position: Position; + private removalTarget: Target | undefined; constructor(parameters: PositionTargetParameters) { super(parameters); this.position = parameters.position; this.insertionDelimiter = parameters.insertionDelimiter; this.isRaw = parameters.isRaw; + this.removalTarget = parameters.removalTarget; } getLeadingDelimiterTarget = () => undefined; getTrailingDelimiterTarget = () => undefined; - getRemovalRange = () => this.contentRange; + getRemovalRange = () => + this.removalTarget?.getRemovalRange() ?? this.contentRange; constructChangeEdit(text: string): EditWithRangeUpdater { if (this.isInsertion()) { @@ -46,6 +50,7 @@ export default class PositionTarget extends BaseTarget { position: this.position, insertionDelimiter: this.insertionDelimiter, isRaw: this.isRaw, + removalTarget: this.removalTarget, }; } diff --git a/src/test/suite/fixtures/recorded/positions/chuckAfterWhale.yml b/src/test/suite/fixtures/recorded/positions/chuckAfterWhale.yml new file mode 100644 index 0000000000..77a770fd0f --- /dev/null +++ b/src/test/suite/fixtures/recorded/positions/chuckAfterWhale.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: chuck after whale + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: w} + modifiers: + - {type: position, position: after} + usePrePhraseSnapshot: true + action: {name: remove} +initialState: + documentContents: hello world whatever + selections: + - anchor: {line: 0, character: 20} + active: {line: 0, character: 20} + marks: + default.w: + start: {line: 0, character: 6} + end: {line: 0, character: 11} +finalState: + documentContents: hello worldwhatever + selections: + - anchor: {line: 0, character: 19} + active: {line: 0, character: 19} + thatMark: + - anchor: {line: 0, character: 11} + active: {line: 0, character: 11} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: w}, modifiers: [{type: position, position: after}]}] diff --git a/src/test/suite/fixtures/recorded/positions/chuckBeforeWhale.yml b/src/test/suite/fixtures/recorded/positions/chuckBeforeWhale.yml new file mode 100644 index 0000000000..9e41c231ec --- /dev/null +++ b/src/test/suite/fixtures/recorded/positions/chuckBeforeWhale.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: chuck before whale + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: w} + modifiers: + - {type: position, position: before} + usePrePhraseSnapshot: true + action: {name: remove} +initialState: + documentContents: hello world whatever + selections: + - anchor: {line: 0, character: 20} + active: {line: 0, character: 20} + marks: + default.w: + start: {line: 0, character: 6} + end: {line: 0, character: 11} +finalState: + documentContents: helloworld whatever + selections: + - anchor: {line: 0, character: 19} + active: {line: 0, character: 19} + thatMark: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: w}, modifiers: [{type: position, position: before}]}] diff --git a/src/test/suite/fixtures/recorded/positions/chuckEndOfWhale.yml b/src/test/suite/fixtures/recorded/positions/chuckEndOfWhale.yml new file mode 100644 index 0000000000..9dbf8f8257 --- /dev/null +++ b/src/test/suite/fixtures/recorded/positions/chuckEndOfWhale.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: chuck end of whale + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: w} + modifiers: + - {type: position, position: end} + usePrePhraseSnapshot: true + action: {name: remove} +initialState: + documentContents: hello world whatever + selections: + - anchor: {line: 0, character: 20} + active: {line: 0, character: 20} + marks: + default.w: + start: {line: 0, character: 6} + end: {line: 0, character: 11} +finalState: + documentContents: hello world whatever + selections: + - anchor: {line: 0, character: 20} + active: {line: 0, character: 20} + thatMark: + - anchor: {line: 0, character: 11} + active: {line: 0, character: 11} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: w}, modifiers: [{type: position, position: end}]}] diff --git a/src/test/suite/fixtures/recorded/positions/chuckStartOfWhale.yml b/src/test/suite/fixtures/recorded/positions/chuckStartOfWhale.yml new file mode 100644 index 0000000000..36908ff70d --- /dev/null +++ b/src/test/suite/fixtures/recorded/positions/chuckStartOfWhale.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: chuck start of whale + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: w} + modifiers: + - {type: position, position: start} + usePrePhraseSnapshot: true + action: {name: remove} +initialState: + documentContents: hello world whatever + selections: + - anchor: {line: 0, character: 20} + active: {line: 0, character: 20} + marks: + default.w: + start: {line: 0, character: 6} + end: {line: 0, character: 11} +finalState: + documentContents: hello world whatever + selections: + - anchor: {line: 0, character: 20} + active: {line: 0, character: 20} + thatMark: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 6} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: w}, modifiers: [{type: position, position: start}]}] diff --git a/src/test/suite/fixtures/recorded/positions/takeAfterWhale.yml b/src/test/suite/fixtures/recorded/positions/takeAfterWhale.yml new file mode 100644 index 0000000000..8f88fdc1d6 --- /dev/null +++ b/src/test/suite/fixtures/recorded/positions/takeAfterWhale.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: take after whale + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: w} + modifiers: + - {type: position, position: after} + usePrePhraseSnapshot: true + action: {name: setSelection} +initialState: + documentContents: hello world whatever + selections: + - anchor: {line: 0, character: 20} + active: {line: 0, character: 20} + marks: + default.w: + start: {line: 0, character: 6} + end: {line: 0, character: 11} +finalState: + documentContents: hello world whatever + selections: + - anchor: {line: 0, character: 11} + active: {line: 0, character: 11} + thatMark: + - anchor: {line: 0, character: 11} + active: {line: 0, character: 11} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: w}, modifiers: [{type: position, position: after}]}] diff --git a/src/test/suite/fixtures/recorded/positions/takeBeforeWhale.yml b/src/test/suite/fixtures/recorded/positions/takeBeforeWhale.yml new file mode 100644 index 0000000000..5c80bf5464 --- /dev/null +++ b/src/test/suite/fixtures/recorded/positions/takeBeforeWhale.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: take before whale + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: w} + modifiers: + - {type: position, position: before} + usePrePhraseSnapshot: true + action: {name: setSelection} +initialState: + documentContents: hello world whatever + selections: + - anchor: {line: 0, character: 20} + active: {line: 0, character: 20} + marks: + default.w: + start: {line: 0, character: 6} + end: {line: 0, character: 11} +finalState: + documentContents: hello world whatever + selections: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 6} + thatMark: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 6} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: w}, modifiers: [{type: position, position: before}]}] diff --git a/src/test/suite/fixtures/recorded/positions/takeEndOfWhale.yml b/src/test/suite/fixtures/recorded/positions/takeEndOfWhale.yml new file mode 100644 index 0000000000..96f457a00f --- /dev/null +++ b/src/test/suite/fixtures/recorded/positions/takeEndOfWhale.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: take end of whale + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: w} + modifiers: + - {type: position, position: end} + usePrePhraseSnapshot: true + action: {name: setSelection} +initialState: + documentContents: hello world whatever + selections: + - anchor: {line: 0, character: 20} + active: {line: 0, character: 20} + marks: + default.w: + start: {line: 0, character: 6} + end: {line: 0, character: 11} +finalState: + documentContents: hello world whatever + selections: + - anchor: {line: 0, character: 11} + active: {line: 0, character: 11} + thatMark: + - anchor: {line: 0, character: 11} + active: {line: 0, character: 11} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: w}, modifiers: [{type: position, position: end}]}] diff --git a/src/test/suite/fixtures/recorded/positions/takeStartOfWhale.yml b/src/test/suite/fixtures/recorded/positions/takeStartOfWhale.yml new file mode 100644 index 0000000000..32898faeb2 --- /dev/null +++ b/src/test/suite/fixtures/recorded/positions/takeStartOfWhale.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: take start of whale + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: w} + modifiers: + - {type: position, position: start} + usePrePhraseSnapshot: true + action: {name: setSelection} +initialState: + documentContents: hello world whatever + selections: + - anchor: {line: 0, character: 20} + active: {line: 0, character: 20} + marks: + default.w: + start: {line: 0, character: 6} + end: {line: 0, character: 11} +finalState: + documentContents: hello world whatever + selections: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 6} + thatMark: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 6} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: w}, modifiers: [{type: position, position: start}]}] From 67bf607ef43268c66f8e939564c4870e9166796d Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Wed, 1 Jun 2022 23:51:16 +0100 Subject: [PATCH 271/314] Add hack for "paste to to" --- cursorless-talon/src/csv_overrides.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cursorless-talon/src/csv_overrides.py b/cursorless-talon/src/csv_overrides.py index baf1f7880a..5e25bbeee9 100644 --- a/cursorless-talon/src/csv_overrides.py +++ b/cursorless-talon/src/csv_overrides.py @@ -159,6 +159,14 @@ def update_dicts( key = obj["key"] if not is_removed(key): for k in key.split("|"): + if value == "pasteFromClipboard" and k.endswith(" to"): + # FIXME: This is a hack to work around the fact that the + # spoken form of the `pasteFromClipboard` action used to be + # "paste to", but now the spoken form is just "paste" and + # the two is part of the positional target. Users who had + # cursorless before this change would have "paste to" as + # their spoken form and so would need to say "paste to to". + k = k[:-3] results[obj["list"]][k.strip()] = value # Assign result to talon context list From 51abd442842e230390f194b6c832c3d7fd1b8178 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Thu, 2 Jun 2022 00:10:06 +0100 Subject: [PATCH 272/314] Add run single test launch config --- .vscode/launch.json | 21 +++++++++++++++++++++ src/test/suite/runSingleRecordedTest.ts | 8 +++----- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 7bfd69da44..04bd3976c7 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -41,6 +41,27 @@ "!**/node_modules/**" ] }, + { + "name": "Run Single Extension Test", + "type": "extensionHost", + "request": "launch", + "env": { + "CURSORLESS_TEST": "true", + "CURSORLESS_RUN_SINGLE_TEST": "true" + }, + "args": [ + "--extensions-dir=${workspaceFolder}/.vscode-sandbox/extensions", + "--extensionDevelopmentPath=${workspaceFolder}", + "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" + ], + "outFiles": ["${workspaceFolder}/out/test/**/*.js"], + "preLaunchTask": "${defaultBuildTask}", + "resolveSourceMapLocations": [ + "${workspaceFolder}/**", + "!${workspaceFolder}/.vscode-sandbox/**", + "!**/node_modules/**" + ] + }, { "name": "Update fixtures", "type": "extensionHost", diff --git a/src/test/suite/runSingleRecordedTest.ts b/src/test/suite/runSingleRecordedTest.ts index f9ea62d9df..37d0671679 100644 --- a/src/test/suite/runSingleRecordedTest.ts +++ b/src/test/suite/runSingleRecordedTest.ts @@ -1,14 +1,12 @@ /** * Add the file path ending of a recorded test and ONLY that one will run + * when using the "Run Single Extension Test" launch configuration. */ -// example: -// const filenameEnd = "textual/takePairRound.yml"; - -const filenameEnd = ""; +const filenameEnd = "actions/postVest.yml"; export function runSingleTest() { - return !!filenameEnd; + return process.env.CURSORLESS_RUN_SINGLE_TEST === "true"; } export function getSingleTestFilename(): string { From e6a1f5f6e41fc46ccaadb2be90b9310d6ba9eadc Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Thu, 2 Jun 2022 00:16:48 +0100 Subject: [PATCH 273/314] Add comment about running a single test to contributing docs --- docs/contributing/CONTRIBUTING.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/contributing/CONTRIBUTING.md b/docs/contributing/CONTRIBUTING.md index 57be15a15c..2c64700f13 100644 --- a/docs/contributing/CONTRIBUTING.md +++ b/docs/contributing/CONTRIBUTING.md @@ -34,6 +34,10 @@ locally, you need to run the extension in debug mode. To do so you need to run the `workbench.action.debug.selectandstart` command in VSCode and then select either "Run Extension" or "Extension Tests". +### Running a single test + +The entire test suite takes a little while to run (1-2 mins), so if you'd like to repeat a single test, you can edit [`runSingleRecordedTest`](../../src/test/suite/runSingleRecordedTest.ts) to refer to the desired test and use the "Run Single Extension Test" launch config instead of the usual "Extension Tests". + ## Code formatting We use [`pre-commit`](https://pre-commit.com/) to automate autoformatting. From 9f86eabd5fe260d4885306ad6d2ef0b9786265c6 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Thu, 2 Jun 2022 08:44:15 +0100 Subject: [PATCH 274/314] Update cursorless-talon/src/csv_overrides.py --- cursorless-talon/src/csv_overrides.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cursorless-talon/src/csv_overrides.py b/cursorless-talon/src/csv_overrides.py index 5e25bbeee9..ed06601aec 100644 --- a/cursorless-talon/src/csv_overrides.py +++ b/cursorless-talon/src/csv_overrides.py @@ -163,7 +163,7 @@ def update_dicts( # FIXME: This is a hack to work around the fact that the # spoken form of the `pasteFromClipboard` action used to be # "paste to", but now the spoken form is just "paste" and - # the two is part of the positional target. Users who had + # the "to" is part of the positional target. Users who had # cursorless before this change would have "paste to" as # their spoken form and so would need to say "paste to to". k = k[:-3] From 4568442d523987ebca9cc6a2a195e29486de6a98 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 2 Jun 2022 10:06:14 +0200 Subject: [PATCH 275/314] Update cursorless-talon/src/positional_target.py Co-authored-by: Pokey Rule <755842+pokey@users.noreply.github.com> --- cursorless-talon/src/positional_target.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cursorless-talon/src/positional_target.py b/cursorless-talon/src/positional_target.py index 3681b1309a..ce1396dd66 100644 --- a/cursorless-talon/src/positional_target.py +++ b/cursorless-talon/src/positional_target.py @@ -15,7 +15,6 @@ **POSITION_AFTER, } -print(positional_connectives) ctx.lists["self.cursorless_positional_connective"] = positional_connectives.keys() From eba5a1c5549adddf17aafaad052cb4d13ae1f46c Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 2 Jun 2022 10:06:24 +0200 Subject: [PATCH 276/314] Update cursorless-talon/src/positional_target.py Co-authored-by: Pokey Rule <755842+pokey@users.noreply.github.com> --- cursorless-talon/src/positional_target.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cursorless-talon/src/positional_target.py b/cursorless-talon/src/positional_target.py index ce1396dd66..10e9c5fd31 100644 --- a/cursorless-talon/src/positional_target.py +++ b/cursorless-talon/src/positional_target.py @@ -7,7 +7,7 @@ mod.list( "cursorless_positional_connective", - desc="The connective used to separate source and destination targets", + desc='Connectives used to separate source and destination targets that indicate position, eg "before" or "after"', ) positional_connectives = { From 4e78c2805010e4d4d86f2209a8448b283e16c502 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 2 Jun 2022 10:38:46 +0200 Subject: [PATCH 277/314] Use plain target in clear action --- src/actions/Clear.ts | 13 ++++++++++--- .../modifiers/RawSelectionStage.ts | 16 +++++++--------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/actions/Clear.ts b/src/actions/Clear.ts index ea0109fe87..0bc4291783 100644 --- a/src/actions/Clear.ts +++ b/src/actions/Clear.ts @@ -1,4 +1,4 @@ -import { toRawTarget } from "../processTargets/modifiers/RawSelectionStage"; +import PlainTarget from "../processTargets/targets/PlainTarget"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; import { setSelectionsAndFocusEditor } from "../util/setSelectionsAndFocusEditor"; @@ -12,9 +12,16 @@ export default class Clear implements Action { async run([targets]: [Target[]]): Promise { const editor = ensureSingleEditor(targets); - const rawTargets = targets.map(toRawTarget); + const plainTargets = targets.map( + (target) => + new PlainTarget({ + editor: target.editor, + isReversed: target.isReversed, + contentRange: target.contentRange, + }) + ); - const { thatMark } = await this.graph.actions.remove.run([rawTargets]); + const { thatMark } = await this.graph.actions.remove.run([plainTargets]); if (thatMark != null) { await setSelectionsAndFocusEditor( diff --git a/src/processTargets/modifiers/RawSelectionStage.ts b/src/processTargets/modifiers/RawSelectionStage.ts index e54772a3c9..468fb8f23a 100644 --- a/src/processTargets/modifiers/RawSelectionStage.ts +++ b/src/processTargets/modifiers/RawSelectionStage.ts @@ -7,14 +7,12 @@ export default class RawSelectionStage implements ModifierStage { constructor(private modifier: RawSelectionModifier) {} run(context: ProcessedTargetsContext, target: Target): Target[] { - return [toRawTarget(target)]; + return [ + new RawSelectionTarget({ + editor: target.editor, + contentRange: target.contentRange, + isReversed: target.isReversed, + }), + ]; } } - -export function toRawTarget(target: Target) { - return new RawSelectionTarget({ - editor: target.editor, - contentRange: target.contentRange, - isReversed: target.isReversed, - }); -} From d4183a27bf0c0e43000977eea075f0aa3b34316c Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Thu, 2 Jun 2022 12:13:10 +0100 Subject: [PATCH 278/314] Initial modifier unification work --- cursorless-talon/src/modifiers/interior_boundary.py | 8 ++++---- cursorless-talon/src/modifiers/modifiers.py | 4 ++-- cursorless-talon/src/primitive_target.py | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cursorless-talon/src/modifiers/interior_boundary.py b/cursorless-talon/src/modifiers/interior_boundary.py index 909b9aa6b7..dd6688a741 100644 --- a/cursorless-talon/src/modifiers/interior_boundary.py +++ b/cursorless-talon/src/modifiers/interior_boundary.py @@ -3,14 +3,14 @@ mod = Module() mod.list( - "cursorless_delimiter_inclusion", + "cursorless_interior_boundary", desc="Inside or boundary delimiter inclusion", ) -@mod.capture(rule="{user.cursorless_delimiter_inclusion}") -def cursorless_delimiter_inclusion(m) -> dict[str, str]: +@mod.capture(rule="{user.cursorless_interior_boundary}") +def cursorless_interior_boundary(m) -> dict[str, str]: """Inside or boundary delimiter inclusion""" return { - "type": m.cursorless_delimiter_inclusion, + "type": m.cursorless_interior_boundary, } diff --git a/cursorless-talon/src/modifiers/modifiers.py b/cursorless-talon/src/modifiers/modifiers.py index 238d18a9f3..721850779c 100644 --- a/cursorless-talon/src/modifiers/modifiers.py +++ b/cursorless-talon/src/modifiers/modifiers.py @@ -7,7 +7,7 @@ # NOTE: Please do not change these dicts. Use the CSVs for customization. # See https://www.cursorless.org/docs/user/customization/ -delimiter_inclusions = { +interior_boundary_modifiers = { "inside": "interiorOnly", "bound": "excludeInterior", } @@ -18,7 +18,7 @@ def on_ready(): init_csv_and_watch_changes( "modifiers", { - "delimiter_inclusion": delimiter_inclusions, + "interior_boundary": interior_boundary_modifiers, "range_type": range_types, "head_tail": head_tail, "to_raw_selection": to_raw_selection, diff --git a/cursorless-talon/src/primitive_target.py b/cursorless-talon/src/primitive_target.py index 75fb41985b..de83cb5a86 100644 --- a/cursorless-talon/src/primitive_target.py +++ b/cursorless-talon/src/primitive_target.py @@ -15,7 +15,7 @@ "", # first past second word "", # matching/pair [curly, round] "", # just - "", # inside, bounds + "", # inside, bounds "", # leading, trailing ] From 3fd0c181a332c7aa02293029d21acdc6e79f5d8c Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Thu, 2 Jun 2022 13:34:29 +0100 Subject: [PATCH 279/314] Unify simple modifiers --- .../src/modifiers/delimiter_range.py | 23 ------------- cursorless-talon/src/modifiers/head_tail.py | 29 ---------------- .../src/modifiers/interior_boundary.py | 16 --------- cursorless-talon/src/modifiers/modifiers.py | 33 ++++++++++++++----- cursorless-talon/src/primitive_target.py | 5 +-- .../upgradeV1ToV2/upgradeV1ToV2.ts | 18 +++++----- src/processTargets/getModifierStage.ts | 12 ++++--- .../modifiers/DelimiterRangeStage.ts | 25 -------------- .../modifiers/LeadingTrailingStages.ts | 31 +++++++++++++++++ .../chuckPastLeadingTrap.yml} | 20 ++++++----- .../chuckPastTrailingLook.yml} | 20 ++++++----- .../positions/chuckLeadingBlockAir.yml | 2 +- .../positions/chuckTrailingBlockVest.yml | 2 +- src/typings/target.types.ts | 24 +++++++------- 14 files changed, 109 insertions(+), 151 deletions(-) delete mode 100644 cursorless-talon/src/modifiers/delimiter_range.py delete mode 100644 cursorless-talon/src/modifiers/head_tail.py delete mode 100644 cursorless-talon/src/modifiers/interior_boundary.py delete mode 100644 src/processTargets/modifiers/DelimiterRangeStage.ts create mode 100644 src/processTargets/modifiers/LeadingTrailingStages.ts rename src/test/suite/fixtures/recorded/{positions/chuckPastBeforeTrap.yml => leadingTrailing/chuckPastLeadingTrap.yml} (51%) rename src/test/suite/fixtures/recorded/{positions/chuckPastAfterLook.yml => leadingTrailing/chuckPastTrailingLook.yml} (51%) diff --git a/cursorless-talon/src/modifiers/delimiter_range.py b/cursorless-talon/src/modifiers/delimiter_range.py deleted file mode 100644 index 1a20e9c43a..0000000000 --- a/cursorless-talon/src/modifiers/delimiter_range.py +++ /dev/null @@ -1,23 +0,0 @@ -from typing import Any - -from talon import Context, Module - -mod = Module() -ctx = Context() - - -delimiter_ranges = { - "leading": {"direction": "leading"}, - "trailing": {"direction": "trailing"}, -} - -mod.list("cursorless_delimiter_range", desc="Types of delimiter ranges") -ctx.lists["self.cursorless_delimiter_range"] = delimiter_ranges.keys() - - -@mod.capture(rule="{user.cursorless_delimiter_range}") -def cursorless_delimiter_range(m) -> dict[str, Any]: - return { - "type": "delimiterRange", - **delimiter_ranges[m.cursorless_delimiter_range], - } diff --git a/cursorless-talon/src/modifiers/head_tail.py b/cursorless-talon/src/modifiers/head_tail.py deleted file mode 100644 index 9d8dd07b49..0000000000 --- a/cursorless-talon/src/modifiers/head_tail.py +++ /dev/null @@ -1,29 +0,0 @@ -from dataclasses import dataclass -from typing import Any - -from talon import Module - -mod = Module() -mod.list("cursorless_head_tail", desc="Cursorless modifier for head or tail of line") - - -@dataclass -class HeadTail: - defaultSpokenForm: str - cursorlessIdentifier: str - type: str - - -head_tail_list = [ - HeadTail("head", "extendThroughStartOf", "head"), - HeadTail("tail", "extendThroughEndOf", "tail"), -] -head_tail_map = {i.cursorlessIdentifier: i.type for i in head_tail_list} -head_tail = {i.defaultSpokenForm: i.cursorlessIdentifier for i in head_tail_list} - - -@mod.capture(rule="{user.cursorless_head_tail}") -def cursorless_head_tail(m) -> dict[str, Any]: - return { - "type": head_tail_map[m.cursorless_head_tail], - } diff --git a/cursorless-talon/src/modifiers/interior_boundary.py b/cursorless-talon/src/modifiers/interior_boundary.py deleted file mode 100644 index dd6688a741..0000000000 --- a/cursorless-talon/src/modifiers/interior_boundary.py +++ /dev/null @@ -1,16 +0,0 @@ -from talon import Module - -mod = Module() - -mod.list( - "cursorless_interior_boundary", - desc="Inside or boundary delimiter inclusion", -) - - -@mod.capture(rule="{user.cursorless_interior_boundary}") -def cursorless_interior_boundary(m) -> dict[str, str]: - """Inside or boundary delimiter inclusion""" - return { - "type": m.cursorless_interior_boundary, - } diff --git a/cursorless-talon/src/modifiers/modifiers.py b/cursorless-talon/src/modifiers/modifiers.py index 721850779c..9aea4532e9 100644 --- a/cursorless-talon/src/modifiers/modifiers.py +++ b/cursorless-talon/src/modifiers/modifiers.py @@ -1,27 +1,42 @@ -from talon import app +from talon import Module, app from ..csv_overrides import init_csv_and_watch_changes -from .head_tail import head_tail from .range_type import range_types +mod = Module() + # NOTE: Please do not change these dicts. Use the CSVs for customization. # See https://www.cursorless.org/docs/user/customization/ - -interior_boundary_modifiers = { +simple_modifiers = { "inside": "interiorOnly", - "bound": "excludeInterior", + "bounds": "excludeInterior", + "just": "toRawSelection", + "head": "extendThroughStartOf", + "tail": "extendThroughEndOf", + "leading": "leading", + "trailing": "trailing", } -to_raw_selection = {"just": "toRawSelection"} + +mod.list( + "cursorless_simple_modifier", + desc="Simple cursorless modifiers that only need to specify their type", +) + + +@mod.capture(rule="{user.cursorless_simple_modifier}") +def cursorless_simple_modifier(m) -> dict[str, str]: + """Inside or boundary delimiter inclusion""" + return { + "type": m.cursorless_simple_modifier, + } def on_ready(): init_csv_and_watch_changes( "modifiers", { - "interior_boundary": interior_boundary_modifiers, + "simple_modifier": simple_modifiers, "range_type": range_types, - "head_tail": head_tail, - "to_raw_selection": to_raw_selection, }, ) diff --git a/cursorless-talon/src/primitive_target.py b/cursorless-talon/src/primitive_target.py index de83cb5a86..d7a769a46a 100644 --- a/cursorless-talon/src/primitive_target.py +++ b/cursorless-talon/src/primitive_target.py @@ -10,13 +10,10 @@ modifiers = [ "", # before, end of - "", # head, tail + "", # eg inside, bounds, just, head, tail, leading, trailing "", # funk, state, class "", # first past second word "", # matching/pair [curly, round] - "", # just - "", # inside, bounds - "", # leading, trailing ] diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts index 96dac3d269..37dca4d34d 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts @@ -80,14 +80,18 @@ function upgradeModifier(modifier: ModifierV0V1): Modifier[] { ]; } + case "head": + return [{ type: "extendThroughStartOf" }]; + case "tail": + return [{ type: "extendThroughEndOf" }]; + default: return [modifier]; } } function upgradePrimitiveTarget( - target: PartialPrimitiveTargetV0V1, - action: ActionType + target: PartialPrimitiveTargetV0V1 ): PartialPrimitiveTargetDesc { const { type, @@ -104,16 +108,12 @@ function upgradePrimitiveTarget( if (position === "before") { if (insideOutsideType === "inside") { modifiers.push({ type: "position", position: "start" }); - } else if (action === "remove") { - modifiers.push({ type: "delimiterRange", direction: "leading" }); } else { modifiers.push({ type: "position", position: "before" }); } } else { if (insideOutsideType === "inside") { modifiers.push({ type: "position", position: "end" }); - } else if (action === "remove") { - modifiers.push({ type: "delimiterRange", direction: "trailing" }); } else { modifiers.push({ type: "position", position: "after" }); } @@ -172,13 +172,13 @@ function upgradeTarget( return { type, rangeType, - anchor: upgradePrimitiveTarget(start, action), - active: upgradePrimitiveTarget(end, action), + anchor: upgradePrimitiveTarget(start), + active: upgradePrimitiveTarget(end), excludeAnchor: excludeStart ?? false, excludeActive: excludeEnd ?? false, }; case "primitive": - return upgradePrimitiveTarget(target, action); + return upgradePrimitiveTarget(target); } } diff --git a/src/processTargets/getModifierStage.ts b/src/processTargets/getModifierStage.ts index e95951f140..b4517877d3 100644 --- a/src/processTargets/getModifierStage.ts +++ b/src/processTargets/getModifierStage.ts @@ -4,12 +4,12 @@ import { EveryScopeModifier, Modifier, } from "../typings/target.types"; -import DelimiterRangeStage from "./modifiers/DelimiterRangeStage"; import { HeadStage, TailStage } from "./modifiers/HeadTailStage"; import { ExcludeInteriorStage, InteriorOnlyStage, } from "./modifiers/InteriorStage"; +import { LeadingStage, TrailingStage } from "./modifiers/LeadingTrailingStages"; import OrdinalRangeSubTokenStage, { OrdinalRangeSubTokenModifier, } from "./modifiers/OrdinalRangeSubTokenStage"; @@ -36,9 +36,9 @@ export default (modifier: Modifier): ModifierStage => { switch (modifier.type) { case "position": return new PositionStage(modifier); - case "head": + case "extendThroughStartOf": return new HeadStage(modifier); - case "tail": + case "extendThroughEndOf": return new TailStage(modifier); case "toRawSelection": return new RawSelectionStage(modifier); @@ -46,8 +46,10 @@ export default (modifier: Modifier): ModifierStage => { return new InteriorOnlyStage(modifier); case "excludeInterior": return new ExcludeInteriorStage(modifier); - case "delimiterRange": - return new DelimiterRangeStage(modifier); + case "leading": + return new LeadingStage(modifier); + case "trailing": + return new TrailingStage(modifier); case "containingScope": case "everyScope": return getContainingScopeStage(modifier); diff --git a/src/processTargets/modifiers/DelimiterRangeStage.ts b/src/processTargets/modifiers/DelimiterRangeStage.ts deleted file mode 100644 index 4aa2990e3b..0000000000 --- a/src/processTargets/modifiers/DelimiterRangeStage.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { DelimiterRangeModifier, Target } from "../../typings/target.types"; -import { ProcessedTargetsContext } from "../../typings/Types"; -import { ModifierStage } from "../PipelineStages.types"; - -export default class DelimiterRangeStage implements ModifierStage { - constructor(private modifier: DelimiterRangeModifier) {} - - run(context: ProcessedTargetsContext, target: Target): Target[] { - switch (this.modifier.direction) { - case "leading": - const leading = target.getLeadingDelimiterTarget(); - if (leading == null) { - throw Error("No available leading range"); - } - return [leading]; - - case "trailing": - const trailing = target.getTrailingDelimiterTarget(); - if (trailing == null) { - throw Error("No available trailing range"); - } - return [trailing]; - } - } -} diff --git a/src/processTargets/modifiers/LeadingTrailingStages.ts b/src/processTargets/modifiers/LeadingTrailingStages.ts new file mode 100644 index 0000000000..1f7f639e67 --- /dev/null +++ b/src/processTargets/modifiers/LeadingTrailingStages.ts @@ -0,0 +1,31 @@ +import { + LeadingModifier, + Target, + TrailingModifier, +} from "../../typings/target.types"; +import { ProcessedTargetsContext } from "../../typings/Types"; +import { ModifierStage } from "../PipelineStages.types"; + +export class LeadingStage implements ModifierStage { + constructor(private modifier: LeadingModifier) {} + + run(context: ProcessedTargetsContext, target: Target): Target[] { + const leading = target.getLeadingDelimiterTarget(); + if (leading == null) { + throw Error("No available leading range"); + } + return [leading]; + } +} + +export class TrailingStage implements ModifierStage { + constructor(private modifier: TrailingModifier) {} + + run(context: ProcessedTargetsContext, target: Target): Target[] { + const trailing = target.getTrailingDelimiterTarget(); + if (trailing == null) { + throw Error("No available trailing range"); + } + return [trailing]; + } +} diff --git a/src/test/suite/fixtures/recorded/positions/chuckPastBeforeTrap.yml b/src/test/suite/fixtures/recorded/leadingTrailing/chuckPastLeadingTrap.yml similarity index 51% rename from src/test/suite/fixtures/recorded/positions/chuckPastBeforeTrap.yml rename to src/test/suite/fixtures/recorded/leadingTrailing/chuckPastLeadingTrap.yml index eaf03d5562..3fa3ff3f2c 100644 --- a/src/test/suite/fixtures/recorded/positions/chuckPastBeforeTrap.yml +++ b/src/test/suite/fixtures/recorded/leadingTrailing/chuckPastLeadingTrap.yml @@ -1,17 +1,19 @@ languageId: plaintext command: - version: 1 - spokenForm: chuck past before trap - action: remove + spokenForm: chuck past leading trap + version: 2 targets: - type: range - start: {type: primitive} - end: + anchor: {type: primitive} + active: type: primitive - position: before mark: {type: decoratedSymbol, symbolColor: default, character: t} - excludeStart: false - excludeEnd: false + modifiers: + - {type: leading} + excludeAnchor: false + excludeActive: false + usePrePhraseSnapshot: true + action: {name: remove} initialState: documentContents: hello there selections: @@ -29,4 +31,4 @@ finalState: thatMark: - anchor: {line: 0, character: 5} active: {line: 0, character: 5} -fullTargets: [{type: range, excludeStart: false, excludeEnd: false, start: {type: primitive, mark: {type: cursor}, selectionType: token, position: contents, modifier: {type: identity}, insideOutsideType: outside}, end: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: t}, selectionType: token, position: before, modifier: {type: identity}, insideOutsideType: outside}}] +fullTargets: [{type: range, excludeAnchor: false, excludeActive: false, rangeType: continuous, anchor: {type: primitive, mark: {type: cursor}, modifiers: []}, active: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: t}, modifiers: [{type: leading}]}}] diff --git a/src/test/suite/fixtures/recorded/positions/chuckPastAfterLook.yml b/src/test/suite/fixtures/recorded/leadingTrailing/chuckPastTrailingLook.yml similarity index 51% rename from src/test/suite/fixtures/recorded/positions/chuckPastAfterLook.yml rename to src/test/suite/fixtures/recorded/leadingTrailing/chuckPastTrailingLook.yml index f6757b62ac..d7171aad08 100644 --- a/src/test/suite/fixtures/recorded/positions/chuckPastAfterLook.yml +++ b/src/test/suite/fixtures/recorded/leadingTrailing/chuckPastTrailingLook.yml @@ -1,17 +1,19 @@ languageId: plaintext command: - version: 1 - spokenForm: chuck past after look - action: remove + spokenForm: chuck past trailing look + version: 2 targets: - type: range - start: {type: primitive} - end: + anchor: {type: primitive} + active: type: primitive - position: after mark: {type: decoratedSymbol, symbolColor: default, character: l} - excludeStart: false - excludeEnd: false + modifiers: + - {type: trailing} + excludeAnchor: false + excludeActive: false + usePrePhraseSnapshot: true + action: {name: remove} initialState: documentContents: hello there selections: @@ -29,4 +31,4 @@ finalState: thatMark: - anchor: {line: 0, character: 2} active: {line: 0, character: 2} -fullTargets: [{type: range, excludeStart: false, excludeEnd: false, start: {type: primitive, mark: {type: cursor}, selectionType: token, position: contents, modifier: {type: identity}, insideOutsideType: outside}, end: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: l}, selectionType: token, position: after, modifier: {type: identity}, insideOutsideType: outside}}] +fullTargets: [{type: range, excludeAnchor: false, excludeActive: false, rangeType: continuous, anchor: {type: primitive, mark: {type: cursor}, modifiers: []}, active: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: l}, modifiers: [{type: trailing}]}}] diff --git a/src/test/suite/fixtures/recorded/positions/chuckLeadingBlockAir.yml b/src/test/suite/fixtures/recorded/positions/chuckLeadingBlockAir.yml index e806ead97b..94c10e6fb6 100644 --- a/src/test/suite/fixtures/recorded/positions/chuckLeadingBlockAir.yml +++ b/src/test/suite/fixtures/recorded/positions/chuckLeadingBlockAir.yml @@ -6,7 +6,7 @@ command: - type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: a} modifiers: - - {type: delimiterRange, direction: leading} + - {type: leading} - type: containingScope scopeType: {type: paragraph} usePrePhraseSnapshot: true diff --git a/src/test/suite/fixtures/recorded/positions/chuckTrailingBlockVest.yml b/src/test/suite/fixtures/recorded/positions/chuckTrailingBlockVest.yml index 0b7a3665ed..3053fa513c 100644 --- a/src/test/suite/fixtures/recorded/positions/chuckTrailingBlockVest.yml +++ b/src/test/suite/fixtures/recorded/positions/chuckTrailingBlockVest.yml @@ -6,7 +6,7 @@ command: - type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: v} modifiers: - - {type: delimiterRange, direction: trailing} + - {type: trailing} - type: containingScope scopeType: {type: paragraph} usePrePhraseSnapshot: true diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index c788db2ec0..63081bc4b9 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -167,11 +167,19 @@ export interface RawSelectionModifier { } export interface HeadModifier { - type: "head"; + type: "extendThroughStartOf"; } export interface TailModifier { - type: "tail"; + type: "extendThroughEndOf"; +} + +export interface LeadingModifier { + type: "leading"; +} + +export interface TrailingModifier { + type: "trailing"; } export type Position = "before" | "after" | "start" | "end"; @@ -181,13 +189,6 @@ export interface PositionModifier { position: Position; } -export type DelimiterRangeDirection = "leading" | "trailing"; - -export interface DelimiterRangeModifier { - type: "delimiterRange"; - direction: DelimiterRangeDirection; -} - export interface PartialPrimitiveTargetDesc { type: "primitive"; mark?: Mark; @@ -204,8 +205,9 @@ export type Modifier = | OrdinalRangeModifier | HeadModifier | TailModifier - | RawSelectionModifier - | DelimiterRangeModifier; + | LeadingModifier + | TrailingModifier + | RawSelectionModifier; export interface PartialRangeTargetDesc { type: "range"; From 9497e51cd7f5bdeb83dda1c3d0e8881bcd902972 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Thu, 2 Jun 2022 13:44:45 +0100 Subject: [PATCH 280/314] docstring --- 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 9aea4532e9..217c6033f8 100644 --- a/cursorless-talon/src/modifiers/modifiers.py +++ b/cursorless-talon/src/modifiers/modifiers.py @@ -25,7 +25,7 @@ @mod.capture(rule="{user.cursorless_simple_modifier}") def cursorless_simple_modifier(m) -> dict[str, str]: - """Inside or boundary delimiter inclusion""" + """Simple cursorless modifiers that only need to specify their type""" return { "type": m.cursorless_simple_modifier, } From 47dbb584442df4cfe035d604a62e74624628599b Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Thu, 2 Jun 2022 15:35:59 +0100 Subject: [PATCH 281/314] Clean up position code --- cursorless-talon/src/modifiers/position.py | 42 +++++++++------------- cursorless-talon/src/positional_target.py | 14 ++++---- 2 files changed, 23 insertions(+), 33 deletions(-) diff --git a/cursorless-talon/src/modifiers/position.py b/cursorless-talon/src/modifiers/position.py index ba060826e6..5b84a78bde 100644 --- a/cursorless-talon/src/modifiers/position.py +++ b/cursorless-talon/src/modifiers/position.py @@ -5,34 +5,26 @@ mod = Module() ctx = Context() -POSITION_BEFORE = { - "before": { - "type": "position", - "position": "before", - } -} - -POSITION_AFTER = { - "after": {"type": "position", "position": "after"}, +mod.list("cursorless_position", desc="Types of positions") +ctx.lists["self.cursorless_position"] = { + "start of": "start", + "end of": "end", } -positions = { - "before": {"position": "before"}, - "after": {"position": "after"}, - "start of": {"position": "start"}, - "end of": {"position": "end"}, - # Disabled for now because "below" can misrecognize with "blue" and we may move away from allowing positional modifiers in arbitrary places anyway - # "above": {"position": "before", **LINE.json_repr}, - # "below": {"position": "after", **LINE.json_repr} -} -mod.list("cursorless_position", desc="Types of positions") -ctx.lists["self.cursorless_position"] = positions.keys() +def construct_positional_modifier(position: str) -> dict: + return {"type": "position", "position": position} -@mod.capture(rule="{user.cursorless_position}") +# Note that we allow positional connectives such as "before" and "after" to appear +# as modifiers. We may disallow this in the future. +@mod.capture( + rule="{user.cursorless_position} | {user.cursorless_positional_connective}" +) def cursorless_position(m) -> dict[str, Any]: - return { - "type": "position", - **positions[m.cursorless_position], - } + try: + position = m.cursorless_position + except AttributeError: + position = m.cursorless_positional_connective + + return construct_positional_modifier(position) diff --git a/cursorless-talon/src/positional_target.py b/cursorless-talon/src/positional_target.py index 10e9c5fd31..d257203574 100644 --- a/cursorless-talon/src/positional_target.py +++ b/cursorless-talon/src/positional_target.py @@ -1,6 +1,6 @@ from talon import Context, Module -from .modifiers.position import POSITION_AFTER, POSITION_BEFORE +from .modifiers.position import construct_positional_modifier mod = Module() ctx = Context() @@ -10,13 +10,11 @@ desc='Connectives used to separate source and destination targets that indicate position, eg "before" or "after"', ) -positional_connectives = { - **POSITION_BEFORE, - **POSITION_AFTER, +ctx.lists["self.cursorless_positional_connective"] = { + "before": "before", + "after": "after", } -ctx.lists["self.cursorless_positional_connective"] = positional_connectives.keys() - @mod.capture( rule=( @@ -27,7 +25,7 @@ def cursorless_positional_target(m) -> list[dict]: target = m.cursorless_target try: - modifier = positional_connectives[m.cursorless_positional_connective] + modifier = construct_positional_modifier(m.cursorless_positional_connective) return update_first_primitive_target(target, modifier) except AttributeError: return target @@ -42,7 +40,7 @@ def update_first_primitive_target(target: dict, modifier: dict): elif target["type"] == "range": return { **target, - "start": update_first_primitive_target(target["start"], modifier), + "anchor": update_first_primitive_target(target["anchor"], modifier), } else: elements = target["elements"] From 4e084a82b2319c6c6546111d10ec5fbc950eda16 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Thu, 2 Jun 2022 15:49:00 +0100 Subject: [PATCH 282/314] At a couple comments --- src/actions/BringMoveSwap.ts | 3 +++ src/actions/Clear.ts | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/actions/BringMoveSwap.ts b/src/actions/BringMoveSwap.ts index 79f98ae179..462d8d5c10 100644 --- a/src/actions/BringMoveSwap.ts +++ b/src/actions/BringMoveSwap.ts @@ -187,6 +187,9 @@ class BringMoveSwap implements Action { [editSelectionInfos, cursorSelectionInfos] ); + // NB: We set the selections here because we don't trust vscode to + // properly move the cursor on a bring. Sometimes it will smear an + // empty selection setSelectionsWithoutFocusingEditor(editor, cursorSelections); return edits.map((edit, index): MarkEntry => { diff --git a/src/actions/Clear.ts b/src/actions/Clear.ts index 0bc4291783..c51d64d404 100644 --- a/src/actions/Clear.ts +++ b/src/actions/Clear.ts @@ -12,6 +12,8 @@ export default class Clear implements Action { async run([targets]: [Target[]]): Promise { const editor = ensureSingleEditor(targets); + // Convert to plain targets so that the remove action just removes the + // content range instead of the removal range const plainTargets = targets.map( (target) => new PlainTarget({ From ae1b1e25c0ee4b9d628445995503a42c9eea4266 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Thu, 2 Jun 2022 16:29:47 +0100 Subject: [PATCH 283/314] Creates separate file for target descriptor types --- src/actions/EditNew.ts | 2 +- src/core/commandRunner/command.types.ts | 2 +- .../canonicalizeAndValidateCommand.ts | 4 +- .../canonicalizeTargets.ts | 4 +- .../upgradeV1ToV2/upgradeStrictHere.ts | 2 +- .../upgradeV1ToV2/upgradeV1ToV2.ts | 4 +- src/core/inferFullTargets.ts | 4 +- src/languages/clojure.ts | 2 +- src/languages/cpp.ts | 2 +- src/languages/csharp.ts | 2 +- src/languages/getNodeMatcher.ts | 2 +- src/languages/go.ts | 2 +- src/languages/html.ts | 2 +- src/languages/java.ts | 2 +- src/languages/json.ts | 2 +- src/languages/markdown.ts | 2 +- src/languages/php.ts | 2 +- src/languages/python.ts | 2 +- src/languages/ruby.ts | 2 +- src/languages/scala.ts | 2 +- src/languages/scss.ts | 2 +- src/languages/typescript.ts | 2 +- src/processTargets/getMarkStage.ts | 2 +- src/processTargets/getModifierStage.ts | 4 +- src/processTargets/marks/CursorStage.ts | 3 +- .../marks/DecoratedSymbolStage.ts | 3 +- src/processTargets/marks/LineNumberStage.ts | 2 +- src/processTargets/marks/NothingStage.ts | 3 +- src/processTargets/marks/SourceStage.ts | 3 +- src/processTargets/marks/ThatStage.ts | 3 +- src/processTargets/modifiers/HeadTailStage.ts | 3 +- src/processTargets/modifiers/InteriorStage.ts | 6 +- .../modifiers/LeadingTrailingStages.ts | 3 +- .../modifiers/ModifyIfWeakStage.ts | 3 +- .../modifiers/OrdinalRangeSubTokenStage.ts | 6 +- src/processTargets/modifiers/PositionStage.ts | 3 +- .../modifiers/RawSelectionStage.ts | 3 +- .../modifiers/SurroundingPairStage.ts | 2 +- .../ContainingSyntaxScopeStage.ts | 8 +- .../scopeTypeStages/DocumentStage.ts | 6 +- .../modifiers/scopeTypeStages/LineStage.ts | 6 +- .../scopeTypeStages/NotebookCellStage.ts | 6 +- .../scopeTypeStages/ParagraphStage.ts | 6 +- .../modifiers/scopeTypeStages/RegexStage.ts | 6 +- .../modifiers/scopeTypeStages/TokenStage.ts | 6 +- .../surroundingPair/delimiterMaps.ts | 4 +- .../findDelimiterPairContainingSelection.ts | 2 +- .../surroundingPair/findOppositeDelimiter.ts | 2 +- .../findSurroundingPairCore.ts | 2 +- .../findSurroundingPairParseTreeBased.ts | 4 +- .../findSurroundingPairTextBased.ts | 4 +- .../generateUnmatchedDelimiters.ts | 2 +- .../getIndividualDelimiters.ts | 2 +- .../modifiers/surroundingPair/index.ts | 4 +- .../modifiers/surroundingPair/types.ts | 2 +- src/processTargets/processTargets.ts | 7 +- src/processTargets/targets/BaseTarget.ts | 1 + .../targets/NotebookCellTarget.ts | 1 + src/processTargets/targets/PositionTarget.ts | 3 +- src/processTargets/targets/ScopeTypeTarget.ts | 3 +- .../transformations/upgradeFromVersion0.ts | 2 +- src/testUtil/TestCase.ts | 2 +- src/testUtil/TestCaseRecorder.ts | 2 +- src/testUtil/extractTargetedMarks.ts | 4 +- src/typings/snippet.ts | 2 +- src/typings/target.types.ts | 270 +----------------- src/typings/targetDescriptor.types.ts | 267 +++++++++++++++++ src/util/getPrimitiveTargets.ts | 4 +- src/util/nodeMatchers.ts | 2 +- 69 files changed, 390 insertions(+), 356 deletions(-) create mode 100644 src/typings/targetDescriptor.types.ts diff --git a/src/actions/EditNew.ts b/src/actions/EditNew.ts index 6b9b7f9e3d..94cc1e2324 100644 --- a/src/actions/EditNew.ts +++ b/src/actions/EditNew.ts @@ -68,7 +68,7 @@ class EditNew implements Action { } // Only update selection if all targets are agreeing on this - if (!richTargets.find(({ updateSelection }) => !updateSelection)) { + if (!richTargets.some(({ updateSelection }) => !updateSelection)) { const newSelections = richTargets.map((target) => selectionFromRange(target.target.isReversed, target.cursorRange) ); diff --git a/src/core/commandRunner/command.types.ts b/src/core/commandRunner/command.types.ts index f4767b24e4..bd9128a768 100644 --- a/src/core/commandRunner/command.types.ts +++ b/src/core/commandRunner/command.types.ts @@ -1,4 +1,4 @@ -import { PartialTargetDesc } from "../../typings/target.types"; +import { PartialTargetDesc } from "../../typings/targetDescriptor.types"; import { ActionType } from "../../actions/actions.types"; import { CommandV0, diff --git a/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts b/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts index 20e5756f2b..6099277bee 100644 --- a/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts +++ b/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts @@ -3,8 +3,8 @@ import { ActionableError } from "../../errors"; import { Modifier, PartialTargetDesc, - SimpleScopeTypeType, -} from "../../typings/target.types"; + SimpleScopeTypeType +} from "../../typings/targetDescriptor.types"; import { ActionType } from "../../actions/actions.types"; import { getPartialPrimitiveTargets } from "../../util/getPrimitiveTargets"; import { diff --git a/src/core/commandVersionUpgrades/canonicalizeTargets.ts b/src/core/commandVersionUpgrades/canonicalizeTargets.ts index 0198d06a92..d4d7b8af05 100644 --- a/src/core/commandVersionUpgrades/canonicalizeTargets.ts +++ b/src/core/commandVersionUpgrades/canonicalizeTargets.ts @@ -3,8 +3,8 @@ import { flow } from "lodash"; import { PartialPrimitiveTargetDesc, PartialTargetDesc, - SimpleScopeTypeType, -} from "../../typings/target.types"; + SimpleScopeTypeType +} from "../../typings/targetDescriptor.types"; import { transformPartialPrimitiveTargets } from "../../util/getPrimitiveTargets"; import { HatStyleName } from "../constants"; diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeStrictHere.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeStrictHere.ts index d960e8eb67..626f500072 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeStrictHere.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeStrictHere.ts @@ -1,5 +1,5 @@ import { isDeepStrictEqual } from "util"; -import { PartialPrimitiveTargetDesc } from "../../../typings/target.types"; +import { PartialPrimitiveTargetDesc } from "../../../typings/targetDescriptor.types"; const STRICT_HERE = { type: "primitive", diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts index 37dca4d34d..859ae10e87 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts @@ -4,8 +4,8 @@ import { PartialPrimitiveTargetDesc, PartialRangeTargetDesc, PartialTargetDesc, - SimpleScopeTypeType, -} from "../../../typings/target.types"; + SimpleScopeTypeType +} from "../../../typings/targetDescriptor.types"; import { ActionType } from "../../../actions/actions.types"; import { transformPartialPrimitiveTargets } from "../../../util/getPrimitiveTargets"; import { CommandV2 } from "../../commandRunner/command.types"; diff --git a/src/core/inferFullTargets.ts b/src/core/inferFullTargets.ts index 27f45f885a..7dc0c8aa2b 100644 --- a/src/core/inferFullTargets.ts +++ b/src/core/inferFullTargets.ts @@ -5,8 +5,8 @@ import { PartialTargetDesc, PrimitiveTargetDescriptor, RangeTargetDescriptor, - TargetDescriptor, -} from "../typings/target.types"; + TargetDescriptor +} from "../typings/targetDescriptor.types"; /** * Performs inference on the partial targets provided by the user, using diff --git a/src/languages/clojure.ts b/src/languages/clojure.ts index f1dffd8a24..d79751a187 100644 --- a/src/languages/clojure.ts +++ b/src/languages/clojure.ts @@ -6,7 +6,7 @@ import { patternMatcher, } from "../util/nodeMatchers"; import { NodeMatcherAlternative, NodeFinder } from "../typings/Types"; -import { SimpleScopeTypeType } from "../typings/target.types"; +import { SimpleScopeTypeType } from "../typings/targetDescriptor.types"; import { SyntaxNode } from "web-tree-sitter"; import { delimitedSelector } from "../util/nodeSelectors"; import { identity } from "lodash"; diff --git a/src/languages/cpp.ts b/src/languages/cpp.ts index bf8355cea1..1521c9177d 100644 --- a/src/languages/cpp.ts +++ b/src/languages/cpp.ts @@ -5,7 +5,7 @@ import { trailingMatcher, } from "../util/nodeMatchers"; import { NodeMatcherAlternative } from "../typings/Types"; -import { SimpleScopeTypeType } from "../typings/target.types"; +import { SimpleScopeTypeType } from "../typings/targetDescriptor.types"; // Generated by the following command: // > curl https://raw.githubusercontent.com/tree-sitter/tree-sitter-cpp/master/src/node-types.json | jq '[.[] | select(.type == "compound_statement") | .children.types[].type] + [.[] | select(.type == "_statement") | .subtypes[].type]' diff --git a/src/languages/csharp.ts b/src/languages/csharp.ts index 8100ef6684..f4ea4f35d6 100644 --- a/src/languages/csharp.ts +++ b/src/languages/csharp.ts @@ -11,7 +11,7 @@ import { patternMatcher, } from "../util/nodeMatchers"; import { NodeMatcherAlternative } from "../typings/Types"; -import { SimpleScopeTypeType } from "../typings/target.types"; +import { SimpleScopeTypeType } from "../typings/targetDescriptor.types"; import { nodeFinder, typedNodeFinder } from "../util/nodeFinders"; import { delimitedSelector } from "../util/nodeSelectors"; diff --git a/src/languages/getNodeMatcher.ts b/src/languages/getNodeMatcher.ts index 21bf322bb2..d368e46686 100644 --- a/src/languages/getNodeMatcher.ts +++ b/src/languages/getNodeMatcher.ts @@ -6,7 +6,7 @@ import { NodeMatcherValue, SelectionWithEditor, } from "../typings/Types"; -import { SimpleScopeTypeType } from "../typings/target.types"; +import { SimpleScopeTypeType } from "../typings/targetDescriptor.types"; import cpp from "./cpp"; import clojure from "./clojure"; import csharp from "./csharp"; diff --git a/src/languages/go.ts b/src/languages/go.ts index c372308e62..66b265ee40 100644 --- a/src/languages/go.ts +++ b/src/languages/go.ts @@ -6,7 +6,7 @@ import { patternMatcher, } from "../util/nodeMatchers"; import { NodeMatcherAlternative } from "../typings/Types"; -import { SimpleScopeTypeType } from "../typings/target.types"; +import { SimpleScopeTypeType } from "../typings/targetDescriptor.types"; // Generated by the following command: // `curl https://raw.githubusercontent.com/tree-sitter/tree-sitter-go/master/src/node-types.json | jq '[.[] | select(.type == "_statement" or .type == "_simple_statement") | .subtypes[].type]'` diff --git a/src/languages/html.ts b/src/languages/html.ts index f9b393ba83..73aec7a8b3 100644 --- a/src/languages/html.ts +++ b/src/languages/html.ts @@ -4,7 +4,7 @@ import { patternMatcher, } from "../util/nodeMatchers"; import { NodeMatcherAlternative, SelectionWithEditor } from "../typings/Types"; -import { SimpleScopeTypeType } from "../typings/target.types"; +import { SimpleScopeTypeType } from "../typings/targetDescriptor.types"; import { SyntaxNode } from "web-tree-sitter"; import { getNodeRange } from "../util/nodeSelectors"; diff --git a/src/languages/java.ts b/src/languages/java.ts index 19247fd768..526e353a00 100644 --- a/src/languages/java.ts +++ b/src/languages/java.ts @@ -6,7 +6,7 @@ import { trailingMatcher, } from "../util/nodeMatchers"; import { NodeMatcherAlternative } from "../typings/Types"; -import { SimpleScopeTypeType } from "../typings/target.types"; +import { SimpleScopeTypeType } from "../typings/targetDescriptor.types"; // Generated by the following command: // > curl https://raw.githubusercontent.com/tree-sitter/tree-sitter-java/master/src/node-types.json | jq '[.[] | select(.type == "statement" or .type == "declaration") | .subtypes[].type]' diff --git a/src/languages/json.ts b/src/languages/json.ts index cf4f619a7e..23c69c0718 100644 --- a/src/languages/json.ts +++ b/src/languages/json.ts @@ -5,7 +5,7 @@ import { trailingMatcher, } from "../util/nodeMatchers"; import { NodeMatcherAlternative, SelectionWithEditor } from "../typings/Types"; -import { SimpleScopeTypeType } from "../typings/target.types"; +import { SimpleScopeTypeType } from "../typings/targetDescriptor.types"; import { SyntaxNode } from "web-tree-sitter"; import { getNodeRange } from "../util/nodeSelectors"; diff --git a/src/languages/markdown.ts b/src/languages/markdown.ts index d82c657b99..7b4dbf32bd 100644 --- a/src/languages/markdown.ts +++ b/src/languages/markdown.ts @@ -5,7 +5,7 @@ import { NodeMatcherAlternative, SelectionWithContext, } from "../typings/Types"; -import { SimpleScopeTypeType } from "../typings/target.types"; +import { SimpleScopeTypeType } from "../typings/targetDescriptor.types"; import { leadingSiblingNodeFinder, patternFinder } from "../util/nodeFinders"; import { createPatternMatchers, diff --git a/src/languages/php.ts b/src/languages/php.ts index 404118945b..f9e5b629fc 100644 --- a/src/languages/php.ts +++ b/src/languages/php.ts @@ -5,7 +5,7 @@ import { SelectionWithContext, SelectionWithEditor, } from "../typings/Types"; -import { SimpleScopeTypeType } from "../typings/target.types"; +import { SimpleScopeTypeType } from "../typings/targetDescriptor.types"; import { patternFinder } from "../util/nodeFinders"; import { argumentMatcher, diff --git a/src/languages/python.ts b/src/languages/python.ts index 25e908874a..e8ab89249b 100644 --- a/src/languages/python.ts +++ b/src/languages/python.ts @@ -11,7 +11,7 @@ import { } from "../util/nodeMatchers"; import { patternFinder } from "../util/nodeFinders"; import { NodeMatcherAlternative } from "../typings/Types"; -import { SimpleScopeTypeType } from "../typings/target.types"; +import { SimpleScopeTypeType } from "../typings/targetDescriptor.types"; import { childRangeSelector } from "../util/nodeSelectors"; // Generated by the following command: diff --git a/src/languages/ruby.ts b/src/languages/ruby.ts index 15930e6de4..ac7a9aa1ed 100644 --- a/src/languages/ruby.ts +++ b/src/languages/ruby.ts @@ -10,7 +10,7 @@ import { trailingMatcher, } from "../util/nodeMatchers"; import { NodeMatcherAlternative, SelectionWithEditor } from "../typings/Types"; -import { SimpleScopeTypeType } from "../typings/target.types"; +import { SimpleScopeTypeType } from "../typings/targetDescriptor.types"; import { SyntaxNode } from "web-tree-sitter"; import { getNodeRange } from "../util/nodeSelectors"; import { patternFinder } from "../util/nodeFinders"; diff --git a/src/languages/scala.ts b/src/languages/scala.ts index 94d3be74db..37f69ff80a 100644 --- a/src/languages/scala.ts +++ b/src/languages/scala.ts @@ -5,7 +5,7 @@ import { conditionMatcher, } from "../util/nodeMatchers"; import { NodeMatcherAlternative } from "../typings/Types"; -import { SimpleScopeTypeType } from "../typings/target.types"; +import { SimpleScopeTypeType } from "../typings/targetDescriptor.types"; const nodeMatchers: Partial< Record diff --git a/src/languages/scss.ts b/src/languages/scss.ts index a162e11cf5..9e25a0933c 100644 --- a/src/languages/scss.ts +++ b/src/languages/scss.ts @@ -1,6 +1,6 @@ import { SyntaxNode } from "web-tree-sitter"; import { NodeMatcherAlternative, SelectionWithEditor } from "../typings/Types"; -import { SimpleScopeTypeType } from "../typings/target.types"; +import { SimpleScopeTypeType } from "../typings/targetDescriptor.types"; import { patternFinder } from "../util/nodeFinders"; import { cascadingMatcher, diff --git a/src/languages/typescript.ts b/src/languages/typescript.ts index 067283d584..cf5efd26d9 100644 --- a/src/languages/typescript.ts +++ b/src/languages/typescript.ts @@ -13,7 +13,7 @@ import { NodeMatcherAlternative, SelectionWithEditor, } from "../typings/Types"; -import { SimpleScopeTypeType } from "../typings/target.types"; +import { SimpleScopeTypeType } from "../typings/targetDescriptor.types"; import { getNodeInternalRange, getNodeRange, diff --git a/src/processTargets/getMarkStage.ts b/src/processTargets/getMarkStage.ts index afc6c25356..400cd5595c 100644 --- a/src/processTargets/getMarkStage.ts +++ b/src/processTargets/getMarkStage.ts @@ -1,4 +1,4 @@ -import { Mark } from "../typings/target.types"; +import { Mark } from "../typings/targetDescriptor.types"; import CursorStage from "./marks/CursorStage"; import DecoratedSymbolStage from "./marks/DecoratedSymbolStage"; import LineNumberStage from "./marks/LineNumberStage"; diff --git a/src/processTargets/getModifierStage.ts b/src/processTargets/getModifierStage.ts index b4517877d3..af0b7f035c 100644 --- a/src/processTargets/getModifierStage.ts +++ b/src/processTargets/getModifierStage.ts @@ -2,8 +2,8 @@ import { ContainingScopeModifier, ContainingSurroundingPairModifier, EveryScopeModifier, - Modifier, -} from "../typings/target.types"; + Modifier +} from "../typings/targetDescriptor.types"; import { HeadStage, TailStage } from "./modifiers/HeadTailStage"; import { ExcludeInteriorStage, diff --git a/src/processTargets/marks/CursorStage.ts b/src/processTargets/marks/CursorStage.ts index ae97453caf..71a4727fb8 100644 --- a/src/processTargets/marks/CursorStage.ts +++ b/src/processTargets/marks/CursorStage.ts @@ -1,4 +1,5 @@ -import { CursorMark, Target } from "../../typings/target.types"; +import { Target } from "../../typings/target.types"; +import { CursorMark } from "../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { isReversed } from "../../util/selectionUtils"; import { MarkStage } from "../PipelineStages.types"; diff --git a/src/processTargets/marks/DecoratedSymbolStage.ts b/src/processTargets/marks/DecoratedSymbolStage.ts index b1939c026e..76050d95a3 100644 --- a/src/processTargets/marks/DecoratedSymbolStage.ts +++ b/src/processTargets/marks/DecoratedSymbolStage.ts @@ -1,4 +1,5 @@ -import { DecoratedSymbolMark, Target } from "../../typings/target.types"; +import { Target } from "../../typings/target.types"; +import { DecoratedSymbolMark } from "../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { MarkStage } from "../PipelineStages.types"; import WeakTarget from "../targets/WeakTarget"; diff --git a/src/processTargets/marks/LineNumberStage.ts b/src/processTargets/marks/LineNumberStage.ts index bdffde02ec..1d6c37690e 100644 --- a/src/processTargets/marks/LineNumberStage.ts +++ b/src/processTargets/marks/LineNumberStage.ts @@ -1,5 +1,5 @@ import { TextEditor } from "vscode"; -import { LineNumberMark, LineNumberPosition } from "../../typings/target.types"; +import { LineNumberMark, LineNumberPosition } from "../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { createLineTarget } from "../modifiers/scopeTypeStages/LineStage"; import { MarkStage } from "../PipelineStages.types"; diff --git a/src/processTargets/marks/NothingStage.ts b/src/processTargets/marks/NothingStage.ts index e64feb0596..818b242173 100644 --- a/src/processTargets/marks/NothingStage.ts +++ b/src/processTargets/marks/NothingStage.ts @@ -1,4 +1,5 @@ -import { NothingMark, Target } from "../../typings/target.types"; +import { Target } from "../../typings/target.types"; +import { NothingMark } from "../../typings/targetDescriptor.types"; import { MarkStage } from "../PipelineStages.types"; export default class implements MarkStage { diff --git a/src/processTargets/marks/SourceStage.ts b/src/processTargets/marks/SourceStage.ts index fca3f7d62f..c57e4f0136 100644 --- a/src/processTargets/marks/SourceStage.ts +++ b/src/processTargets/marks/SourceStage.ts @@ -1,4 +1,5 @@ -import { SourceMark, Target } from "../../typings/target.types"; +import { Target } from "../../typings/target.types"; +import { SourceMark } from "../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { isReversed } from "../../util/selectionUtils"; import { MarkStage } from "../PipelineStages.types"; diff --git a/src/processTargets/marks/ThatStage.ts b/src/processTargets/marks/ThatStage.ts index 22e0e27dd7..0dbd05518f 100644 --- a/src/processTargets/marks/ThatStage.ts +++ b/src/processTargets/marks/ThatStage.ts @@ -1,4 +1,5 @@ -import { Target, ThatMark } from "../../typings/target.types"; +import { Target } from "../../typings/target.types"; +import { ThatMark } from "../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { isReversed } from "../../util/selectionUtils"; import { MarkStage } from "../PipelineStages.types"; diff --git a/src/processTargets/modifiers/HeadTailStage.ts b/src/processTargets/modifiers/HeadTailStage.ts index fcd4eaa1d7..322578b3b6 100644 --- a/src/processTargets/modifiers/HeadTailStage.ts +++ b/src/processTargets/modifiers/HeadTailStage.ts @@ -1,5 +1,6 @@ import { Position, Range, TextEditor } from "vscode"; -import { HeadModifier, TailModifier, Target } from "../../typings/target.types"; +import { Target } from "../../typings/target.types"; +import { HeadModifier, TailModifier } from "../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; import TokenTarget from "../targets/TokenTarget"; diff --git a/src/processTargets/modifiers/InteriorStage.ts b/src/processTargets/modifiers/InteriorStage.ts index fc46dbda49..afb67e8b8c 100644 --- a/src/processTargets/modifiers/InteriorStage.ts +++ b/src/processTargets/modifiers/InteriorStage.ts @@ -1,8 +1,10 @@ import { - ExcludeInteriorModifier, - InteriorOnlyModifier, Target, } from "../../typings/target.types"; +import { + ExcludeInteriorModifier, + InteriorOnlyModifier +} from "../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; import { weakContainingSurroundingPairStage } from "./commonWeakContainingScopeStages"; diff --git a/src/processTargets/modifiers/LeadingTrailingStages.ts b/src/processTargets/modifiers/LeadingTrailingStages.ts index 1f7f639e67..54c22e0905 100644 --- a/src/processTargets/modifiers/LeadingTrailingStages.ts +++ b/src/processTargets/modifiers/LeadingTrailingStages.ts @@ -1,8 +1,7 @@ import { - LeadingModifier, Target, - TrailingModifier, } from "../../typings/target.types"; +import { LeadingModifier, TrailingModifier } from "../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; diff --git a/src/processTargets/modifiers/ModifyIfWeakStage.ts b/src/processTargets/modifiers/ModifyIfWeakStage.ts index 344923b359..6ac3289956 100644 --- a/src/processTargets/modifiers/ModifyIfWeakStage.ts +++ b/src/processTargets/modifiers/ModifyIfWeakStage.ts @@ -1,4 +1,5 @@ -import { Modifier, Target } from "../../typings/target.types"; +import { Target } from "../../typings/target.types"; +import { Modifier } from "../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import getModifierStage from "../getModifierStage"; import { ModifierStage } from "../PipelineStages.types"; diff --git a/src/processTargets/modifiers/OrdinalRangeSubTokenStage.ts b/src/processTargets/modifiers/OrdinalRangeSubTokenStage.ts index b711a1583a..76a19cc724 100644 --- a/src/processTargets/modifiers/OrdinalRangeSubTokenStage.ts +++ b/src/processTargets/modifiers/OrdinalRangeSubTokenStage.ts @@ -2,10 +2,12 @@ import { range } from "lodash"; import { Range } from "vscode"; import { SUBWORD_MATCHER } from "../../core/constants"; import { - OrdinalRangeModifier, - SimpleScopeType, Target, } from "../../typings/target.types"; +import { + OrdinalRangeModifier, + SimpleScopeType +} from "../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; import PlainTarget from "../targets/PlainTarget"; diff --git a/src/processTargets/modifiers/PositionStage.ts b/src/processTargets/modifiers/PositionStage.ts index 6019163869..1c19ab9cfb 100644 --- a/src/processTargets/modifiers/PositionStage.ts +++ b/src/processTargets/modifiers/PositionStage.ts @@ -1,5 +1,6 @@ import { Range } from "vscode"; -import { Position, PositionModifier, Target } from "../../typings/target.types"; +import { Target } from "../../typings/target.types"; +import { Position, PositionModifier } from "../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; import PositionTarget from "../targets/PositionTarget"; diff --git a/src/processTargets/modifiers/RawSelectionStage.ts b/src/processTargets/modifiers/RawSelectionStage.ts index 468fb8f23a..2b8da3ccb9 100644 --- a/src/processTargets/modifiers/RawSelectionStage.ts +++ b/src/processTargets/modifiers/RawSelectionStage.ts @@ -1,4 +1,5 @@ -import { RawSelectionModifier, Target } from "../../typings/target.types"; +import { Target } from "../../typings/target.types"; +import { RawSelectionModifier } from "../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; import RawSelectionTarget from "../targets/RawSelectionTarget"; diff --git a/src/processTargets/modifiers/SurroundingPairStage.ts b/src/processTargets/modifiers/SurroundingPairStage.ts index 017aa01b8f..2a32369cf3 100644 --- a/src/processTargets/modifiers/SurroundingPairStage.ts +++ b/src/processTargets/modifiers/SurroundingPairStage.ts @@ -1,7 +1,7 @@ import { - ContainingSurroundingPairModifier, Target, } from "../../typings/target.types"; +import { ContainingSurroundingPairModifier } from "../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; import SurroundingPairTarget from "../targets/SurroundingPairTarget"; diff --git a/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts b/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts index 443ab59e4b..222d772870 100644 --- a/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts @@ -2,11 +2,13 @@ import { Location, Selection } from "vscode"; import { SyntaxNode } from "web-tree-sitter"; import { getNodeMatcher } from "../../../languages/getNodeMatcher"; import { - ContainingScopeModifier, - EveryScopeModifier, - SimpleScopeType, Target, } from "../../../typings/target.types"; +import { + ContainingScopeModifier, + EveryScopeModifier, + SimpleScopeType +} from "../../../typings/targetDescriptor.types"; import { NodeMatcher, ProcessedTargetsContext, diff --git a/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts b/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts index 341eda1d2d..c64181296b 100644 --- a/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts @@ -1,9 +1,11 @@ import { Position, Range, TextEditor } from "vscode"; import { - ContainingScopeModifier, - EveryScopeModifier, Target, } from "../../../typings/target.types"; +import { + ContainingScopeModifier, + EveryScopeModifier +} from "../../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../../typings/Types"; import { ModifierStage } from "../../PipelineStages.types"; import DocumentTarget from "../../targets/DocumentTarget"; diff --git a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts index d0427670f2..94ef84b010 100644 --- a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts @@ -1,9 +1,11 @@ import { Range, TextEditor } from "vscode"; import { - ContainingScopeModifier, - EveryScopeModifier, Target, } from "../../../typings/target.types"; +import { + ContainingScopeModifier, + EveryScopeModifier +} from "../../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../../typings/Types"; import { ModifierStage } from "../../PipelineStages.types"; import LineTarget from "../../targets/LineTarget"; diff --git a/src/processTargets/modifiers/scopeTypeStages/NotebookCellStage.ts b/src/processTargets/modifiers/scopeTypeStages/NotebookCellStage.ts index df895fa1a5..e6fd7d98cf 100644 --- a/src/processTargets/modifiers/scopeTypeStages/NotebookCellStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/NotebookCellStage.ts @@ -1,8 +1,10 @@ import { - ContainingScopeModifier, - EveryScopeModifier, Target, } from "../../../typings/target.types"; +import { + ContainingScopeModifier, + EveryScopeModifier +} from "../../../typings/targetDescriptor.types"; import NotebookCellTarget from "../../targets/NotebookCellTarget"; import { ProcessedTargetsContext } from "../../../typings/Types"; import { ModifierStage } from "../../PipelineStages.types"; diff --git a/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts b/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts index c9abde566e..3f94950048 100644 --- a/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts @@ -1,9 +1,11 @@ import { Range } from "vscode"; import { - ContainingScopeModifier, - EveryScopeModifier, Target, } from "../../../typings/target.types"; +import { + ContainingScopeModifier, + EveryScopeModifier +} from "../../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../../typings/Types"; import { ModifierStage } from "../../PipelineStages.types"; import ParagraphTarget from "../../targets/ParagraphTarget"; diff --git a/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts b/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts index de7edc0898..7244b72fff 100644 --- a/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts @@ -1,9 +1,11 @@ import { Position, Range, TextEditor } from "vscode"; import { - ContainingScopeModifier, - EveryScopeModifier, Target, } from "../../../typings/target.types"; +import { + ContainingScopeModifier, + EveryScopeModifier +} from "../../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../../typings/Types"; import { ModifierStage } from "../../PipelineStages.types"; import ScopeTypeTarget from "../../targets/ScopeTypeTarget"; diff --git a/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts index 5714d67490..71b073138c 100644 --- a/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts @@ -1,9 +1,11 @@ import { Range, TextEditor } from "vscode"; import { - ContainingScopeModifier, - EveryScopeModifier, Target, } from "../../../typings/target.types"; +import { + ContainingScopeModifier, + EveryScopeModifier +} from "../../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../../typings/Types"; import { getTokensInRange, PartialToken } from "../../../util/getTokensInRange"; import { ModifierStage } from "../../PipelineStages.types"; diff --git a/src/processTargets/modifiers/surroundingPair/delimiterMaps.ts b/src/processTargets/modifiers/surroundingPair/delimiterMaps.ts index 68c40a19b6..ad3f6e0d84 100644 --- a/src/processTargets/modifiers/surroundingPair/delimiterMaps.ts +++ b/src/processTargets/modifiers/surroundingPair/delimiterMaps.ts @@ -1,7 +1,7 @@ import { ComplexSurroundingPairName, - SimpleSurroundingPairName, -} from "../../../typings/target.types"; + SimpleSurroundingPairName +} from "../../../typings/targetDescriptor.types"; type IndividualDelimiterText = string | string[]; diff --git a/src/processTargets/modifiers/surroundingPair/findDelimiterPairContainingSelection.ts b/src/processTargets/modifiers/surroundingPair/findDelimiterPairContainingSelection.ts index 68614fba17..692ed3c1c5 100644 --- a/src/processTargets/modifiers/surroundingPair/findDelimiterPairContainingSelection.ts +++ b/src/processTargets/modifiers/surroundingPair/findDelimiterPairContainingSelection.ts @@ -5,7 +5,7 @@ import { Offsets, } from "./types"; import { generateUnmatchedDelimiters } from "./generateUnmatchedDelimiters"; -import { SimpleSurroundingPairName } from "../../../typings/target.types"; +import { SimpleSurroundingPairName } from "../../../typings/targetDescriptor.types"; /** * Looks for a surrounding pair that contains the selection, returning null if none is found. diff --git a/src/processTargets/modifiers/surroundingPair/findOppositeDelimiter.ts b/src/processTargets/modifiers/surroundingPair/findOppositeDelimiter.ts index f7f4d3bad1..3f61c8e127 100644 --- a/src/processTargets/modifiers/surroundingPair/findOppositeDelimiter.ts +++ b/src/processTargets/modifiers/surroundingPair/findOppositeDelimiter.ts @@ -1,4 +1,4 @@ -import { SurroundingPairDirection } from "../../../typings/target.types"; +import { SurroundingPairDirection } from "../../../typings/targetDescriptor.types"; import { findUnmatchedDelimiter } from "./generateUnmatchedDelimiters"; import { DelimiterOccurrence, diff --git a/src/processTargets/modifiers/surroundingPair/findSurroundingPairCore.ts b/src/processTargets/modifiers/surroundingPair/findSurroundingPairCore.ts index 4f569c661e..d0485053b6 100644 --- a/src/processTargets/modifiers/surroundingPair/findSurroundingPairCore.ts +++ b/src/processTargets/modifiers/surroundingPair/findSurroundingPairCore.ts @@ -1,5 +1,5 @@ import { sortedIndexBy } from "lodash"; -import { SimpleSurroundingPairName } from "../../../typings/target.types"; +import { SimpleSurroundingPairName } from "../../../typings/targetDescriptor.types"; import { findDelimiterPairAdjacentToSelection } from "./findDelimiterPairAdjacentToSelection"; import { findDelimiterPairContainingSelection } from "./findDelimiterPairContainingSelection"; import { diff --git a/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts b/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts index ce1e24dee4..97e0d86ed5 100644 --- a/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts +++ b/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts @@ -2,8 +2,8 @@ import { Range, TextDocument, TextEditor } from "vscode"; import { SyntaxNode } from "web-tree-sitter"; import { SimpleSurroundingPairName, - SurroundingPairDirection, -} from "../../../typings/target.types"; + SurroundingPairDirection +} from "../../../typings/targetDescriptor.types"; import { getNodeRange } from "../../../util/nodeSelectors"; import { isContainedInErrorNode } from "../../../util/treeSitterUtils"; import { extractSelectionFromSurroundingPairOffsets } from "./extractSelectionFromSurroundingPairOffsets"; diff --git a/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts b/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts index 3eae43f80c..7c88166e8d 100644 --- a/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts +++ b/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts @@ -3,8 +3,8 @@ import { Range, TextDocument, TextEditor } from "vscode"; import { SimpleSurroundingPairName, SurroundingPairDirection, - SurroundingPairName, -} from "../../../typings/target.types"; + SurroundingPairName +} from "../../../typings/targetDescriptor.types"; import { getDocumentRange } from "../../../util/range"; import { matchAll } from "../../../util/regex"; import { extractSelectionFromSurroundingPairOffsets } from "./extractSelectionFromSurroundingPairOffsets"; diff --git a/src/processTargets/modifiers/surroundingPair/generateUnmatchedDelimiters.ts b/src/processTargets/modifiers/surroundingPair/generateUnmatchedDelimiters.ts index 4812c943d1..12c8e9cd10 100644 --- a/src/processTargets/modifiers/surroundingPair/generateUnmatchedDelimiters.ts +++ b/src/processTargets/modifiers/surroundingPair/generateUnmatchedDelimiters.ts @@ -1,5 +1,5 @@ import { range } from "lodash"; -import { SimpleSurroundingPairName } from "../../../typings/target.types"; +import { SimpleSurroundingPairName } from "../../../typings/targetDescriptor.types"; import { DelimiterOccurrence, DelimiterSide, diff --git a/src/processTargets/modifiers/surroundingPair/getIndividualDelimiters.ts b/src/processTargets/modifiers/surroundingPair/getIndividualDelimiters.ts index 5998d154f3..35dd7b0de4 100644 --- a/src/processTargets/modifiers/surroundingPair/getIndividualDelimiters.ts +++ b/src/processTargets/modifiers/surroundingPair/getIndividualDelimiters.ts @@ -1,4 +1,4 @@ -import { SimpleSurroundingPairName } from "../../../typings/target.types"; +import { SimpleSurroundingPairName } from "../../../typings/targetDescriptor.types"; import { IndividualDelimiter } from "./types"; import { delimiterToText } from "./delimiterMaps"; import { concat, uniq } from "lodash"; diff --git a/src/processTargets/modifiers/surroundingPair/index.ts b/src/processTargets/modifiers/surroundingPair/index.ts index c73a21e12a..e1c0e9e9b1 100644 --- a/src/processTargets/modifiers/surroundingPair/index.ts +++ b/src/processTargets/modifiers/surroundingPair/index.ts @@ -5,8 +5,8 @@ import getTextFragmentExtractor, { } from "../../../languages/getTextFragmentExtractor"; import { ComplexSurroundingPairName, - SurroundingPairScopeType, -} from "../../../typings/target.types"; + SurroundingPairScopeType +} from "../../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../../typings/Types"; import { complexDelimiterMap } from "./delimiterMaps"; import { SurroundingPairInfo } from "./extractSelectionFromSurroundingPairOffsets"; diff --git a/src/processTargets/modifiers/surroundingPair/types.ts b/src/processTargets/modifiers/surroundingPair/types.ts index 875a0530b8..428fe852b8 100644 --- a/src/processTargets/modifiers/surroundingPair/types.ts +++ b/src/processTargets/modifiers/surroundingPair/types.ts @@ -1,4 +1,4 @@ -import { SimpleSurroundingPairName } from "../../../typings/target.types"; +import { SimpleSurroundingPairName } from "../../../typings/targetDescriptor.types"; /** * Used to indicate whether a particular side of the delimiter is left or right diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index c021e3fcc6..357871a927 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -1,11 +1,12 @@ import { uniqWith, zip } from "lodash"; import { Range } from "vscode"; import { - PrimitiveTargetDescriptor, - RangeTargetDescriptor, Target, - TargetDescriptor, } from "../typings/target.types"; +import { + PrimitiveTargetDescriptor, + RangeTargetDescriptor, TargetDescriptor +} from "../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../typings/Types"; import { ensureSingleEditor } from "../util/targetUtils"; import getMarkStage from "./getMarkStage"; diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index 1a8c388e36..9c76a5b1dd 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -27,6 +27,7 @@ export default abstract class BaseTarget implements Target { isLine = false; isWeak = false; isRaw = false; + isNotebookCell = false; constructor(parameters: CommonTargetParameters) { this.state = { diff --git a/src/processTargets/targets/NotebookCellTarget.ts b/src/processTargets/targets/NotebookCellTarget.ts index ddfa09dcfb..b4c3e62590 100644 --- a/src/processTargets/targets/NotebookCellTarget.ts +++ b/src/processTargets/targets/NotebookCellTarget.ts @@ -5,6 +5,7 @@ import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; export default class NotebookCellTarget extends BaseTarget { insertionDelimiter = "\n"; + isNotebookCell = true; constructor(parameters: CommonTargetParameters) { super(parameters); diff --git a/src/processTargets/targets/PositionTarget.ts b/src/processTargets/targets/PositionTarget.ts index 996305ad8c..6a2f6adf45 100644 --- a/src/processTargets/targets/PositionTarget.ts +++ b/src/processTargets/targets/PositionTarget.ts @@ -1,6 +1,7 @@ import * as vscode from "vscode"; import { Range, TextEditor } from "vscode"; -import { Position, Target } from "../../typings/target.types"; +import { Target } from "../../typings/target.types"; +import { Position } from "../../typings/targetDescriptor.types"; import { EditWithRangeUpdater } from "../../typings/Types"; import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; diff --git a/src/processTargets/targets/ScopeTypeTarget.ts b/src/processTargets/targets/ScopeTypeTarget.ts index dcd1b1d838..c41b976513 100644 --- a/src/processTargets/targets/ScopeTypeTarget.ts +++ b/src/processTargets/targets/ScopeTypeTarget.ts @@ -1,5 +1,6 @@ import { Range } from "vscode"; -import { SimpleScopeTypeType, Target } from "../../typings/target.types"; +import { Target } from "../../typings/target.types"; +import { SimpleScopeTypeType } from "../../typings/targetDescriptor.types"; import { isSameType } from "../../util/typeUtils"; import { createContinuousRange, diff --git a/src/scripts/transformRecordedTests/transformations/upgradeFromVersion0.ts b/src/scripts/transformRecordedTests/transformations/upgradeFromVersion0.ts index edea866e53..a6892c0442 100644 --- a/src/scripts/transformRecordedTests/transformations/upgradeFromVersion0.ts +++ b/src/scripts/transformRecordedTests/transformations/upgradeFromVersion0.ts @@ -1,6 +1,6 @@ import { TestCaseFixture } from "../../../testUtil/TestCase"; import { transformPartialPrimitiveTargets } from "../../../util/getPrimitiveTargets"; -import { PartialPrimitiveTargetDesc } from "../../../typings/target.types"; +import { PartialPrimitiveTargetDesc } from "../../../typings/targetDescriptor.types"; export function upgradeFromVersion0(fixture: TestCaseFixture) { const { command, spokenForm: oldSpokenForm, ...rest } = fixture as any; diff --git a/src/testUtil/TestCase.ts b/src/testUtil/TestCase.ts index bafad84787..5068d8b65e 100644 --- a/src/testUtil/TestCase.ts +++ b/src/testUtil/TestCase.ts @@ -4,7 +4,7 @@ import { CommandLatest } from "../core/commandRunner/command.types"; import { TestDecoration } from "../core/editStyles"; import { ReadOnlyHatMap } from "../core/IndividualHatMap"; import { ThatMark } from "../core/ThatMark"; -import { TargetDescriptor } from "../typings/target.types"; +import { TargetDescriptor } from "../typings/targetDescriptor.types"; import { Token } from "../typings/Types"; import { cleanUpTestCaseCommand } from "./cleanUpTestCaseCommand"; import { diff --git a/src/testUtil/TestCaseRecorder.ts b/src/testUtil/TestCaseRecorder.ts index b26d7cd2da..0767cdadb2 100644 --- a/src/testUtil/TestCaseRecorder.ts +++ b/src/testUtil/TestCaseRecorder.ts @@ -4,7 +4,7 @@ import * as path from "path"; import * as vscode from "vscode"; import HatTokenMap from "../core/HatTokenMap"; import { Graph } from "../typings/Types"; -import { DecoratedSymbolMark } from "../typings/target.types"; +import { DecoratedSymbolMark } from "../typings/targetDescriptor.types"; import { getDocumentRange } from "../util/range"; import sleep from "../util/sleep"; import { extractTargetedMarks } from "./extractTargetedMarks"; diff --git a/src/testUtil/extractTargetedMarks.ts b/src/testUtil/extractTargetedMarks.ts index 9313180c49..ec94439c2c 100644 --- a/src/testUtil/extractTargetedMarks.ts +++ b/src/testUtil/extractTargetedMarks.ts @@ -3,8 +3,8 @@ import HatTokenMap from "../core/HatTokenMap"; import { Token } from "../typings/Types"; import { PrimitiveTargetDescriptor, - TargetDescriptor, -} from "../typings/target.types"; + TargetDescriptor +} from "../typings/targetDescriptor.types"; function extractPrimitiveTargetKeys(...targets: PrimitiveTargetDescriptor[]) { const keys: string[] = []; diff --git a/src/typings/snippet.ts b/src/typings/snippet.ts index e96872f663..940a2f9391 100644 --- a/src/typings/snippet.ts +++ b/src/typings/snippet.ts @@ -1,4 +1,4 @@ -import { ScopeType, SimpleScopeTypeType } from "./target.types"; +import { ScopeType, SimpleScopeTypeType } from "./targetDescriptor.types"; export interface SnippetScope { langIds?: string[]; diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 63081bc4b9..176cedf8c2 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -1,273 +1,6 @@ import { Range, Selection, TextEditor } from "vscode"; -import { HatStyleName } from "../core/constants"; import { EditWithRangeUpdater } from "./Types"; -export interface CursorMark { - type: "cursor"; -} - -export interface ThatMark { - type: "that"; -} - -export interface SourceMark { - type: "source"; -} - -export interface NothingMark { - type: "nothing"; -} - -export interface LastCursorPositionMark { - type: "lastCursorPosition"; -} - -export interface DecoratedSymbolMark { - type: "decoratedSymbol"; - symbolColor: HatStyleName; - character: string; -} - -export type LineNumberType = "absolute" | "relative" | "modulo100"; - -export interface LineNumberPosition { - type: LineNumberType; - lineNumber: number; -} - -export interface LineNumberMark { - type: "lineNumber"; - anchor: LineNumberPosition; - active: LineNumberPosition; -} - -export type Mark = - | CursorMark - | ThatMark - | SourceMark - // | LastCursorPositionMark Not implemented yet - | DecoratedSymbolMark - | NothingMark - | LineNumberMark; - -export type SimpleSurroundingPairName = - | "angleBrackets" - | "backtickQuotes" - | "curlyBrackets" - | "doubleQuotes" - | "escapedDoubleQuotes" - | "escapedParentheses" - | "escapedSquareBrackets" - | "escapedSingleQuotes" - | "parentheses" - | "singleQuotes" - | "squareBrackets"; -export type ComplexSurroundingPairName = "string" | "any"; -export type SurroundingPairName = - | SimpleSurroundingPairName - | ComplexSurroundingPairName; - -export type SimpleScopeTypeType = - | "argumentOrParameter" - | "anonymousFunction" - | "attribute" - | "class" - | "className" - | "collectionItem" - | "collectionKey" - | "comment" - | "functionCall" - | "functionName" - | "ifStatement" - | "list" - | "map" - | "name" - | "namedFunction" - | "regularExpression" - | "statement" - | "string" - | "type" - | "value" - | "condition" - | "section" - | "sectionLevelOne" - | "sectionLevelTwo" - | "sectionLevelThree" - | "sectionLevelFour" - | "sectionLevelFive" - | "sectionLevelSix" - | "selector" - | "xmlBothTags" - | "xmlElement" - | "xmlEndTag" - | "xmlStartTag" - // Text based scopes - | "token" - | "line" - | "notebookCell" - | "paragraph" - | "document" - | "character" - | "word" - | "nonWhitespaceSequence" - | "url"; - -export interface SimpleScopeType { - type: SimpleScopeTypeType; -} - -export type SurroundingPairDirection = "left" | "right"; -export interface SurroundingPairScopeType { - type: "surroundingPair"; - delimiter: SurroundingPairName; - forceDirection?: SurroundingPairDirection; -} - -export type ScopeType = SimpleScopeType | SurroundingPairScopeType; - -export interface ContainingSurroundingPairModifier - extends ContainingScopeModifier { - scopeType: SurroundingPairScopeType; -} - -export interface InteriorOnlyModifier { - type: "interiorOnly"; -} - -export interface ExcludeInteriorModifier { - type: "excludeInterior"; -} - -export interface ContainingScopeModifier { - type: "containingScope"; - scopeType: ScopeType; -} - -export interface EveryScopeModifier { - type: "everyScope"; - scopeType: ScopeType; -} - -export interface OrdinalRangeModifier { - type: "ordinalRange"; - scopeType: ScopeType; - anchor: number; - active: number; - excludeAnchor?: boolean; - excludeActive?: boolean; -} - -/** - * Converts its input to a raw selection with no type information so for - * example if it is the destination of a bring or move it should inherit the - * type information such as delimiters from its source. - */ -export interface RawSelectionModifier { - type: "toRawSelection"; -} - -export interface HeadModifier { - type: "extendThroughStartOf"; -} - -export interface TailModifier { - type: "extendThroughEndOf"; -} - -export interface LeadingModifier { - type: "leading"; -} - -export interface TrailingModifier { - type: "trailing"; -} - -export type Position = "before" | "after" | "start" | "end"; - -export interface PositionModifier { - type: "position"; - position: Position; -} - -export interface PartialPrimitiveTargetDesc { - type: "primitive"; - mark?: Mark; - modifiers?: Modifier[]; - isImplicit?: boolean; -} - -export type Modifier = - | PositionModifier - | InteriorOnlyModifier - | ExcludeInteriorModifier - | ContainingScopeModifier - | EveryScopeModifier - | OrdinalRangeModifier - | HeadModifier - | TailModifier - | LeadingModifier - | TrailingModifier - | RawSelectionModifier; - -export interface PartialRangeTargetDesc { - type: "range"; - anchor: PartialPrimitiveTargetDesc; - active: PartialPrimitiveTargetDesc; - excludeAnchor: boolean; - excludeActive: boolean; - rangeType?: RangeType; -} - -export interface PartialListTargetDesc { - type: "list"; - elements: (PartialPrimitiveTargetDesc | PartialRangeTargetDesc)[]; -} - -export type PartialTargetDesc = - | PartialPrimitiveTargetDesc - | PartialRangeTargetDesc - | PartialListTargetDesc; - -export interface PrimitiveTargetDescriptor extends PartialPrimitiveTargetDesc { - /** - * The mark, eg "air", "this", "that", etc - */ - mark: Mark; - - /** - * Zero or more modifiers that will be applied in sequence to the output from - * the mark. Note that the modifiers will be applied in reverse order. For - * example, if the user says "take first char name air", then we will apply - * "name" to the output of "air" to select the name of the function or - * statement containing "air", then apply "first char" to select the first - * character of the name. - */ - modifiers: Modifier[]; -} - -export interface RangeTargetDescriptor { - type: "range"; - anchor: PrimitiveTargetDescriptor; - active: PrimitiveTargetDescriptor; - excludeAnchor: boolean; - excludeActive: boolean; - rangeType: RangeType; -} - -// continuous is one single continuous selection between the two targets -// vertical puts a selection on each line vertically between the two targets -export type RangeType = "continuous" | "vertical"; - -export interface ListTargetDescriptor { - type: "list"; - elements: (PrimitiveTargetDescriptor | RangeTargetDescriptor)[]; -} - -export type TargetDescriptor = - | PrimitiveTargetDescriptor - | RangeTargetDescriptor - | ListTargetDescriptor; - export interface EditNewCommandContext { type: "command"; command: string; @@ -302,6 +35,9 @@ export interface Target { /** If true this target is a raw selection and its insertion delimiter should not be used on bring action */ readonly isRaw: boolean; + /** If true this target is a notebook cell */ + readonly isNotebookCell: boolean; + /** The text contained in the content range */ readonly contentText: string; diff --git a/src/typings/targetDescriptor.types.ts b/src/typings/targetDescriptor.types.ts new file mode 100644 index 0000000000..db7e468825 --- /dev/null +++ b/src/typings/targetDescriptor.types.ts @@ -0,0 +1,267 @@ +import { HatStyleName } from "../core/constants"; + +export interface CursorMark { + type: "cursor"; +} + +export interface ThatMark { + type: "that"; +} + +export interface SourceMark { + type: "source"; +} + +export interface NothingMark { + type: "nothing"; +} + +export interface LastCursorPositionMark { + type: "lastCursorPosition"; +} + +export interface DecoratedSymbolMark { + type: "decoratedSymbol"; + symbolColor: HatStyleName; + character: string; +} + +export type LineNumberType = "absolute" | "relative" | "modulo100"; + +export interface LineNumberPosition { + type: LineNumberType; + lineNumber: number; +} + +export interface LineNumberMark { + type: "lineNumber"; + anchor: LineNumberPosition; + active: LineNumberPosition; +} + +export type Mark = + | CursorMark + | ThatMark + | SourceMark + // | LastCursorPositionMark Not implemented yet + | DecoratedSymbolMark + | NothingMark + | LineNumberMark; + +export type SimpleSurroundingPairName = + | "angleBrackets" + | "backtickQuotes" + | "curlyBrackets" + | "doubleQuotes" + | "escapedDoubleQuotes" + | "escapedParentheses" + | "escapedSquareBrackets" + | "escapedSingleQuotes" + | "parentheses" + | "singleQuotes" + | "squareBrackets"; +export type ComplexSurroundingPairName = "string" | "any"; +export type SurroundingPairName = + | SimpleSurroundingPairName + | ComplexSurroundingPairName; + +export type SimpleScopeTypeType = + | "argumentOrParameter" + | "anonymousFunction" + | "attribute" + | "class" + | "className" + | "collectionItem" + | "collectionKey" + | "comment" + | "functionCall" + | "functionName" + | "ifStatement" + | "list" + | "map" + | "name" + | "namedFunction" + | "regularExpression" + | "statement" + | "string" + | "type" + | "value" + | "condition" + | "section" + | "sectionLevelOne" + | "sectionLevelTwo" + | "sectionLevelThree" + | "sectionLevelFour" + | "sectionLevelFive" + | "sectionLevelSix" + | "selector" + | "xmlBothTags" + | "xmlElement" + | "xmlEndTag" + | "xmlStartTag" + // Text based scopes + | "token" + | "line" + | "notebookCell" + | "paragraph" + | "document" + | "character" + | "word" + | "nonWhitespaceSequence" + | "url"; + +export interface SimpleScopeType { + type: SimpleScopeTypeType; +} + +export type SurroundingPairDirection = "left" | "right"; +export interface SurroundingPairScopeType { + type: "surroundingPair"; + delimiter: SurroundingPairName; + forceDirection?: SurroundingPairDirection; +} + +export type ScopeType = SimpleScopeType | SurroundingPairScopeType; + +export interface ContainingSurroundingPairModifier + extends ContainingScopeModifier { + scopeType: SurroundingPairScopeType; +} + +export interface InteriorOnlyModifier { + type: "interiorOnly"; +} + +export interface ExcludeInteriorModifier { + type: "excludeInterior"; +} + +export interface ContainingScopeModifier { + type: "containingScope"; + scopeType: ScopeType; +} + +export interface EveryScopeModifier { + type: "everyScope"; + scopeType: ScopeType; +} + +export interface OrdinalRangeModifier { + type: "ordinalRange"; + scopeType: ScopeType; + anchor: number; + active: number; + excludeAnchor?: boolean; + excludeActive?: boolean; +} +/** + * Converts its input to a raw selection with no type information so for + * example if it is the destination of a bring or move it should inherit the + * type information such as delimiters from its source. + */ + +export interface RawSelectionModifier { + type: "toRawSelection"; +} + +export interface HeadModifier { + type: "extendThroughStartOf"; +} + +export interface TailModifier { + type: "extendThroughEndOf"; +} + +export interface LeadingModifier { + type: "leading"; +} + +export interface TrailingModifier { + type: "trailing"; +} + +export type Position = "before" | "after" | "start" | "end"; + +export interface PositionModifier { + type: "position"; + position: Position; +} + +export interface PartialPrimitiveTargetDesc { + type: "primitive"; + mark?: Mark; + modifiers?: Modifier[]; + isImplicit?: boolean; +} + +export type Modifier = + | PositionModifier + | InteriorOnlyModifier + | ExcludeInteriorModifier + | ContainingScopeModifier + | EveryScopeModifier + | OrdinalRangeModifier + | HeadModifier + | TailModifier + | LeadingModifier + | TrailingModifier + | RawSelectionModifier; + +export interface PartialRangeTargetDesc { + type: "range"; + anchor: PartialPrimitiveTargetDesc; + active: PartialPrimitiveTargetDesc; + excludeAnchor: boolean; + excludeActive: boolean; + rangeType?: RangeType; +} + +export interface PartialListTargetDesc { + type: "list"; + elements: (PartialPrimitiveTargetDesc | PartialRangeTargetDesc)[]; +} + +export type PartialTargetDesc = + | PartialPrimitiveTargetDesc + | PartialRangeTargetDesc + | PartialListTargetDesc; + +export interface PrimitiveTargetDescriptor extends PartialPrimitiveTargetDesc { + /** + * The mark, eg "air", "this", "that", etc + */ + mark: Mark; + + /** + * Zero or more modifiers that will be applied in sequence to the output from + * the mark. Note that the modifiers will be applied in reverse order. For + * example, if the user says "take first char name air", then we will apply + * "name" to the output of "air" to select the name of the function or + * statement containing "air", then apply "first char" to select the first + * character of the name. + */ + modifiers: Modifier[]; +} + +export interface RangeTargetDescriptor { + type: "range"; + anchor: PrimitiveTargetDescriptor; + active: PrimitiveTargetDescriptor; + excludeAnchor: boolean; + excludeActive: boolean; + rangeType: RangeType; +} +// continuous is one single continuous selection between the two targets +// vertical puts a selection on each line vertically between the two targets + +export type RangeType = "continuous" | "vertical"; + +export interface ListTargetDescriptor { + type: "list"; + elements: (PrimitiveTargetDescriptor | RangeTargetDescriptor)[]; +} + +export type TargetDescriptor = + | PrimitiveTargetDescriptor + | RangeTargetDescriptor + | ListTargetDescriptor; diff --git a/src/util/getPrimitiveTargets.ts b/src/util/getPrimitiveTargets.ts index 5d550cf608..996b463303 100644 --- a/src/util/getPrimitiveTargets.ts +++ b/src/util/getPrimitiveTargets.ts @@ -3,8 +3,8 @@ import { PartialRangeTargetDesc, PartialTargetDesc, PrimitiveTargetDescriptor, - TargetDescriptor, -} from "../typings/target.types"; + TargetDescriptor +} from "../typings/targetDescriptor.types"; /** * Given a list of targets, recursively descends all targets and returns every diff --git a/src/util/nodeMatchers.ts b/src/util/nodeMatchers.ts index 6a47f7c2d3..e4bc87f8ec 100644 --- a/src/util/nodeMatchers.ts +++ b/src/util/nodeMatchers.ts @@ -6,7 +6,7 @@ import { NodeMatcherAlternative, SelectionWithEditor, } from "../typings/Types"; -import { SimpleScopeTypeType } from "../typings/target.types"; +import { SimpleScopeTypeType } from "../typings/targetDescriptor.types"; import { simpleSelectionExtractor, argumentSelectionExtractor, From 9eb2010f94a221f585953404e99b027247900a34 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Thu, 2 Jun 2022 17:19:48 +0100 Subject: [PATCH 284/314] Separate notebook cell edit new from regular edit new --- src/actions/EditNew.ts | 63 +++++++++++++------ .../targets/NotebookCellTarget.ts | 18 ++---- src/typings/target.types.ts | 1 - 3 files changed, 48 insertions(+), 34 deletions(-) diff --git a/src/actions/EditNew.ts b/src/actions/EditNew.ts index 94cc1e2324..4cf27062e9 100644 --- a/src/actions/EditNew.ts +++ b/src/actions/EditNew.ts @@ -12,11 +12,16 @@ import { } from "../core/updateSelections/updateSelections"; import { weakContainingLineStage } from "../processTargets/modifiers/commonWeakContainingScopeStages"; import { toPositionTarget } from "../processTargets/modifiers/PositionStage"; +import NotebookCellTarget from "../processTargets/targets/NotebookCellTarget"; import { Target } from "../typings/target.types"; import { Graph } from "../typings/Types"; import { selectionFromRange } from "../util/selectionUtils"; import { setSelectionsAndFocusEditor } from "../util/setSelectionsAndFocusEditor"; -import { createThatMark, ensureSingleEditor } from "../util/targetUtils"; +import { + createThatMark, + ensureSingleEditor, + ensureSingleTarget, +} from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; class EditNew implements Action { @@ -27,6 +32,10 @@ class EditNew implements Action { } async run([targets]: [Target[]]): Promise { + if (targets.some((target) => target.isNotebookCell)) { + return this.handleNotebookCellTargets(targets); + } + const editor = ensureSingleEditor(targets); const richTargets: RichTarget[] = targets.map((target) => { @@ -41,14 +50,12 @@ class EditNew implements Action { ...common, type: "command", command: context.command, - updateSelection: !context.dontUpdateSelection, }; case "delimiter": return { ...common, type: "delimiter", delimiter: context.delimiter, - updateSelection: true, }; } }); @@ -67,19 +74,35 @@ class EditNew implements Action { await this.runDelimiterTargets(editor, commandTargets, delimiterTargets); } - // Only update selection if all targets are agreeing on this - if (!richTargets.some(({ updateSelection }) => !updateSelection)) { - const newSelections = richTargets.map((target) => - selectionFromRange(target.target.isReversed, target.cursorRange) - ); - await setSelectionsAndFocusEditor(editor, newSelections); - } + const newSelections = richTargets.map((target) => + selectionFromRange(target.target.isReversed, target.cursorRange) + ); + await setSelectionsAndFocusEditor(editor, newSelections); return { thatMark: createThatMark(richTargets.map(({ target }) => target)), }; } + async handleNotebookCellTargets( + targets: Target[] + ): Promise { + const target = ensureSingleTarget(targets) as NotebookCellTarget; + await this.setSelections([target]); + const command = target.getEditNewCommand(this.isBefore); + await commands.executeCommand(command); + + const thatTarget = ? target.thatTarget : ; + let thatMark = createThatMark([target.thatTarget]); + if (command === "jupyter.insertCellAbove") { + thatMark. + } + + return { + thatMark, + }; + } + async runDelimiterTargets( editor: TextEditor, commandTargets: CommandTarget[], @@ -129,15 +152,7 @@ class EditNew implements Action { ) { const command = ensureSingleCommand(commandTargets); - if (this.isBefore) { - await this.graph.actions.setSelectionBefore.run([ - commandTargets.map(({ target }) => target), - ]); - } else { - await this.graph.actions.setSelectionAfter.run([ - commandTargets.map(({ target }) => target), - ]); - } + await this.setSelections(commandTargets.map(({ target }) => target)); const [updatedTargetRanges, updatedCursorRanges] = await callFunctionAndUpdateRanges( @@ -153,6 +168,14 @@ class EditNew implements Action { updateTargets(targets, updatedTargetRanges, updatedCursorRanges); updateCommandTargets(commandTargets, editor.selections); } + + private async setSelections(targets: Target[]) { + if (this.isBefore) { + await this.graph.actions.setSelectionBefore.run([targets]); + } else { + await this.graph.actions.setSelectionAfter.run([targets]); + } + } } export class EditNewBefore extends EditNew { @@ -170,8 +193,8 @@ export class EditNewAfter extends EditNew { interface CommonTarget { target: Target; cursorRange: Range; - updateSelection: boolean; } + interface CommandTarget extends CommonTarget { type: "command"; command: string; diff --git a/src/processTargets/targets/NotebookCellTarget.ts b/src/processTargets/targets/NotebookCellTarget.ts index b4c3e62590..50bd63c807 100644 --- a/src/processTargets/targets/NotebookCellTarget.ts +++ b/src/processTargets/targets/NotebookCellTarget.ts @@ -15,21 +15,13 @@ export default class NotebookCellTarget extends BaseTarget { getTrailingDelimiterTarget = () => undefined; getRemovalRange = () => this.contentRange; - getEditNewContext(isBefore: boolean): EditNewContext { + getEditNewCommand(isBefore: boolean): string { if (this.isNotebookEditor(this.editor)) { - return { - type: "command", - dontUpdateSelection: true, - command: isBefore - ? "notebook.cell.insertCodeCellAbove" - : "notebook.cell.insertCodeCellBelow", - }; + return isBefore + ? "notebook.cell.insertCodeCellAbove" + : "notebook.cell.insertCodeCellBelow"; } - return { - type: "command", - dontUpdateSelection: true, - command: isBefore ? "jupyter.insertCellAbove" : "jupyter.insertCellBelow", - }; + return isBefore ? "jupyter.insertCellAbove" : "jupyter.insertCellBelow"; } protected getCloneParameters() { diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 176cedf8c2..6de21efaf3 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -4,7 +4,6 @@ import { EditWithRangeUpdater } from "./Types"; export interface EditNewCommandContext { type: "command"; command: string; - dontUpdateSelection?: boolean; } export interface EditNewDelimiterContext { type: "delimiter"; From e4ee36f599d7e37ccebe8e1a2c7425b4e1ac46bd Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 2 Jun 2022 16:20:26 +0000 Subject: [PATCH 285/314] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/actions/EditNew.ts | 2 +- .../canonicalizeAndValidateCommand.ts | 2 +- src/core/commandVersionUpgrades/canonicalizeTargets.ts | 2 +- .../commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts | 2 +- src/core/inferFullTargets.ts | 2 +- src/processTargets/getModifierStage.ts | 2 +- src/processTargets/marks/LineNumberStage.ts | 5 ++++- src/processTargets/modifiers/HeadTailStage.ts | 5 ++++- src/processTargets/modifiers/InteriorStage.ts | 6 ++---- src/processTargets/modifiers/LeadingTrailingStages.ts | 7 ++++--- src/processTargets/modifiers/OrdinalRangeSubTokenStage.ts | 6 ++---- src/processTargets/modifiers/PositionStage.ts | 5 ++++- src/processTargets/modifiers/SurroundingPairStage.ts | 4 +--- .../scopeTypeStages/ContainingSyntaxScopeStage.ts | 6 ++---- .../modifiers/scopeTypeStages/DocumentStage.ts | 6 ++---- src/processTargets/modifiers/scopeTypeStages/LineStage.ts | 6 ++---- .../modifiers/scopeTypeStages/NotebookCellStage.ts | 6 ++---- .../modifiers/scopeTypeStages/ParagraphStage.ts | 6 ++---- src/processTargets/modifiers/scopeTypeStages/RegexStage.ts | 6 ++---- src/processTargets/modifiers/scopeTypeStages/TokenStage.ts | 6 ++---- .../modifiers/surroundingPair/delimiterMaps.ts | 2 +- .../surroundingPair/findSurroundingPairParseTreeBased.ts | 2 +- .../surroundingPair/findSurroundingPairTextBased.ts | 2 +- src/processTargets/modifiers/surroundingPair/index.ts | 2 +- src/processTargets/processTargets.ts | 7 +++---- src/testUtil/extractTargetedMarks.ts | 2 +- src/util/getPrimitiveTargets.ts | 2 +- 27 files changed, 50 insertions(+), 61 deletions(-) diff --git a/src/actions/EditNew.ts b/src/actions/EditNew.ts index 4cf27062e9..b5f737672d 100644 --- a/src/actions/EditNew.ts +++ b/src/actions/EditNew.ts @@ -97,7 +97,7 @@ class EditNew implements Action { if (command === "jupyter.insertCellAbove") { thatMark. } - + return { thatMark, }; diff --git a/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts b/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts index 6099277bee..2c4d4424a3 100644 --- a/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts +++ b/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts @@ -3,7 +3,7 @@ import { ActionableError } from "../../errors"; import { Modifier, PartialTargetDesc, - SimpleScopeTypeType + SimpleScopeTypeType, } from "../../typings/targetDescriptor.types"; import { ActionType } from "../../actions/actions.types"; import { getPartialPrimitiveTargets } from "../../util/getPrimitiveTargets"; diff --git a/src/core/commandVersionUpgrades/canonicalizeTargets.ts b/src/core/commandVersionUpgrades/canonicalizeTargets.ts index d4d7b8af05..37a0ea352a 100644 --- a/src/core/commandVersionUpgrades/canonicalizeTargets.ts +++ b/src/core/commandVersionUpgrades/canonicalizeTargets.ts @@ -3,7 +3,7 @@ import { flow } from "lodash"; import { PartialPrimitiveTargetDesc, PartialTargetDesc, - SimpleScopeTypeType + SimpleScopeTypeType, } from "../../typings/targetDescriptor.types"; import { transformPartialPrimitiveTargets } from "../../util/getPrimitiveTargets"; import { HatStyleName } from "../constants"; diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts index 859ae10e87..114ac70dbf 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts @@ -4,7 +4,7 @@ import { PartialPrimitiveTargetDesc, PartialRangeTargetDesc, PartialTargetDesc, - SimpleScopeTypeType + SimpleScopeTypeType, } from "../../../typings/targetDescriptor.types"; import { ActionType } from "../../../actions/actions.types"; import { transformPartialPrimitiveTargets } from "../../../util/getPrimitiveTargets"; diff --git a/src/core/inferFullTargets.ts b/src/core/inferFullTargets.ts index 7dc0c8aa2b..7f65422bb7 100644 --- a/src/core/inferFullTargets.ts +++ b/src/core/inferFullTargets.ts @@ -5,7 +5,7 @@ import { PartialTargetDesc, PrimitiveTargetDescriptor, RangeTargetDescriptor, - TargetDescriptor + TargetDescriptor, } from "../typings/targetDescriptor.types"; /** diff --git a/src/processTargets/getModifierStage.ts b/src/processTargets/getModifierStage.ts index af0b7f035c..5d40653d5b 100644 --- a/src/processTargets/getModifierStage.ts +++ b/src/processTargets/getModifierStage.ts @@ -2,7 +2,7 @@ import { ContainingScopeModifier, ContainingSurroundingPairModifier, EveryScopeModifier, - Modifier + Modifier, } from "../typings/targetDescriptor.types"; import { HeadStage, TailStage } from "./modifiers/HeadTailStage"; import { diff --git a/src/processTargets/marks/LineNumberStage.ts b/src/processTargets/marks/LineNumberStage.ts index 1d6c37690e..955264936f 100644 --- a/src/processTargets/marks/LineNumberStage.ts +++ b/src/processTargets/marks/LineNumberStage.ts @@ -1,5 +1,8 @@ import { TextEditor } from "vscode"; -import { LineNumberMark, LineNumberPosition } from "../../typings/targetDescriptor.types"; +import { + LineNumberMark, + LineNumberPosition, +} from "../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { createLineTarget } from "../modifiers/scopeTypeStages/LineStage"; import { MarkStage } from "../PipelineStages.types"; diff --git a/src/processTargets/modifiers/HeadTailStage.ts b/src/processTargets/modifiers/HeadTailStage.ts index 322578b3b6..175eaceb64 100644 --- a/src/processTargets/modifiers/HeadTailStage.ts +++ b/src/processTargets/modifiers/HeadTailStage.ts @@ -1,6 +1,9 @@ import { Position, Range, TextEditor } from "vscode"; import { Target } from "../../typings/target.types"; -import { HeadModifier, TailModifier } from "../../typings/targetDescriptor.types"; +import { + HeadModifier, + TailModifier, +} from "../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; import TokenTarget from "../targets/TokenTarget"; diff --git a/src/processTargets/modifiers/InteriorStage.ts b/src/processTargets/modifiers/InteriorStage.ts index afb67e8b8c..2905b7fec3 100644 --- a/src/processTargets/modifiers/InteriorStage.ts +++ b/src/processTargets/modifiers/InteriorStage.ts @@ -1,9 +1,7 @@ -import { - Target, -} from "../../typings/target.types"; +import { Target } from "../../typings/target.types"; import { ExcludeInteriorModifier, - InteriorOnlyModifier + InteriorOnlyModifier, } from "../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; diff --git a/src/processTargets/modifiers/LeadingTrailingStages.ts b/src/processTargets/modifiers/LeadingTrailingStages.ts index 54c22e0905..0494e08290 100644 --- a/src/processTargets/modifiers/LeadingTrailingStages.ts +++ b/src/processTargets/modifiers/LeadingTrailingStages.ts @@ -1,7 +1,8 @@ +import { Target } from "../../typings/target.types"; import { - Target, -} from "../../typings/target.types"; -import { LeadingModifier, TrailingModifier } from "../../typings/targetDescriptor.types"; + LeadingModifier, + TrailingModifier, +} from "../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; diff --git a/src/processTargets/modifiers/OrdinalRangeSubTokenStage.ts b/src/processTargets/modifiers/OrdinalRangeSubTokenStage.ts index 76a19cc724..ac1d14855b 100644 --- a/src/processTargets/modifiers/OrdinalRangeSubTokenStage.ts +++ b/src/processTargets/modifiers/OrdinalRangeSubTokenStage.ts @@ -1,12 +1,10 @@ import { range } from "lodash"; import { Range } from "vscode"; import { SUBWORD_MATCHER } from "../../core/constants"; -import { - Target, -} from "../../typings/target.types"; +import { Target } from "../../typings/target.types"; import { OrdinalRangeModifier, - SimpleScopeType + SimpleScopeType, } from "../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; diff --git a/src/processTargets/modifiers/PositionStage.ts b/src/processTargets/modifiers/PositionStage.ts index 1c19ab9cfb..492f1fb0c0 100644 --- a/src/processTargets/modifiers/PositionStage.ts +++ b/src/processTargets/modifiers/PositionStage.ts @@ -1,6 +1,9 @@ import { Range } from "vscode"; import { Target } from "../../typings/target.types"; -import { Position, PositionModifier } from "../../typings/targetDescriptor.types"; +import { + Position, + PositionModifier, +} from "../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; import PositionTarget from "../targets/PositionTarget"; diff --git a/src/processTargets/modifiers/SurroundingPairStage.ts b/src/processTargets/modifiers/SurroundingPairStage.ts index 2a32369cf3..bb92ef29b1 100644 --- a/src/processTargets/modifiers/SurroundingPairStage.ts +++ b/src/processTargets/modifiers/SurroundingPairStage.ts @@ -1,6 +1,4 @@ -import { - Target, -} from "../../typings/target.types"; +import { Target } from "../../typings/target.types"; import { ContainingSurroundingPairModifier } from "../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../typings/Types"; import { ModifierStage } from "../PipelineStages.types"; diff --git a/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts b/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts index 222d772870..3ac451c89c 100644 --- a/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts @@ -1,13 +1,11 @@ import { Location, Selection } from "vscode"; import { SyntaxNode } from "web-tree-sitter"; import { getNodeMatcher } from "../../../languages/getNodeMatcher"; -import { - Target, -} from "../../../typings/target.types"; +import { Target } from "../../../typings/target.types"; import { ContainingScopeModifier, EveryScopeModifier, - SimpleScopeType + SimpleScopeType, } from "../../../typings/targetDescriptor.types"; import { NodeMatcher, diff --git a/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts b/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts index c64181296b..ebd7dcd39c 100644 --- a/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/DocumentStage.ts @@ -1,10 +1,8 @@ import { Position, Range, TextEditor } from "vscode"; -import { - Target, -} from "../../../typings/target.types"; +import { Target } from "../../../typings/target.types"; import { ContainingScopeModifier, - EveryScopeModifier + EveryScopeModifier, } from "../../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../../typings/Types"; import { ModifierStage } from "../../PipelineStages.types"; diff --git a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts index 94ef84b010..2e8afefcfa 100644 --- a/src/processTargets/modifiers/scopeTypeStages/LineStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/LineStage.ts @@ -1,10 +1,8 @@ import { Range, TextEditor } from "vscode"; -import { - Target, -} from "../../../typings/target.types"; +import { Target } from "../../../typings/target.types"; import { ContainingScopeModifier, - EveryScopeModifier + EveryScopeModifier, } from "../../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../../typings/Types"; import { ModifierStage } from "../../PipelineStages.types"; diff --git a/src/processTargets/modifiers/scopeTypeStages/NotebookCellStage.ts b/src/processTargets/modifiers/scopeTypeStages/NotebookCellStage.ts index e6fd7d98cf..0ff8c9b5e8 100644 --- a/src/processTargets/modifiers/scopeTypeStages/NotebookCellStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/NotebookCellStage.ts @@ -1,9 +1,7 @@ -import { - Target, -} from "../../../typings/target.types"; +import { Target } from "../../../typings/target.types"; import { ContainingScopeModifier, - EveryScopeModifier + EveryScopeModifier, } from "../../../typings/targetDescriptor.types"; import NotebookCellTarget from "../../targets/NotebookCellTarget"; import { ProcessedTargetsContext } from "../../../typings/Types"; diff --git a/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts b/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts index 3f94950048..cac90e429a 100644 --- a/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ParagraphStage.ts @@ -1,10 +1,8 @@ import { Range } from "vscode"; -import { - Target, -} from "../../../typings/target.types"; +import { Target } from "../../../typings/target.types"; import { ContainingScopeModifier, - EveryScopeModifier + EveryScopeModifier, } from "../../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../../typings/Types"; import { ModifierStage } from "../../PipelineStages.types"; diff --git a/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts b/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts index 7244b72fff..a0b7bf86cd 100644 --- a/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/RegexStage.ts @@ -1,10 +1,8 @@ import { Position, Range, TextEditor } from "vscode"; -import { - Target, -} from "../../../typings/target.types"; +import { Target } from "../../../typings/target.types"; import { ContainingScopeModifier, - EveryScopeModifier + EveryScopeModifier, } from "../../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../../typings/Types"; import { ModifierStage } from "../../PipelineStages.types"; diff --git a/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts index 71b073138c..be7f943683 100644 --- a/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/TokenStage.ts @@ -1,10 +1,8 @@ import { Range, TextEditor } from "vscode"; -import { - Target, -} from "../../../typings/target.types"; +import { Target } from "../../../typings/target.types"; import { ContainingScopeModifier, - EveryScopeModifier + EveryScopeModifier, } from "../../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../../typings/Types"; import { getTokensInRange, PartialToken } from "../../../util/getTokensInRange"; diff --git a/src/processTargets/modifiers/surroundingPair/delimiterMaps.ts b/src/processTargets/modifiers/surroundingPair/delimiterMaps.ts index ad3f6e0d84..b0d69574c9 100644 --- a/src/processTargets/modifiers/surroundingPair/delimiterMaps.ts +++ b/src/processTargets/modifiers/surroundingPair/delimiterMaps.ts @@ -1,6 +1,6 @@ import { ComplexSurroundingPairName, - SimpleSurroundingPairName + SimpleSurroundingPairName, } from "../../../typings/targetDescriptor.types"; type IndividualDelimiterText = string | string[]; diff --git a/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts b/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts index 97e0d86ed5..374f1772e2 100644 --- a/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts +++ b/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts @@ -2,7 +2,7 @@ import { Range, TextDocument, TextEditor } from "vscode"; import { SyntaxNode } from "web-tree-sitter"; import { SimpleSurroundingPairName, - SurroundingPairDirection + SurroundingPairDirection, } from "../../../typings/targetDescriptor.types"; import { getNodeRange } from "../../../util/nodeSelectors"; import { isContainedInErrorNode } from "../../../util/treeSitterUtils"; diff --git a/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts b/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts index 7c88166e8d..7caf64353c 100644 --- a/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts +++ b/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts @@ -3,7 +3,7 @@ import { Range, TextDocument, TextEditor } from "vscode"; import { SimpleSurroundingPairName, SurroundingPairDirection, - SurroundingPairName + SurroundingPairName, } from "../../../typings/targetDescriptor.types"; import { getDocumentRange } from "../../../util/range"; import { matchAll } from "../../../util/regex"; diff --git a/src/processTargets/modifiers/surroundingPair/index.ts b/src/processTargets/modifiers/surroundingPair/index.ts index e1c0e9e9b1..b86b154785 100644 --- a/src/processTargets/modifiers/surroundingPair/index.ts +++ b/src/processTargets/modifiers/surroundingPair/index.ts @@ -5,7 +5,7 @@ import getTextFragmentExtractor, { } from "../../../languages/getTextFragmentExtractor"; import { ComplexSurroundingPairName, - SurroundingPairScopeType + SurroundingPairScopeType, } from "../../../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../../../typings/Types"; import { complexDelimiterMap } from "./delimiterMaps"; diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index 357871a927..bceb634892 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -1,11 +1,10 @@ import { uniqWith, zip } from "lodash"; import { Range } from "vscode"; -import { - Target, -} from "../typings/target.types"; +import { Target } from "../typings/target.types"; import { PrimitiveTargetDescriptor, - RangeTargetDescriptor, TargetDescriptor + RangeTargetDescriptor, + TargetDescriptor, } from "../typings/targetDescriptor.types"; import { ProcessedTargetsContext } from "../typings/Types"; import { ensureSingleEditor } from "../util/targetUtils"; diff --git a/src/testUtil/extractTargetedMarks.ts b/src/testUtil/extractTargetedMarks.ts index ec94439c2c..11235db1d3 100644 --- a/src/testUtil/extractTargetedMarks.ts +++ b/src/testUtil/extractTargetedMarks.ts @@ -3,7 +3,7 @@ import HatTokenMap from "../core/HatTokenMap"; import { Token } from "../typings/Types"; import { PrimitiveTargetDescriptor, - TargetDescriptor + TargetDescriptor, } from "../typings/targetDescriptor.types"; function extractPrimitiveTargetKeys(...targets: PrimitiveTargetDescriptor[]) { diff --git a/src/util/getPrimitiveTargets.ts b/src/util/getPrimitiveTargets.ts index 996b463303..2903b62346 100644 --- a/src/util/getPrimitiveTargets.ts +++ b/src/util/getPrimitiveTargets.ts @@ -3,7 +3,7 @@ import { PartialRangeTargetDesc, PartialTargetDesc, PrimitiveTargetDescriptor, - TargetDescriptor + TargetDescriptor, } from "../typings/targetDescriptor.types"; /** From 02294fa0060bf42702f3344f2e3a09218e2f894e Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 2 Jun 2022 18:38:17 +0200 Subject: [PATCH 286/314] Fixed that mark on notebook cells --- src/actions/EditNew.ts | 14 ++++++++------ .../fixtures/recorded/selectionTypes/drinkCell.yml | 4 ++-- .../recorded/selectionTypes/drinkCellEach.yml | 4 ++-- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/actions/EditNew.ts b/src/actions/EditNew.ts index b5f737672d..f4f238fdb5 100644 --- a/src/actions/EditNew.ts +++ b/src/actions/EditNew.ts @@ -92,15 +92,17 @@ class EditNew implements Action { const command = target.getEditNewCommand(this.isBefore); await commands.executeCommand(command); - const thatTarget = ? target.thatTarget : ; - let thatMark = createThatMark([target.thatTarget]); + const thatMark = createThatMark([target.thatTarget]); + + // Inserting a new jupyter cell above pushes the previous one down two lines if (command === "jupyter.insertCellAbove") { - thatMark. + thatMark[0].selection = new Selection( + thatMark[0].selection.anchor.translate({ lineDelta: 2 }), + thatMark[0].selection.active.translate({ lineDelta: 2 }) + ); } - return { - thatMark, - }; + return { thatMark }; } async runDelimiterTargets( diff --git a/src/test/suite/fixtures/recorded/selectionTypes/drinkCell.yml b/src/test/suite/fixtures/recorded/selectionTypes/drinkCell.yml index dabe7edab0..6aa20bf0ee 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/drinkCell.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/drinkCell.yml @@ -21,6 +21,6 @@ finalState: - anchor: {line: 1, character: 0} active: {line: 1, character: 0} thatMark: - - anchor: {line: 1, character: 12} - active: {line: 1, character: 12} + - anchor: {line: 3, character: 12} + active: {line: 3, character: 12} fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: notebookCell, position: contents, insideOutsideType: inside, modifier: {type: identity}}] diff --git a/src/test/suite/fixtures/recorded/selectionTypes/drinkCellEach.yml b/src/test/suite/fixtures/recorded/selectionTypes/drinkCellEach.yml index 5828044cf6..18344eaed4 100644 --- a/src/test/suite/fixtures/recorded/selectionTypes/drinkCellEach.yml +++ b/src/test/suite/fixtures/recorded/selectionTypes/drinkCellEach.yml @@ -32,6 +32,6 @@ finalState: - anchor: {line: 1, character: 0} active: {line: 1, character: 0} thatMark: - - anchor: {line: 1, character: 7} - active: {line: 1, character: 12} + - anchor: {line: 3, character: 7} + active: {line: 3, character: 12} fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: e}, selectionType: notebookCell, position: contents, insideOutsideType: inside, modifier: {type: identity}}] From 24f71a109b4b99d263d941646fbd1a8ff9a62ce8 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Thu, 2 Jun 2022 18:56:01 +0200 Subject: [PATCH 287/314] Cleanup --- src/actions/EditNew.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/actions/EditNew.ts b/src/actions/EditNew.ts index f4f238fdb5..608d1bb18d 100644 --- a/src/actions/EditNew.ts +++ b/src/actions/EditNew.ts @@ -91,7 +91,6 @@ class EditNew implements Action { await this.setSelections([target]); const command = target.getEditNewCommand(this.isBefore); await commands.executeCommand(command); - const thatMark = createThatMark([target.thatTarget]); // Inserting a new jupyter cell above pushes the previous one down two lines From 1c3b39111eeef510c0ac19ba9163031bf3de0680 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Fri, 3 Jun 2022 11:51:54 +0100 Subject: [PATCH 288/314] More positional tweaks on talon side --- cursorless-talon/src/modifiers/position.py | 32 ++++++++++++++-------- cursorless-talon/src/positional_target.py | 17 ++---------- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/cursorless-talon/src/modifiers/position.py b/cursorless-talon/src/modifiers/position.py index 5b84a78bde..508bdb2880 100644 --- a/cursorless-talon/src/modifiers/position.py +++ b/cursorless-talon/src/modifiers/position.py @@ -1,14 +1,21 @@ from typing import Any -from talon import Context, Module +from talon import Context, Module, app + +from ..csv_overrides import init_csv_and_watch_changes mod = Module() ctx = Context() -mod.list("cursorless_position", desc="Types of positions") -ctx.lists["self.cursorless_position"] = { +mod.list("cursorless_position", desc='Positions such as "before", "after" etc') + +# NOTE: Please do not change these dicts. Use the CSVs for customization. +# See https://www.cursorless.org/docs/user/customization/ +positions = { "start of": "start", "end of": "end", + "before": "before", + "after": "after", } @@ -18,13 +25,16 @@ def construct_positional_modifier(position: str) -> dict: # Note that we allow positional connectives such as "before" and "after" to appear # as modifiers. We may disallow this in the future. -@mod.capture( - rule="{user.cursorless_position} | {user.cursorless_positional_connective}" -) +@mod.capture(rule="{user.cursorless_position}") def cursorless_position(m) -> dict[str, Any]: - try: - position = m.cursorless_position - except AttributeError: - position = m.cursorless_positional_connective + return construct_positional_modifier(m.cursorless_position) + + +def on_ready(): + init_csv_and_watch_changes( + "positions", + {"position": positions}, + ) + - return construct_positional_modifier(position) +app.register("ready", on_ready) diff --git a/cursorless-talon/src/positional_target.py b/cursorless-talon/src/positional_target.py index d257203574..3f5594a883 100644 --- a/cursorless-talon/src/positional_target.py +++ b/cursorless-talon/src/positional_target.py @@ -1,31 +1,20 @@ -from talon import Context, Module +from talon import Module from .modifiers.position import construct_positional_modifier mod = Module() -ctx = Context() - -mod.list( - "cursorless_positional_connective", - desc='Connectives used to separate source and destination targets that indicate position, eg "before" or "after"', -) - -ctx.lists["self.cursorless_positional_connective"] = { - "before": "before", - "after": "after", -} @mod.capture( rule=( - "({user.cursorless_positional_connective} | {user.cursorless_source_destination_connective}) " + "({user.cursorless_position} | {user.cursorless_source_destination_connective}) " "" ) ) def cursorless_positional_target(m) -> list[dict]: target = m.cursorless_target try: - modifier = construct_positional_modifier(m.cursorless_positional_connective) + modifier = construct_positional_modifier(m.cursorless_position) return update_first_primitive_target(target, modifier) except AttributeError: return target From 6e308cec8dde36b542102a52386362348121a16a Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Fri, 3 Jun 2022 12:26:13 +0100 Subject: [PATCH 289/314] Removes support for chuck after and chuck before --- src/errors.ts | 7 +++++++ src/processTargets/modifiers/PositionStage.ts | 12 ------------ .../targets/NotebookCellTarget.ts | 1 - src/processTargets/targets/PositionTarget.ts | 19 ++++++++++++------- 4 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/errors.ts b/src/errors.ts index 4180046773..ed250e9d5e 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -9,6 +9,13 @@ export class UnsupportedLanguageError extends Error { } } +export class UnsupportedError extends Error { + constructor(message: string) { + super(message); + this.name = "UnsupportedError"; + } +} + interface ErrorAction { /** * The name of the action to show to the user diff --git a/src/processTargets/modifiers/PositionStage.ts b/src/processTargets/modifiers/PositionStage.ts index 492f1fb0c0..5b9847e608 100644 --- a/src/processTargets/modifiers/PositionStage.ts +++ b/src/processTargets/modifiers/PositionStage.ts @@ -21,26 +21,15 @@ export function toPositionTarget(target: Target, position: Position): Target { let contentRange: Range; let insertionDelimiter: string; - /** - * We give "after" and "before" targets a removal range for backwards - * compatibility. This allows user to continue saying "chuck before" and - * "chuck after" to remove leading or trailing delimiter. We prefer that users - * use leading and trailing instead, but "before" and "after" are sometimes - * easier to think of, so we're keeping them for now - */ - let removalTarget: Target | undefined = undefined; - switch (position) { case "before": contentRange = new Range(start, start); insertionDelimiter = target.insertionDelimiter; - removalTarget = target.getLeadingDelimiterTarget(); break; case "after": contentRange = new Range(end, end); insertionDelimiter = target.insertionDelimiter; - removalTarget = target.getTrailingDelimiterTarget(); break; case "start": @@ -62,6 +51,5 @@ export function toPositionTarget(target: Target, position: Position): Target { position, insertionDelimiter, isRaw: target.isRaw, - removalTarget, }); } diff --git a/src/processTargets/targets/NotebookCellTarget.ts b/src/processTargets/targets/NotebookCellTarget.ts index 50bd63c807..8f32615c07 100644 --- a/src/processTargets/targets/NotebookCellTarget.ts +++ b/src/processTargets/targets/NotebookCellTarget.ts @@ -1,5 +1,4 @@ import { TextEditor } from "vscode"; -import { EditNewContext } from "../../typings/target.types"; import { getNotebookFromCellDocument } from "../../util/notebook"; import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; diff --git a/src/processTargets/targets/PositionTarget.ts b/src/processTargets/targets/PositionTarget.ts index 6a2f6adf45..3289c843d2 100644 --- a/src/processTargets/targets/PositionTarget.ts +++ b/src/processTargets/targets/PositionTarget.ts @@ -1,6 +1,6 @@ import * as vscode from "vscode"; import { Range, TextEditor } from "vscode"; -import { Target } from "../../typings/target.types"; +import { UnsupportedError } from "../../errors"; import { Position } from "../../typings/targetDescriptor.types"; import { EditWithRangeUpdater } from "../../typings/Types"; import BaseTarget, { CommonTargetParameters } from "./BaseTarget"; @@ -9,27 +9,33 @@ interface PositionTargetParameters extends CommonTargetParameters { readonly position: Position; readonly insertionDelimiter: string; readonly isRaw: boolean; - readonly removalTarget: Target | undefined; } export default class PositionTarget extends BaseTarget { insertionDelimiter: string; isRaw: boolean; private position: Position; - private removalTarget: Target | undefined; constructor(parameters: PositionTargetParameters) { super(parameters); this.position = parameters.position; this.insertionDelimiter = parameters.insertionDelimiter; this.isRaw = parameters.isRaw; - this.removalTarget = parameters.removalTarget; } getLeadingDelimiterTarget = () => undefined; getTrailingDelimiterTarget = () => undefined; - getRemovalRange = () => - this.removalTarget?.getRemovalRange() ?? this.contentRange; + + getRemovalRange(): Range { + const preferredModifier = + this.position === "after" || this.position === "end" + ? "trailing" + : "leading"; + + throw new UnsupportedError( + `Please use "${preferredModifier}" modifier; removal is not supported for "${this.position}"` + ); + } constructChangeEdit(text: string): EditWithRangeUpdater { if (this.isInsertion()) { @@ -51,7 +57,6 @@ export default class PositionTarget extends BaseTarget { position: this.position, insertionDelimiter: this.insertionDelimiter, isRaw: this.isRaw, - removalTarget: this.removalTarget, }; } From 1119fba00c84ba76a6d6015053556f2b01c224b6 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Fri, 3 Jun 2022 13:29:07 +0100 Subject: [PATCH 290/314] Clean up names --- src/processTargets/targets/PositionTarget.ts | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/processTargets/targets/PositionTarget.ts b/src/processTargets/targets/PositionTarget.ts index 3289c843d2..003980cfa6 100644 --- a/src/processTargets/targets/PositionTarget.ts +++ b/src/processTargets/targets/PositionTarget.ts @@ -38,17 +38,15 @@ export default class PositionTarget extends BaseTarget { } constructChangeEdit(text: string): EditWithRangeUpdater { - if (this.isInsertion()) { - return this.constructInsertionEdit(text, true); - } - return this.constructReplaceEdit(text); + return this.includeDelimitersInChangeEdit + ? this.constructEditWithDelimiters(text, true) + : this.constructEditWithoutDelimiters(text); } constructEmptyChangeEdit(): EditWithRangeUpdater { - if (this.isInsertion()) { - return this.constructInsertionEdit("", false); - } - return this.constructReplaceEdit(""); + return this.includeDelimitersInChangeEdit + ? this.constructEditWithDelimiters("", false) + : this.constructEditWithoutDelimiters(""); } protected getCloneParameters(): PositionTargetParameters { @@ -60,7 +58,7 @@ export default class PositionTarget extends BaseTarget { }; } - private constructInsertionEdit( + private constructEditWithDelimiters( text: string, useLinePadding: boolean ): EditWithRangeUpdater { @@ -104,7 +102,7 @@ export default class PositionTarget extends BaseTarget { }; } - private constructReplaceEdit(text: string): EditWithRangeUpdater { + private constructEditWithoutDelimiters(text: string): EditWithRangeUpdater { return { range: this.contentRange, text, @@ -112,7 +110,7 @@ export default class PositionTarget extends BaseTarget { }; } - private isInsertion() { + private get includeDelimitersInChangeEdit() { return this.position === "before" || this.position === "after"; } } From 852345aaff9dbd6f1ecf3e792fe188dfba64b011 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Fri, 3 Jun 2022 13:52:36 +0100 Subject: [PATCH 291/314] Use proper error for syntax scope not found --- .../modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts b/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts index 3ac451c89c..5844e86b7d 100644 --- a/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts +++ b/src/processTargets/modifiers/scopeTypeStages/ContainingSyntaxScopeStage.ts @@ -1,5 +1,6 @@ import { Location, Selection } from "vscode"; import { SyntaxNode } from "web-tree-sitter"; +import { NoContainingScopeError } from "../../../errors"; import { getNodeMatcher } from "../../../languages/getNodeMatcher"; import { Target } from "../../../typings/target.types"; import { @@ -50,9 +51,7 @@ export default class implements ModifierStage { }); if (scopeNodes == null) { - throw new Error( - `Couldn't find containing ${this.modifier.scopeType.type}` - ); + throw new NoContainingScopeError(this.modifier.scopeType.type); } return scopeNodes.map((scope) => { From 61f204504aeb1ebe6947cb384c8c35ff6d391d60 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Fri, 3 Jun 2022 13:58:33 +0100 Subject: [PATCH 292/314] Record tests for leading trailing before and after --- .../leadingTrailing/chuckLeadingWhale.yml | 29 +++++++++++++++++++ .../leadingTrailing/chuckTrailingDrum.yml | 29 +++++++++++++++++++ .../leadingTrailing/clearLeadingWhale.yml | 29 +++++++++++++++++++ .../leadingTrailing/clearTrailingWhale.yml | 29 +++++++++++++++++++ .../recorded/positions/chuckAfterWhale.yml | 10 ++----- .../recorded/positions/chuckBeforeWhale.yml | 10 ++----- .../recorded/positions/chuckEndOfWhale.yml | 10 ++----- .../recorded/positions/chuckStartOfWhale.yml | 10 ++----- 8 files changed, 124 insertions(+), 32 deletions(-) create mode 100644 src/test/suite/fixtures/recorded/leadingTrailing/chuckLeadingWhale.yml create mode 100644 src/test/suite/fixtures/recorded/leadingTrailing/chuckTrailingDrum.yml create mode 100644 src/test/suite/fixtures/recorded/leadingTrailing/clearLeadingWhale.yml create mode 100644 src/test/suite/fixtures/recorded/leadingTrailing/clearTrailingWhale.yml diff --git a/src/test/suite/fixtures/recorded/leadingTrailing/chuckLeadingWhale.yml b/src/test/suite/fixtures/recorded/leadingTrailing/chuckLeadingWhale.yml new file mode 100644 index 0000000000..96024e1b35 --- /dev/null +++ b/src/test/suite/fixtures/recorded/leadingTrailing/chuckLeadingWhale.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: chuck leading whale + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: w} + modifiers: + - {type: leading} + usePrePhraseSnapshot: true + action: {name: remove} +initialState: + documentContents: hello world whatever + selections: + - anchor: {line: 0, character: 20} + active: {line: 0, character: 20} + marks: + default.w: + start: {line: 0, character: 6} + end: {line: 0, character: 11} +finalState: + documentContents: helloworld whatever + selections: + - anchor: {line: 0, character: 19} + active: {line: 0, character: 19} + thatMark: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: w}, modifiers: [{type: leading}]}] diff --git a/src/test/suite/fixtures/recorded/leadingTrailing/chuckTrailingDrum.yml b/src/test/suite/fixtures/recorded/leadingTrailing/chuckTrailingDrum.yml new file mode 100644 index 0000000000..c678b5efb8 --- /dev/null +++ b/src/test/suite/fixtures/recorded/leadingTrailing/chuckTrailingDrum.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: chuck trailing drum + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: d} + modifiers: + - {type: trailing} + usePrePhraseSnapshot: true + action: {name: remove} +initialState: + documentContents: hello world whatever + selections: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 6} + marks: + default.d: + start: {line: 0, character: 6} + end: {line: 0, character: 11} +finalState: + documentContents: hello worldwhatever + selections: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 6} + thatMark: + - anchor: {line: 0, character: 11} + active: {line: 0, character: 11} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: d}, modifiers: [{type: trailing}]}] diff --git a/src/test/suite/fixtures/recorded/leadingTrailing/clearLeadingWhale.yml b/src/test/suite/fixtures/recorded/leadingTrailing/clearLeadingWhale.yml new file mode 100644 index 0000000000..a8cc4caee0 --- /dev/null +++ b/src/test/suite/fixtures/recorded/leadingTrailing/clearLeadingWhale.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: clear leading whale + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: w} + modifiers: + - {type: leading} + usePrePhraseSnapshot: true + action: {name: clearAndSetSelection} +initialState: + documentContents: hello world whatever + selections: + - anchor: {line: 0, character: 20} + active: {line: 0, character: 20} + marks: + default.w: + start: {line: 0, character: 6} + end: {line: 0, character: 11} +finalState: + documentContents: helloworld whatever + selections: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} + thatMark: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: w}, modifiers: [{type: leading}]}] diff --git a/src/test/suite/fixtures/recorded/leadingTrailing/clearTrailingWhale.yml b/src/test/suite/fixtures/recorded/leadingTrailing/clearTrailingWhale.yml new file mode 100644 index 0000000000..9df6a3ca4f --- /dev/null +++ b/src/test/suite/fixtures/recorded/leadingTrailing/clearTrailingWhale.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: clear trailing whale + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: w} + modifiers: + - {type: trailing} + usePrePhraseSnapshot: true + action: {name: clearAndSetSelection} +initialState: + documentContents: hello world whatever + selections: + - anchor: {line: 0, character: 20} + active: {line: 0, character: 20} + marks: + default.w: + start: {line: 0, character: 6} + end: {line: 0, character: 11} +finalState: + documentContents: hello worldwhatever + selections: + - anchor: {line: 0, character: 11} + active: {line: 0, character: 11} + thatMark: + - anchor: {line: 0, character: 11} + active: {line: 0, character: 11} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: w}, modifiers: [{type: trailing}]}] diff --git a/src/test/suite/fixtures/recorded/positions/chuckAfterWhale.yml b/src/test/suite/fixtures/recorded/positions/chuckAfterWhale.yml index 77a770fd0f..a2947fc505 100644 --- a/src/test/suite/fixtures/recorded/positions/chuckAfterWhale.yml +++ b/src/test/suite/fixtures/recorded/positions/chuckAfterWhale.yml @@ -18,12 +18,6 @@ initialState: default.w: start: {line: 0, character: 6} end: {line: 0, character: 11} -finalState: - documentContents: hello worldwhatever - selections: - - anchor: {line: 0, character: 19} - active: {line: 0, character: 19} - thatMark: - - anchor: {line: 0, character: 11} - active: {line: 0, character: 11} +returnValue: null fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: w}, modifiers: [{type: position, position: after}]}] +thrownError: {name: UnsupportedError} diff --git a/src/test/suite/fixtures/recorded/positions/chuckBeforeWhale.yml b/src/test/suite/fixtures/recorded/positions/chuckBeforeWhale.yml index 9e41c231ec..b0baaff459 100644 --- a/src/test/suite/fixtures/recorded/positions/chuckBeforeWhale.yml +++ b/src/test/suite/fixtures/recorded/positions/chuckBeforeWhale.yml @@ -18,12 +18,6 @@ initialState: default.w: start: {line: 0, character: 6} end: {line: 0, character: 11} -finalState: - documentContents: helloworld whatever - selections: - - anchor: {line: 0, character: 19} - active: {line: 0, character: 19} - thatMark: - - anchor: {line: 0, character: 5} - active: {line: 0, character: 5} +returnValue: null fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: w}, modifiers: [{type: position, position: before}]}] +thrownError: {name: UnsupportedError} diff --git a/src/test/suite/fixtures/recorded/positions/chuckEndOfWhale.yml b/src/test/suite/fixtures/recorded/positions/chuckEndOfWhale.yml index 9dbf8f8257..b18a832a0c 100644 --- a/src/test/suite/fixtures/recorded/positions/chuckEndOfWhale.yml +++ b/src/test/suite/fixtures/recorded/positions/chuckEndOfWhale.yml @@ -18,12 +18,6 @@ initialState: default.w: start: {line: 0, character: 6} end: {line: 0, character: 11} -finalState: - documentContents: hello world whatever - selections: - - anchor: {line: 0, character: 20} - active: {line: 0, character: 20} - thatMark: - - anchor: {line: 0, character: 11} - active: {line: 0, character: 11} +returnValue: null fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: w}, modifiers: [{type: position, position: end}]}] +thrownError: {name: UnsupportedError} diff --git a/src/test/suite/fixtures/recorded/positions/chuckStartOfWhale.yml b/src/test/suite/fixtures/recorded/positions/chuckStartOfWhale.yml index 36908ff70d..e3773ace82 100644 --- a/src/test/suite/fixtures/recorded/positions/chuckStartOfWhale.yml +++ b/src/test/suite/fixtures/recorded/positions/chuckStartOfWhale.yml @@ -18,12 +18,6 @@ initialState: default.w: start: {line: 0, character: 6} end: {line: 0, character: 11} -finalState: - documentContents: hello world whatever - selections: - - anchor: {line: 0, character: 20} - active: {line: 0, character: 20} - thatMark: - - anchor: {line: 0, character: 6} - active: {line: 0, character: 6} +returnValue: null fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: w}, modifiers: [{type: position, position: start}]}] +thrownError: {name: UnsupportedError} From 223517b39ac2909f1982cb5701b137ece448ad27 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Fri, 3 Jun 2022 16:06:56 +0200 Subject: [PATCH 293/314] Add chuck before after to upgrade --- .../upgradeV1ToV2/upgradeV1ToV2.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts index 114ac70dbf..b18273e442 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts @@ -91,7 +91,8 @@ function upgradeModifier(modifier: ModifierV0V1): Modifier[] { } function upgradePrimitiveTarget( - target: PartialPrimitiveTargetV0V1 + target: PartialPrimitiveTargetV0V1, + action: ActionType ): PartialPrimitiveTargetDesc { const { type, @@ -108,12 +109,16 @@ function upgradePrimitiveTarget( if (position === "before") { if (insideOutsideType === "inside") { modifiers.push({ type: "position", position: "start" }); + } else if (action === "remove") { + modifiers.push({ type: "leading" }); } else { modifiers.push({ type: "position", position: "before" }); } } else { if (insideOutsideType === "inside") { modifiers.push({ type: "position", position: "end" }); + } else if (action === "remove") { + modifiers.push({ type: "trailing" }); } else { modifiers.push({ type: "position", position: "after" }); } @@ -172,13 +177,13 @@ function upgradeTarget( return { type, rangeType, - anchor: upgradePrimitiveTarget(start), - active: upgradePrimitiveTarget(end), + anchor: upgradePrimitiveTarget(start, action), + active: upgradePrimitiveTarget(end, action), excludeAnchor: excludeStart ?? false, excludeActive: excludeEnd ?? false, }; case "primitive": - return upgradePrimitiveTarget(target); + return upgradePrimitiveTarget(target, action); } } From 52193ae65130d472ff4526bdd72c5100d320b6f0 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Fri, 3 Jun 2022 16:41:50 +0100 Subject: [PATCH 294/314] Failed attempt at trying to simplify edit new --- src/actions/EditNew.ts | 132 +++++++++++++++++++++++++++++------------ 1 file changed, 94 insertions(+), 38 deletions(-) diff --git a/src/actions/EditNew.ts b/src/actions/EditNew.ts index 608d1bb18d..d977fbac6f 100644 --- a/src/actions/EditNew.ts +++ b/src/actions/EditNew.ts @@ -38,22 +38,23 @@ class EditNew implements Action { const editor = ensureSingleEditor(targets); - const richTargets: RichTarget[] = targets.map((target) => { + const richTargets = targets.map((target) => { const context = target.getEditNewContext(this.isBefore); - const common = { - target, - cursorRange: target.contentRange, - }; + switch (context.type) { case "command": return { - ...common, + target, + thatTarget: target.thatTarget, + cursorRange: undefined, type: "command", command: context.command, }; case "delimiter": return { - ...common, + target, + thatTarget: target.thatTarget, + cursorRange: undefined, type: "delimiter", delimiter: context.delimiter, }; @@ -71,11 +72,16 @@ class EditNew implements Action { await this.runCommandTargets(editor, richTargets, commandTargets); } if (delimiterTargets.length > 0) { - await this.runDelimiterTargets(editor, commandTargets, delimiterTargets); + await this.runDelimiterTargets( + editor, + richTargets, + commandTargets, + delimiterTargets + ); } const newSelections = richTargets.map((target) => - selectionFromRange(target.target.isReversed, target.cursorRange) + selectionFromRange(target.target.isReversed, target.cursorRange!) ); await setSelectionsAndFocusEditor(editor, newSelections); @@ -106,18 +112,23 @@ class EditNew implements Action { async runDelimiterTargets( editor: TextEditor, + allTargets: RichTarget[], commandTargets: CommandTarget[], delimiterTargets: DelimiterTarget[] ) { const position = this.isBefore ? "before" : "after"; + // NB: We don't use `constructEmptyChangeEdit` here because we want padding + // if it's a line target const edits = delimiterTargets.flatMap((target) => toPositionTarget(target.target, position).constructChangeEdit("") ); - const cursorSelections = { selections: editor.selections }; - const contentSelections = { - selections: delimiterTargets.map( - ({ target }) => target.thatTarget.contentSelection + const commandTargetCursorSelections = commandTargets.map( + (richTarget) => richTarget.cursorRange + ); + const thatTargetSelections = { + selections: allTargets.map( + ({ thatTarget }) => thatTarget.contentSelection ), }; const editSelections = { @@ -129,20 +140,24 @@ class EditNew implements Action { const [ updatedEditorSelections, - updatedContentSelections, + updatedThatTargetSelections, updatedEditSelections, ]: Selection[][] = await performEditsAndUpdateSelectionsWithBehavior( this.graph.rangeUpdater, editor, edits, - [cursorSelections, contentSelections, editSelections] + [commandTargetCursorSelections, thatTargetSelections, editSelections] ); const insertionRanges = zip(edits, updatedEditSelections).map( ([edit, selection]) => edit!.updateRange(selection!) ); - updateTargets(delimiterTargets, updatedContentSelections, insertionRanges); + updateRichTargets( + delimiterTargets, + updatedThatTargetSelections, + insertionRanges + ); updateCommandTargets(commandTargets, updatedEditorSelections); } @@ -155,19 +170,24 @@ class EditNew implements Action { await this.setSelections(commandTargets.map(({ target }) => target)); - const [updatedTargetRanges, updatedCursorRanges] = + const [updatedThatTargetRanges, updatedTargetRanges] = await callFunctionAndUpdateRanges( this.graph.rangeUpdater, () => commands.executeCommand(command), editor.document, [ targets.map(({ target }) => target.thatTarget.contentRange), - targets.map(({ cursorRange }) => cursorRange), + targets.map(({ target }) => target.contentRange), ] ); - updateTargets(targets, updatedTargetRanges, updatedCursorRanges); - updateCommandTargets(commandTargets, editor.selections); + updateRichTargets(targets, { + updatedThatTargetRanges, + updatedTargetRanges, + }); + updateRichTargets(commandTargets, { + updatedCursorRanges: editor.selections, + }); } private async setSelections(targets: Target[]) { @@ -192,10 +212,24 @@ export class EditNewAfter extends EditNew { } interface CommonTarget { + /** + * The target that we apply the edit to. Note that we keep this target up to + * date as edits come in + */ target: Target; - cursorRange: Range; -} + /** + * The `that` target that we will return. Note that we keep this target up to + * date as edits come in + */ + thatTarget: Target; + + /** + * The range of where we would like the cursor to end up before or after this + * target. Note that this will be undefined at the start + */ + cursorRange: Range | undefined; +} interface CommandTarget extends CommonTarget { type: "command"; command: string; @@ -204,6 +238,12 @@ interface DelimiterTarget extends CommonTarget { type: "delimiter"; delimiter: string; } +/** + * Keeps a target as well as information about how to perform and edit. The + * target will be kept up to date as the edit is performed so that we can turn + * it as a that mark. We also keep track of where the cursor should end up after + * applying this edit + */ type RichTarget = CommandTarget | DelimiterTarget; function ensureSingleCommand(targets: CommandTarget[]) { @@ -214,24 +254,40 @@ function ensureSingleCommand(targets: CommandTarget[]) { return commands[0]; } -function updateCommandTargets( - targets: CommandTarget[], - cursorRanges: readonly Range[] -) { - targets.forEach((target, i) => { - target.cursorRange = cursorRanges[i]; - }); +interface RangesToUpdate { + updatedTargetRanges?: readonly Range[]; + updatedThatTargetRanges?: readonly Range[]; + updatedCursorRanges?: readonly Range[]; } -function updateTargets( +function updateRichTargets( targets: RichTarget[], - updatedTargetRanges: Range[], - updatedCursorRanges: Range[] + rangesToUpdate: RangesToUpdate ) { - zip(targets, updatedTargetRanges, updatedCursorRanges).forEach( - ([target, updatedTargetRange, updatedCursorRange]) => { - target!.target = target!.target.withContentRange(updatedTargetRange!); - target!.cursorRange = updatedCursorRange!; - } - ); + const { updatedTargetRanges, updatedThatTargetRanges, updatedCursorRanges } = + rangesToUpdate; + + if (updatedTargetRanges != null) { + zip(targets, updatedTargetRanges).forEach( + ([target, updatedTargetRange]) => { + target!.target = target!.target.withContentRange(updatedTargetRange!); + } + ); + } + + if (updatedThatTargetRanges != null) { + zip(targets, updatedThatTargetRanges).forEach( + ([target, updatedTargetRange]) => { + target!.target = target!.target.withContentRange(updatedTargetRange!); + } + ); + } + + if (updatedCursorRanges != null) { + zip(targets, updatedCursorRanges).forEach( + ([target, updatedCursorRange]) => { + target!.cursorRange = updatedCursorRange!; + } + ); + } } From c92e6f8e7bf17bbc1caa43576b6117daee9cd448 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Fri, 3 Jun 2022 17:50:12 +0100 Subject: [PATCH 295/314] Revert "Failed attempt at trying to simplify edit new" This reverts commit 52193ae65130d472ff4526bdd72c5100d320b6f0. --- src/actions/EditNew.ts | 132 ++++++++++++----------------------------- 1 file changed, 38 insertions(+), 94 deletions(-) diff --git a/src/actions/EditNew.ts b/src/actions/EditNew.ts index d977fbac6f..608d1bb18d 100644 --- a/src/actions/EditNew.ts +++ b/src/actions/EditNew.ts @@ -38,23 +38,22 @@ class EditNew implements Action { const editor = ensureSingleEditor(targets); - const richTargets = targets.map((target) => { + const richTargets: RichTarget[] = targets.map((target) => { const context = target.getEditNewContext(this.isBefore); - + const common = { + target, + cursorRange: target.contentRange, + }; switch (context.type) { case "command": return { - target, - thatTarget: target.thatTarget, - cursorRange: undefined, + ...common, type: "command", command: context.command, }; case "delimiter": return { - target, - thatTarget: target.thatTarget, - cursorRange: undefined, + ...common, type: "delimiter", delimiter: context.delimiter, }; @@ -72,16 +71,11 @@ class EditNew implements Action { await this.runCommandTargets(editor, richTargets, commandTargets); } if (delimiterTargets.length > 0) { - await this.runDelimiterTargets( - editor, - richTargets, - commandTargets, - delimiterTargets - ); + await this.runDelimiterTargets(editor, commandTargets, delimiterTargets); } const newSelections = richTargets.map((target) => - selectionFromRange(target.target.isReversed, target.cursorRange!) + selectionFromRange(target.target.isReversed, target.cursorRange) ); await setSelectionsAndFocusEditor(editor, newSelections); @@ -112,23 +106,18 @@ class EditNew implements Action { async runDelimiterTargets( editor: TextEditor, - allTargets: RichTarget[], commandTargets: CommandTarget[], delimiterTargets: DelimiterTarget[] ) { const position = this.isBefore ? "before" : "after"; - // NB: We don't use `constructEmptyChangeEdit` here because we want padding - // if it's a line target const edits = delimiterTargets.flatMap((target) => toPositionTarget(target.target, position).constructChangeEdit("") ); - const commandTargetCursorSelections = commandTargets.map( - (richTarget) => richTarget.cursorRange - ); - const thatTargetSelections = { - selections: allTargets.map( - ({ thatTarget }) => thatTarget.contentSelection + const cursorSelections = { selections: editor.selections }; + const contentSelections = { + selections: delimiterTargets.map( + ({ target }) => target.thatTarget.contentSelection ), }; const editSelections = { @@ -140,24 +129,20 @@ class EditNew implements Action { const [ updatedEditorSelections, - updatedThatTargetSelections, + updatedContentSelections, updatedEditSelections, ]: Selection[][] = await performEditsAndUpdateSelectionsWithBehavior( this.graph.rangeUpdater, editor, edits, - [commandTargetCursorSelections, thatTargetSelections, editSelections] + [cursorSelections, contentSelections, editSelections] ); const insertionRanges = zip(edits, updatedEditSelections).map( ([edit, selection]) => edit!.updateRange(selection!) ); - updateRichTargets( - delimiterTargets, - updatedThatTargetSelections, - insertionRanges - ); + updateTargets(delimiterTargets, updatedContentSelections, insertionRanges); updateCommandTargets(commandTargets, updatedEditorSelections); } @@ -170,24 +155,19 @@ class EditNew implements Action { await this.setSelections(commandTargets.map(({ target }) => target)); - const [updatedThatTargetRanges, updatedTargetRanges] = + const [updatedTargetRanges, updatedCursorRanges] = await callFunctionAndUpdateRanges( this.graph.rangeUpdater, () => commands.executeCommand(command), editor.document, [ targets.map(({ target }) => target.thatTarget.contentRange), - targets.map(({ target }) => target.contentRange), + targets.map(({ cursorRange }) => cursorRange), ] ); - updateRichTargets(targets, { - updatedThatTargetRanges, - updatedTargetRanges, - }); - updateRichTargets(commandTargets, { - updatedCursorRanges: editor.selections, - }); + updateTargets(targets, updatedTargetRanges, updatedCursorRanges); + updateCommandTargets(commandTargets, editor.selections); } private async setSelections(targets: Target[]) { @@ -212,24 +192,10 @@ export class EditNewAfter extends EditNew { } interface CommonTarget { - /** - * The target that we apply the edit to. Note that we keep this target up to - * date as edits come in - */ target: Target; - - /** - * The `that` target that we will return. Note that we keep this target up to - * date as edits come in - */ - thatTarget: Target; - - /** - * The range of where we would like the cursor to end up before or after this - * target. Note that this will be undefined at the start - */ - cursorRange: Range | undefined; + cursorRange: Range; } + interface CommandTarget extends CommonTarget { type: "command"; command: string; @@ -238,12 +204,6 @@ interface DelimiterTarget extends CommonTarget { type: "delimiter"; delimiter: string; } -/** - * Keeps a target as well as information about how to perform and edit. The - * target will be kept up to date as the edit is performed so that we can turn - * it as a that mark. We also keep track of where the cursor should end up after - * applying this edit - */ type RichTarget = CommandTarget | DelimiterTarget; function ensureSingleCommand(targets: CommandTarget[]) { @@ -254,40 +214,24 @@ function ensureSingleCommand(targets: CommandTarget[]) { return commands[0]; } -interface RangesToUpdate { - updatedTargetRanges?: readonly Range[]; - updatedThatTargetRanges?: readonly Range[]; - updatedCursorRanges?: readonly Range[]; +function updateCommandTargets( + targets: CommandTarget[], + cursorRanges: readonly Range[] +) { + targets.forEach((target, i) => { + target.cursorRange = cursorRanges[i]; + }); } -function updateRichTargets( +function updateTargets( targets: RichTarget[], - rangesToUpdate: RangesToUpdate + updatedTargetRanges: Range[], + updatedCursorRanges: Range[] ) { - const { updatedTargetRanges, updatedThatTargetRanges, updatedCursorRanges } = - rangesToUpdate; - - if (updatedTargetRanges != null) { - zip(targets, updatedTargetRanges).forEach( - ([target, updatedTargetRange]) => { - target!.target = target!.target.withContentRange(updatedTargetRange!); - } - ); - } - - if (updatedThatTargetRanges != null) { - zip(targets, updatedThatTargetRanges).forEach( - ([target, updatedTargetRange]) => { - target!.target = target!.target.withContentRange(updatedTargetRange!); - } - ); - } - - if (updatedCursorRanges != null) { - zip(targets, updatedCursorRanges).forEach( - ([target, updatedCursorRange]) => { - target!.cursorRange = updatedCursorRange!; - } - ); - } + zip(targets, updatedTargetRanges, updatedCursorRanges).forEach( + ([target, updatedTargetRange, updatedCursorRange]) => { + target!.target = target!.target.withContentRange(updatedTargetRange!); + target!.cursorRange = updatedCursorRange!; + } + ); } From dce732da8e22a92a8bb54977e2f97cd45e37ac0d Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Fri, 3 Jun 2022 18:05:29 +0100 Subject: [PATCH 296/314] Cleanup vscode ignore --- .vscodeignore | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/.vscodeignore b/.vscodeignore index 135d5e9483..228984ff94 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -1,16 +1,12 @@ -.vscode/** -.vscode-test/** -src/** -.gitignore -.yarnrc -vsc-extension-quickstart.md -**/tsconfig.json -**/.eslintrc.json -**/*.map -**/*.ts -node_modules/** -.vscode-sandbox/** -out/** -dist/** +** +!CHANGELOG.md +!cursorless-snippets/** !dist/extension.js -website/** +!images/hats/** +!images/icon.png +!LICENSE +!NOTICE.md +!package.json +!README.md +!schemas/** +!third-party-licenses.csv From 8639b5659c7a520c6899de4bb35ac93d4ca6c0f9 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 5 Jun 2022 10:55:11 +0200 Subject: [PATCH 297/314] Fixed regression in vertical range target (#735) --- src/processTargets/processTargets.ts | 14 ++++- .../chuckLineRiskSliceMade.yml | 51 +++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 src/test/suite/fixtures/recorded/compoundTargets/chuckLineRiskSliceMade.yml diff --git a/src/processTargets/processTargets.ts b/src/processTargets/processTargets.ts index bceb634892..922bd7371d 100644 --- a/src/processTargets/processTargets.ts +++ b/src/processTargets/processTargets.ts @@ -10,6 +10,8 @@ import { ProcessedTargetsContext } from "../typings/Types"; import { ensureSingleEditor } from "../util/targetUtils"; import getMarkStage from "./getMarkStage"; import getModifierStage from "./getModifierStage"; +import PlainTarget from "./targets/PlainTarget"; +import PositionTarget from "./targets/PositionTarget"; /** * Converts the abstract target descriptions provided by the user to a concrete @@ -144,7 +146,17 @@ function processVerticalRangeTarget( anchorTarget.contentRange.end.character ); - results.push(anchorTarget.withContentRange(contentRange)); + if (anchorTarget instanceof PositionTarget) { + results.push(anchorTarget.withContentRange(contentRange)); + } else { + results.push( + new PlainTarget({ + editor: anchorTarget.editor, + isReversed: anchorTarget.isReversed, + contentRange, + }) + ); + } if (i === activeLine) { return results; diff --git a/src/test/suite/fixtures/recorded/compoundTargets/chuckLineRiskSliceMade.yml b/src/test/suite/fixtures/recorded/compoundTargets/chuckLineRiskSliceMade.yml new file mode 100644 index 0000000000..426a7ef371 --- /dev/null +++ b/src/test/suite/fixtures/recorded/compoundTargets/chuckLineRiskSliceMade.yml @@ -0,0 +1,51 @@ +languageId: plaintext +command: + spokenForm: chuck line risk slice made + version: 2 + targets: + - type: range + anchor: + type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: r} + modifiers: + - type: containingScope + scopeType: {type: line} + active: + type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: m} + excludeAnchor: false + excludeActive: false + rangeType: vertical + usePrePhraseSnapshot: true + action: {name: remove} +initialState: + documentContents: |- + short + something longer + something even longer + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: + default.r: + start: {line: 0, character: 0} + end: {line: 0, character: 5} + default.m: + start: {line: 2, character: 0} + end: {line: 2, character: 9} +finalState: + documentContents: |- + + hing longer + hing even longer + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} +fullTargets: [{type: range, excludeAnchor: false, excludeActive: false, rangeType: vertical, anchor: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: r}, modifiers: &ref_0 [{type: containingScope, scopeType: {type: line}}]}, active: {type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: m}, modifiers: *ref_0}}] From 2e88e20fe1c83075772debc9bc45c9aeff065cbb Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Mon, 6 Jun 2022 15:45:09 +0100 Subject: [PATCH 298/314] Revert generic insert empty lines code --- src/actions/InsertEmptyLines.ts | 91 +++++++++----------- src/processTargets/targets/BaseTarget.ts | 4 - src/processTargets/targets/PositionTarget.ts | 22 ++--- src/typings/target.types.ts | 2 - 4 files changed, 49 insertions(+), 70 deletions(-) diff --git a/src/actions/InsertEmptyLines.ts b/src/actions/InsertEmptyLines.ts index 09cc7aefc2..fefc942d62 100644 --- a/src/actions/InsertEmptyLines.ts +++ b/src/actions/InsertEmptyLines.ts @@ -1,10 +1,8 @@ -import { flatten, zip } from "lodash"; -import { DecorationRangeBehavior, Selection } from "vscode"; -import { performEditsAndUpdateSelectionsWithBehavior } from "../core/updateSelections/updateSelections"; -import { toPositionTarget } from "../processTargets/modifiers/PositionStage"; -import { toLineTarget } from "../processTargets/modifiers/scopeTypeStages/LineStage"; +import { flatten } from "lodash"; +import { Range, Selection } from "vscode"; +import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; import { Target } from "../typings/target.types"; -import { EditWithRangeUpdater, Graph } from "../typings/Types"; +import { Graph } from "../typings/Types"; import { setSelectionsWithoutFocusingEditor } from "../util/setSelectionsAndFocusEditor"; import { runOnTargetsForEachEditor } from "../util/targetUtils"; import { Action, ActionReturnValue } from "./actions.types"; @@ -18,67 +16,64 @@ class InsertEmptyLines implements Action { this.run = this.run.bind(this); } - private getEdits(targets: Target[]) { - return targets.flatMap((target) => { - const lineTarget = toLineTarget(target); - const edits: EditWithRangeUpdater[] = []; + private getRanges(targets: Target[]) { + let lines = targets.flatMap((target) => { + const lines: number[] = []; if (this.insertAbove) { - edits.push( - toPositionTarget(lineTarget, "before").constructEmptyChangeEdit() - ); + lines.push(target.contentRange.start.line); } if (this.insertBelow) { - edits.push( - toPositionTarget(lineTarget, "after").constructEmptyChangeEdit() - ); + lines.push(target.contentRange.end.line + 1); } - return edits; + return lines; }); + // Remove duplicates + lines = [...new Set(lines)]; + + return lines.map((line) => new Range(line, 0, line, 0)); + } + + private getEdits(ranges: Range[]) { + return ranges.map((range) => ({ + range, + text: "\n", + })); } async run([targets]: [Target[]]): Promise { const results = flatten( await runOnTargetsForEachEditor(targets, async (editor, targets) => { - const edits = this.getEdits(targets); - - const cursorSelections = { selections: editor.selections }; - const contentSelections = { - selections: targets.map( - (target) => target.thatTarget.contentSelection - ), - }; - const editSelections = { - selections: edits.map( - ({ range }) => new Selection(range.start, range.end) - ), - rangeBehavior: DecorationRangeBehavior.OpenOpen, - }; + const ranges = this.getRanges(targets); + const edits = this.getEdits(ranges); - const [ - updatedCursorSelections, - updatedContentSelections, - updatedEditSelections, - ]: Selection[][] = await performEditsAndUpdateSelectionsWithBehavior( - this.graph.rangeUpdater, - editor, - edits, - [cursorSelections, contentSelections, editSelections] - ); - - const insertionRanges = zip(edits, updatedEditSelections).map( - ([edit, selection]) => edit!.updateRange(selection!) - ); + const [updatedThatSelections, lineSelections, updatedCursorSelections] = + await performEditsAndUpdateSelections( + this.graph.rangeUpdater, + editor, + edits, + [ + targets.map((target) => target.thatTarget.contentSelection), + ranges.map((range) => new Selection(range.start, range.end)), + editor.selections, + ] + ); setSelectionsWithoutFocusingEditor(editor, updatedCursorSelections); return { - thatMark: updatedContentSelections.map((selection) => ({ + thatMark: updatedThatSelections.map((selection) => ({ editor, selection, })), - lineSelections: insertionRanges.map((range) => ({ + lineSelections: lineSelections.map((selection, index) => ({ editor, - range, + range: + ranges[index].start.line < editor.document.lineCount - 1 + ? new Range( + selection.start.translate({ lineDelta: -1 }), + selection.end.translate({ lineDelta: -1 }) + ) + : selection, })), }; }) diff --git a/src/processTargets/targets/BaseTarget.ts b/src/processTargets/targets/BaseTarget.ts index 9c76a5b1dd..3c1a7a1fcd 100644 --- a/src/processTargets/targets/BaseTarget.ts +++ b/src/processTargets/targets/BaseTarget.ts @@ -71,10 +71,6 @@ export default abstract class BaseTarget implements Target { }; } - constructEmptyChangeEdit(): EditWithRangeUpdater { - return this.constructChangeEdit(""); - } - constructRemovalEdit(): EditWithRangeUpdater { return { range: this.getRemovalRange(), diff --git a/src/processTargets/targets/PositionTarget.ts b/src/processTargets/targets/PositionTarget.ts index 003980cfa6..826f939cee 100644 --- a/src/processTargets/targets/PositionTarget.ts +++ b/src/processTargets/targets/PositionTarget.ts @@ -37,18 +37,6 @@ export default class PositionTarget extends BaseTarget { ); } - constructChangeEdit(text: string): EditWithRangeUpdater { - return this.includeDelimitersInChangeEdit - ? this.constructEditWithDelimiters(text, true) - : this.constructEditWithoutDelimiters(text); - } - - constructEmptyChangeEdit(): EditWithRangeUpdater { - return this.includeDelimitersInChangeEdit - ? this.constructEditWithDelimiters("", false) - : this.constructEditWithoutDelimiters(""); - } - protected getCloneParameters(): PositionTargetParameters { return { ...this.state, @@ -58,6 +46,12 @@ export default class PositionTarget extends BaseTarget { }; } + constructChangeEdit(text: string): EditWithRangeUpdater { + return this.position === "before" || this.position === "after" + ? this.constructEditWithDelimiters(text, true) + : this.constructEditWithoutDelimiters(text); + } + private constructEditWithDelimiters( text: string, useLinePadding: boolean @@ -109,10 +103,6 @@ export default class PositionTarget extends BaseTarget { updateRange: (range) => range, }; } - - private get includeDelimitersInChangeEdit() { - return this.position === "before" || this.position === "after"; - } } function getLinePadding(editor: TextEditor, range: Range, isBefore: boolean) { diff --git a/src/typings/target.types.ts b/src/typings/target.types.ts index 6de21efaf3..080e571a21 100644 --- a/src/typings/target.types.ts +++ b/src/typings/target.types.ts @@ -65,8 +65,6 @@ export interface Target { ): Target; /** Constructs change/insertion edit. Adds delimiter before/after if needed */ constructChangeEdit(text: string): EditWithRangeUpdater; - /** Constructs change/insertion edit. Differs from constructChangeEdit in that it does not add padding on insertion */ - constructEmptyChangeEdit(): EditWithRangeUpdater; /** Constructs removal edit */ constructRemovalEdit(): EditWithRangeUpdater; isEqual(target: Target): boolean; From 3a70fce250f366eb7a9b6b65e15306ddf2de3f38 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Mon, 6 Jun 2022 16:19:30 +0100 Subject: [PATCH 299/314] Add broken float and puff tests --- .../fixtures/recorded/actions/floatThis.yml | 25 ++++++++++++++++ .../fixtures/recorded/actions/floatThis10.yml | 28 ++++++++++++++++++ .../fixtures/recorded/actions/floatThis2.yml | 25 ++++++++++++++++ .../fixtures/recorded/actions/floatThis3.yml | 25 ++++++++++++++++ .../fixtures/recorded/actions/floatThis4.yml | 25 ++++++++++++++++ .../fixtures/recorded/actions/floatThis5.yml | 28 ++++++++++++++++++ .../fixtures/recorded/actions/floatThis6.yml | 28 ++++++++++++++++++ .../fixtures/recorded/actions/floatThis7.yml | 27 +++++++++++++++++ .../fixtures/recorded/actions/floatThis8.yml | 27 +++++++++++++++++ .../fixtures/recorded/actions/floatThis9.yml | 28 ++++++++++++++++++ .../fixtures/recorded/actions/puffThis.yml | 26 +++++++++++++++++ .../fixtures/recorded/actions/puffThis10.yml | 29 +++++++++++++++++++ .../fixtures/recorded/actions/puffThis11.yml | 29 +++++++++++++++++++ .../fixtures/recorded/actions/puffThis2.yml | 26 +++++++++++++++++ .../fixtures/recorded/actions/puffThis3.yml | 26 +++++++++++++++++ .../fixtures/recorded/actions/puffThis4.yml | 26 +++++++++++++++++ .../fixtures/recorded/actions/puffThis5.yml | 29 +++++++++++++++++++ .../fixtures/recorded/actions/puffThis6.yml | 29 +++++++++++++++++++ .../fixtures/recorded/actions/puffThis7.yml | 29 +++++++++++++++++++ .../fixtures/recorded/actions/puffThis8.yml | 28 ++++++++++++++++++ .../fixtures/recorded/actions/puffThis9.yml | 28 ++++++++++++++++++ 21 files changed, 571 insertions(+) create mode 100644 src/test/suite/fixtures/recorded/actions/floatThis.yml create mode 100644 src/test/suite/fixtures/recorded/actions/floatThis10.yml create mode 100644 src/test/suite/fixtures/recorded/actions/floatThis2.yml create mode 100644 src/test/suite/fixtures/recorded/actions/floatThis3.yml create mode 100644 src/test/suite/fixtures/recorded/actions/floatThis4.yml create mode 100644 src/test/suite/fixtures/recorded/actions/floatThis5.yml create mode 100644 src/test/suite/fixtures/recorded/actions/floatThis6.yml create mode 100644 src/test/suite/fixtures/recorded/actions/floatThis7.yml create mode 100644 src/test/suite/fixtures/recorded/actions/floatThis8.yml create mode 100644 src/test/suite/fixtures/recorded/actions/floatThis9.yml create mode 100644 src/test/suite/fixtures/recorded/actions/puffThis.yml create mode 100644 src/test/suite/fixtures/recorded/actions/puffThis10.yml create mode 100644 src/test/suite/fixtures/recorded/actions/puffThis11.yml create mode 100644 src/test/suite/fixtures/recorded/actions/puffThis2.yml create mode 100644 src/test/suite/fixtures/recorded/actions/puffThis3.yml create mode 100644 src/test/suite/fixtures/recorded/actions/puffThis4.yml create mode 100644 src/test/suite/fixtures/recorded/actions/puffThis5.yml create mode 100644 src/test/suite/fixtures/recorded/actions/puffThis6.yml create mode 100644 src/test/suite/fixtures/recorded/actions/puffThis7.yml create mode 100644 src/test/suite/fixtures/recorded/actions/puffThis8.yml create mode 100644 src/test/suite/fixtures/recorded/actions/puffThis9.yml diff --git a/src/test/suite/fixtures/recorded/actions/floatThis.yml b/src/test/suite/fixtures/recorded/actions/floatThis.yml new file mode 100644 index 0000000000..d1844ff8cb --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/floatThis.yml @@ -0,0 +1,25 @@ +languageId: plaintext +command: + spokenForm: float this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: true + action: {name: insertEmptyLineAfter} +initialState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: {} +finalState: + documentContents: |+ + + selections: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} + thatMark: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/floatThis10.yml b/src/test/suite/fixtures/recorded/actions/floatThis10.yml new file mode 100644 index 0000000000..5323e6f741 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/floatThis10.yml @@ -0,0 +1,28 @@ +languageId: plaintext +command: + spokenForm: float this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: true + action: {name: insertEmptyLineAfter} +initialState: + documentContents: |2- + + hello + selections: + - anchor: {line: 1, character: 9} + active: {line: 1, character: 9} + marks: {} +finalState: + documentContents: |2 + + hello + selections: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} + thatMark: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/floatThis2.yml b/src/test/suite/fixtures/recorded/actions/floatThis2.yml new file mode 100644 index 0000000000..a0452c6fa0 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/floatThis2.yml @@ -0,0 +1,25 @@ +languageId: plaintext +command: + spokenForm: float this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: true + action: {name: insertEmptyLineAfter} +initialState: + documentContents: hello + selections: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} + marks: {} +finalState: + documentContents: | + hello + selections: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} + thatMark: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/floatThis3.yml b/src/test/suite/fixtures/recorded/actions/floatThis3.yml new file mode 100644 index 0000000000..a7ddf51e0d --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/floatThis3.yml @@ -0,0 +1,25 @@ +languageId: plaintext +command: + spokenForm: float this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: true + action: {name: insertEmptyLineAfter} +initialState: + documentContents: " hello" + selections: + - anchor: {line: 0, character: 9} + active: {line: 0, character: 9} + marks: {} +finalState: + documentContents: |2 + hello + selections: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} + thatMark: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/floatThis4.yml b/src/test/suite/fixtures/recorded/actions/floatThis4.yml new file mode 100644 index 0000000000..416677e9a3 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/floatThis4.yml @@ -0,0 +1,25 @@ +languageId: plaintext +command: + spokenForm: float this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: true + action: {name: insertEmptyLineAfter} +initialState: + documentContents: " " + selections: + - anchor: {line: 0, character: 4} + active: {line: 0, character: 4} + marks: {} +finalState: + documentContents: |2 + + selections: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} + thatMark: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/floatThis5.yml b/src/test/suite/fixtures/recorded/actions/floatThis5.yml new file mode 100644 index 0000000000..ebc4fa8a73 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/floatThis5.yml @@ -0,0 +1,28 @@ +languageId: plaintext +command: + spokenForm: float this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: true + action: {name: insertEmptyLineAfter} +initialState: + documentContents: |2- + whatever + hello + selections: + - anchor: {line: 1, character: 9} + active: {line: 1, character: 9} + marks: {} +finalState: + documentContents: |2 + whatever + hello + selections: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} + thatMark: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/floatThis6.yml b/src/test/suite/fixtures/recorded/actions/floatThis6.yml new file mode 100644 index 0000000000..1a0b46d20b --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/floatThis6.yml @@ -0,0 +1,28 @@ +languageId: plaintext +command: + spokenForm: float this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: true + action: {name: insertEmptyLineAfter} +initialState: + documentContents: |- + whatever + hello + selections: + - anchor: {line: 1, character: 5} + active: {line: 1, character: 5} + marks: {} +finalState: + documentContents: | + whatever + hello + selections: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} + thatMark: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/floatThis7.yml b/src/test/suite/fixtures/recorded/actions/floatThis7.yml new file mode 100644 index 0000000000..ebdb1d95a5 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/floatThis7.yml @@ -0,0 +1,27 @@ +languageId: plaintext +command: + spokenForm: float this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: true + action: {name: insertEmptyLineAfter} +initialState: + documentContents: | + hello + selections: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} + marks: {} +finalState: + documentContents: |+ + hello + + selections: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} + thatMark: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/floatThis8.yml b/src/test/suite/fixtures/recorded/actions/floatThis8.yml new file mode 100644 index 0000000000..9d61117bb7 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/floatThis8.yml @@ -0,0 +1,27 @@ +languageId: plaintext +command: + spokenForm: float this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: true + action: {name: insertEmptyLineAfter} +initialState: + documentContents: |2 + hello + selections: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} + marks: {} +finalState: + documentContents: |2+ + hello + + selections: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} + thatMark: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/floatThis9.yml b/src/test/suite/fixtures/recorded/actions/floatThis9.yml new file mode 100644 index 0000000000..dad23128db --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/floatThis9.yml @@ -0,0 +1,28 @@ +languageId: plaintext +command: + spokenForm: float this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: true + action: {name: insertEmptyLineAfter} +initialState: + documentContents: |2- + hello + + selections: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} + marks: {} +finalState: + documentContents: |2 + hello + + selections: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} + thatMark: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/puffThis.yml b/src/test/suite/fixtures/recorded/actions/puffThis.yml new file mode 100644 index 0000000000..f9c22d40ef --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/puffThis.yml @@ -0,0 +1,26 @@ +languageId: plaintext +command: + spokenForm: puff this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: true + action: {name: insertEmptyLinesAround} +initialState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: {} +finalState: + documentContents: |+ + + + selections: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} + thatMark: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/puffThis10.yml b/src/test/suite/fixtures/recorded/actions/puffThis10.yml new file mode 100644 index 0000000000..30249d91bd --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/puffThis10.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: puff this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: true + action: {name: insertEmptyLinesAround} +initialState: + documentContents: |2- + hello + + selections: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} + marks: {} +finalState: + documentContents: |2 + hello + + + selections: + - anchor: {line: 3, character: 0} + active: {line: 3, character: 0} + thatMark: + - anchor: {line: 3, character: 0} + active: {line: 3, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/puffThis11.yml b/src/test/suite/fixtures/recorded/actions/puffThis11.yml new file mode 100644 index 0000000000..a1c45092e2 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/puffThis11.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: puff this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: true + action: {name: insertEmptyLinesAround} +initialState: + documentContents: |2- + + hello + selections: + - anchor: {line: 1, character: 9} + active: {line: 1, character: 9} + marks: {} +finalState: + documentContents: |2 + + + hello + selections: + - anchor: {line: 3, character: 0} + active: {line: 3, character: 0} + thatMark: + - anchor: {line: 3, character: 0} + active: {line: 3, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/puffThis2.yml b/src/test/suite/fixtures/recorded/actions/puffThis2.yml new file mode 100644 index 0000000000..9973652b98 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/puffThis2.yml @@ -0,0 +1,26 @@ +languageId: plaintext +command: + spokenForm: puff this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: true + action: {name: insertEmptyLinesAround} +initialState: + documentContents: hello + selections: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} + marks: {} +finalState: + documentContents: | + + hello + selections: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} + thatMark: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/puffThis3.yml b/src/test/suite/fixtures/recorded/actions/puffThis3.yml new file mode 100644 index 0000000000..afbab4df7c --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/puffThis3.yml @@ -0,0 +1,26 @@ +languageId: plaintext +command: + spokenForm: puff this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: true + action: {name: insertEmptyLinesAround} +initialState: + documentContents: " hello" + selections: + - anchor: {line: 0, character: 9} + active: {line: 0, character: 9} + marks: {} +finalState: + documentContents: |2 + + hello + selections: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} + thatMark: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/puffThis4.yml b/src/test/suite/fixtures/recorded/actions/puffThis4.yml new file mode 100644 index 0000000000..367cdd1cc6 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/puffThis4.yml @@ -0,0 +1,26 @@ +languageId: plaintext +command: + spokenForm: puff this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: true + action: {name: insertEmptyLinesAround} +initialState: + documentContents: " " + selections: + - anchor: {line: 0, character: 4} + active: {line: 0, character: 4} + marks: {} +finalState: + documentContents: |2 + + + selections: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} + thatMark: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/puffThis5.yml b/src/test/suite/fixtures/recorded/actions/puffThis5.yml new file mode 100644 index 0000000000..084cf4c0ad --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/puffThis5.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: puff this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: true + action: {name: insertEmptyLinesAround} +initialState: + documentContents: |2- + whatever + hello + selections: + - anchor: {line: 1, character: 9} + active: {line: 1, character: 9} + marks: {} +finalState: + documentContents: |2 + whatever + + hello + selections: + - anchor: {line: 3, character: 0} + active: {line: 3, character: 0} + thatMark: + - anchor: {line: 3, character: 0} + active: {line: 3, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/puffThis6.yml b/src/test/suite/fixtures/recorded/actions/puffThis6.yml new file mode 100644 index 0000000000..761565502d --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/puffThis6.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: puff this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: true + action: {name: insertEmptyLinesAround} +initialState: + documentContents: |- + whatever + hello + selections: + - anchor: {line: 1, character: 5} + active: {line: 1, character: 5} + marks: {} +finalState: + documentContents: | + whatever + + hello + selections: + - anchor: {line: 3, character: 0} + active: {line: 3, character: 0} + thatMark: + - anchor: {line: 3, character: 0} + active: {line: 3, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/puffThis7.yml b/src/test/suite/fixtures/recorded/actions/puffThis7.yml new file mode 100644 index 0000000000..8233b80c15 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/puffThis7.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: puff this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: true + action: {name: insertEmptyLinesAround} +initialState: + documentContents: |- + whatever + hello + selections: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} + marks: {} +finalState: + documentContents: | + whatever + + hello + selections: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} + thatMark: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/puffThis8.yml b/src/test/suite/fixtures/recorded/actions/puffThis8.yml new file mode 100644 index 0000000000..c9bb1c2b06 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/puffThis8.yml @@ -0,0 +1,28 @@ +languageId: plaintext +command: + spokenForm: puff this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: true + action: {name: insertEmptyLinesAround} +initialState: + documentContents: | + hello + selections: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} + marks: {} +finalState: + documentContents: |+ + hello + + + selections: + - anchor: {line: 3, character: 0} + active: {line: 3, character: 0} + thatMark: + - anchor: {line: 3, character: 0} + active: {line: 3, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/puffThis9.yml b/src/test/suite/fixtures/recorded/actions/puffThis9.yml new file mode 100644 index 0000000000..c77f6eacf9 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/puffThis9.yml @@ -0,0 +1,28 @@ +languageId: plaintext +command: + spokenForm: puff this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: true + action: {name: insertEmptyLinesAround} +initialState: + documentContents: |2 + hello + selections: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} + marks: {} +finalState: + documentContents: |2+ + hello + + + selections: + - anchor: {line: 3, character: 0} + active: {line: 3, character: 0} + thatMark: + - anchor: {line: 3, character: 0} + active: {line: 3, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] From 7781afaf39fafd25af40eedd293237d4e3295e65 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Mon, 6 Jun 2022 16:28:10 +0100 Subject: [PATCH 300/314] Add working puff float drop tests --- .../fixtures/recorded/actions/dropThis.yml | 25 +++++++++++++++ .../fixtures/recorded/actions/dropThis10.yml | 29 +++++++++++++++++ .../fixtures/recorded/actions/dropThis11.yml | 29 +++++++++++++++++ .../fixtures/recorded/actions/dropThis12.yml | 29 +++++++++++++++++ .../fixtures/recorded/actions/dropThis2.yml | 26 +++++++++++++++ .../fixtures/recorded/actions/dropThis3.yml | 26 +++++++++++++++ .../fixtures/recorded/actions/dropThis4.yml | 26 +++++++++++++++ .../fixtures/recorded/actions/dropThis5.yml | 26 +++++++++++++++ .../fixtures/recorded/actions/dropThis6.yml | 26 +++++++++++++++ .../fixtures/recorded/actions/dropThis7.yml | 26 +++++++++++++++ .../fixtures/recorded/actions/dropThis8.yml | 26 +++++++++++++++ .../fixtures/recorded/actions/dropThis9.yml | 29 +++++++++++++++++ .../fixtures/recorded/actions/floatThis11.yml | 27 ++++++++++++++++ .../fixtures/recorded/actions/floatThis12.yml | 27 ++++++++++++++++ .../fixtures/recorded/actions/floatThis13.yml | 27 ++++++++++++++++ .../fixtures/recorded/actions/puffThis12.yml | 28 ++++++++++++++++ .../fixtures/recorded/actions/puffThis13.yml | 28 ++++++++++++++++ .../fixtures/recorded/actions/puffThis14.yml | 28 ++++++++++++++++ .../fixtures/recorded/actions/puffThis15.yml | 28 ++++++++++++++++ .../fixtures/recorded/actions/puffThis16.yml | 28 ++++++++++++++++ .../fixtures/recorded/actions/puffThis17.yml | 28 ++++++++++++++++ .../fixtures/recorded/actions/puffThis18.yml | 30 +++++++++++++++++ .../fixtures/recorded/actions/puffThis19.yml | 30 +++++++++++++++++ .../fixtures/recorded/actions/puffThis20.yml | 32 +++++++++++++++++++ .../fixtures/recorded/actions/puffThis21.yml | 32 +++++++++++++++++++ .../fixtures/recorded/actions/puffThis22.yml | 32 +++++++++++++++++++ 26 files changed, 728 insertions(+) create mode 100644 src/test/suite/fixtures/recorded/actions/dropThis.yml create mode 100644 src/test/suite/fixtures/recorded/actions/dropThis10.yml create mode 100644 src/test/suite/fixtures/recorded/actions/dropThis11.yml create mode 100644 src/test/suite/fixtures/recorded/actions/dropThis12.yml create mode 100644 src/test/suite/fixtures/recorded/actions/dropThis2.yml create mode 100644 src/test/suite/fixtures/recorded/actions/dropThis3.yml create mode 100644 src/test/suite/fixtures/recorded/actions/dropThis4.yml create mode 100644 src/test/suite/fixtures/recorded/actions/dropThis5.yml create mode 100644 src/test/suite/fixtures/recorded/actions/dropThis6.yml create mode 100644 src/test/suite/fixtures/recorded/actions/dropThis7.yml create mode 100644 src/test/suite/fixtures/recorded/actions/dropThis8.yml create mode 100644 src/test/suite/fixtures/recorded/actions/dropThis9.yml create mode 100644 src/test/suite/fixtures/recorded/actions/floatThis11.yml create mode 100644 src/test/suite/fixtures/recorded/actions/floatThis12.yml create mode 100644 src/test/suite/fixtures/recorded/actions/floatThis13.yml create mode 100644 src/test/suite/fixtures/recorded/actions/puffThis12.yml create mode 100644 src/test/suite/fixtures/recorded/actions/puffThis13.yml create mode 100644 src/test/suite/fixtures/recorded/actions/puffThis14.yml create mode 100644 src/test/suite/fixtures/recorded/actions/puffThis15.yml create mode 100644 src/test/suite/fixtures/recorded/actions/puffThis16.yml create mode 100644 src/test/suite/fixtures/recorded/actions/puffThis17.yml create mode 100644 src/test/suite/fixtures/recorded/actions/puffThis18.yml create mode 100644 src/test/suite/fixtures/recorded/actions/puffThis19.yml create mode 100644 src/test/suite/fixtures/recorded/actions/puffThis20.yml create mode 100644 src/test/suite/fixtures/recorded/actions/puffThis21.yml create mode 100644 src/test/suite/fixtures/recorded/actions/puffThis22.yml diff --git a/src/test/suite/fixtures/recorded/actions/dropThis.yml b/src/test/suite/fixtures/recorded/actions/dropThis.yml new file mode 100644 index 0000000000..304d86fc24 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/dropThis.yml @@ -0,0 +1,25 @@ +languageId: plaintext +command: + spokenForm: drop this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: true + action: {name: insertEmptyLineBefore} +initialState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: {} +finalState: + documentContents: |+ + + selections: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} + thatMark: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/dropThis10.yml b/src/test/suite/fixtures/recorded/actions/dropThis10.yml new file mode 100644 index 0000000000..96d4830da7 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/dropThis10.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: drop this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: false + action: {name: insertEmptyLineBefore} +initialState: + documentContents: |- + hello + there + selections: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} + marks: {} +finalState: + documentContents: |- + hello + + there + selections: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} + thatMark: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/dropThis11.yml b/src/test/suite/fixtures/recorded/actions/dropThis11.yml new file mode 100644 index 0000000000..a7d7a7e10f --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/dropThis11.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: drop this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: false + action: {name: insertEmptyLineBefore} +initialState: + documentContents: |2- + hello + there + selections: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} + marks: {} +finalState: + documentContents: |2- + hello + + there + selections: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} + thatMark: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/dropThis12.yml b/src/test/suite/fixtures/recorded/actions/dropThis12.yml new file mode 100644 index 0000000000..65ca31fa3d --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/dropThis12.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: drop this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: true + action: {name: insertEmptyLineBefore} +initialState: + documentContents: |2- + hello + + selections: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} + marks: {} +finalState: + documentContents: |2- + hello + + + selections: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} + thatMark: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/dropThis2.yml b/src/test/suite/fixtures/recorded/actions/dropThis2.yml new file mode 100644 index 0000000000..427a4b1402 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/dropThis2.yml @@ -0,0 +1,26 @@ +languageId: plaintext +command: + spokenForm: drop this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: true + action: {name: insertEmptyLineBefore} +initialState: + documentContents: hello + selections: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} + marks: {} +finalState: + documentContents: |- + + hello + selections: + - anchor: {line: 1, character: 5} + active: {line: 1, character: 5} + thatMark: + - anchor: {line: 1, character: 5} + active: {line: 1, character: 5} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/dropThis3.yml b/src/test/suite/fixtures/recorded/actions/dropThis3.yml new file mode 100644 index 0000000000..d53bf68679 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/dropThis3.yml @@ -0,0 +1,26 @@ +languageId: plaintext +command: + spokenForm: drop this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: false + action: {name: insertEmptyLineBefore} +initialState: + documentContents: hello + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: {} +finalState: + documentContents: |- + + hello + selections: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} + thatMark: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/dropThis4.yml b/src/test/suite/fixtures/recorded/actions/dropThis4.yml new file mode 100644 index 0000000000..f67774acbb --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/dropThis4.yml @@ -0,0 +1,26 @@ +languageId: plaintext +command: + spokenForm: drop this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: false + action: {name: insertEmptyLineBefore} +initialState: + documentContents: " hello" + selections: + - anchor: {line: 0, character: 4} + active: {line: 0, character: 4} + marks: {} +finalState: + documentContents: |2- + + hello + selections: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} + thatMark: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/dropThis5.yml b/src/test/suite/fixtures/recorded/actions/dropThis5.yml new file mode 100644 index 0000000000..f7243dae5c --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/dropThis5.yml @@ -0,0 +1,26 @@ +languageId: plaintext +command: + spokenForm: drop this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: false + action: {name: insertEmptyLineBefore} +initialState: + documentContents: " hello" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: {} +finalState: + documentContents: |2- + + hello + selections: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} + thatMark: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/dropThis6.yml b/src/test/suite/fixtures/recorded/actions/dropThis6.yml new file mode 100644 index 0000000000..acb8228d8a --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/dropThis6.yml @@ -0,0 +1,26 @@ +languageId: plaintext +command: + spokenForm: drop this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: false + action: {name: insertEmptyLineBefore} +initialState: + documentContents: " hello" + selections: + - anchor: {line: 0, character: 9} + active: {line: 0, character: 9} + marks: {} +finalState: + documentContents: |2- + + hello + selections: + - anchor: {line: 1, character: 9} + active: {line: 1, character: 9} + thatMark: + - anchor: {line: 1, character: 9} + active: {line: 1, character: 9} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/dropThis7.yml b/src/test/suite/fixtures/recorded/actions/dropThis7.yml new file mode 100644 index 0000000000..6a26e54edc --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/dropThis7.yml @@ -0,0 +1,26 @@ +languageId: plaintext +command: + spokenForm: drop this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: false + action: {name: insertEmptyLineBefore} +initialState: + documentContents: " " + selections: + - anchor: {line: 0, character: 4} + active: {line: 0, character: 4} + marks: {} +finalState: + documentContents: |2- + + + selections: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} + thatMark: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/dropThis8.yml b/src/test/suite/fixtures/recorded/actions/dropThis8.yml new file mode 100644 index 0000000000..832aac66fb --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/dropThis8.yml @@ -0,0 +1,26 @@ +languageId: plaintext +command: + spokenForm: drop this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: false + action: {name: insertEmptyLineBefore} +initialState: + documentContents: " " + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: {} +finalState: + documentContents: |2- + + + selections: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} + thatMark: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/dropThis9.yml b/src/test/suite/fixtures/recorded/actions/dropThis9.yml new file mode 100644 index 0000000000..d356ad04b0 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/dropThis9.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: drop this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: false + action: {name: insertEmptyLineBefore} +initialState: + documentContents: |- + hello + there + selections: + - anchor: {line: 1, character: 5} + active: {line: 1, character: 5} + marks: {} +finalState: + documentContents: |- + hello + + there + selections: + - anchor: {line: 2, character: 5} + active: {line: 2, character: 5} + thatMark: + - anchor: {line: 2, character: 5} + active: {line: 2, character: 5} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/floatThis11.yml b/src/test/suite/fixtures/recorded/actions/floatThis11.yml new file mode 100644 index 0000000000..f24af11a7b --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/floatThis11.yml @@ -0,0 +1,27 @@ +languageId: plaintext +command: + spokenForm: float this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: true + action: {name: insertEmptyLineAfter} +initialState: + documentContents: | + there + selections: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} + marks: {} +finalState: + documentContents: |+ + there + + selections: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} + thatMark: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/floatThis12.yml b/src/test/suite/fixtures/recorded/actions/floatThis12.yml new file mode 100644 index 0000000000..476429f2e3 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/floatThis12.yml @@ -0,0 +1,27 @@ +languageId: plaintext +command: + spokenForm: float this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: true + action: {name: insertEmptyLineAfter} +initialState: + documentContents: |2 + + selections: + - anchor: {line: 0, character: 4} + active: {line: 0, character: 4} + marks: {} +finalState: + documentContents: |2+ + + + 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: []}] diff --git a/src/test/suite/fixtures/recorded/actions/floatThis13.yml b/src/test/suite/fixtures/recorded/actions/floatThis13.yml new file mode 100644 index 0000000000..45485936cc --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/floatThis13.yml @@ -0,0 +1,27 @@ +languageId: plaintext +command: + spokenForm: float this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: false + action: {name: insertEmptyLineAfter} +initialState: + documentContents: |2 + there + selections: + - anchor: {line: 0, character: 9} + active: {line: 0, character: 9} + marks: {} +finalState: + documentContents: |2+ + there + + 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: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/puffThis12.yml b/src/test/suite/fixtures/recorded/actions/puffThis12.yml new file mode 100644 index 0000000000..870a9e1868 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/puffThis12.yml @@ -0,0 +1,28 @@ +languageId: plaintext +command: + spokenForm: puff this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: true + action: {name: insertEmptyLinesAround} +initialState: + documentContents: | + there + selections: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} + marks: {} +finalState: + documentContents: |+ + + there + + selections: + - anchor: {line: 1, character: 5} + active: {line: 1, character: 5} + thatMark: + - anchor: {line: 1, character: 5} + active: {line: 1, character: 5} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/puffThis13.yml b/src/test/suite/fixtures/recorded/actions/puffThis13.yml new file mode 100644 index 0000000000..6668547a63 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/puffThis13.yml @@ -0,0 +1,28 @@ +languageId: plaintext +command: + spokenForm: puff this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: false + action: {name: insertEmptyLinesAround} +initialState: + documentContents: | + there + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: {} +finalState: + documentContents: |+ + + there + + selections: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} + thatMark: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/puffThis14.yml b/src/test/suite/fixtures/recorded/actions/puffThis14.yml new file mode 100644 index 0000000000..df50fe5f96 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/puffThis14.yml @@ -0,0 +1,28 @@ +languageId: plaintext +command: + spokenForm: puff this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: false + action: {name: insertEmptyLinesAround} +initialState: + documentContents: |2 + there + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: {} +finalState: + documentContents: |2+ + + there + + selections: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} + thatMark: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/puffThis15.yml b/src/test/suite/fixtures/recorded/actions/puffThis15.yml new file mode 100644 index 0000000000..e7e4623c95 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/puffThis15.yml @@ -0,0 +1,28 @@ +languageId: plaintext +command: + spokenForm: puff this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: false + action: {name: insertEmptyLinesAround} +initialState: + documentContents: |2 + there + selections: + - anchor: {line: 0, character: 9} + active: {line: 0, character: 9} + marks: {} +finalState: + documentContents: |2+ + + there + + selections: + - anchor: {line: 1, character: 9} + active: {line: 1, character: 9} + thatMark: + - anchor: {line: 1, character: 9} + active: {line: 1, character: 9} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/puffThis16.yml b/src/test/suite/fixtures/recorded/actions/puffThis16.yml new file mode 100644 index 0000000000..b081949c92 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/puffThis16.yml @@ -0,0 +1,28 @@ +languageId: plaintext +command: + spokenForm: puff this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: false + action: {name: insertEmptyLinesAround} +initialState: + documentContents: |2 + + selections: + - anchor: {line: 0, character: 4} + active: {line: 0, character: 4} + marks: {} +finalState: + documentContents: |2+ + + + + selections: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} + thatMark: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/puffThis17.yml b/src/test/suite/fixtures/recorded/actions/puffThis17.yml new file mode 100644 index 0000000000..059612aa40 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/puffThis17.yml @@ -0,0 +1,28 @@ +languageId: plaintext +command: + spokenForm: puff this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: false + action: {name: insertEmptyLinesAround} +initialState: + documentContents: |2 + + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: {} +finalState: + documentContents: |2+ + + + + selections: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} + thatMark: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/puffThis18.yml b/src/test/suite/fixtures/recorded/actions/puffThis18.yml new file mode 100644 index 0000000000..ec5a28566c --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/puffThis18.yml @@ -0,0 +1,30 @@ +languageId: plaintext +command: + spokenForm: puff this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: true + action: {name: insertEmptyLinesAround} +initialState: + documentContents: | + hello + there + selections: + - anchor: {line: 1, character: 5} + active: {line: 1, character: 5} + marks: {} +finalState: + documentContents: |+ + hello + + there + + selections: + - anchor: {line: 2, character: 5} + active: {line: 2, character: 5} + thatMark: + - anchor: {line: 2, character: 5} + active: {line: 2, character: 5} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/puffThis19.yml b/src/test/suite/fixtures/recorded/actions/puffThis19.yml new file mode 100644 index 0000000000..cdefcbd587 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/puffThis19.yml @@ -0,0 +1,30 @@ +languageId: plaintext +command: + spokenForm: puff this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: false + action: {name: insertEmptyLinesAround} +initialState: + documentContents: |+ + hello + + selections: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} + marks: {} +finalState: + documentContents: |+ + hello + + + + selections: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} + thatMark: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/puffThis20.yml b/src/test/suite/fixtures/recorded/actions/puffThis20.yml new file mode 100644 index 0000000000..95818bc35d --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/puffThis20.yml @@ -0,0 +1,32 @@ +languageId: plaintext +command: + spokenForm: puff this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: false + action: {name: insertEmptyLinesAround} +initialState: + documentContents: |- + hello + + there + selections: + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} + marks: {} +finalState: + documentContents: |- + hello + + + + there + selections: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} + thatMark: + - anchor: {line: 2, character: 0} + active: {line: 2, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/puffThis21.yml b/src/test/suite/fixtures/recorded/actions/puffThis21.yml new file mode 100644 index 0000000000..d236f55c70 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/puffThis21.yml @@ -0,0 +1,32 @@ +languageId: plaintext +command: + spokenForm: puff this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: false + action: {name: insertEmptyLinesAround} +initialState: + documentContents: |- + hello + now + there + selections: + - anchor: {line: 1, character: 3} + active: {line: 1, character: 3} + marks: {} +finalState: + documentContents: |- + hello + + now + + there + selections: + - anchor: {line: 2, character: 3} + active: {line: 2, character: 3} + thatMark: + - anchor: {line: 2, character: 3} + active: {line: 2, character: 3} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/actions/puffThis22.yml b/src/test/suite/fixtures/recorded/actions/puffThis22.yml new file mode 100644 index 0000000000..89900a5dca --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/puffThis22.yml @@ -0,0 +1,32 @@ +languageId: plaintext +command: + spokenForm: puff this + version: 2 + targets: + - type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: false + action: {name: insertEmptyLinesAround} +initialState: + documentContents: |2- + hello + now + there + selections: + - anchor: {line: 1, character: 7} + active: {line: 1, character: 7} + marks: {} +finalState: + documentContents: |2- + hello + + now + + there + selections: + - anchor: {line: 2, character: 7} + active: {line: 2, character: 7} + thatMark: + - anchor: {line: 2, character: 7} + active: {line: 2, character: 7} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] From 11054b176719a6e3aed486aec5e069074f00287a Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Mon, 6 Jun 2022 18:50:14 +0100 Subject: [PATCH 301/314] Switch to mocha grep syntax for running subset of tests --- .vscode/launch.json | 4 ++-- docs/contributing/CONTRIBUTING.md | 4 ++-- src/test/suite/index.ts | 10 +++++----- src/test/suite/recorded.test.ts | 3 +-- src/test/suite/runSingleRecordedTest.ts | 14 -------------- src/test/suite/runTestSubset.ts | 16 ++++++++++++++++ src/test/util/getFixturePaths.ts | 11 ----------- 7 files changed, 26 insertions(+), 36 deletions(-) delete mode 100644 src/test/suite/runSingleRecordedTest.ts create mode 100644 src/test/suite/runTestSubset.ts diff --git a/.vscode/launch.json b/.vscode/launch.json index 04bd3976c7..3cb63ee5a8 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -42,12 +42,12 @@ ] }, { - "name": "Run Single Extension Test", + "name": "Run Test Subset", "type": "extensionHost", "request": "launch", "env": { "CURSORLESS_TEST": "true", - "CURSORLESS_RUN_SINGLE_TEST": "true" + "CURSORLESS_RUN_TEST_SUBSET": "true" }, "args": [ "--extensions-dir=${workspaceFolder}/.vscode-sandbox/extensions", diff --git a/docs/contributing/CONTRIBUTING.md b/docs/contributing/CONTRIBUTING.md index 2c64700f13..ebeba5b069 100644 --- a/docs/contributing/CONTRIBUTING.md +++ b/docs/contributing/CONTRIBUTING.md @@ -34,9 +34,9 @@ locally, you need to run the extension in debug mode. To do so you need to run the `workbench.action.debug.selectandstart` command in VSCode and then select either "Run Extension" or "Extension Tests". -### Running a single test +### Running a subset of tests -The entire test suite takes a little while to run (1-2 mins), so if you'd like to repeat a single test, you can edit [`runSingleRecordedTest`](../../src/test/suite/runSingleRecordedTest.ts) to refer to the desired test and use the "Run Single Extension Test" launch config instead of the usual "Extension Tests". +The entire test suite takes a little while to run (1-2 mins), so if you'd like to run just a subset of the tests, you can edit the constant in [`runTestSubset`](../../src/test/suite/runTestSubset.ts) to a string supported by [mocha grep](https://mochajs.org/#-grep-regexp-g-regexp) and use the "Run Test Subset" launch config instead of the usual "Extension Tests". ## Code formatting diff --git a/src/test/suite/index.ts b/src/test/suite/index.ts index 11d2d54ac0..5939c8e50d 100644 --- a/src/test/suite/index.ts +++ b/src/test/suite/index.ts @@ -1,20 +1,20 @@ -import * as path from "path"; -import * as Mocha from "mocha"; import * as glob from "glob"; -import { runSingleTest } from "./runSingleRecordedTest"; +import * as Mocha from "mocha"; +import * as path from "path"; +import { runTestSubset, TEST_SUBSET_GREP_STRING } from "./runTestSubset"; export function run(): Promise { // Create the mocha test const mocha = new Mocha({ ui: "tdd", color: true, + grep: runTestSubset() ? TEST_SUBSET_GREP_STRING : undefined, // Only run a subset of tests }); const testsRoot = path.resolve(__dirname, ".."); return new Promise((c, e) => { - const pattern = runSingleTest() ? "**/recorded.test.js" : "**/**.test.js"; - glob(pattern, { cwd: testsRoot }, (err, files) => { + glob("**/**.test.js", { cwd: testsRoot }, (err, files) => { if (err) { return e(err); } diff --git a/src/test/suite/recorded.test.ts b/src/test/suite/recorded.test.ts index 224b574412..840fed52af 100644 --- a/src/test/suite/recorded.test.ts +++ b/src/test/suite/recorded.test.ts @@ -26,7 +26,6 @@ import sleep from "../../util/sleep"; import { openNewEditor } from "../openNewEditor"; import asyncSafety from "../util/asyncSafety"; import { getRecordedTestPaths } from "../util/getFixturePaths"; -import { runSingleTest } from "./runSingleRecordedTest"; function createPosition(position: PositionPlainObject) { return new vscode.Position(position.line, position.character); @@ -40,7 +39,7 @@ function createSelection(selection: SelectionPlainObject): vscode.Selection { suite("recorded test cases", async function () { this.timeout("100s"); - this.retries(runSingleTest() ? 0 : 5); + this.retries(5); teardown(() => { sinon.restore(); diff --git a/src/test/suite/runSingleRecordedTest.ts b/src/test/suite/runSingleRecordedTest.ts deleted file mode 100644 index 37d0671679..0000000000 --- a/src/test/suite/runSingleRecordedTest.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Add the file path ending of a recorded test and ONLY that one will run - * when using the "Run Single Extension Test" launch configuration. - */ - -const filenameEnd = "actions/postVest.yml"; - -export function runSingleTest() { - return process.env.CURSORLESS_RUN_SINGLE_TEST === "true"; -} - -export function getSingleTestFilename(): string { - return filenameEnd; -} diff --git a/src/test/suite/runTestSubset.ts b/src/test/suite/runTestSubset.ts new file mode 100644 index 0000000000..c3c37bf1d4 --- /dev/null +++ b/src/test/suite/runTestSubset.ts @@ -0,0 +1,16 @@ +/** + * The grep string to pass to Mocha when running a subset of tests. This grep + * string will be used with the "Run Single Extension Test" launch + * configuration. + * See https://mochajs.org/#-grep-regexp-g-regexp for supported syntax + */ +export const TEST_SUBSET_GREP_STRING = "actions/insertEmptyLines"; + +/** + * Determine whether we should run just the subset of the tests specified by + * {@link TEST_SUBSET_GREP_STRING}. + * @returns `true` if we are using the run test subset launch config + */ +export function runTestSubset() { + return process.env.CURSORLESS_RUN_TEST_SUBSET === "true"; +} diff --git a/src/test/util/getFixturePaths.ts b/src/test/util/getFixturePaths.ts index 83952a489b..3d51f33985 100644 --- a/src/test/util/getFixturePaths.ts +++ b/src/test/util/getFixturePaths.ts @@ -1,9 +1,5 @@ import * as path from "path"; import { walkFilesSync } from "../../testUtil/walkSync"; -import { - getSingleTestFilename, - runSingleTest, -} from "../suite/runSingleRecordedTest"; export function getFixturesPath() { return path.join(__dirname, "../../../src/test/suite/fixtures"); @@ -16,13 +12,6 @@ export function getFixturePath(fixturePath: string) { export function getRecordedTestPaths() { const directory = path.join(getFixturesPath(), "recorded"); - if (runSingleTest()) { - const test = walkFilesSync(directory).find((path) => - path.endsWith(getSingleTestFilename()) - ); - return test ? [test] : []; - } - return walkFilesSync(directory).filter( (path) => path.endsWith(".yml") || path.endsWith(".yaml") ); From cb9f3220b6434a793babe95b5ff8dfc46d728c37 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Mon, 6 Jun 2022 18:50:37 +0100 Subject: [PATCH 302/314] Make subdir for insert empty lines tests --- .../fixtures/recorded/actions/{ => insertEmptyLines}/dropThis.yml | 0 .../recorded/actions/{ => insertEmptyLines}/dropThis10.yml | 0 .../recorded/actions/{ => insertEmptyLines}/dropThis11.yml | 0 .../recorded/actions/{ => insertEmptyLines}/dropThis12.yml | 0 .../recorded/actions/{ => insertEmptyLines}/dropThis2.yml | 0 .../recorded/actions/{ => insertEmptyLines}/dropThis3.yml | 0 .../recorded/actions/{ => insertEmptyLines}/dropThis4.yml | 0 .../recorded/actions/{ => insertEmptyLines}/dropThis5.yml | 0 .../recorded/actions/{ => insertEmptyLines}/dropThis6.yml | 0 .../recorded/actions/{ => insertEmptyLines}/dropThis7.yml | 0 .../recorded/actions/{ => insertEmptyLines}/dropThis8.yml | 0 .../recorded/actions/{ => insertEmptyLines}/dropThis9.yml | 0 .../recorded/actions/{ => insertEmptyLines}/floatThis.yml | 0 .../recorded/actions/{ => insertEmptyLines}/floatThis10.yml | 0 .../recorded/actions/{ => insertEmptyLines}/floatThis11.yml | 0 .../recorded/actions/{ => insertEmptyLines}/floatThis12.yml | 0 .../recorded/actions/{ => insertEmptyLines}/floatThis13.yml | 0 .../recorded/actions/{ => insertEmptyLines}/floatThis2.yml | 0 .../recorded/actions/{ => insertEmptyLines}/floatThis3.yml | 0 .../recorded/actions/{ => insertEmptyLines}/floatThis4.yml | 0 .../recorded/actions/{ => insertEmptyLines}/floatThis5.yml | 0 .../recorded/actions/{ => insertEmptyLines}/floatThis6.yml | 0 .../recorded/actions/{ => insertEmptyLines}/floatThis7.yml | 0 .../recorded/actions/{ => insertEmptyLines}/floatThis8.yml | 0 .../recorded/actions/{ => insertEmptyLines}/floatThis9.yml | 0 .../recorded/actions/{ => insertEmptyLines}/floatVest.yml | 0 .../recorded/actions/{ => insertEmptyLines}/floatVest2.yml | 0 .../fixtures/recorded/actions/{ => insertEmptyLines}/puffThis.yml | 0 .../recorded/actions/{ => insertEmptyLines}/puffThis10.yml | 0 .../recorded/actions/{ => insertEmptyLines}/puffThis11.yml | 0 .../recorded/actions/{ => insertEmptyLines}/puffThis12.yml | 0 .../recorded/actions/{ => insertEmptyLines}/puffThis13.yml | 0 .../recorded/actions/{ => insertEmptyLines}/puffThis14.yml | 0 .../recorded/actions/{ => insertEmptyLines}/puffThis15.yml | 0 .../recorded/actions/{ => insertEmptyLines}/puffThis16.yml | 0 .../recorded/actions/{ => insertEmptyLines}/puffThis17.yml | 0 .../recorded/actions/{ => insertEmptyLines}/puffThis18.yml | 0 .../recorded/actions/{ => insertEmptyLines}/puffThis19.yml | 0 .../recorded/actions/{ => insertEmptyLines}/puffThis2.yml | 0 .../recorded/actions/{ => insertEmptyLines}/puffThis20.yml | 0 .../recorded/actions/{ => insertEmptyLines}/puffThis21.yml | 0 .../recorded/actions/{ => insertEmptyLines}/puffThis22.yml | 0 .../recorded/actions/{ => insertEmptyLines}/puffThis3.yml | 0 .../recorded/actions/{ => insertEmptyLines}/puffThis4.yml | 0 .../recorded/actions/{ => insertEmptyLines}/puffThis5.yml | 0 .../recorded/actions/{ => insertEmptyLines}/puffThis6.yml | 0 .../recorded/actions/{ => insertEmptyLines}/puffThis7.yml | 0 .../recorded/actions/{ => insertEmptyLines}/puffThis8.yml | 0 .../recorded/actions/{ => insertEmptyLines}/puffThis9.yml | 0 .../fixtures/recorded/actions/{ => insertEmptyLines}/puffVest.yml | 0 .../recorded/actions/{ => insertEmptyLines}/puffVest2.yml | 0 51 files changed, 0 insertions(+), 0 deletions(-) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/dropThis.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/dropThis10.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/dropThis11.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/dropThis12.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/dropThis2.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/dropThis3.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/dropThis4.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/dropThis5.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/dropThis6.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/dropThis7.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/dropThis8.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/dropThis9.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/floatThis.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/floatThis10.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/floatThis11.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/floatThis12.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/floatThis13.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/floatThis2.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/floatThis3.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/floatThis4.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/floatThis5.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/floatThis6.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/floatThis7.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/floatThis8.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/floatThis9.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/floatVest.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/floatVest2.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/puffThis.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/puffThis10.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/puffThis11.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/puffThis12.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/puffThis13.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/puffThis14.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/puffThis15.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/puffThis16.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/puffThis17.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/puffThis18.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/puffThis19.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/puffThis2.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/puffThis20.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/puffThis21.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/puffThis22.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/puffThis3.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/puffThis4.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/puffThis5.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/puffThis6.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/puffThis7.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/puffThis8.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/puffThis9.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/puffVest.yml (100%) rename src/test/suite/fixtures/recorded/actions/{ => insertEmptyLines}/puffVest2.yml (100%) diff --git a/src/test/suite/fixtures/recorded/actions/dropThis.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/dropThis.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis.yml diff --git a/src/test/suite/fixtures/recorded/actions/dropThis10.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis10.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/dropThis10.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis10.yml diff --git a/src/test/suite/fixtures/recorded/actions/dropThis11.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis11.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/dropThis11.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis11.yml diff --git a/src/test/suite/fixtures/recorded/actions/dropThis12.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis12.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/dropThis12.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis12.yml diff --git a/src/test/suite/fixtures/recorded/actions/dropThis2.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis2.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/dropThis2.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis2.yml diff --git a/src/test/suite/fixtures/recorded/actions/dropThis3.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis3.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/dropThis3.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis3.yml diff --git a/src/test/suite/fixtures/recorded/actions/dropThis4.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis4.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/dropThis4.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis4.yml diff --git a/src/test/suite/fixtures/recorded/actions/dropThis5.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis5.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/dropThis5.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis5.yml diff --git a/src/test/suite/fixtures/recorded/actions/dropThis6.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis6.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/dropThis6.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis6.yml diff --git a/src/test/suite/fixtures/recorded/actions/dropThis7.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis7.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/dropThis7.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis7.yml diff --git a/src/test/suite/fixtures/recorded/actions/dropThis8.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis8.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/dropThis8.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis8.yml diff --git a/src/test/suite/fixtures/recorded/actions/dropThis9.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis9.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/dropThis9.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis9.yml diff --git a/src/test/suite/fixtures/recorded/actions/floatThis.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/floatThis.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis.yml diff --git a/src/test/suite/fixtures/recorded/actions/floatThis10.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis10.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/floatThis10.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis10.yml diff --git a/src/test/suite/fixtures/recorded/actions/floatThis11.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis11.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/floatThis11.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis11.yml diff --git a/src/test/suite/fixtures/recorded/actions/floatThis12.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis12.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/floatThis12.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis12.yml diff --git a/src/test/suite/fixtures/recorded/actions/floatThis13.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis13.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/floatThis13.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis13.yml diff --git a/src/test/suite/fixtures/recorded/actions/floatThis2.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis2.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/floatThis2.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis2.yml diff --git a/src/test/suite/fixtures/recorded/actions/floatThis3.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis3.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/floatThis3.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis3.yml diff --git a/src/test/suite/fixtures/recorded/actions/floatThis4.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis4.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/floatThis4.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis4.yml diff --git a/src/test/suite/fixtures/recorded/actions/floatThis5.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis5.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/floatThis5.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis5.yml diff --git a/src/test/suite/fixtures/recorded/actions/floatThis6.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis6.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/floatThis6.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis6.yml diff --git a/src/test/suite/fixtures/recorded/actions/floatThis7.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis7.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/floatThis7.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis7.yml diff --git a/src/test/suite/fixtures/recorded/actions/floatThis8.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis8.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/floatThis8.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis8.yml diff --git a/src/test/suite/fixtures/recorded/actions/floatThis9.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis9.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/floatThis9.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis9.yml diff --git a/src/test/suite/fixtures/recorded/actions/floatVest.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatVest.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/floatVest.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatVest.yml diff --git a/src/test/suite/fixtures/recorded/actions/floatVest2.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatVest2.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/floatVest2.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatVest2.yml diff --git a/src/test/suite/fixtures/recorded/actions/puffThis.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/puffThis.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis.yml diff --git a/src/test/suite/fixtures/recorded/actions/puffThis10.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis10.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/puffThis10.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis10.yml diff --git a/src/test/suite/fixtures/recorded/actions/puffThis11.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis11.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/puffThis11.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis11.yml diff --git a/src/test/suite/fixtures/recorded/actions/puffThis12.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis12.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/puffThis12.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis12.yml diff --git a/src/test/suite/fixtures/recorded/actions/puffThis13.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis13.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/puffThis13.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis13.yml diff --git a/src/test/suite/fixtures/recorded/actions/puffThis14.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis14.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/puffThis14.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis14.yml diff --git a/src/test/suite/fixtures/recorded/actions/puffThis15.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis15.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/puffThis15.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis15.yml diff --git a/src/test/suite/fixtures/recorded/actions/puffThis16.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis16.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/puffThis16.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis16.yml diff --git a/src/test/suite/fixtures/recorded/actions/puffThis17.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis17.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/puffThis17.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis17.yml diff --git a/src/test/suite/fixtures/recorded/actions/puffThis18.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis18.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/puffThis18.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis18.yml diff --git a/src/test/suite/fixtures/recorded/actions/puffThis19.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis19.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/puffThis19.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis19.yml diff --git a/src/test/suite/fixtures/recorded/actions/puffThis2.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis2.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/puffThis2.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis2.yml diff --git a/src/test/suite/fixtures/recorded/actions/puffThis20.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis20.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/puffThis20.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis20.yml diff --git a/src/test/suite/fixtures/recorded/actions/puffThis21.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis21.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/puffThis21.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis21.yml diff --git a/src/test/suite/fixtures/recorded/actions/puffThis22.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis22.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/puffThis22.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis22.yml diff --git a/src/test/suite/fixtures/recorded/actions/puffThis3.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis3.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/puffThis3.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis3.yml diff --git a/src/test/suite/fixtures/recorded/actions/puffThis4.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis4.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/puffThis4.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis4.yml diff --git a/src/test/suite/fixtures/recorded/actions/puffThis5.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis5.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/puffThis5.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis5.yml diff --git a/src/test/suite/fixtures/recorded/actions/puffThis6.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis6.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/puffThis6.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis6.yml diff --git a/src/test/suite/fixtures/recorded/actions/puffThis7.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis7.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/puffThis7.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis7.yml diff --git a/src/test/suite/fixtures/recorded/actions/puffThis8.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis8.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/puffThis8.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis8.yml diff --git a/src/test/suite/fixtures/recorded/actions/puffThis9.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis9.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/puffThis9.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis9.yml diff --git a/src/test/suite/fixtures/recorded/actions/puffVest.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffVest.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/puffVest.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffVest.yml diff --git a/src/test/suite/fixtures/recorded/actions/puffVest2.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffVest2.yml similarity index 100% rename from src/test/suite/fixtures/recorded/actions/puffVest2.yml rename to src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffVest2.yml From 445cc6a3239b25fa940aca17abd17f225df98ecc Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Mon, 6 Jun 2022 19:06:16 +0100 Subject: [PATCH 303/314] Support updating fixture decorations --- .vscode/launch.json | 22 ++++++++++++++++++++++ src/test/suite/recorded.test.ts | 25 +++++++++++++++++-------- 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 3cb63ee5a8..9fa7d9f27f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -83,6 +83,28 @@ "!**/node_modules/**" ] }, + { + "name": "Update fixtures subset", + "type": "extensionHost", + "request": "launch", + "env": { + "CURSORLESS_TEST": "true", + "CURSORLESS_TEST_UPDATE_FIXTURES": "true", + "CURSORLESS_RUN_TEST_SUBSET": "true" + }, + "args": [ + "--extensions-dir=${workspaceFolder}/.vscode-sandbox/extensions", + "--extensionDevelopmentPath=${workspaceFolder}", + "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" + ], + "outFiles": ["${workspaceFolder}/out/test/**/*.js"], + "preLaunchTask": "${defaultBuildTask}", + "resolveSourceMapLocations": [ + "${workspaceFolder}/**", + "!${workspaceFolder}/.vscode-sandbox/**", + "!**/node_modules/**" + ] + }, { "name": "Docusaurus Start (Debug)", "type": "node", diff --git a/src/test/suite/recorded.test.ts b/src/test/suite/recorded.test.ts index 840fed52af..24aebf2f6a 100644 --- a/src/test/suite/recorded.test.ts +++ b/src/test/suite/recorded.test.ts @@ -165,8 +165,19 @@ async function runTest(file: string) { marks ); + const actualDecorations = + fixture.decorations == null + ? undefined + : testDecorationsToPlainObject(graph.editStyles.testDecorations); + if (process.env.CURSORLESS_TEST_UPDATE_FIXTURES === "true") { - const outputFixture = { ...fixture, finalState: resultState, returnValue }; + const outputFixture = { + ...fixture, + finalState: resultState, + decorations: actualDecorations, + returnValue, + }; + await fsp.writeFile(file, serialize(outputFixture)); } else { assert.deepStrictEqual( @@ -175,13 +186,11 @@ async function runTest(file: string) { "Unexpected final state" ); - if (fixture.decorations != null) { - assert.deepStrictEqual( - testDecorationsToPlainObject(graph.editStyles.testDecorations), - fixture.decorations, - "Unexpected decorations" - ); - } + assert.deepStrictEqual( + actualDecorations, + fixture.decorations, + "Unexpected decorations" + ); assert.deepStrictEqual( returnValue, From 6665f7d00445bb86726125987e223ad9e5ca5838 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Mon, 6 Jun 2022 19:06:42 +0100 Subject: [PATCH 304/314] Add decorations to float drop puff tests --- .../recorded/actions/insertEmptyLines/dropThis.yml | 5 +++++ .../recorded/actions/insertEmptyLines/dropThis10.yml | 5 +++++ .../recorded/actions/insertEmptyLines/dropThis11.yml | 5 +++++ .../recorded/actions/insertEmptyLines/dropThis12.yml | 5 +++++ .../recorded/actions/insertEmptyLines/dropThis2.yml | 5 +++++ .../recorded/actions/insertEmptyLines/dropThis3.yml | 5 +++++ .../recorded/actions/insertEmptyLines/dropThis4.yml | 5 +++++ .../recorded/actions/insertEmptyLines/dropThis5.yml | 5 +++++ .../recorded/actions/insertEmptyLines/dropThis6.yml | 5 +++++ .../recorded/actions/insertEmptyLines/dropThis7.yml | 5 +++++ .../recorded/actions/insertEmptyLines/dropThis8.yml | 5 +++++ .../recorded/actions/insertEmptyLines/dropThis9.yml | 5 +++++ .../recorded/actions/insertEmptyLines/floatThis.yml | 5 +++++ .../recorded/actions/insertEmptyLines/floatThis10.yml | 5 +++++ .../recorded/actions/insertEmptyLines/floatThis11.yml | 5 +++++ .../recorded/actions/insertEmptyLines/floatThis12.yml | 5 +++++ .../recorded/actions/insertEmptyLines/floatThis13.yml | 5 +++++ .../recorded/actions/insertEmptyLines/floatThis2.yml | 5 +++++ .../recorded/actions/insertEmptyLines/floatThis3.yml | 5 +++++ .../recorded/actions/insertEmptyLines/floatThis4.yml | 5 +++++ .../recorded/actions/insertEmptyLines/floatThis5.yml | 5 +++++ .../recorded/actions/insertEmptyLines/floatThis6.yml | 5 +++++ .../recorded/actions/insertEmptyLines/floatThis7.yml | 5 +++++ .../recorded/actions/insertEmptyLines/floatThis8.yml | 5 +++++ .../recorded/actions/insertEmptyLines/floatThis9.yml | 5 +++++ .../recorded/actions/insertEmptyLines/floatVest.yml | 5 +++++ .../recorded/actions/insertEmptyLines/floatVest2.yml | 5 +++++ .../recorded/actions/insertEmptyLines/puffThis.yml | 9 +++++++++ .../recorded/actions/insertEmptyLines/puffThis10.yml | 9 +++++++++ .../recorded/actions/insertEmptyLines/puffThis11.yml | 9 +++++++++ .../recorded/actions/insertEmptyLines/puffThis12.yml | 9 +++++++++ .../recorded/actions/insertEmptyLines/puffThis13.yml | 9 +++++++++ .../recorded/actions/insertEmptyLines/puffThis14.yml | 9 +++++++++ .../recorded/actions/insertEmptyLines/puffThis15.yml | 9 +++++++++ .../recorded/actions/insertEmptyLines/puffThis16.yml | 9 +++++++++ .../recorded/actions/insertEmptyLines/puffThis17.yml | 9 +++++++++ .../recorded/actions/insertEmptyLines/puffThis18.yml | 9 +++++++++ .../recorded/actions/insertEmptyLines/puffThis19.yml | 9 +++++++++ .../recorded/actions/insertEmptyLines/puffThis2.yml | 9 +++++++++ .../recorded/actions/insertEmptyLines/puffThis20.yml | 9 +++++++++ .../recorded/actions/insertEmptyLines/puffThis21.yml | 9 +++++++++ .../recorded/actions/insertEmptyLines/puffThis22.yml | 9 +++++++++ .../recorded/actions/insertEmptyLines/puffThis3.yml | 9 +++++++++ .../recorded/actions/insertEmptyLines/puffThis4.yml | 9 +++++++++ .../recorded/actions/insertEmptyLines/puffThis5.yml | 9 +++++++++ .../recorded/actions/insertEmptyLines/puffThis6.yml | 9 +++++++++ .../recorded/actions/insertEmptyLines/puffThis7.yml | 9 +++++++++ .../recorded/actions/insertEmptyLines/puffThis8.yml | 9 +++++++++ .../recorded/actions/insertEmptyLines/puffThis9.yml | 9 +++++++++ .../recorded/actions/insertEmptyLines/puffVest.yml | 9 +++++++++ .../recorded/actions/insertEmptyLines/puffVest2.yml | 9 +++++++++ 51 files changed, 351 insertions(+) diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis.yml index 304d86fc24..e163a204f5 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis.yml @@ -23,3 +23,8 @@ finalState: - anchor: {line: 1, character: 0} active: {line: 1, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 0, character: 0} + end: {line: 0, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis10.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis10.yml index 96d4830da7..85e18936b1 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis10.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis10.yml @@ -27,3 +27,8 @@ finalState: - anchor: {line: 2, character: 0} active: {line: 2, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 1, character: 0} + end: {line: 1, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis11.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis11.yml index a7d7a7e10f..25ab7eb6dc 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis11.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis11.yml @@ -27,3 +27,8 @@ finalState: - anchor: {line: 2, character: 0} active: {line: 2, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 1, character: 0} + end: {line: 1, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis12.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis12.yml index 65ca31fa3d..40d89660e1 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis12.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis12.yml @@ -27,3 +27,8 @@ finalState: - anchor: {line: 2, character: 0} active: {line: 2, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 1, character: 0} + end: {line: 1, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis2.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis2.yml index 427a4b1402..c7ba6b5e8a 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis2.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis2.yml @@ -24,3 +24,8 @@ finalState: - anchor: {line: 1, character: 5} active: {line: 1, character: 5} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 0, character: 0} + end: {line: 0, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis3.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis3.yml index d53bf68679..c95851cdcf 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis3.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis3.yml @@ -24,3 +24,8 @@ finalState: - anchor: {line: 1, character: 0} active: {line: 1, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 0, character: 0} + end: {line: 0, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis4.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis4.yml index f67774acbb..2b47c044c9 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis4.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis4.yml @@ -24,3 +24,8 @@ finalState: - anchor: {line: 1, character: 4} active: {line: 1, character: 4} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 0, character: 0} + end: {line: 0, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis5.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis5.yml index f7243dae5c..ed800ca184 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis5.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis5.yml @@ -24,3 +24,8 @@ finalState: - anchor: {line: 1, character: 0} active: {line: 1, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 0, character: 0} + end: {line: 0, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis6.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis6.yml index acb8228d8a..2d291d32cd 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis6.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis6.yml @@ -24,3 +24,8 @@ finalState: - anchor: {line: 1, character: 9} active: {line: 1, character: 9} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 0, character: 0} + end: {line: 0, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis7.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis7.yml index 6a26e54edc..f5ff29d5d9 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis7.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis7.yml @@ -24,3 +24,8 @@ finalState: - anchor: {line: 1, character: 4} active: {line: 1, character: 4} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 0, character: 0} + end: {line: 0, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis8.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis8.yml index 832aac66fb..bab7b26fbd 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis8.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis8.yml @@ -24,3 +24,8 @@ finalState: - anchor: {line: 1, character: 0} active: {line: 1, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 0, character: 0} + end: {line: 0, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis9.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis9.yml index d356ad04b0..3893999caa 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis9.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropThis9.yml @@ -27,3 +27,8 @@ finalState: - anchor: {line: 2, character: 5} active: {line: 2, character: 5} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 1, character: 0} + end: {line: 1, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis.yml index d1844ff8cb..44f4647525 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis.yml @@ -23,3 +23,8 @@ finalState: - anchor: {line: 1, character: 0} active: {line: 1, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 1, character: 0} + end: {line: 1, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis10.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis10.yml index 5323e6f741..12141b100b 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis10.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis10.yml @@ -26,3 +26,8 @@ finalState: - anchor: {line: 2, character: 0} active: {line: 2, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 2, character: 0} + end: {line: 2, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis11.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis11.yml index f24af11a7b..c7b2c96cf0 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis11.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis11.yml @@ -25,3 +25,8 @@ finalState: - anchor: {line: 0, character: 5} active: {line: 0, character: 5} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 1, character: 0} + end: {line: 1, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis12.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis12.yml index 476429f2e3..6b6331830a 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis12.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis12.yml @@ -25,3 +25,8 @@ finalState: - anchor: {line: 0, character: 4} active: {line: 0, character: 4} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 1, character: 0} + end: {line: 1, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis13.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis13.yml index 45485936cc..cbee2b219f 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis13.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis13.yml @@ -25,3 +25,8 @@ finalState: - anchor: {line: 0, character: 9} active: {line: 0, character: 9} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 1, character: 0} + end: {line: 1, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis2.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis2.yml index a0452c6fa0..ac97b8af72 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis2.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis2.yml @@ -23,3 +23,8 @@ finalState: - anchor: {line: 1, character: 0} active: {line: 1, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 1, character: 0} + end: {line: 1, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis3.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis3.yml index a7ddf51e0d..02b96e3a6b 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis3.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis3.yml @@ -23,3 +23,8 @@ finalState: - anchor: {line: 1, character: 0} active: {line: 1, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 1, character: 0} + end: {line: 1, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis4.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis4.yml index 416677e9a3..7a1438b8ce 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis4.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis4.yml @@ -23,3 +23,8 @@ finalState: - anchor: {line: 1, character: 0} active: {line: 1, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 1, character: 0} + end: {line: 1, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis5.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis5.yml index ebc4fa8a73..9892927a0d 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis5.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis5.yml @@ -26,3 +26,8 @@ finalState: - anchor: {line: 2, character: 0} active: {line: 2, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 2, character: 0} + end: {line: 2, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis6.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis6.yml index 1a0b46d20b..895b0e49b6 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis6.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis6.yml @@ -26,3 +26,8 @@ finalState: - anchor: {line: 2, character: 0} active: {line: 2, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 2, character: 0} + end: {line: 2, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis7.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis7.yml index ebdb1d95a5..9ed220ea06 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis7.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis7.yml @@ -25,3 +25,8 @@ finalState: - anchor: {line: 2, character: 0} active: {line: 2, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 2, character: 0} + end: {line: 2, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis8.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis8.yml index 9d61117bb7..d5ad098dbc 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis8.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis8.yml @@ -25,3 +25,8 @@ finalState: - anchor: {line: 2, character: 0} active: {line: 2, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 2, character: 0} + end: {line: 2, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis9.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis9.yml index dad23128db..e67adbf4ef 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis9.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatThis9.yml @@ -26,3 +26,8 @@ finalState: - anchor: {line: 2, character: 0} active: {line: 2, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 2, character: 0} + end: {line: 2, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatVest.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatVest.yml index da3a3beb0b..fc52dd8b5d 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatVest.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatVest.yml @@ -29,3 +29,8 @@ finalState: - anchor: {line: 1, character: 6} active: {line: 1, character: 11} fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: v}, selectionType: token, position: contents, modifier: {type: identity}, insideOutsideType: inside}] +decorations: + - name: justAddedBackground + type: line + start: {line: 2, character: 0} + end: {line: 2, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatVest2.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatVest2.yml index 7a96fb4a2f..81ea2b2020 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatVest2.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/floatVest2.yml @@ -30,3 +30,8 @@ finalState: - anchor: {line: 1, character: 10} active: {line: 1, character: 15} fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: v}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 2, character: 0} + end: {line: 2, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis.yml index f9c22d40ef..9be2896dfb 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis.yml @@ -24,3 +24,12 @@ finalState: - anchor: {line: 2, character: 0} active: {line: 2, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 1, character: 0} + end: {line: 1, character: 0} + - name: justAddedBackground + type: line + start: {line: 1, character: 0} + end: {line: 1, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis10.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis10.yml index 30249d91bd..2d042e6f3a 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis10.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis10.yml @@ -27,3 +27,12 @@ finalState: - anchor: {line: 3, character: 0} active: {line: 3, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 1, character: 0} + end: {line: 1, character: 0} + - name: justAddedBackground + type: line + start: {line: 2, character: 0} + end: {line: 2, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis11.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis11.yml index a1c45092e2..783ad2d7bc 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis11.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis11.yml @@ -27,3 +27,12 @@ finalState: - anchor: {line: 3, character: 0} active: {line: 3, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 1, character: 0} + end: {line: 1, character: 0} + - name: justAddedBackground + type: line + start: {line: 2, character: 0} + end: {line: 2, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis12.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis12.yml index 870a9e1868..b83b5601e8 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis12.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis12.yml @@ -26,3 +26,12 @@ finalState: - anchor: {line: 1, character: 5} active: {line: 1, character: 5} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 0, character: 0} + end: {line: 0, character: 0} + - name: justAddedBackground + type: line + start: {line: 2, character: 0} + end: {line: 2, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis13.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis13.yml index 6668547a63..07fec702bd 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis13.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis13.yml @@ -26,3 +26,12 @@ finalState: - anchor: {line: 1, character: 0} active: {line: 1, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 0, character: 0} + end: {line: 0, character: 0} + - name: justAddedBackground + type: line + start: {line: 2, character: 0} + end: {line: 2, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis14.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis14.yml index df50fe5f96..5f2f8c0f9a 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis14.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis14.yml @@ -26,3 +26,12 @@ finalState: - anchor: {line: 1, character: 0} active: {line: 1, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 0, character: 0} + end: {line: 0, character: 0} + - name: justAddedBackground + type: line + start: {line: 2, character: 0} + end: {line: 2, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis15.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis15.yml index e7e4623c95..b07217e08e 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis15.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis15.yml @@ -26,3 +26,12 @@ finalState: - anchor: {line: 1, character: 9} active: {line: 1, character: 9} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 0, character: 0} + end: {line: 0, character: 0} + - name: justAddedBackground + type: line + start: {line: 2, character: 0} + end: {line: 2, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis16.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis16.yml index b081949c92..2dfa1aafa0 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis16.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis16.yml @@ -26,3 +26,12 @@ finalState: - anchor: {line: 1, character: 4} active: {line: 1, character: 4} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 0, character: 0} + end: {line: 0, character: 0} + - name: justAddedBackground + type: line + start: {line: 2, character: 0} + end: {line: 2, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis17.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis17.yml index 059612aa40..c67aef5bde 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis17.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis17.yml @@ -26,3 +26,12 @@ finalState: - anchor: {line: 1, character: 0} active: {line: 1, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 0, character: 0} + end: {line: 0, character: 0} + - name: justAddedBackground + type: line + start: {line: 2, character: 0} + end: {line: 2, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis18.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis18.yml index ec5a28566c..48b6b114ed 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis18.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis18.yml @@ -28,3 +28,12 @@ finalState: - anchor: {line: 2, character: 5} active: {line: 2, character: 5} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 1, character: 0} + end: {line: 1, character: 0} + - name: justAddedBackground + type: line + start: {line: 3, character: 0} + end: {line: 3, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis19.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis19.yml index cdefcbd587..6ed741c710 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis19.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis19.yml @@ -28,3 +28,12 @@ finalState: - anchor: {line: 2, character: 0} active: {line: 2, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 1, character: 0} + end: {line: 1, character: 0} + - name: justAddedBackground + type: line + start: {line: 3, character: 0} + end: {line: 3, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis2.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis2.yml index 9973652b98..d927bca2b0 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis2.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis2.yml @@ -24,3 +24,12 @@ finalState: - anchor: {line: 2, character: 0} active: {line: 2, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 0, character: 0} + end: {line: 0, character: 0} + - name: justAddedBackground + type: line + start: {line: 1, character: 0} + end: {line: 1, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis20.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis20.yml index 95818bc35d..136b0922dc 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis20.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis20.yml @@ -30,3 +30,12 @@ finalState: - anchor: {line: 2, character: 0} active: {line: 2, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 1, character: 0} + end: {line: 1, character: 0} + - name: justAddedBackground + type: line + start: {line: 3, character: 0} + end: {line: 3, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis21.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis21.yml index d236f55c70..348835ed49 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis21.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis21.yml @@ -30,3 +30,12 @@ finalState: - anchor: {line: 2, character: 3} active: {line: 2, character: 3} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 1, character: 0} + end: {line: 1, character: 0} + - name: justAddedBackground + type: line + start: {line: 3, character: 0} + end: {line: 3, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis22.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis22.yml index 89900a5dca..55af8d644f 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis22.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis22.yml @@ -30,3 +30,12 @@ finalState: - anchor: {line: 2, character: 7} active: {line: 2, character: 7} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 1, character: 0} + end: {line: 1, character: 0} + - name: justAddedBackground + type: line + start: {line: 3, character: 0} + end: {line: 3, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis3.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis3.yml index afbab4df7c..f102ba9976 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis3.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis3.yml @@ -24,3 +24,12 @@ finalState: - anchor: {line: 2, character: 0} active: {line: 2, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 0, character: 0} + end: {line: 0, character: 0} + - name: justAddedBackground + type: line + start: {line: 1, character: 0} + end: {line: 1, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis4.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis4.yml index 367cdd1cc6..cc85907453 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis4.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis4.yml @@ -24,3 +24,12 @@ finalState: - anchor: {line: 2, character: 0} active: {line: 2, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 0, character: 0} + end: {line: 0, character: 0} + - name: justAddedBackground + type: line + start: {line: 1, character: 0} + end: {line: 1, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis5.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis5.yml index 084cf4c0ad..d05ef8a883 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis5.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis5.yml @@ -27,3 +27,12 @@ finalState: - anchor: {line: 3, character: 0} active: {line: 3, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 1, character: 0} + end: {line: 1, character: 0} + - name: justAddedBackground + type: line + start: {line: 2, character: 0} + end: {line: 2, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis6.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis6.yml index 761565502d..2c04455b2a 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis6.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis6.yml @@ -27,3 +27,12 @@ finalState: - anchor: {line: 3, character: 0} active: {line: 3, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 1, character: 0} + end: {line: 1, character: 0} + - name: justAddedBackground + type: line + start: {line: 2, character: 0} + end: {line: 2, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis7.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis7.yml index 8233b80c15..4abd1e33f1 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis7.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis7.yml @@ -27,3 +27,12 @@ finalState: - anchor: {line: 2, character: 0} active: {line: 2, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 1, character: 0} + end: {line: 1, character: 0} + - name: justAddedBackground + type: line + start: {line: 2, character: 0} + end: {line: 2, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis8.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis8.yml index c9bb1c2b06..ae301a3457 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis8.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis8.yml @@ -26,3 +26,12 @@ finalState: - anchor: {line: 3, character: 0} active: {line: 3, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 2, character: 0} + end: {line: 2, character: 0} + - name: justAddedBackground + type: line + start: {line: 2, character: 0} + end: {line: 2, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis9.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis9.yml index c77f6eacf9..b634d91653 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis9.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffThis9.yml @@ -26,3 +26,12 @@ finalState: - anchor: {line: 3, character: 0} active: {line: 3, character: 0} fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 2, character: 0} + end: {line: 2, character: 0} + - name: justAddedBackground + type: line + start: {line: 2, character: 0} + end: {line: 2, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffVest.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffVest.yml index b6db2e5e6a..c62e9723be 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffVest.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffVest.yml @@ -30,3 +30,12 @@ finalState: - anchor: {line: 2, character: 6} active: {line: 2, character: 11} fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: v}, selectionType: token, position: contents, modifier: {type: identity}, insideOutsideType: inside}] +decorations: + - name: justAddedBackground + type: line + start: {line: 1, character: 0} + end: {line: 1, character: 0} + - name: justAddedBackground + type: line + start: {line: 3, character: 0} + end: {line: 3, character: 0} diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffVest2.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffVest2.yml index 9c4f98fe06..139f34296a 100644 --- a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffVest2.yml +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/puffVest2.yml @@ -31,3 +31,12 @@ finalState: - anchor: {line: 2, character: 10} active: {line: 2, character: 15} fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: v}, modifiers: []}] +decorations: + - name: justAddedBackground + type: line + start: {line: 1, character: 0} + end: {line: 1, character: 0} + - name: justAddedBackground + type: line + start: {line: 3, character: 0} + end: {line: 3, character: 0} From a0bd2c5398d0d9361a985e2be79974d23f52e1e4 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Mon, 6 Jun 2022 20:03:53 +0100 Subject: [PATCH 305/314] Cleanup test case recorder docs --- docs/contributing/test-case-recorder.md | 41 ++++++++++++++++++++----- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/docs/contributing/test-case-recorder.md b/docs/contributing/test-case-recorder.md index 95ce165b5c..23f7a1c292 100644 --- a/docs/contributing/test-case-recorder.md +++ b/docs/contributing/test-case-recorder.md @@ -10,22 +10,47 @@ command run, and the final state, all in the form of a yaml document. See ## Initial setup -1. Add a voice command for recording to your personal talon files: - - `cursorless record: user.vscode("cursorless.recordTestCase")` - - We don't want to commit this so add it to your own repository. -1. If you'd like to be able to record tests which check the navigation map, please add the following to your personal talon files: +Add a voice command for recording to your personal talon files: - - https://github.com/pokey/pokey_talon/blob/9298c25dd6d28fd9fcf5ed39f305bc6b93e5f229/apps/vscode/vscode.talon#L468 - - https://github.com/pokey/pokey_talon/blob/49643bfa8f62cbec18b5ddad1658f5a28785eb01/apps/vscode/vscode.py#L203-L205 +```talon +cursorless record: user.vscode("cursorless.recordTestCase") +``` + +We don't want to commit this so please add it to your own Talon user file set. + +### Configuring the test case Recorder + +The test case recorder has several additional configuration options. The default configuration works for most tests, but you may find the following useful. + +#### Testing the hat map + +We have a way to test that the hats in the hat map update correctly during the course of a single phrase. These tests are also how we usually test our [range updating code](api/modules/core_updateSelections_updateSelections). + +Please add the following to your personal talon files: + +- https://github.com/pokey/pokey_talon/blob/9298c25dd6d28fd9fcf5ed39f305bc6b93e5f229/apps/vscode/vscode.talon#L468 +- https://github.com/pokey/pokey_talon/blob/49643bfa8f62cbec18b5ddad1658f5a28785eb01/apps/vscode/vscode.py#L203-L205 - It is quite unlikely you'll need this second step. Most tests don't check the navigation map. +It is quite unlikely you'll need this second step. Most tests don't check the navigation map. -1. If you'd like to be able to record tests which assert on non-matches, please add another command to your personal talon files. See the two files links above for context. Add the command below to your to your `vscode.py` and ensure that there is a matching Talon command. +#### Capturing errors + +We support recording tests where the expected result is an error + +Please add a command to your personal talon files. See the two files links above for context. Add the command below to your to your `vscode.py` and ensure that there is a matching Talon command. ``` actions.user.vscode_with_plugin("cursorless.recordTestCase", {"recordErrors": True}) ``` +#### Testing decoration highlights + +We support testing our decoration highlights, eg the flash of red when something is deleted. If you'd like to be able to record tests which check our decoration highlights, please add another command to your personal talon files. See the two files links above for context. Add the command below to your to your `vscode.py` and ensure that there is a matching Talon command. + +``` + actions.user.vscode_with_plugin("cursorless.recordTestCase", {"isDecorationsTest": True}) +``` + ## Recording new tests 1. Start debugging (F5) From 6066ce08ef9c2d2eca5906c33d52e31c5cc517b6 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Mon, 6 Jun 2022 20:07:22 +0100 Subject: [PATCH 306/314] Add bunch of clone tests --- .../fixtures/recorded/actions/cloneArgue.yml | 44 +++++++++++++++++++ .../fixtures/recorded/actions/cloneArgue2.yml | 35 +++++++++++++++ .../fixtures/recorded/actions/cloneToken.yml | 34 ++++++++++++++ .../fixtures/recorded/actions/cloneToken2.yml | 34 ++++++++++++++ .../fixtures/recorded/actions/cloneToken3.yml | 29 ++++++++++++ .../fixtures/recorded/actions/cloneToken4.yml | 29 ++++++++++++ .../fixtures/recorded/actions/cloneToken5.yml | 29 ++++++++++++ .../recorded/actions/cloneUpArgue.yml | 44 +++++++++++++++++++ .../recorded/actions/cloneUpArgue2.yml | 35 +++++++++++++++ .../recorded/actions/cloneUpToken.yml | 34 ++++++++++++++ .../recorded/actions/cloneUpToken2.yml | 34 ++++++++++++++ .../recorded/actions/cloneUpToken3.yml | 29 ++++++++++++ .../recorded/actions/cloneUpToken4.yml | 29 ++++++++++++ .../recorded/actions/cloneUpToken5.yml | 29 ++++++++++++ .../fixtures/recorded/actions/dropVest.yml | 31 ------------- .../fixtures/recorded/actions/dropVest2.yml | 32 -------------- 16 files changed, 468 insertions(+), 63 deletions(-) create mode 100644 src/test/suite/fixtures/recorded/actions/cloneArgue.yml create mode 100644 src/test/suite/fixtures/recorded/actions/cloneArgue2.yml create mode 100644 src/test/suite/fixtures/recorded/actions/cloneToken.yml create mode 100644 src/test/suite/fixtures/recorded/actions/cloneToken2.yml create mode 100644 src/test/suite/fixtures/recorded/actions/cloneToken3.yml create mode 100644 src/test/suite/fixtures/recorded/actions/cloneToken4.yml create mode 100644 src/test/suite/fixtures/recorded/actions/cloneToken5.yml create mode 100644 src/test/suite/fixtures/recorded/actions/cloneUpArgue.yml create mode 100644 src/test/suite/fixtures/recorded/actions/cloneUpArgue2.yml create mode 100644 src/test/suite/fixtures/recorded/actions/cloneUpToken.yml create mode 100644 src/test/suite/fixtures/recorded/actions/cloneUpToken2.yml create mode 100644 src/test/suite/fixtures/recorded/actions/cloneUpToken3.yml create mode 100644 src/test/suite/fixtures/recorded/actions/cloneUpToken4.yml create mode 100644 src/test/suite/fixtures/recorded/actions/cloneUpToken5.yml delete mode 100644 src/test/suite/fixtures/recorded/actions/dropVest.yml delete mode 100644 src/test/suite/fixtures/recorded/actions/dropVest2.yml diff --git a/src/test/suite/fixtures/recorded/actions/cloneArgue.yml b/src/test/suite/fixtures/recorded/actions/cloneArgue.yml new file mode 100644 index 0000000000..e4a4c6e5a8 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/cloneArgue.yml @@ -0,0 +1,44 @@ +languageId: typescript +command: + spokenForm: clone argue + version: 2 + targets: + - type: primitive + modifiers: + - type: containingScope + scopeType: {type: argumentOrParameter} + usePrePhraseSnapshot: true + action: {name: insertCopyAfter} +initialState: + documentContents: |- + function foo(bar: number) { + + } + selections: + - anchor: {line: 0, character: 15} + active: {line: 0, character: 15} + - anchor: {line: 0, character: 20} + active: {line: 0, character: 20} + marks: {} +finalState: + documentContents: |- + function foo(bar: number, bar: number) { + + } + selections: + - anchor: {line: 0, character: 28} + active: {line: 0, character: 28} + - anchor: {line: 0, character: 33} + active: {line: 0, character: 33} + thatMark: + - anchor: {line: 0, character: 26} + active: {line: 0, character: 37} + sourceMark: + - anchor: {line: 0, character: 13} + active: {line: 0, character: 24} +decorations: + - name: justAddedBackground + type: token + start: {line: 0, character: 26} + end: {line: 0, character: 37} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: containingScope, scopeType: {type: argumentOrParameter}}]}] diff --git a/src/test/suite/fixtures/recorded/actions/cloneArgue2.yml b/src/test/suite/fixtures/recorded/actions/cloneArgue2.yml new file mode 100644 index 0000000000..561855f6ab --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/cloneArgue2.yml @@ -0,0 +1,35 @@ +languageId: typescript +command: + spokenForm: clone argue + version: 2 + targets: + - type: primitive + modifiers: + - type: containingScope + scopeType: {type: argumentOrParameter} + usePrePhraseSnapshot: true + action: {name: insertCopyAfter} +initialState: + documentContents: |- + function foo(bar: number) { + + } + selections: + - anchor: {line: 0, character: 24} + active: {line: 0, character: 24} + marks: {} +finalState: + documentContents: |- + function foo(bar: number, bar: number) { + + } + selections: + - anchor: {line: 0, character: 37} + active: {line: 0, character: 37} + thatMark: + - anchor: {line: 0, character: 26} + active: {line: 0, character: 37} + sourceMark: + - anchor: {line: 0, character: 13} + active: {line: 0, character: 24} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: containingScope, scopeType: {type: argumentOrParameter}}]}] diff --git a/src/test/suite/fixtures/recorded/actions/cloneToken.yml b/src/test/suite/fixtures/recorded/actions/cloneToken.yml new file mode 100644 index 0000000000..62c60fc1b9 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/cloneToken.yml @@ -0,0 +1,34 @@ +languageId: plaintext +command: + spokenForm: clone token + version: 2 + targets: + - type: primitive + modifiers: + - type: containingScope + scopeType: {type: token} + usePrePhraseSnapshot: true + action: {name: insertCopyAfter} +initialState: + documentContents: hello world + selections: + - anchor: {line: 0, character: 8} + active: {line: 0, character: 8} + marks: {} +finalState: + documentContents: hello world world + selections: + - anchor: {line: 0, character: 14} + active: {line: 0, character: 14} + thatMark: + - anchor: {line: 0, character: 12} + active: {line: 0, character: 17} + sourceMark: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 11} +decorations: + - name: justAddedBackground + type: token + start: {line: 0, character: 12} + end: {line: 0, character: 17} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: containingScope, scopeType: {type: token}}]}] diff --git a/src/test/suite/fixtures/recorded/actions/cloneToken2.yml b/src/test/suite/fixtures/recorded/actions/cloneToken2.yml new file mode 100644 index 0000000000..ce0cda4cf8 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/cloneToken2.yml @@ -0,0 +1,34 @@ +languageId: plaintext +command: + spokenForm: clone token + version: 2 + targets: + - type: primitive + modifiers: + - type: containingScope + scopeType: {type: token} + usePrePhraseSnapshot: true + action: {name: insertCopyAfter} +initialState: + documentContents: hello + selections: + - anchor: {line: 0, character: 3} + active: {line: 0, character: 3} + marks: {} +finalState: + documentContents: hello hello + selections: + - anchor: {line: 0, character: 9} + active: {line: 0, character: 9} + thatMark: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 11} + sourceMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 5} +decorations: + - name: justAddedBackground + type: token + start: {line: 0, character: 6} + end: {line: 0, character: 11} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: containingScope, scopeType: {type: token}}]}] diff --git a/src/test/suite/fixtures/recorded/actions/cloneToken3.yml b/src/test/suite/fixtures/recorded/actions/cloneToken3.yml new file mode 100644 index 0000000000..ba314d0cea --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/cloneToken3.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: clone token + version: 2 + targets: + - type: primitive + modifiers: + - type: containingScope + scopeType: {type: token} + usePrePhraseSnapshot: true + action: {name: insertCopyAfter} +initialState: + documentContents: hello + selections: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} + marks: {} +finalState: + documentContents: hello hello + selections: + - anchor: {line: 0, character: 11} + active: {line: 0, character: 11} + thatMark: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 11} + sourceMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 5} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: containingScope, scopeType: {type: token}}]}] diff --git a/src/test/suite/fixtures/recorded/actions/cloneToken4.yml b/src/test/suite/fixtures/recorded/actions/cloneToken4.yml new file mode 100644 index 0000000000..2db92264c7 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/cloneToken4.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: clone token + version: 2 + targets: + - type: primitive + modifiers: + - type: containingScope + scopeType: {type: token} + usePrePhraseSnapshot: true + action: {name: insertCopyAfter} +initialState: + documentContents: hello + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: {} +finalState: + documentContents: hello hello + selections: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 6} + thatMark: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 11} + sourceMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 5} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: containingScope, scopeType: {type: token}}]}] diff --git a/src/test/suite/fixtures/recorded/actions/cloneToken5.yml b/src/test/suite/fixtures/recorded/actions/cloneToken5.yml new file mode 100644 index 0000000000..2edb3cc89d --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/cloneToken5.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: clone token + version: 2 + targets: + - type: primitive + modifiers: + - type: containingScope + scopeType: {type: token} + usePrePhraseSnapshot: true + action: {name: insertCopyAfter} +initialState: + documentContents: hello + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 5} + marks: {} +finalState: + documentContents: hello hello + selections: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 11} + thatMark: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 11} + sourceMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 5} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: containingScope, scopeType: {type: token}}]}] diff --git a/src/test/suite/fixtures/recorded/actions/cloneUpArgue.yml b/src/test/suite/fixtures/recorded/actions/cloneUpArgue.yml new file mode 100644 index 0000000000..f4083eec4c --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/cloneUpArgue.yml @@ -0,0 +1,44 @@ +languageId: typescript +command: + spokenForm: clone up argue + version: 2 + targets: + - type: primitive + modifiers: + - type: containingScope + scopeType: {type: argumentOrParameter} + usePrePhraseSnapshot: true + action: {name: insertCopyBefore} +initialState: + documentContents: |- + function foo(bar: number) { + + } + selections: + - anchor: {line: 0, character: 15} + active: {line: 0, character: 15} + - anchor: {line: 0, character: 20} + active: {line: 0, character: 20} + marks: {} +finalState: + documentContents: |- + function foo(bar: number, bar: number) { + + } + selections: + - anchor: {line: 0, character: 15} + active: {line: 0, character: 15} + - anchor: {line: 0, character: 20} + active: {line: 0, character: 20} + thatMark: + - anchor: {line: 0, character: 13} + active: {line: 0, character: 24} + sourceMark: + - anchor: {line: 0, character: 26} + active: {line: 0, character: 37} +decorations: + - name: justAddedBackground + type: token + start: {line: 0, character: 13} + end: {line: 0, character: 24} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: containingScope, scopeType: {type: argumentOrParameter}}]}] diff --git a/src/test/suite/fixtures/recorded/actions/cloneUpArgue2.yml b/src/test/suite/fixtures/recorded/actions/cloneUpArgue2.yml new file mode 100644 index 0000000000..7a8e34064d --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/cloneUpArgue2.yml @@ -0,0 +1,35 @@ +languageId: typescript +command: + spokenForm: clone up argue + version: 2 + targets: + - type: primitive + modifiers: + - type: containingScope + scopeType: {type: argumentOrParameter} + usePrePhraseSnapshot: true + action: {name: insertCopyBefore} +initialState: + documentContents: |- + function foo(bar: number) { + + } + selections: + - anchor: {line: 0, character: 13} + active: {line: 0, character: 13} + marks: {} +finalState: + documentContents: |- + function foo(bar: number, bar: number) { + + } + selections: + - anchor: {line: 0, character: 13} + active: {line: 0, character: 13} + thatMark: + - anchor: {line: 0, character: 13} + active: {line: 0, character: 24} + sourceMark: + - anchor: {line: 0, character: 26} + active: {line: 0, character: 37} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: containingScope, scopeType: {type: argumentOrParameter}}]}] diff --git a/src/test/suite/fixtures/recorded/actions/cloneUpToken.yml b/src/test/suite/fixtures/recorded/actions/cloneUpToken.yml new file mode 100644 index 0000000000..008ffbd7a0 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/cloneUpToken.yml @@ -0,0 +1,34 @@ +languageId: plaintext +command: + spokenForm: clone up token + version: 2 + targets: + - type: primitive + modifiers: + - type: containingScope + scopeType: {type: token} + usePrePhraseSnapshot: true + action: {name: insertCopyBefore} +initialState: + documentContents: hello world + selections: + - anchor: {line: 0, character: 8} + active: {line: 0, character: 8} + marks: {} +finalState: + documentContents: hello world world + selections: + - anchor: {line: 0, character: 8} + active: {line: 0, character: 8} + thatMark: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 11} + sourceMark: + - anchor: {line: 0, character: 12} + active: {line: 0, character: 17} +decorations: + - name: justAddedBackground + type: token + start: {line: 0, character: 6} + end: {line: 0, character: 11} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: containingScope, scopeType: {type: token}}]}] diff --git a/src/test/suite/fixtures/recorded/actions/cloneUpToken2.yml b/src/test/suite/fixtures/recorded/actions/cloneUpToken2.yml new file mode 100644 index 0000000000..1d02e467a6 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/cloneUpToken2.yml @@ -0,0 +1,34 @@ +languageId: plaintext +command: + spokenForm: clone up token + version: 2 + targets: + - type: primitive + modifiers: + - type: containingScope + scopeType: {type: token} + usePrePhraseSnapshot: true + action: {name: insertCopyBefore} +initialState: + documentContents: hello + selections: + - anchor: {line: 0, character: 3} + active: {line: 0, character: 3} + marks: {} +finalState: + documentContents: hello hello + selections: + - anchor: {line: 0, character: 3} + active: {line: 0, character: 3} + thatMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 5} + sourceMark: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 11} +decorations: + - name: justAddedBackground + type: token + start: {line: 0, character: 0} + end: {line: 0, character: 5} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: containingScope, scopeType: {type: token}}]}] diff --git a/src/test/suite/fixtures/recorded/actions/cloneUpToken3.yml b/src/test/suite/fixtures/recorded/actions/cloneUpToken3.yml new file mode 100644 index 0000000000..d70491b759 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/cloneUpToken3.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: clone up token + version: 2 + targets: + - type: primitive + modifiers: + - type: containingScope + scopeType: {type: token} + usePrePhraseSnapshot: true + action: {name: insertCopyBefore} +initialState: + documentContents: hello + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: {} +finalState: + documentContents: hello hello + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 5} + sourceMark: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 11} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: containingScope, scopeType: {type: token}}]}] diff --git a/src/test/suite/fixtures/recorded/actions/cloneUpToken4.yml b/src/test/suite/fixtures/recorded/actions/cloneUpToken4.yml new file mode 100644 index 0000000000..49604b4c05 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/cloneUpToken4.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: clone up token + version: 2 + targets: + - type: primitive + modifiers: + - type: containingScope + scopeType: {type: token} + usePrePhraseSnapshot: false + action: {name: insertCopyBefore} +initialState: + documentContents: hello + selections: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} + marks: {} +finalState: + documentContents: hello hello + selections: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} + thatMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 5} + sourceMark: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 11} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: containingScope, scopeType: {type: token}}]}] diff --git a/src/test/suite/fixtures/recorded/actions/cloneUpToken5.yml b/src/test/suite/fixtures/recorded/actions/cloneUpToken5.yml new file mode 100644 index 0000000000..416f5310b8 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/cloneUpToken5.yml @@ -0,0 +1,29 @@ +languageId: plaintext +command: + spokenForm: clone up token + version: 2 + targets: + - type: primitive + modifiers: + - type: containingScope + scopeType: {type: token} + usePrePhraseSnapshot: true + action: {name: insertCopyBefore} +initialState: + documentContents: hello + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 5} + marks: {} +finalState: + documentContents: hello hello + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 5} + thatMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 5} + sourceMark: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 11} +fullTargets: [{type: primitive, mark: {type: cursor}, modifiers: [{type: containingScope, scopeType: {type: token}}]}] diff --git a/src/test/suite/fixtures/recorded/actions/dropVest.yml b/src/test/suite/fixtures/recorded/actions/dropVest.yml deleted file mode 100644 index 4b526729e5..0000000000 --- a/src/test/suite/fixtures/recorded/actions/dropVest.yml +++ /dev/null @@ -1,31 +0,0 @@ -languageId: typescript -command: - version: 1 - spokenForm: drop vest - action: insertEmptyLineBefore - targets: - - type: primitive - mark: {type: decoratedSymbol, symbolColor: default, character: v} -initialState: - documentContents: | - - const value = "Hello world"; - selections: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} - marks: - default.v: - start: {line: 1, character: 6} - end: {line: 1, character: 11} -finalState: - documentContents: | - - - const value = "Hello world"; - selections: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} - thatMark: - - anchor: {line: 2, character: 6} - active: {line: 2, character: 11} -fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: v}, selectionType: token, position: contents, modifier: {type: identity}, insideOutsideType: inside}] diff --git a/src/test/suite/fixtures/recorded/actions/dropVest2.yml b/src/test/suite/fixtures/recorded/actions/dropVest2.yml deleted file mode 100644 index 2c0d0b5372..0000000000 --- a/src/test/suite/fixtures/recorded/actions/dropVest2.yml +++ /dev/null @@ -1,32 +0,0 @@ -languageId: plaintext -command: - spokenForm: drop vest - version: 2 - targets: - - type: primitive - mark: {type: decoratedSymbol, symbolColor: default, character: v} - usePrePhraseSnapshot: true - action: {name: insertEmptyLineBefore} -initialState: - documentContents: |2 - - const value = "Hello world"; - selections: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} - marks: - default.v: - start: {line: 1, character: 10} - end: {line: 1, character: 15} -finalState: - documentContents: |2 - - - const value = "Hello world"; - selections: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} - thatMark: - - anchor: {line: 2, character: 10} - active: {line: 2, character: 15} -fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: v}, modifiers: []}] From d12fd412fdb6014fe4a112e228f8422086823c2b Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Mon, 6 Jun 2022 20:07:48 +0100 Subject: [PATCH 307/314] Move files --- .../actions/insertEmptyLines/dropVest.yml | 31 ++++++++++++++++++ .../actions/insertEmptyLines/dropVest2.yml | 32 +++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropVest.yml create mode 100644 src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropVest2.yml diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropVest.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropVest.yml new file mode 100644 index 0000000000..4b526729e5 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropVest.yml @@ -0,0 +1,31 @@ +languageId: typescript +command: + version: 1 + spokenForm: drop vest + action: insertEmptyLineBefore + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: v} +initialState: + documentContents: | + + const value = "Hello world"; + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: + default.v: + start: {line: 1, character: 6} + end: {line: 1, character: 11} +finalState: + documentContents: | + + + const value = "Hello world"; + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 2, character: 6} + active: {line: 2, character: 11} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: v}, selectionType: token, position: contents, modifier: {type: identity}, insideOutsideType: inside}] diff --git a/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropVest2.yml b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropVest2.yml new file mode 100644 index 0000000000..2c0d0b5372 --- /dev/null +++ b/src/test/suite/fixtures/recorded/actions/insertEmptyLines/dropVest2.yml @@ -0,0 +1,32 @@ +languageId: plaintext +command: + spokenForm: drop vest + version: 2 + targets: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: v} + usePrePhraseSnapshot: true + action: {name: insertEmptyLineBefore} +initialState: + documentContents: |2 + + const value = "Hello world"; + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: + default.v: + start: {line: 1, character: 10} + end: {line: 1, character: 15} +finalState: + documentContents: |2 + + + const value = "Hello world"; + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 2, character: 10} + active: {line: 2, character: 15} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: v}, modifiers: []}] From 6ee45f5ab6063f0bae0fddacbad4adff2340a625 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Mon, 6 Jun 2022 20:58:41 +0100 Subject: [PATCH 308/314] More cleanup --- .../fixtures/recorded/actions/takeLast.yml | 33 ------------------- ...kePairRound2.yml => clearBoundsRound2.yml} | 0 ...kePairRound2.yml => clearBoundsRound2.yml} | 0 third-party-licenses.csv | 17 +++++++++- 4 files changed, 16 insertions(+), 34 deletions(-) delete mode 100644 src/test/suite/fixtures/recorded/actions/takeLast.yml rename src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/{takePairRound2.yml => clearBoundsRound2.yml} (100%) rename src/test/suite/fixtures/recorded/surroundingPair/textual/{takePairRound2.yml => clearBoundsRound2.yml} (100%) diff --git a/src/test/suite/fixtures/recorded/actions/takeLast.yml b/src/test/suite/fixtures/recorded/actions/takeLast.yml deleted file mode 100644 index d0b0d3acde..0000000000 --- a/src/test/suite/fixtures/recorded/actions/takeLast.yml +++ /dev/null @@ -1,33 +0,0 @@ -languageId: typescript -command: - spokenForm: take last - version: 2 - targets: - - type: primitive - mark: {type: that} - usePrePhraseSnapshot: true - action: {name: setSelection} -initialState: - documentContents: "function myFunk(a: number, a: number, b: number, b: number) {}" - selections: - - anchor: {line: 0, character: 20} - active: {line: 0, character: 20} - marks: {} - thatMark: - - anchor: {line: 0, character: 16} - active: {line: 0, character: 25} - - anchor: {line: 0, character: 38} - active: {line: 0, character: 47} -finalState: - documentContents: "function myFunk(a: number, a: number, b: number, b: number) {}" - selections: - - anchor: {line: 0, character: 16} - active: {line: 0, character: 25} - - anchor: {line: 0, character: 38} - active: {line: 0, character: 47} - thatMark: - - anchor: {line: 0, character: 16} - active: {line: 0, character: 25} - - anchor: {line: 0, character: 38} - active: {line: 0, character: 47} -fullTargets: [{type: primitive, mark: {type: that}, modifiers: []}] diff --git a/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairRound2.yml b/src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/clearBoundsRound2.yml similarity index 100% rename from src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/takePairRound2.yml rename to src/test/suite/fixtures/recorded/surroundingPair/parseTreeParity/clearBoundsRound2.yml diff --git a/src/test/suite/fixtures/recorded/surroundingPair/textual/takePairRound2.yml b/src/test/suite/fixtures/recorded/surroundingPair/textual/clearBoundsRound2.yml similarity index 100% rename from src/test/suite/fixtures/recorded/surroundingPair/textual/takePairRound2.yml rename to src/test/suite/fixtures/recorded/surroundingPair/textual/clearBoundsRound2.yml diff --git a/third-party-licenses.csv b/third-party-licenses.csv index e6029ac60c..d95fd3e299 100644 --- a/third-party-licenses.csv +++ b/third-party-licenses.csv @@ -1,4 +1,19 @@ "module name","licenses","repository","licenseUrl","parents" +"@docusaurus/core@2.0.0-beta.17","MIT","https://github.com/facebook/docusaurus","https://github.com/facebook/docusaurus/raw/master/LICENSE","website" +"@docusaurus/preset-classic@2.0.0-beta.17","MIT","https://github.com/facebook/docusaurus","https://github.com/facebook/docusaurus/raw/master/LICENSE","website" +"@mdx-js/react@1.6.22","MIT","https://github.com/mdx-js/mdx","https://github.com/mdx-js/mdx/raw/master/license","website" "@types/lodash@4.14.181","MIT","https://github.com/DefinitelyTyped/DefinitelyTyped","https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE","cursorless" +"ansicolor@1.1.100","Unlicense","https://github.com/xpl/ansicolor","https://github.com/xpl/ansicolor/raw/master/LICENSE","metals" +"brace-expansion@2.0.1","MIT","https://github.com/juliangruber/brace-expansion","https://github.com/juliangruber/brace-expansion/raw/master/LICENSE","vscode-fileutils" +"clsx@1.1.1","MIT","https://github.com/lukeed/clsx","https://github.com/lukeed/clsx/raw/master/license","website" "immutability-helper@3.1.1","MIT","https://github.com/kolodny/immutability-helper","https://github.com/kolodny/immutability-helper/raw/master/LICENSE","cursorless" -"lodash@4.17.21","MIT","https://github.com/lodash/lodash","https://github.com/lodash/lodash/raw/master/LICENSE","cursorless" +"jsonc-parser@2.3.1","MIT","https://github.com/microsoft/node-jsonc-parser","https://github.com/microsoft/node-jsonc-parser/raw/master/LICENSE.md","parse-tree" +"mdast-util-find-and-replace@2.1.0","MIT","https://github.com/syntax-tree/mdast-util-find-and-replace","https://github.com/syntax-tree/mdast-util-find-and-replace/raw/master/license","website" +"metals-languageclient@0.5.15","Apache-2.0","https://github.com/scalameta/metals-languageclient","https://github.com/scalameta/metals-languageclient/raw/master/LICENSE","metals" +"prism-react-renderer@1.3.1","MIT","https://github.com/FormidableLabs/prism-react-renderer","https://github.com/FormidableLabs/prism-react-renderer/raw/master/LICENSE","website" +"promisify-child-process@4.1.1","MIT","https://github.com/jcoreio/promisify-child-process","https://github.com/jcoreio/promisify-child-process/raw/master/LICENSE.md","metals" +"react-dom@17.0.2","MIT","https://github.com/facebook/react","https://github.com/facebook/react/raw/master/LICENSE","website" +"react@17.0.2","MIT","https://github.com/facebook/react","https://github.com/facebook/react/raw/master/LICENSE","website" +"tar@6.1.11","ISC","https://github.com/npm/node-tar","https://github.com/npm/node-tar/raw/master/LICENSE","parse-tree" +"unist-util-visit@4.1.0","MIT","https://github.com/syntax-tree/unist-util-visit","https://github.com/syntax-tree/unist-util-visit/raw/master/license","website" +"vscode-languageclient@7.0.0","MIT","https://github.com/Microsoft/vscode-languageserver-node","https://github.com/Microsoft/vscode-languageserver-node/raw/master/License.txt","metals" From 3ed14d76160f12266afa820bc92255b64e305487 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Mon, 6 Jun 2022 21:04:41 +0100 Subject: [PATCH 309/314] `PartialTargetDesc` => `PartialTargetDescriptor` --- src/core/commandRunner/command.types.ts | 4 +- .../canonicalizeAndValidateCommand.ts | 6 +-- .../canonicalizeTargets.ts | 14 +++--- .../upgradeV1ToV2/upgradeStrictHere.ts | 8 ++-- .../upgradeV1ToV2/upgradeV1ToV2.ts | 16 +++---- src/core/inferFullTargets.ts | 44 +++++++++---------- .../transformations/upgradeFromVersion0.ts | 4 +- src/typings/targetDescriptor.types.ts | 23 +++++----- src/util/getPrimitiveTargets.ts | 26 +++++------ 9 files changed, 73 insertions(+), 72 deletions(-) diff --git a/src/core/commandRunner/command.types.ts b/src/core/commandRunner/command.types.ts index bd9128a768..4d22a22175 100644 --- a/src/core/commandRunner/command.types.ts +++ b/src/core/commandRunner/command.types.ts @@ -1,4 +1,4 @@ -import { PartialTargetDesc } from "../../typings/targetDescriptor.types"; +import { PartialTargetDescriptor } from "../../typings/targetDescriptor.types"; import { ActionType } from "../../actions/actions.types"; import { CommandV0, @@ -53,5 +53,5 @@ export interface CommandV2 { * A list of targets expected by the action. Inference will be run on the * targets */ - targets: PartialTargetDesc[]; + targets: PartialTargetDescriptor[]; } diff --git a/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts b/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts index 2c4d4424a3..cf3b6cfb8d 100644 --- a/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts +++ b/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts @@ -2,7 +2,7 @@ import { commands } from "vscode"; import { ActionableError } from "../../errors"; import { Modifier, - PartialTargetDesc, + PartialTargetDescriptor, SimpleScopeTypeType, } from "../../typings/targetDescriptor.types"; import { ActionType } from "../../actions/actions.types"; @@ -94,7 +94,7 @@ function upgradeCommand(command: Command): CommandLatest { export function validateCommand( actionName: ActionType, - partialTargets: PartialTargetDesc[] + partialTargets: PartialTargetDescriptor[] ) { if ( usesScopeType("notebookCell", partialTargets) && @@ -108,7 +108,7 @@ export function validateCommand( function usesScopeType( scopeTypeType: SimpleScopeTypeType, - partialTargets: PartialTargetDesc[] + partialTargets: PartialTargetDescriptor[] ) { return getPartialPrimitiveTargets(partialTargets).some((partialTarget) => partialTarget.modifiers?.find( diff --git a/src/core/commandVersionUpgrades/canonicalizeTargets.ts b/src/core/commandVersionUpgrades/canonicalizeTargets.ts index 37a0ea352a..809368900a 100644 --- a/src/core/commandVersionUpgrades/canonicalizeTargets.ts +++ b/src/core/commandVersionUpgrades/canonicalizeTargets.ts @@ -1,8 +1,8 @@ import update from "immutability-helper"; import { flow } from "lodash"; import { - PartialPrimitiveTargetDesc, - PartialTargetDesc, + PartialPrimitiveTargetDescriptor, + PartialTargetDescriptor, SimpleScopeTypeType, } from "../../typings/targetDescriptor.types"; import { transformPartialPrimitiveTargets } from "../../util/getPrimitiveTargets"; @@ -20,8 +20,8 @@ const COLOR_CANONICALIZATION_MAPPING: Record = { }; const canonicalizeScopeTypes = ( - target: PartialPrimitiveTargetDesc -): PartialPrimitiveTargetDesc => { + target: PartialPrimitiveTargetDescriptor +): PartialPrimitiveTargetDescriptor => { target.modifiers?.forEach((mod) => { if (mod.type === "containingScope" || mod.type === "everyScope") { mod.scopeType.type = @@ -33,8 +33,8 @@ const canonicalizeScopeTypes = ( }; const canonicalizeColors = ( - target: PartialPrimitiveTargetDesc -): PartialPrimitiveTargetDesc => + target: PartialPrimitiveTargetDescriptor +): PartialPrimitiveTargetDescriptor => target.mark?.type === "decoratedSymbol" ? update(target, { mark: { @@ -45,7 +45,7 @@ const canonicalizeColors = ( : target; export default function canonicalizeTargets( - partialTargets: PartialTargetDesc[] + partialTargets: PartialTargetDescriptor[] ) { return transformPartialPrimitiveTargets( partialTargets, diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeStrictHere.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeStrictHere.ts index 626f500072..95f15c3b44 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeStrictHere.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeStrictHere.ts @@ -1,5 +1,5 @@ import { isDeepStrictEqual } from "util"; -import { PartialPrimitiveTargetDesc } from "../../../typings/targetDescriptor.types"; +import { PartialPrimitiveTargetDescriptor } from "../../../typings/targetDescriptor.types"; const STRICT_HERE = { type: "primitive", @@ -9,11 +9,11 @@ const STRICT_HERE = { modifier: { type: "identity" }, insideOutsideType: "inside", }; -const IMPLICIT_TARGET: PartialPrimitiveTargetDesc = { +const IMPLICIT_TARGET: PartialPrimitiveTargetDescriptor = { type: "primitive", isImplicit: true, }; export const upgradeStrictHere = ( - target: PartialPrimitiveTargetDesc -): PartialPrimitiveTargetDesc => + target: PartialPrimitiveTargetDescriptor +): PartialPrimitiveTargetDescriptor => isDeepStrictEqual(target, STRICT_HERE) ? IMPLICIT_TARGET : target; diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts index b18273e442..8ebb2a879e 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts @@ -1,9 +1,9 @@ import { flow } from "lodash"; import { Modifier, - PartialPrimitiveTargetDesc, - PartialRangeTargetDesc, - PartialTargetDesc, + PartialPrimitiveTargetDescriptor, + PartialRangeTargetDescriptor, + PartialTargetDescriptor, SimpleScopeTypeType, } from "../../../typings/targetDescriptor.types"; import { ActionType } from "../../../actions/actions.types"; @@ -93,7 +93,7 @@ function upgradeModifier(modifier: ModifierV0V1): Modifier[] { function upgradePrimitiveTarget( target: PartialPrimitiveTargetV0V1, action: ActionType -): PartialPrimitiveTargetDesc { +): PartialPrimitiveTargetDescriptor { const { type, isImplicit, @@ -160,7 +160,7 @@ function upgradePrimitiveTarget( function upgradeTarget( target: PartialTargetV0V1, action: ActionType -): PartialTargetDesc { +): PartialTargetDescriptor { switch (target.type) { case "list": return { @@ -168,8 +168,8 @@ function upgradeTarget( elements: target.elements.map( (target) => upgradeTarget(target, action) as - | PartialPrimitiveTargetDesc - | PartialRangeTargetDesc + | PartialPrimitiveTargetDescriptor + | PartialRangeTargetDescriptor ), }; case "range": @@ -191,7 +191,7 @@ function upgradeTargets( partialTargets: PartialTargetV0V1[], action: ActionType ) { - const partialTargetsV2: PartialTargetDesc[] = partialTargets.map((target) => + const partialTargetsV2: PartialTargetDescriptor[] = partialTargets.map((target) => upgradeTarget(target, action) ); return transformPartialPrimitiveTargets( diff --git a/src/core/inferFullTargets.ts b/src/core/inferFullTargets.ts index 7f65422bb7..270177095f 100644 --- a/src/core/inferFullTargets.ts +++ b/src/core/inferFullTargets.ts @@ -1,8 +1,8 @@ import { - PartialListTargetDesc, - PartialPrimitiveTargetDesc, - PartialRangeTargetDesc, - PartialTargetDesc, + PartialListTargetDescriptor, + PartialPrimitiveTargetDescriptor, + PartialRangeTargetDescriptor, + PartialTargetDescriptor, PrimitiveTargetDescriptor, RangeTargetDescriptor, TargetDescriptor, @@ -18,7 +18,7 @@ import { * @returns Target objects fully filled out and ready to be processed by {@link processTargets}. */ export default function inferFullTargets( - targets: PartialTargetDesc[] + targets: PartialTargetDescriptor[] ): TargetDescriptor[] { return targets.map((target, index) => inferTarget(target, targets.slice(0, index)) @@ -26,8 +26,8 @@ export default function inferFullTargets( } function inferTarget( - target: PartialTargetDesc, - previousTargets: PartialTargetDesc[] + target: PartialTargetDescriptor, + previousTargets: PartialTargetDescriptor[] ): TargetDescriptor { switch (target.type) { case "list": @@ -39,8 +39,8 @@ function inferTarget( } function inferListTarget( - target: PartialListTargetDesc, - previousTargets: PartialTargetDesc[] + target: PartialListTargetDescriptor, + previousTargets: PartialTargetDescriptor[] ): TargetDescriptor { return { ...target, @@ -54,8 +54,8 @@ function inferListTarget( } function inferNonListTarget( - target: PartialPrimitiveTargetDesc | PartialRangeTargetDesc, - previousTargets: PartialTargetDesc[] + target: PartialPrimitiveTargetDescriptor | PartialRangeTargetDescriptor, + previousTargets: PartialTargetDescriptor[] ): PrimitiveTargetDescriptor | RangeTargetDescriptor { switch (target.type) { case "primitive": @@ -66,8 +66,8 @@ function inferNonListTarget( } function inferRangeTarget( - target: PartialRangeTargetDesc, - previousTargets: PartialTargetDesc[] + target: PartialRangeTargetDescriptor, + previousTargets: PartialTargetDescriptor[] ): RangeTargetDescriptor { return { type: "range", @@ -83,8 +83,8 @@ function inferRangeTarget( } function inferPrimitiveTarget( - target: PartialPrimitiveTargetDesc, - previousTargets: PartialTargetDesc[] + target: PartialPrimitiveTargetDescriptor, + previousTargets: PartialTargetDescriptor[] ): PrimitiveTargetDescriptor { if (target.isImplicit) { return { @@ -132,24 +132,24 @@ function inferPrimitiveTarget( }; } -function getPreviousMark(previousTargets: PartialTargetDesc[]) { +function getPreviousMark(previousTargets: PartialTargetDescriptor[]) { return getPreviousTarget( previousTargets, - (target: PartialPrimitiveTargetDesc) => target.mark != null + (target: PartialPrimitiveTargetDescriptor) => target.mark != null )?.mark; } -function getPreviousModifiers(previousTargets: PartialTargetDesc[]) { +function getPreviousModifiers(previousTargets: PartialTargetDescriptor[]) { return getPreviousTarget( previousTargets, - (target: PartialPrimitiveTargetDesc) => target.modifiers != null + (target: PartialPrimitiveTargetDescriptor) => target.modifiers != null )?.modifiers; } function getPreviousTarget( - previousTargets: PartialTargetDesc[], - useTarget: (target: PartialPrimitiveTargetDesc) => boolean -): PartialPrimitiveTargetDesc | null { + previousTargets: PartialTargetDescriptor[], + useTarget: (target: PartialPrimitiveTargetDescriptor) => boolean +): PartialPrimitiveTargetDescriptor | null { // Search from back(last) to front(first) for (let i = previousTargets.length - 1; i > -1; --i) { const target = previousTargets[i]; diff --git a/src/scripts/transformRecordedTests/transformations/upgradeFromVersion0.ts b/src/scripts/transformRecordedTests/transformations/upgradeFromVersion0.ts index a6892c0442..55f45655d0 100644 --- a/src/scripts/transformRecordedTests/transformations/upgradeFromVersion0.ts +++ b/src/scripts/transformRecordedTests/transformations/upgradeFromVersion0.ts @@ -1,6 +1,6 @@ import { TestCaseFixture } from "../../../testUtil/TestCase"; import { transformPartialPrimitiveTargets } from "../../../util/getPrimitiveTargets"; -import { PartialPrimitiveTargetDesc } from "../../../typings/targetDescriptor.types"; +import { PartialPrimitiveTargetDescriptor } from "../../../typings/targetDescriptor.types"; export function upgradeFromVersion0(fixture: TestCaseFixture) { const { command, spokenForm: oldSpokenForm, ...rest } = fixture as any; @@ -16,7 +16,7 @@ export function upgradeFromVersion0(fixture: TestCaseFixture) { const targets = transformPartialPrimitiveTargets( newTargets ?? oldTargets, - (target: PartialPrimitiveTargetDesc) => { + (target: PartialPrimitiveTargetDescriptor) => { if (target.mark?.type === "decoratedSymbol") { (target.mark as any).usePrePhraseSnapshot = undefined; } diff --git a/src/typings/targetDescriptor.types.ts b/src/typings/targetDescriptor.types.ts index db7e468825..042b70a050 100644 --- a/src/typings/targetDescriptor.types.ts +++ b/src/typings/targetDescriptor.types.ts @@ -187,7 +187,7 @@ export interface PositionModifier { position: Position; } -export interface PartialPrimitiveTargetDesc { +export interface PartialPrimitiveTargetDescriptor { type: "primitive"; mark?: Mark; modifiers?: Modifier[]; @@ -207,26 +207,27 @@ export type Modifier = | TrailingModifier | RawSelectionModifier; -export interface PartialRangeTargetDesc { +export interface PartialRangeTargetDescriptor { type: "range"; - anchor: PartialPrimitiveTargetDesc; - active: PartialPrimitiveTargetDesc; + anchor: PartialPrimitiveTargetDescriptor; + active: PartialPrimitiveTargetDescriptor; excludeAnchor: boolean; excludeActive: boolean; rangeType?: RangeType; } -export interface PartialListTargetDesc { +export interface PartialListTargetDescriptor { type: "list"; - elements: (PartialPrimitiveTargetDesc | PartialRangeTargetDesc)[]; + elements: (PartialPrimitiveTargetDescriptor | PartialRangeTargetDescriptor)[]; } -export type PartialTargetDesc = - | PartialPrimitiveTargetDesc - | PartialRangeTargetDesc - | PartialListTargetDesc; +export type PartialTargetDescriptor = + | PartialPrimitiveTargetDescriptor + | PartialRangeTargetDescriptor + | PartialListTargetDescriptor; -export interface PrimitiveTargetDescriptor extends PartialPrimitiveTargetDesc { +export interface PrimitiveTargetDescriptor + extends PartialPrimitiveTargetDescriptor { /** * The mark, eg "air", "this", "that", etc */ diff --git a/src/util/getPrimitiveTargets.ts b/src/util/getPrimitiveTargets.ts index 2903b62346..29e7f57aec 100644 --- a/src/util/getPrimitiveTargets.ts +++ b/src/util/getPrimitiveTargets.ts @@ -1,7 +1,7 @@ import { - PartialPrimitiveTargetDesc, - PartialRangeTargetDesc, - PartialTargetDesc, + PartialPrimitiveTargetDescriptor, + PartialRangeTargetDescriptor, + PartialTargetDescriptor, PrimitiveTargetDescriptor, TargetDescriptor, } from "../typings/targetDescriptor.types"; @@ -13,13 +13,13 @@ import { * @param targets The targets to extract from * @returns A list of primitive targets */ -export function getPartialPrimitiveTargets(targets: PartialTargetDesc[]) { +export function getPartialPrimitiveTargets(targets: PartialTargetDescriptor[]) { return targets.flatMap(getPartialPrimitiveTargetsHelper); } function getPartialPrimitiveTargetsHelper( - target: PartialTargetDesc -): PartialPrimitiveTargetDesc[] { + target: PartialTargetDescriptor +): PartialPrimitiveTargetDescriptor[] { switch (target.type) { case "primitive": return [target]; @@ -61,8 +61,8 @@ function getPrimitiveTargetsHelper( * @returns A list of primitive targets */ export function transformPartialPrimitiveTargets( - targets: PartialTargetDesc[], - func: (target: PartialPrimitiveTargetDesc) => PartialPrimitiveTargetDesc + targets: PartialTargetDescriptor[], + func: (target: PartialPrimitiveTargetDescriptor) => PartialPrimitiveTargetDescriptor ) { return targets.map((target) => transformPartialPrimitiveTargetsHelper(target, func) @@ -70,9 +70,9 @@ export function transformPartialPrimitiveTargets( } function transformPartialPrimitiveTargetsHelper( - target: PartialTargetDesc, - func: (target: PartialPrimitiveTargetDesc) => PartialPrimitiveTargetDesc -): PartialTargetDesc { + target: PartialTargetDescriptor, + func: (target: PartialPrimitiveTargetDescriptor) => PartialPrimitiveTargetDescriptor +): PartialTargetDescriptor { switch (target.type) { case "primitive": return func(target); @@ -82,8 +82,8 @@ function transformPartialPrimitiveTargetsHelper( elements: target.elements.map( (element) => transformPartialPrimitiveTargetsHelper(element, func) as - | PartialPrimitiveTargetDesc - | PartialRangeTargetDesc + | PartialPrimitiveTargetDescriptor + | PartialRangeTargetDescriptor ), }; case "range": From cc6e673bffddfac120f8f73cb495ed6512611c13 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 6 Jun 2022 20:05:51 +0000 Subject: [PATCH 310/314] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts | 4 ++-- src/util/getPrimitiveTargets.ts | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts index 8ebb2a879e..69f0cae050 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts @@ -191,8 +191,8 @@ function upgradeTargets( partialTargets: PartialTargetV0V1[], action: ActionType ) { - const partialTargetsV2: PartialTargetDescriptor[] = partialTargets.map((target) => - upgradeTarget(target, action) + const partialTargetsV2: PartialTargetDescriptor[] = partialTargets.map( + (target) => upgradeTarget(target, action) ); return transformPartialPrimitiveTargets( partialTargetsV2, diff --git a/src/util/getPrimitiveTargets.ts b/src/util/getPrimitiveTargets.ts index 29e7f57aec..686451fd71 100644 --- a/src/util/getPrimitiveTargets.ts +++ b/src/util/getPrimitiveTargets.ts @@ -62,7 +62,9 @@ function getPrimitiveTargetsHelper( */ export function transformPartialPrimitiveTargets( targets: PartialTargetDescriptor[], - func: (target: PartialPrimitiveTargetDescriptor) => PartialPrimitiveTargetDescriptor + func: ( + target: PartialPrimitiveTargetDescriptor + ) => PartialPrimitiveTargetDescriptor ) { return targets.map((target) => transformPartialPrimitiveTargetsHelper(target, func) @@ -71,7 +73,9 @@ export function transformPartialPrimitiveTargets( function transformPartialPrimitiveTargetsHelper( target: PartialTargetDescriptor, - func: (target: PartialPrimitiveTargetDescriptor) => PartialPrimitiveTargetDescriptor + func: ( + target: PartialPrimitiveTargetDescriptor + ) => PartialPrimitiveTargetDescriptor ): PartialTargetDescriptor { switch (target.type) { case "primitive": From aed448099012b739d002ce0652a9bce9754ed88d Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Mon, 6 Jun 2022 21:07:07 +0100 Subject: [PATCH 311/314] Re-add provenance file --- .vscodeignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.vscodeignore b/.vscodeignore index 228984ff94..bf66ead03b 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -10,3 +10,4 @@ !README.md !schemas/** !third-party-licenses.csv +!build-info.json From de8f5a990e6e127016cdf1d2c8b872b8f909f205 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Mon, 6 Jun 2022 21:15:51 +0100 Subject: [PATCH 312/314] Comments --- src/actions/CommandAction.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/actions/CommandAction.ts b/src/actions/CommandAction.ts index 824a717aac..1542682843 100644 --- a/src/actions/CommandAction.ts +++ b/src/actions/CommandAction.ts @@ -60,6 +60,10 @@ export default class CommandAction implements Action { // Reset original selections if (options.restoreSelection) { + // NB: We don't focus the editor here because we'll do that at the + // very end. This code can run on multiple editors in the course of + // one command, so we want to avoid focusing the editor multiple + // times. setSelectionsWithoutFocusingEditor(editor, updatedOriginalSelections); } @@ -112,6 +116,9 @@ export default class CommandAction implements Action { originalEditor != null && originalEditor !== window.activeTextEditor ) { + // NB: We just do one editor focus at the end, instead of using + // setSelectionsAndFocusEditor because the command might operate on + // multiple editors, so we just do one focus at the end. await focusEditor(originalEditor); } From 0b774d3637f5f02db61a84f56dbec3d2c3017028 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Mon, 6 Jun 2022 21:16:25 +0100 Subject: [PATCH 313/314] Bump package version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b7b49b92b8..cb24eeb58b 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "color": "#00001A", "theme": "dark" }, - "version": "0.26.0-SNAPSHOT", + "version": "0.26.0", "publisher": "pokey", "license": "MIT", "repository": { From 744c4d498817e2e7a8da5d98af04f261ac321fec Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Mon, 6 Jun 2022 21:29:02 +0100 Subject: [PATCH 314/314] Attempt to fix docs link --- docs/contributing/test-case-recorder.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributing/test-case-recorder.md b/docs/contributing/test-case-recorder.md index 23f7a1c292..287e822fe2 100644 --- a/docs/contributing/test-case-recorder.md +++ b/docs/contributing/test-case-recorder.md @@ -24,7 +24,7 @@ The test case recorder has several additional configuration options. The default #### Testing the hat map -We have a way to test that the hats in the hat map update correctly during the course of a single phrase. These tests are also how we usually test our [range updating code](api/modules/core_updateSelections_updateSelections). +We have a way to test that the hats in the hat map update correctly during the course of a single phrase. These tests are also how we usually test our [range updating code](../api/modules/core_updateSelections_updateSelections). Please add the following to your personal talon files: