From 94a1226f6601cdddca38c5fe51b7b3a589eb1c96 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 1 Feb 2025 03:04:31 +0100 Subject: [PATCH 01/38] Started working on snippet variants --- cursorless-talon/src/check_community_repo.py | 1 + cursorless-talon/src/snippet_cursorless.talon | 14 - cursorless-talon/src/snippet_types.py | 76 +++++ cursorless-talon/src/snippets.py | 272 +++++++----------- ...nippets_community.talon => snippets.talon} | 1 - cursorless-talon/src/snippets_deprecated.py | 49 ++++ cursorless-talon/src/spoken_forms.py | 4 +- .../src/types/command/ActionDescriptor.ts | 24 +- 8 files changed, 260 insertions(+), 181 deletions(-) delete mode 100644 cursorless-talon/src/snippet_cursorless.talon create mode 100644 cursorless-talon/src/snippet_types.py rename cursorless-talon/src/{snippets_community.talon => snippets.talon} (90%) create mode 100644 cursorless-talon/src/snippets_deprecated.py diff --git a/cursorless-talon/src/check_community_repo.py b/cursorless-talon/src/check_community_repo.py index ef776de3ae..79d0a6a677 100644 --- a/cursorless-talon/src/check_community_repo.py +++ b/cursorless-talon/src/check_community_repo.py @@ -9,6 +9,7 @@ required_actions = [ "user.homophones_get", + "user.insert_snippet_by_name", "user.reformat_text", ] diff --git a/cursorless-talon/src/snippet_cursorless.talon b/cursorless-talon/src/snippet_cursorless.talon deleted file mode 100644 index ffc28e20b4..0000000000 --- a/cursorless-talon/src/snippet_cursorless.talon +++ /dev/null @@ -1,14 +0,0 @@ -mode: command -mode: user.cursorless_spoken_form_test -tag: user.cursorless -and not tag: user.cursorless_use_community_snippets -- - -{user.cursorless_insert_snippet_action} : - user.private_cursorless_insert_snippet(cursorless_insertion_snippet) - -{user.cursorless_insert_snippet_action} {user.cursorless_insertion_snippet_single_phrase} [{user.cursorless_phrase_terminator}]: - user.private_cursorless_insert_snippet_with_phrase(cursorless_insertion_snippet_single_phrase, text) - -{user.cursorless_wrapper_snippet} {user.cursorless_wrap_action} : - user.private_cursorless_wrap_with_snippet(cursorless_wrap_action, cursorless_target, cursorless_wrapper_snippet) diff --git a/cursorless-talon/src/snippet_types.py b/cursorless-talon/src/snippet_types.py new file mode 100644 index 0000000000..2a03ac43a3 --- /dev/null +++ b/cursorless-talon/src/snippet_types.py @@ -0,0 +1,76 @@ +from dataclasses import dataclass + +from .targets.target_types import CursorlessDestination, CursorlessTarget + + +@dataclass +class ScopeType: + type: str + + +# Insertion snippets + + +@dataclass +class CustomInsertionSnippet: + name = "custom" + body: str + scopesTypes: list[ScopeType] | None = None + languages: list[str] | None = None + substitutions: dict[str, str] | None = None + + +@dataclass +class ListInsertionSnippet: + name = "list" + snippets: list[CustomInsertionSnippet] + + +@dataclass +class InsertSnippetAction: + name = "insertSnippet" + snippetDescription: CustomInsertionSnippet | ListInsertionSnippet + destination: CursorlessDestination + + +# Wrapper snippets + + +@dataclass +class CustomWrapperSnippet: + name = "custom" + body: str + variableName: str | None = None + scopeType: ScopeType | None = None + languages: list[str] | None = None + + +@dataclass +class ListWrapperSnippet: + name = "list" + snippets: list[CustomWrapperSnippet] + + +@dataclass +class WrapperSnippetAction: + name = "wrapWithSnippet" + snippetDescription: CustomWrapperSnippet | ListWrapperSnippet + target: CursorlessTarget + + +# Community types + + +@dataclass +class CommunityInsertionSnippet: + body: str + languages: list[str] | None = None + scopes: list[str] | None = None + + +@dataclass +class CommunityWrapperSnippet: + body: str + variable_name: str + languages: list[str] | None = None + scope: str | None = None diff --git a/cursorless-talon/src/snippets.py b/cursorless-talon/src/snippets.py index 1a28fb1df8..8ffde069bd 100644 --- a/cursorless-talon/src/snippets.py +++ b/cursorless-talon/src/snippets.py @@ -1,187 +1,112 @@ -from dataclasses import dataclass -from typing import Any, Optional, Union - -from talon import Module, actions - +from typing import Optional, Union + +from talon import Context, Module, actions + +from .snippet_types import ( + CommunityInsertionSnippet, + CommunityWrapperSnippet, + CustomInsertionSnippet, + CustomWrapperSnippet, + InsertSnippetAction, + ListInsertionSnippet, + ListWrapperSnippet, + ScopeType, + WrapperSnippetAction, +) from .targets.target_types import ( CursorlessDestination, CursorlessTarget, ImplicitDestination, ) - -@dataclass -class InsertionSnippet: - name: str - destination: CursorlessDestination - - -@dataclass -class CommunityInsertionSnippet: - body: str - scopes: list[str] | None = None - - -@dataclass -class CommunityWrapperSnippet: - body: str - variable_name: str - scope: str | None = None - - mod = Module() +ctx = Context() mod.list("cursorless_insert_snippet_action", desc="Cursorless insert snippet action") -# Deprecated tag; we should probably remove this and notify users that they -# should get rid of it, but I don't think it's worth the effort right now -mod.tag( - "cursorless_experimental_snippets", - desc="tag for enabling experimental snippet support", -) - -mod.tag( - "cursorless_use_community_snippets", - "If active use community snippets instead of Cursorless snippets", -) - -mod.list("cursorless_wrapper_snippet", desc="Cursorless wrapper snippet") -mod.list( - "cursorless_insertion_snippet_no_phrase", - desc="Cursorless insertion snippets that don't accept a phrase", -) -mod.list( - "cursorless_insertion_snippet_single_phrase", - desc="Cursorless insertion snippet that can accept a single phrase", -) -mod.list("cursorless_phrase_terminator", "Contains term used to terminate a phrase") - -@mod.capture( - rule="({user.cursorless_insertion_snippet_no_phrase} | {user.cursorless_insertion_snippet_single_phrase}) []" -) -def cursorless_insertion_snippet(m) -> InsertionSnippet: - try: - name = m.cursorless_insertion_snippet_no_phrase - except AttributeError: - name = m.cursorless_insertion_snippet_single_phrase.split(".")[0] - - try: - destination = m.cursorless_destination - except AttributeError: - destination = ImplicitDestination() - - return InsertionSnippet(name, destination) - - -def wrap_with_snippet(snippet_description: dict, target: CursorlessTarget): +def insert_snippet( + snippet: CustomInsertionSnippet | ListInsertionSnippet, + destination: CursorlessDestination, +): actions.user.private_cursorless_command_and_wait( - { - "name": "wrapWithSnippet", - "snippetDescription": snippet_description, - "target": target, - }, + InsertSnippetAction(snippet, destination), ) -def insert_snippet(snippet_description: dict, destination: CursorlessDestination): +def wrap_with_snippet( + snippet: CustomWrapperSnippet | ListWrapperSnippet, + target: CursorlessTarget, +): actions.user.private_cursorless_command_and_wait( - { - "name": "insertSnippet", - "snippetDescription": snippet_description, - "destination": destination, - }, + WrapperSnippetAction(snippet, target), ) -def insert_named_snippet( +def insert_community_snippet( name: str, + substitutions: dict[str, str] | None, destination: CursorlessDestination, - substitutions: Optional[dict] = None, ): - snippet: dict = { - "type": "named", - "name": name, - } - if substitutions is not None: - snippet["substitutions"] = substitutions + snippets: list[CommunityInsertionSnippet] = get_insertion_snippets(name) + snippet = ListInsertionSnippet( + [ + CustomInsertionSnippet( + s.body, + to_scope_type(s.scopes), + s.languages, + substitutions, + ) + for s in snippets + ], + ) insert_snippet(snippet, destination) -def insert_custom_snippet( - body: str, - destination: CursorlessDestination, - scope_types: Optional[list[dict]] = None, -): - snippet: dict = { - "type": "custom", - "body": body, - } - - if scope_types: - snippet["scopeTypes"] = scope_types - - insert_snippet(snippet, destination) - +def insert_community_wrapper_snippet(name: str, target: CursorlessTarget): + snippets: list[CommunityWrapperSnippet] = get_wrapper_snippets(name) + snippet = ListWrapperSnippet( + [ + CustomWrapperSnippet( + s.body, + s.variable_name, + ScopeType(s.scope) if s.scope else None, + s.languages, + ) + for s in snippets + ], + ) + wrap_with_snippet(snippet, target) -@mod.action_class -class Actions: - def private_cursorless_insert_snippet(insertion_snippet: InsertionSnippet): # pyright: ignore [reportGeneralTypeIssues] - """Execute Cursorless insert snippet action""" - insert_named_snippet( - insertion_snippet.name, - insertion_snippet.destination, - ) - def private_cursorless_insert_snippet_with_phrase( - snippet_description: str, # pyright: ignore [reportGeneralTypeIssues] - text: str, +@ctx.action_class("user") +class UserActions: + def insert_snippet_by_name( + name: str, # pyright: ignore [reportGeneralTypeIssues] + substitutions: dict[str, str] = None, ): - """Cursorless: Insert snippet with phrase """ - snippet_name, snippet_variable = snippet_description.split(".") - insert_named_snippet( - snippet_name, - ImplicitDestination(), - {snippet_variable: text}, - ) - - def cursorless_insert_snippet_by_name(name: str): # pyright: ignore [reportGeneralTypeIssues] - """Cursorless: Insert named snippet """ - insert_named_snippet( + insert_community_snippet( name, + substitutions, ImplicitDestination(), ) + +@mod.action_class +class Actions: def cursorless_insert_snippet( body: str, # pyright: ignore [reportGeneralTypeIssues] destination: CursorlessDestination = ImplicitDestination(), scope_type: Optional[Union[str, list[str]]] = None, ): """Cursorless: Insert custom snippet """ - if isinstance(scope_type, str): - scope_type = [scope_type] - - if scope_type is not None: - scope_types = [{"type": st} for st in scope_type] - else: - scope_types = None - - insert_custom_snippet(body, destination, scope_types) - - def cursorless_wrap_with_snippet_by_name( - name: str, # pyright: ignore [reportGeneralTypeIssues] - variable_name: str, - target: CursorlessTarget, - ): - """Cursorless: Wrap target with a named snippet """ - wrap_with_snippet( - { - "type": "named", - "name": name, - "variableName": variable_name, - }, - target, + snippet = CustomInsertionSnippet( + body, + to_scope_type(scope_type), + None, # languages + None, # substitutions ) + insert_snippet(snippet, destination) def cursorless_wrap_with_snippet( body: str, # pyright: ignore [reportGeneralTypeIssues] @@ -190,27 +115,23 @@ def cursorless_wrap_with_snippet( scope: Optional[str] = None, ): """Cursorless: Wrap target with custom snippet """ - snippet_arg: dict[str, Any] = { - "type": "custom", - "body": body, - } - if scope is not None: - snippet_arg["scopeType"] = {"type": scope} - if variable_name is not None: - snippet_arg["variableName"] = variable_name - wrap_with_snippet( - snippet_arg, - target, + snippet = CustomWrapperSnippet( + body, + variable_name, + ScopeType(scope) if scope else None, + None, # languages ) + wrap_with_snippet(snippet, target) def private_cursorless_insert_community_snippet( name: str, # pyright: ignore [reportGeneralTypeIssues] destination: CursorlessDestination, ): """Cursorless: Insert community snippet """ - snippet: CommunityInsertionSnippet = actions.user.get_insertion_snippet(name) - actions.user.cursorless_insert_snippet( - snippet.body, destination, snippet.scopes + insert_community_snippet( + name, + None, # substitutions + ImplicitDestination(), ) def private_cursorless_wrap_with_community_snippet( @@ -218,7 +139,32 @@ def private_cursorless_wrap_with_community_snippet( target: CursorlessTarget, ): """Cursorless: Wrap target with community snippet """ - snippet: CommunityWrapperSnippet = actions.user.get_wrapper_snippet(name) - actions.user.cursorless_wrap_with_snippet( - snippet.body, target, snippet.variable_name, snippet.scope - ) + insert_community_wrapper_snippet(name, target) + + +def to_scope_type(scope_type: str | list[str] | None) -> list[ScopeType] | None: + if isinstance(scope_type, str): + return [ScopeType(scope_type)] + elif scope_type is not None: + return [ScopeType(st) for st in scope_type] + return None + + +def get_insertion_snippets(name: str) -> list[CommunityInsertionSnippet]: + try: + return actions.user.get_insertion_snippets(name) + except Exception as ex: + if isinstance(ex, KeyError): + snippet = actions.user.get_insertion_snippet(name) + return [snippet] + raise + + +def get_wrapper_snippets(name: str) -> list[CommunityWrapperSnippet]: + try: + return actions.user.get_wrapper_snippets(name) + except Exception as ex: + if isinstance(ex, KeyError): + snippet = actions.user.get_wrapper_snippet(name) + return [snippet] + raise diff --git a/cursorless-talon/src/snippets_community.talon b/cursorless-talon/src/snippets.talon similarity index 90% rename from cursorless-talon/src/snippets_community.talon rename to cursorless-talon/src/snippets.talon index f94e491f83..f5f1d98ac0 100644 --- a/cursorless-talon/src/snippets_community.talon +++ b/cursorless-talon/src/snippets.talon @@ -1,7 +1,6 @@ mode: command mode: user.cursorless_spoken_form_test tag: user.cursorless -and tag: user.cursorless_use_community_snippets - # These snippets are defined in community diff --git a/cursorless-talon/src/snippets_deprecated.py b/cursorless-talon/src/snippets_deprecated.py new file mode 100644 index 0000000000..9862d1a505 --- /dev/null +++ b/cursorless-talon/src/snippets_deprecated.py @@ -0,0 +1,49 @@ +from typing import Any + +from talon import Module, app, registry + +mod = Module() + +# DEPRECATED @ 2025-02-01 + +tags = [ + "cursorless_experimental_snippets", + "cursorless_use_community_snippets", +] + +lists = [ + "cursorless_insertion_snippet_no_phrase", + "cursorless_insertion_snippet_single_phrase", + "cursorless_phrase_terminator", +] + +for tag in tags: + mod.tag(tag, desc="DEPRECATED") + +for list in lists: + mod.list(list, desc="DEPRECATED") + + +@mod.action_class +class Actions: + def cursorless_insert_snippet_by_name(name: str): # pyright: ignore [reportGeneralTypeIssues] + """[DEPRECATED] Cursorless: Insert named snippet """ + raise ValueError("Cursorless snippets are deprecated. Use community snippets.") + + def cursorless_wrap_with_snippet_by_name( + name: str, # pyright: ignore [reportGeneralTypeIssues] + variable_name: str, + target: Any, + ): + """[DEPRECATED] Cursorless: Wrap target with a named snippet """ + raise ValueError("Cursorless snippets are deprecated. Use community snippets.") + + +def on_ready(): + for tag in tags: + name = f"user.{tag}" + if name in registry.tags: + print(f"WARNING tag: '{name}' is deprecated and should not be used anymore") + + +app.register("ready", on_ready) diff --git a/cursorless-talon/src/spoken_forms.py b/cursorless-talon/src/spoken_forms.py index 044978b95e..92896f3719 100644 --- a/cursorless-talon/src/spoken_forms.py +++ b/cursorless-talon/src/spoken_forms.py @@ -147,7 +147,6 @@ def handle_new_values(csv_name: str, values: list[SpokenFormEntry]): handle_csv("special_marks.csv"), handle_csv("scope_visualizer.csv"), handle_csv("experimental/experimental_actions.csv"), - handle_csv("experimental/miscellaneous.csv"), handle_csv( "modifier_scope_types.csv", pluralize_lists=[ @@ -165,6 +164,7 @@ def handle_new_values(csv_name: str, values: list[SpokenFormEntry]): ], default_list_name="scope_type", ), + # DEPRECATED @ 2025-02-01 handle_csv( "experimental/wrapper_snippets.csv", allow_unknown_values=True, @@ -180,6 +180,8 @@ def handle_new_values(csv_name: str, values: list[SpokenFormEntry]): allow_unknown_values=True, default_list_name="insertion_snippet_single_phrase", ), + handle_csv("experimental/miscellaneous.csv"), + # --- handle_csv( "experimental/actions_custom.csv", headers=[SPOKEN_FORM_HEADER, "VSCode command"], diff --git a/packages/common/src/types/command/ActionDescriptor.ts b/packages/common/src/types/command/ActionDescriptor.ts index c27a35f7ad..b0af40d35f 100644 --- a/packages/common/src/types/command/ActionDescriptor.ts +++ b/packages/common/src/types/command/ActionDescriptor.ts @@ -146,13 +146,24 @@ interface NamedInsertSnippetArg { name: string; substitutions?: Record; } + interface CustomInsertSnippetArg { type: "custom"; body: string; + languages?: string[]; scopeTypes?: ScopeType[]; substitutions?: Record; } -export type InsertSnippetArg = NamedInsertSnippetArg | CustomInsertSnippetArg; + +interface ListInsertSnippetArg { + type: "list"; + snippets: CustomInsertSnippetArg[]; +} + +export type InsertSnippetArg = + | NamedInsertSnippetArg + | CustomInsertSnippetArg + | ListInsertSnippetArg; export interface InsertSnippetActionDescriptor { name: "insertSnippet"; @@ -165,15 +176,24 @@ interface NamedWrapWithSnippetArg { name: string; variableName: string; } + interface CustomWrapWithSnippetArg { type: "custom"; body: string; variableName?: string; scopeType?: ScopeType; + languages?: string[]; +} + +interface ListWrapWithSnippetArg { + type: "list"; + snippets: CustomWrapWithSnippetArg[]; } + export type WrapWithSnippetArg = | NamedWrapWithSnippetArg - | CustomWrapWithSnippetArg; + | CustomWrapWithSnippetArg + | ListWrapWithSnippetArg; export interface WrapWithSnippetActionDescriptor { name: "wrapWithSnippet"; From 7d9cfac4fab7f6d3be9277b4d7da4fadf718c33e Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 1 Feb 2025 03:54:11 +0100 Subject: [PATCH 02/38] More clean up --- cursorless-talon/src/snippets_deprecated.py | 8 +- .../src/types/command/ActionDescriptor.ts | 4 +- .../GenerateSnippet/GenerateSnippet.ts | 236 +++++++++++- .../GenerateSnippetCommunity.ts | 241 ------------ .../GenerateSnippet/GenerateSnippetLegacy.ts | 263 ------------- .../src/actions/InsertSnippet.ts | 73 +--- .../cursorless-engine/src/core/Snippets.ts | 26 +- .../src/core/compareSnippetDefinitions.ts | 40 +- .../src/core/mergeSnippets.test.ts | 348 ------------------ .../src/core/mergeSnippets.ts | 81 ---- .../disabledComponents/DisabledSnippets.ts | 19 +- .../defaultSpokenForms/snippets.ts | 42 +-- .../cursorless-vscode/src/VscodeSnippets.ts | 238 +----------- packages/cursorless-vscode/src/extension.ts | 4 - packages/vscode-common/src/getExtensionApi.ts | 9 +- 15 files changed, 296 insertions(+), 1336 deletions(-) delete mode 100644 packages/cursorless-engine/src/actions/GenerateSnippet/GenerateSnippetCommunity.ts delete mode 100644 packages/cursorless-engine/src/actions/GenerateSnippet/GenerateSnippetLegacy.ts delete mode 100644 packages/cursorless-engine/src/core/mergeSnippets.test.ts delete mode 100644 packages/cursorless-engine/src/core/mergeSnippets.ts diff --git a/cursorless-talon/src/snippets_deprecated.py b/cursorless-talon/src/snippets_deprecated.py index 9862d1a505..2f32fbc48f 100644 --- a/cursorless-talon/src/snippets_deprecated.py +++ b/cursorless-talon/src/snippets_deprecated.py @@ -28,7 +28,9 @@ class Actions: def cursorless_insert_snippet_by_name(name: str): # pyright: ignore [reportGeneralTypeIssues] """[DEPRECATED] Cursorless: Insert named snippet """ - raise ValueError("Cursorless snippets are deprecated. Use community snippets.") + raise NotImplementedError( + "Cursorless snippets are deprecated. Please use community snippets." + ) def cursorless_wrap_with_snippet_by_name( name: str, # pyright: ignore [reportGeneralTypeIssues] @@ -36,7 +38,9 @@ def cursorless_wrap_with_snippet_by_name( target: Any, ): """[DEPRECATED] Cursorless: Wrap target with a named snippet """ - raise ValueError("Cursorless snippets are deprecated. Use community snippets.") + raise NotImplementedError( + "Cursorless snippets are deprecated. Please use community snippets." + ) def on_ready(): diff --git a/packages/common/src/types/command/ActionDescriptor.ts b/packages/common/src/types/command/ActionDescriptor.ts index b0af40d35f..d3f5c0c906 100644 --- a/packages/common/src/types/command/ActionDescriptor.ts +++ b/packages/common/src/types/command/ActionDescriptor.ts @@ -147,7 +147,7 @@ interface NamedInsertSnippetArg { substitutions?: Record; } -interface CustomInsertSnippetArg { +export interface CustomInsertSnippetArg { type: "custom"; body: string; languages?: string[]; @@ -177,7 +177,7 @@ interface NamedWrapWithSnippetArg { variableName: string; } -interface CustomWrapWithSnippetArg { +export interface CustomWrapWithSnippetArg { type: "custom"; body: string; variableName?: string; diff --git a/packages/cursorless-engine/src/actions/GenerateSnippet/GenerateSnippet.ts b/packages/cursorless-engine/src/actions/GenerateSnippet/GenerateSnippet.ts index b7e0aacde2..f3eca4e4d8 100644 --- a/packages/cursorless-engine/src/actions/GenerateSnippet/GenerateSnippet.ts +++ b/packages/cursorless-engine/src/actions/GenerateSnippet/GenerateSnippet.ts @@ -1,9 +1,57 @@ +import { + FlashStyle, + Range, + matchAll, + type EditableTextEditor, + type Selection, + type TextEditor, +} from "@cursorless/common"; +import { + parseSnippetFile, + serializeSnippetFile, + type Snippet, + type SnippetFile, + type SnippetHeader, + type SnippetVariable, +} from "talon-snippets"; import type { Snippets } from "../../core/Snippets"; +import { ide } from "../../singletons/ide.singleton"; import type { Target } from "../../typings/target.types"; +import { ensureSingleTarget, flashTargets } from "../../util/targetUtils"; import type { ActionReturnValue } from "../actions.types"; -import GenerateSnippetCommunity from "./GenerateSnippetCommunity"; -import GenerateSnippetLegacy from "./GenerateSnippetLegacy"; +import { constructSnippetBody } from "./constructSnippetBody"; +import { editText } from "./editText"; +import type { Offsets } from "./Offsets"; +/** + * This action can be used to automatically create a snippet from a target. Any + * cursor selections inside the target will become placeholders in the final + * snippet. This action creates a new file, and inserts a snippet that the user + * can fill out to construct their desired snippet. + * + * Note that there are two snippets involved in this implementation: + * + * - The snippet that the user is trying to create. We refer to this snippet as + * the user snippet. + * - The snippet that we insert that the user can use to build their snippet. We + * refer to this as the meta snippet. + * + * We proceed as follows: + * + * 1. Ask user for snippet name if not provided as arg + * 2. Find all cursor selections inside target - these will become the user + * snippet variables + * 3. Extract text of target + * 4. Replace cursor selections in text with snippet variables + * 4. Construct the user snippet body as a list of strings + * 5. Construct a javascript object that will be serialized to become the meta + * snippet + * 6. Serialize the javascript object + * 7. Escape dollar signs and replace placeholder text with snippet placeholders. + * This modified json output is the meta snippet. + * 8. Open a new document in the snippets dir to hold the new snippet. + * 9. Insert the meta snippet so that the user can construct their snippet. + */ export default class GenerateSnippet { constructor(private snippets: Snippets) { this.run = this.run.bind(this); @@ -11,15 +59,189 @@ export default class GenerateSnippet { async run( targets: Target[], - directory?: string, + directory: string, snippetName?: string, ): Promise { if (directory == null) { - const action = new GenerateSnippetLegacy(this.snippets); - return action.run(targets, snippetName); + throw new Error( + "Directory argument is required for GenerateSnippet action. Please update Cursorless Talon", + ); } - const action = new GenerateSnippetCommunity(this.snippets); - return action.run(targets, directory, snippetName); + const target = ensureSingleTarget(targets); + const editor = target.editor; + + // NB: We don't await the pending edit decoration so that if the user + // immediately starts saying the name of the snippet (eg command chain + // "snippet make funk camel my function"), we're more likely to + // win the race and have the input box ready for them + void flashTargets(ide(), targets, FlashStyle.referenced); + + if (snippetName == null) { + snippetName = await ide().showInputBox({ + prompt: "Name of snippet", + placeHolder: "helloWorld", + }); + + // User cancelled; do nothing + if (!snippetName) { + return {}; + } + } + + const baseOffset = editor.document.offsetAt(target.contentRange.start); + + /** + * The variables that will appear in the user snippet. + */ + const selections = getsSnippetSelections(editor, target.contentRange); + const variables = selections.map( + (selection, index): Variable => ({ + offsets: { + start: editor.document.offsetAt(selection.start) - baseOffset, + end: editor.document.offsetAt(selection.end) - baseOffset, + }, + name: index === selections.length - 1 ? "0" : `${index + 1}`, + }), + ); + + /** + * Text before the start of the snippet in the snippet start line. We need + * to pass this to {@link constructSnippetBody} so that it knows the + * baseline indentation of the snippet + */ + const linePrefix = editor.document.getText( + new Range( + target.contentRange.start.with(undefined, 0), + target.contentRange.start, + ), + ); + + const originalText = editor.document.getText(target.contentRange); + + const snippetBodyText = editText(originalText, [ + ...matchAll(originalText, /\$|\\/g, (match) => ({ + offsets: { + start: match.index!, + end: match.index! + match[0].length, + }, + text: `\\${match[0]}`, + })), + ...variables.map(({ offsets, name }) => ({ + offsets, + text: `$${name}`, + })), + ]); + + const snippetLines = constructSnippetBody(snippetBodyText, linePrefix); + + let editableEditor: EditableTextEditor; + let snippetFile: SnippetFile = { snippets: [] }; + + if (ide().runMode === "test") { + // If we're testing, we just overwrite the current document + editableEditor = ide().getEditableTextEditor(editor); + } else { + // Otherwise, we create and open a new document for the snippet + editableEditor = ide().getEditableTextEditor( + await this.snippets.openNewSnippetFile(snippetName, directory), + ); + snippetFile = parseSnippetFile(editableEditor.document.getText()); + } + + await editableEditor.setSelections([ + editableEditor.document.range.toSelection(false), + ]); + + /** The next placeholder index to use for the meta snippet */ + let currentPlaceholderIndex = 1; + + const { header } = snippetFile; + + const phrases = + snippetFile.header?.phrases != null + ? undefined + : [`${PLACEHOLDER}${currentPlaceholderIndex++}`]; + + const createVariable = (variable: Variable): SnippetVariable => { + const hasPhrase = header?.variables?.some( + (v) => v.name === variable.name && v.wrapperPhrases != null, + ); + return { + name: variable.name, + wrapperPhrases: hasPhrase + ? undefined + : [`${PLACEHOLDER}${currentPlaceholderIndex++}`], + }; + }; + + const snippet: Snippet = { + name: header?.name === snippetName ? undefined : snippetName, + phrases, + languages: getSnippetLanguages(editor, header), + body: snippetLines, + variables: variables.map(createVariable), + }; + + snippetFile.snippets.push(snippet); + + /** + * This is the text of the meta-snippet in Textmate format that we will + * insert into the new document where the user will fill out their snippet + * definition + */ + const metaSnippetText = serializeSnippetFile(snippetFile) + // Escape dollar signs in the snippet text so that they don't get used as + // placeholders in the meta snippet + .replace(/\$/g, "\\$") + // Replace constant with dollar sign for meta snippet placeholders + .replaceAll(PLACEHOLDER, "$"); + + // Insert the meta-snippet + await editableEditor.insertSnippet(metaSnippetText); + + return { + thatSelections: targets.map(({ editor, contentSelection }) => ({ + editor, + selection: contentSelection, + })), + }; + } +} + +function getSnippetLanguages( + editor: TextEditor, + header: SnippetHeader | undefined, +): string[] | undefined { + if (header?.languages?.includes(editor.document.languageId)) { + return undefined; } + return [editor.document.languageId]; +} + +function getsSnippetSelections(editor: TextEditor, range: Range): Selection[] { + const selections = editor.selections.filter((selection) => + range.contains(selection), + ); + selections.sort((a, b) => a.start.compareTo(b.start)); + return selections; +} + +// Used to temporarily escape the $1, $2 snippet holes (the "meta snippet" holes +// that become live snippets when the user edits) so we can use traditional +// backslash escaping for the holes in the underlying snippet itself (the "user +// snippet" holes that will be saved as part of their new template). +const PLACEHOLDER = "PLACEHOLDER_VFA77zcbLD6wXNmfMAay"; + +interface Variable { + /** + * The start an end offsets of the variable relative to the text of the + * snippet that contains it + */ + offsets: Offsets; + + /** + * The name for the variable + */ + name: string; } diff --git a/packages/cursorless-engine/src/actions/GenerateSnippet/GenerateSnippetCommunity.ts b/packages/cursorless-engine/src/actions/GenerateSnippet/GenerateSnippetCommunity.ts deleted file mode 100644 index 898c15db7d..0000000000 --- a/packages/cursorless-engine/src/actions/GenerateSnippet/GenerateSnippetCommunity.ts +++ /dev/null @@ -1,241 +0,0 @@ -import { - FlashStyle, - matchAll, - Range, - type EditableTextEditor, - type Selection, - type TextEditor, -} from "@cursorless/common"; -import { - parseSnippetFile, - serializeSnippetFile, - type Snippet, - type SnippetFile, - type SnippetHeader, - type SnippetVariable, -} from "talon-snippets"; -import type { Snippets } from "../../core/Snippets"; -import { ide } from "../../singletons/ide.singleton"; -import type { Target } from "../../typings/target.types"; -import { ensureSingleTarget, flashTargets } from "../../util/targetUtils"; -import type { ActionReturnValue } from "../actions.types"; -import { constructSnippetBody } from "./constructSnippetBody"; -import { editText } from "./editText"; -import type { Offsets } from "./Offsets"; - -/** - * This action can be used to automatically create a snippet from a target. Any - * cursor selections inside the target will become placeholders in the final - * snippet. This action creates a new file, and inserts a snippet that the user - * can fill out to construct their desired snippet. - * - * Note that there are two snippets involved in this implementation: - * - * - The snippet that the user is trying to create. We refer to this snippet as - * the user snippet. - * - The snippet that we insert that the user can use to build their snippet. We - * refer to this as the meta snippet. - * - * We proceed as follows: - * - * 1. Ask user for snippet name if not provided as arg - * 2. Find all cursor selections inside target - these will become the user - * snippet variables - * 3. Extract text of target - * 4. Replace cursor selections in text with snippet variables - * 4. Construct the user snippet body as a list of strings - * 5. Construct a javascript object that will be serialized to become the meta - * snippet - * 6. Serialize the javascript object - * 7. Escape dollar signs and replace placeholder text with snippet placeholders. - * This modified json output is the meta snippet. - * 8. Open a new document in the snippets dir to hold the new snippet. - * 9. Insert the meta snippet so that the user can construct their snippet. - */ -export default class GenerateSnippetCommunity { - constructor(private snippets: Snippets) { - this.run = this.run.bind(this); - } - - async run( - targets: Target[], - directory: string, - snippetName?: string, - ): Promise { - const target = ensureSingleTarget(targets); - const editor = target.editor; - - // NB: We don't await the pending edit decoration so that if the user - // immediately starts saying the name of the snippet (eg command chain - // "snippet make funk camel my function"), we're more likely to - // win the race and have the input box ready for them - void flashTargets(ide(), targets, FlashStyle.referenced); - - if (snippetName == null) { - snippetName = await ide().showInputBox({ - prompt: "Name of snippet", - placeHolder: "helloWorld", - }); - - // User cancelled; do nothing - if (!snippetName) { - return {}; - } - } - - const baseOffset = editor.document.offsetAt(target.contentRange.start); - - /** - * The variables that will appear in the user snippet. - */ - const selections = getsSnippetSelections(editor, target.contentRange); - const variables = selections.map( - (selection, index): Variable => ({ - offsets: { - start: editor.document.offsetAt(selection.start) - baseOffset, - end: editor.document.offsetAt(selection.end) - baseOffset, - }, - name: index === selections.length - 1 ? "0" : `${index + 1}`, - }), - ); - - /** - * Text before the start of the snippet in the snippet start line. We need - * to pass this to {@link constructSnippetBody} so that it knows the - * baseline indentation of the snippet - */ - const linePrefix = editor.document.getText( - new Range( - target.contentRange.start.with(undefined, 0), - target.contentRange.start, - ), - ); - - const originalText = editor.document.getText(target.contentRange); - - const snippetBodyText = editText(originalText, [ - ...matchAll(originalText, /\$|\\/g, (match) => ({ - offsets: { - start: match.index!, - end: match.index! + match[0].length, - }, - text: `\\${match[0]}`, - })), - ...variables.map(({ offsets, name }) => ({ - offsets, - text: `$${name}`, - })), - ]); - - const snippetLines = constructSnippetBody(snippetBodyText, linePrefix); - - let editableEditor: EditableTextEditor; - let snippetFile: SnippetFile = { snippets: [] }; - - if (ide().runMode === "test") { - // If we're testing, we just overwrite the current document - editableEditor = ide().getEditableTextEditor(editor); - } else { - // Otherwise, we create and open a new document for the snippet - editableEditor = ide().getEditableTextEditor( - await this.snippets.openNewSnippetFile(snippetName, directory), - ); - snippetFile = parseSnippetFile(editableEditor.document.getText()); - } - - await editableEditor.setSelections([ - editableEditor.document.range.toSelection(false), - ]); - - /** The next placeholder index to use for the meta snippet */ - let currentPlaceholderIndex = 1; - - const { header } = snippetFile; - - const phrases = - snippetFile.header?.phrases != null - ? undefined - : [`${PLACEHOLDER}${currentPlaceholderIndex++}`]; - - const createVariable = (variable: Variable): SnippetVariable => { - const hasPhrase = header?.variables?.some( - (v) => v.name === variable.name && v.wrapperPhrases != null, - ); - return { - name: variable.name, - wrapperPhrases: hasPhrase - ? undefined - : [`${PLACEHOLDER}${currentPlaceholderIndex++}`], - }; - }; - - const snippet: Snippet = { - name: header?.name === snippetName ? undefined : snippetName, - phrases, - languages: getSnippetLanguages(editor, header), - body: snippetLines, - variables: variables.map(createVariable), - }; - - snippetFile.snippets.push(snippet); - - /** - * This is the text of the meta-snippet in Textmate format that we will - * insert into the new document where the user will fill out their snippet - * definition - */ - const metaSnippetText = serializeSnippetFile(snippetFile) - // Escape dollar signs in the snippet text so that they don't get used as - // placeholders in the meta snippet - .replace(/\$/g, "\\$") - // Replace constant with dollar sign for meta snippet placeholders - .replaceAll(PLACEHOLDER, "$"); - - // Insert the meta-snippet - await editableEditor.insertSnippet(metaSnippetText); - - return { - thatSelections: targets.map(({ editor, contentSelection }) => ({ - editor, - selection: contentSelection, - })), - }; - } -} - -function getSnippetLanguages( - editor: TextEditor, - header: SnippetHeader | undefined, -): string[] | undefined { - if (header?.languages?.includes(editor.document.languageId)) { - return undefined; - } - return [editor.document.languageId]; -} - -function getsSnippetSelections(editor: TextEditor, range: Range): Selection[] { - const selections = editor.selections.filter((selection) => - range.contains(selection), - ); - selections.sort((a, b) => a.start.compareTo(b.start)); - return selections; -} - -// Used to temporarily escape the $1, $2 snippet holes (the "meta snippet" holes -// that become live snippets when the user edits) so we can use traditional -// backslash escaping for the holes in the underlying snippet itself (the "user -// snippet" holes that will be saved as part of their new template). -const PLACEHOLDER = "PLACEHOLDER_VFA77zcbLD6wXNmfMAay"; - -interface Variable { - /** - * The start an end offsets of the variable relative to the text of the - * snippet that contains it - */ - offsets: Offsets; - - /** - * The name for the variable - */ - name: string; -} diff --git a/packages/cursorless-engine/src/actions/GenerateSnippet/GenerateSnippetLegacy.ts b/packages/cursorless-engine/src/actions/GenerateSnippet/GenerateSnippetLegacy.ts deleted file mode 100644 index 76410fbba2..0000000000 --- a/packages/cursorless-engine/src/actions/GenerateSnippet/GenerateSnippetLegacy.ts +++ /dev/null @@ -1,263 +0,0 @@ -import { FlashStyle, matchAll, Range } from "@cursorless/common"; -import type { Snippets } from "../../core/Snippets"; -import { ide } from "../../singletons/ide.singleton"; -import type { Target } from "../../typings/target.types"; -import { ensureSingleTarget, flashTargets } from "../../util/targetUtils"; -import type { ActionReturnValue } from "../actions.types"; -import { constructSnippetBody } from "./constructSnippetBody"; -import { editText } from "./editText"; -import type { Offsets } from "./Offsets"; -import Substituter from "./Substituter"; - -/** - * This action can be used to automatically create a snippet from a target. Any - * cursor selections inside the target will become placeholders in the final - * snippet. This action creates a new file, and inserts a snippet that the user - * can fill out to construct their desired snippet. - * - * Note that there are two snippets involved in this implementation: - * - * - The snippet that the user is trying to create. We refer to this snippet as - * the user snippet. - * - The snippet that we insert that the user can use to build their snippet. We - * refer to this as the meta snippet. - * - * We proceed as follows: - * - * 1. Ask user for snippet name if not provided as arg - * 2. Find all cursor selections inside target - these will become the user - * snippet variables - * 3. Extract text of target - * 4. Replace cursor selections in text with random ids that won't be affected - * by json serialization. After serialization we'll replace these id's by - * snippet placeholders. - * 4. Construct the user snippet body as a list of strings - * 5. Construct a javascript object that will be json-ified to become the meta - * snippet - * 6. Serialize the javascript object to json - * 7. Perform replacements on the random id's appearing in this json to get the - * text we desire. This modified json output is the meta snippet. - * 8. Open a new document in user custom snippets dir to hold the new snippet. - * 9. Insert the meta snippet so that the user can construct their snippet. - * - * Note that we avoid using JS interpolation strings here because the syntax is - * very similar to snippet placeholders, so we would end up with lots of - * confusing escaping. - */ -export default class GenerateSnippetLegacy { - constructor(private snippets: Snippets) { - this.run = this.run.bind(this); - } - - async run( - targets: Target[], - snippetName?: string, - ): Promise { - const target = ensureSingleTarget(targets); - const editor = target.editor; - - // NB: We don't await the pending edit decoration so that if the user - // immediately starts saying the name of the snippet (eg command chain - // "snippet make funk camel my function"), we're more likely to - // win the race and have the input box ready for them - void flashTargets(ide(), targets, FlashStyle.referenced); - - if (snippetName == null) { - snippetName = await ide().showInputBox({ - prompt: "Name of snippet", - placeHolder: "helloWorld", - }); - } - - // User cancelled; don't do anything - if (snippetName == null) { - return {}; - } - - /** The next placeholder index to use for the meta snippet */ - let currentPlaceholderIndex = 1; - - const baseOffset = editor.document.offsetAt(target.contentRange.start); - - /** - * The variables that will appear in the user snippet. Note that - * `placeholderIndex` here is the placeholder index in the meta snippet not - * the user snippet. - */ - const variables: Variable[] = editor.selections - .filter((selection) => target.contentRange.contains(selection)) - .map((selection, index) => ({ - offsets: { - start: editor.document.offsetAt(selection.start) - baseOffset, - end: editor.document.offsetAt(selection.end) - baseOffset, - }, - defaultName: `variable${index + 1}`, - placeholderIndex: currentPlaceholderIndex++, - })); - - /** - * Constructs random ids that can be put into the text that won't be - * modified by json serialization. - */ - const substituter = new Substituter(); - - /** - * Text before the start of the snippet in the snippet start line. We need - * to pass this to {@link constructSnippetBody} so that it knows the - * baseline indentation of the snippet - */ - const linePrefix = editor.document.getText( - new Range( - target.contentRange.start.with(undefined, 0), - target.contentRange.start, - ), - ); - - const originalText = editor.document.getText(target.contentRange); - - /** - * The text of the snippet, with placeholders inserted for variables and - * special characters `$`, `\`, and `}` escaped twice to make it through - * both meta snippet and user snippet. - */ - const snippetBodyText = editText(originalText, [ - ...matchAll(originalText, /\$|\\/g, (match) => ({ - offsets: { - start: match.index!, - end: match.index! + match[0].length, - }, - text: match[0] === "\\" ? `\\${match[0]}` : `\\\\${match[0]}`, - })), - ...variables.map(({ offsets, defaultName, placeholderIndex }) => ({ - offsets, - // Note that the reason we use the substituter here is primarily so - // that the `\` below doesn't get escaped upon conversion to json. - text: substituter.addSubstitution( - [ - // This `\$` will end up being a `$` in the final document. It - // indicates the start of a variable in the user snippet. We need - // the `\` so that the meta-snippet doesn't see it as one of its - // placeholders. - "\\$", - - // The remaining text here is a placeholder in the meta-snippet - // that the user can use to name their snippet variable that will - // be in the user snippet. - "${", - placeholderIndex, - ":", - defaultName, - "}", - ].join(""), - ), - })), - ]); - - const snippetLines = constructSnippetBody(snippetBodyText, linePrefix); - - /** - * Constructs a key-value entry for use in the variable description section - * of the user snippet definition. It contains tabstops for use in the - * meta-snippet. - * @param variable The variable - * @returns A [key, value] pair for use in the meta-snippet - */ - const constructVariableDescriptionEntry = ({ - placeholderIndex, - }: Variable): [string, string] => { - // The key will have the same placeholder index as the other location - // where this variable appears. - const key = "$" + placeholderIndex; - - // The value will end up being an empty object with a tabstop in the - // middle so that the user can add information about the variable, such - // as wrapperScopeType. Ie the output will look like `{|}` (with the `|` - // representing a tabstop in the meta-snippet) - // - // NB: We use the substituter here, with `isQuoted=true` because in order - // to make this work for the meta-snippet, we want to end up with - // something like `{$3}`, which is not valid json. So we instead arrange - // to end up with json like `"hgidfsivhs"`, and then replace the whole - // string (including quotes) with `{$3}` after json-ification - const value = substituter.addSubstitution( - "{$" + currentPlaceholderIndex++ + "}", - true, - ); - - return [key, value]; - }; - - /** An object that will be json-ified to become the meta-snippet */ - const snippet = { - [snippetName]: { - definitions: [ - { - scope: { - langIds: [editor.document.languageId], - }, - body: snippetLines, - }, - ], - description: "$" + currentPlaceholderIndex++, - variables: - variables.length === 0 - ? undefined - : Object.fromEntries( - variables.map(constructVariableDescriptionEntry), - ), - }, - }; - - /** - * This is the text of the meta-snippet in Textmate format that we will - * insert into the new document where the user will fill out their snippet - * definition - */ - const snippetText = substituter.makeSubstitutions( - JSON.stringify(snippet, null, 2), - ); - - const editableEditor = ide().getEditableTextEditor(editor); - - if (ide().runMode === "test") { - // If we're testing, we just overwrite the current document - await editableEditor.setSelections([ - editor.document.range.toSelection(false), - ]); - } else { - // Otherwise, we create and open a new document for the snippet in the - // user snippets dir - await this.snippets.openNewSnippetFile(snippetName); - } - - // Insert the meta-snippet - await editableEditor.insertSnippet(snippetText); - - return { - thatSelections: targets.map(({ editor, contentSelection }) => ({ - editor, - selection: contentSelection, - })), - }; - } -} - -interface Variable { - /** - * The start an end offsets of the variable relative to the text of the - * snippet that contains it - */ - offsets: Offsets; - - /** - * The default name for the given variable that will appear as the placeholder - * text in the meta snippet - */ - defaultName: string; - - /** - * The placeholder to use when filling out the name of this variable in the - * meta snippet. - */ - placeholderIndex: number; -} diff --git a/packages/cursorless-engine/src/actions/InsertSnippet.ts b/packages/cursorless-engine/src/actions/InsertSnippet.ts index f7ca4c9e27..82ccc80d62 100644 --- a/packages/cursorless-engine/src/actions/InsertSnippet.ts +++ b/packages/cursorless-engine/src/actions/InsertSnippet.ts @@ -1,4 +1,5 @@ import type { + CustomInsertSnippetArg, InsertSnippetArg, ScopeType, Snippet, @@ -35,7 +36,10 @@ export default class InsertSnippet { } getFinalStages(snippetDescription: InsertSnippetArg) { - const defaultScopeTypes = this.getScopeTypes(snippetDescription); + const snippets = getSnippets(snippetDescription); + const defaultScopeTypes = snippets.flatMap( + (snippetDescription) => snippetDescription.scopeTypes ?? [], + ); return defaultScopeTypes.length === 0 ? [] @@ -50,58 +54,6 @@ export default class InsertSnippet { ]; } - private getScopeTypes(snippetDescription: InsertSnippetArg): ScopeType[] { - if (snippetDescription.type === "named") { - const { name } = snippetDescription; - - const snippet = this.snippets.getSnippetStrict(name); - - const scopeTypeTypes = snippet.insertionScopeTypes; - return scopeTypeTypes == null - ? [] - : scopeTypeTypes.map((scopeTypeType) => ({ - type: scopeTypeType, - })); - } else { - return snippetDescription.scopeTypes ?? []; - } - } - - private getSnippetInfo( - snippetDescription: InsertSnippetArg, - targets: Target[], - ) { - if (snippetDescription.type === "named") { - const { name } = snippetDescription; - - const snippet = this.snippets.getSnippetStrict(name); - - const definition = findMatchingSnippetDefinitionStrict( - this.modifierStageFactory, - targets, - snippet.definitions, - ); - - return { - body: definition.body.join("\n"), - - formatSubstitutions(substitutions: Record | undefined) { - return substitutions == null - ? undefined - : formatSubstitutions(snippet, definition, substitutions); - }, - }; - } else { - return { - body: snippetDescription.body, - - formatSubstitutions(substitutions: Record | undefined) { - return substitutions; - }, - }; - } - } - async run( destinations: Destination[], snippetDescription: InsertSnippetArg, @@ -109,6 +61,7 @@ export default class InsertSnippet { const editor = ide().getEditableTextEditor( ensureSingleEditor(destinations), ); + const snippets = getSnippets(snippetDescription); await this.actions.editNew.run(destinations); @@ -199,3 +152,17 @@ function formatSubstitutions( }), ); } + +function getSnippets( + snippetDescription: InsertSnippetArg, +): CustomInsertSnippetArg[] { + if (snippetDescription.type === "named") { + throw new Error( + "Cursorless snippets are deprecated. Please use community snippets.", + ); + } + if (snippetDescription.type === "custom") { + return [snippetDescription]; + } + return snippetDescription.snippets; +} diff --git a/packages/cursorless-engine/src/core/Snippets.ts b/packages/cursorless-engine/src/core/Snippets.ts index 190cb1e9ab..b6f2311d57 100644 --- a/packages/cursorless-engine/src/core/Snippets.ts +++ b/packages/cursorless-engine/src/core/Snippets.ts @@ -1,4 +1,4 @@ -import type { Snippet, SnippetMap, TextEditor } from "@cursorless/common"; +import type { TextEditor } from "@cursorless/common"; /** * Handles all cursorless snippets, including core, third-party and @@ -6,28 +6,6 @@ import type { Snippet, SnippetMap, TextEditor } from "@cursorless/common"; * name. */ export interface Snippets { - updateUserSnippets(): Promise; - - /** - * Allows extensions to register third-party snippets. Calling this function - * twice with the same extensionId will replace the older snippets. - * - * Note that third-party snippets take precedence over core snippets, but - * user snippets take precedence over both. - * @param extensionId The id of the extension registering the snippets. - * @param snippets The snippets to be registered. - */ - registerThirdPartySnippets(extensionId: string, snippets: SnippetMap): void; - - /** - * Looks in merged collection of snippets for a snippet with key - * `snippetName`. Throws an exception if the snippet of the given name could - * not be found - * @param snippetName The name of the snippet to look up - * @returns The named snippet - */ - getSnippetStrict(snippetName: string): Snippet; - /** * Opens a new snippet file * @param snippetName The name of the snippet @@ -36,6 +14,6 @@ export interface Snippets { */ openNewSnippetFile( snippetName: string, - directory?: string, + directory: string, ): Promise; } diff --git a/packages/cursorless-engine/src/core/compareSnippetDefinitions.ts b/packages/cursorless-engine/src/core/compareSnippetDefinitions.ts index b10f5e8c56..d20d29a3bd 100644 --- a/packages/cursorless-engine/src/core/compareSnippetDefinitions.ts +++ b/packages/cursorless-engine/src/core/compareSnippetDefinitions.ts @@ -1,9 +1,9 @@ import type { + CustomInsertSnippetArg, + CustomWrapWithSnippetArg, SimpleScopeTypeType, - SnippetDefinition, SnippetScope, } from "@cursorless/common"; -import type { SnippetOrigin } from "./mergeSnippets"; /** * Compares two snippet definitions by how specific their scope, breaking @@ -12,23 +12,26 @@ import type { SnippetOrigin } from "./mergeSnippets"; * @param b The other snippet definition to compare * @returns A negative number if a should come before b, a positive number if b */ -export function compareSnippetDefinitions( - a: SnippetDefinitionWithOrigin, - b: SnippetDefinitionWithOrigin, -): number { - const scopeComparision = compareSnippetScopes( - a.definition.scope, - b.definition.scope, +export function compareSnippetDefinitions< + T extends CustomInsertSnippetArg | CustomWrapWithSnippetArg, +>(a: T, b: T): number { + return compareSnippetScopes( + getScopeFromSnippetDescription(a), + getScopeFromSnippetDescription(b), ); +} - // Prefer the more specific snippet definition, no matter the origin - if (scopeComparision !== 0) { - return scopeComparision; +function getScopeFromSnippetDescription( + snippetDescription: CustomInsertSnippetArg | CustomWrapWithSnippetArg, +): SnippetScope | undefined { + if (snippetDescription.languages != null) { + return { + langIds: snippetDescription.languages, + // Note what is called scopeTypes in the snippet description is the + // insertion scope. Not scope to match against like with the + // function/method snippet example. + }; } - - // If the scopes are the same, prefer the snippet from the higher priority - // origin - return a.origin - b.origin; } function compareSnippetScopes( @@ -88,8 +91,3 @@ function compareScopeTypes( return 0; } - -interface SnippetDefinitionWithOrigin { - origin: SnippetOrigin; - definition: SnippetDefinition; -} diff --git a/packages/cursorless-engine/src/core/mergeSnippets.test.ts b/packages/cursorless-engine/src/core/mergeSnippets.test.ts deleted file mode 100644 index 31a6c8d41d..0000000000 --- a/packages/cursorless-engine/src/core/mergeSnippets.test.ts +++ /dev/null @@ -1,348 +0,0 @@ -import type { SnippetMap } from "@cursorless/common"; -import { mergeSnippets } from "./mergeSnippets"; -import assert from "assert"; - -interface TestCase { - name: string; - coreSnippets?: SnippetMap; - thirdPartySnippets?: Record; - userSnippets?: SnippetMap[]; - expected: SnippetMap; -} - -const testCases: TestCase[] = [ - { - name: "should handle simple case", - coreSnippets: { - aaa: { - definitions: [ - { - body: ["aaa"], - }, - ], - }, - }, - thirdPartySnippets: { - someThirdParty: { - bbb: { - definitions: [ - { - body: ["bbb"], - }, - ], - }, - }, - }, - userSnippets: [ - { - ccc: { - definitions: [ - { - body: ["ccc"], - }, - ], - }, - }, - ], - expected: { - aaa: { - definitions: [ - { - body: ["aaa"], - }, - ], - }, - bbb: { - definitions: [ - { - body: ["bbb"], - }, - ], - }, - ccc: { - definitions: [ - { - body: ["ccc"], - }, - ], - }, - }, - }, - - { - name: "should prefer user snippets", - coreSnippets: { - aaa: { - definitions: [ - { - body: ["core aaa"], - }, - ], - description: "core snippet", - }, - }, - thirdPartySnippets: { - someThirdParty: { - aaa: { - definitions: [ - { - body: ["someThirdParty aaa"], - }, - ], - description: "someThirdParty snippet", - }, - }, - }, - userSnippets: [ - { - aaa: { - definitions: [ - { - body: ["user aaa"], - }, - ], - description: "user snippet", - }, - }, - ], - expected: { - aaa: { - definitions: [ - { - body: ["user aaa"], - }, - { - body: ["someThirdParty aaa"], - }, - { - body: ["core aaa"], - }, - ], - description: "user snippet", - }, - }, - }, - - { - name: "should prefer user snippets when scopes are the same", - coreSnippets: { - aaa: { - definitions: [ - { - body: ["core aaa"], - scope: { - langIds: ["typescript"], - scopeTypes: ["anonymousFunction"], - }, - }, - ], - description: "core snippet", - }, - }, - thirdPartySnippets: { - someThirdParty: { - aaa: { - definitions: [ - { - body: ["someThirdParty aaa"], - scope: { - langIds: ["typescript"], - scopeTypes: ["anonymousFunction"], - }, - }, - ], - description: "someThirdParty snippet", - }, - }, - }, - userSnippets: [ - { - aaa: { - definitions: [ - { - body: ["user aaa"], - scope: { - langIds: ["typescript"], - scopeTypes: ["anonymousFunction"], - }, - }, - ], - description: "user snippet", - }, - }, - ], - expected: { - aaa: { - definitions: [ - { - body: ["user aaa"], - scope: { - langIds: ["typescript"], - scopeTypes: ["anonymousFunction"], - }, - }, - { - body: ["someThirdParty aaa"], - scope: { - langIds: ["typescript"], - scopeTypes: ["anonymousFunction"], - }, - }, - { - body: ["core aaa"], - scope: { - langIds: ["typescript"], - scopeTypes: ["anonymousFunction"], - }, - }, - ], - description: "user snippet", - }, - }, - }, - - { - name: "should prefer more specific snippets, even if they are from a lower priority origin", - coreSnippets: { - aaa: { - definitions: [ - { - body: ["core aaa"], - scope: { - langIds: ["typescript"], - }, - }, - ], - description: "core snippet", - }, - }, - userSnippets: [ - { - aaa: { - definitions: [ - { - body: ["user aaa"], - }, - ], - description: "user snippet", - }, - }, - ], - expected: { - aaa: { - definitions: [ - { - body: ["core aaa"], - scope: { - langIds: ["typescript"], - }, - }, - { - body: ["user aaa"], - }, - ], - description: "user snippet", - }, - }, - }, - - { - name: "should prefer snippets based on specificity", - coreSnippets: { - aaa: { - definitions: [ - { - body: [""], - }, - { - body: [""], - scope: { - langIds: ["typescript"], - }, - }, - { - body: [""], - scope: { - langIds: ["typescript", "javascript"], - }, - }, - { - body: [""], - scope: { - scopeTypes: ["anonymousFunction"], - }, - }, - { - body: [""], - scope: { - langIds: ["typescript"], - scopeTypes: ["anonymousFunction"], - }, - }, - { - body: [""], - scope: { - langIds: ["typescript", "javascript"], - scopeTypes: ["anonymousFunction"], - }, - }, - ], - }, - }, - expected: { - aaa: { - definitions: [ - { - body: [""], - scope: { - langIds: ["typescript"], - scopeTypes: ["anonymousFunction"], - }, - }, - { - body: [""], - scope: { - langIds: ["typescript", "javascript"], - scopeTypes: ["anonymousFunction"], - }, - }, - { - body: [""], - scope: { - langIds: ["typescript"], - }, - }, - { - body: [""], - scope: { - langIds: ["typescript", "javascript"], - }, - }, - { - body: [""], - scope: { - scopeTypes: ["anonymousFunction"], - }, - }, - { - body: [""], - }, - ], - }, - }, - }, -]; - -suite("mergeSnippets", function () { - for (const testCase of testCases) { - test(testCase.name, function () { - const actual = mergeSnippets( - testCase.coreSnippets ?? {}, - testCase.thirdPartySnippets ?? {}, - testCase.userSnippets ?? [], - ); - - assert.deepStrictEqual(actual, testCase.expected); - }); - } -}); diff --git a/packages/cursorless-engine/src/core/mergeSnippets.ts b/packages/cursorless-engine/src/core/mergeSnippets.ts deleted file mode 100644 index e00bdb088e..0000000000 --- a/packages/cursorless-engine/src/core/mergeSnippets.ts +++ /dev/null @@ -1,81 +0,0 @@ -import type { Snippet, SnippetMap } from "@cursorless/common"; -import { cloneDeep, groupBy, mapValues, merge } from "lodash-es"; -import { compareSnippetDefinitions } from "./compareSnippetDefinitions"; - -export function mergeSnippets( - coreSnippets: SnippetMap, - thirdPartySnippets: Record, - userSnippets: SnippetMap[], -): SnippetMap { - const mergedSnippets: SnippetMap = {}; - - // We make a merged map where we map every key to an array of all snippets - // with that key, whether they are core, third-party, or user snippets. - const mergedMap = mapValues( - groupBy( - [ - ...prepareSnippetsFromOrigin(SnippetOrigin.core, coreSnippets), - ...prepareSnippetsFromOrigin( - SnippetOrigin.thirdParty, - ...Object.values(thirdPartySnippets), - ), - ...prepareSnippetsFromOrigin(SnippetOrigin.user, ...userSnippets), - ], - ([key]) => key, - ), - (entries) => entries.map(([, value]) => value), - ); - - Object.entries(mergedMap).forEach(([key, snippets]) => { - const mergedSnippet: Snippet = merge( - {}, - // We sort the snippets by origin as (core, third-party, user) so that - // when we merge them, the user snippets will override the third-party - // snippets, which will override the core snippets. - ...snippets - .sort((a, b) => a.origin - b.origin) - .map(({ snippet }) => snippet), - ); - - // We sort the definitions by decreasing precedence, so that earlier - // definitions will be chosen before later definitions when we're choosing a - // definition for a given target context. - mergedSnippet.definitions = snippets - .flatMap(({ origin, snippet }) => - snippet.definitions.map((definition) => ({ origin, definition })), - ) - .sort((a, b) => -compareSnippetDefinitions(a, b)) - .map(({ definition }) => definition); - - mergedSnippets[key] = mergedSnippet; - }); - - return mergedSnippets; -} - -/** - * Prepares the given snippet maps for merging by adding the given origin to - * each snippet. - * @param origin The origin of the snippets - * @param snippetMaps The snippet maps from the given origin - * @returns An array of entries of the form [key, {origin, snippet}] - */ -function prepareSnippetsFromOrigin( - origin: SnippetOrigin, - ...snippetMaps: SnippetMap[] -) { - return snippetMaps - .map((snippetMap) => - mapValues(cloneDeep(snippetMap), (snippet) => ({ - origin, - snippet, - })), - ) - .flatMap((snippetMap) => Object.entries(snippetMap)); -} - -export enum SnippetOrigin { - core = 0, - thirdParty = 1, - user = 2, -} diff --git a/packages/cursorless-engine/src/disabledComponents/DisabledSnippets.ts b/packages/cursorless-engine/src/disabledComponents/DisabledSnippets.ts index af33393be1..cf40f8f75f 100644 --- a/packages/cursorless-engine/src/disabledComponents/DisabledSnippets.ts +++ b/packages/cursorless-engine/src/disabledComponents/DisabledSnippets.ts @@ -1,25 +1,10 @@ -import type { Snippet, SnippetMap, TextEditor } from "@cursorless/common"; +import type { TextEditor } from "@cursorless/common"; import type { Snippets } from "../core/Snippets"; export class DisabledSnippets implements Snippets { - updateUserSnippets(): Promise { - throw new Error("Snippets are not implemented."); - } - - registerThirdPartySnippets( - _extensionId: string, - _snippets: SnippetMap, - ): void { - throw new Error("Snippets are not implemented."); - } - - getSnippetStrict(_snippetName: string): Snippet { - throw new Error("Snippets are not implemented."); - } - openNewSnippetFile( _snippetName: string, - _directory?: string, + _directory: string, ): Promise { throw new Error("Snippets are not implemented."); } diff --git a/packages/cursorless-engine/src/generateSpokenForm/defaultSpokenForms/snippets.ts b/packages/cursorless-engine/src/generateSpokenForm/defaultSpokenForms/snippets.ts index 808d36e52e..ab16d35e7c 100644 --- a/packages/cursorless-engine/src/generateSpokenForm/defaultSpokenForms/snippets.ts +++ b/packages/cursorless-engine/src/generateSpokenForm/defaultSpokenForms/snippets.ts @@ -1,52 +1,14 @@ import type { InsertSnippetArg, WrapWithSnippetArg } from "@cursorless/common"; import { NoSpokenFormError } from "../NoSpokenFormError"; -const insertionSnippets: Record = { - ifStatement: "if", - ifElseStatement: "if else", - tryCatchStatement: "try", - functionDeclaration: "funk", - link: "link", -}; - -const wrapperSnippets: Record = { - "ifElseStatement.alternative": "else", - "functionDeclaration.body": "funk", - "ifElseStatement.consequence": "if else", - "ifStatement.consequence": "if", - "tryCatchStatement.body": "try", - "link.text": "link", -}; - export function insertionSnippetToSpokenForm( snippetDescription: InsertSnippetArg, ): string { - if (snippetDescription.type === "custom") { - throw new NoSpokenFormError("Custom insertion snippet"); - } - const result = insertionSnippets[snippetDescription.name]; - if (result == null) { - throw new NoSpokenFormError( - `Named insertion snippet '${snippetDescription.name}'`, - ); - } - if (snippetDescription.substitutions != null) { - const values = Object.values(snippetDescription.substitutions); - return `${result} ${values.join(" ")}`; - } - return result; + throw new NoSpokenFormError(`${snippetDescription.type} insertion snippet`); } export function wrapperSnippetToSpokenForm( snippetDescription: WrapWithSnippetArg, ): string { - if (snippetDescription.type === "custom") { - throw new NoSpokenFormError("Custom wrap with snippet"); - } - const name = `${snippetDescription.name}.${snippetDescription.variableName}`; - const result = wrapperSnippets[name]; - if (result == null) { - throw new NoSpokenFormError(`Named wrap with snippet '${name}'`); - } - return result; + throw new NoSpokenFormError(`${snippetDescription.type} wrap with snippet`); } diff --git a/packages/cursorless-vscode/src/VscodeSnippets.ts b/packages/cursorless-vscode/src/VscodeSnippets.ts index 4514809b3b..89ae362387 100644 --- a/packages/cursorless-vscode/src/VscodeSnippets.ts +++ b/packages/cursorless-vscode/src/VscodeSnippets.ts @@ -1,18 +1,13 @@ -import type { Snippet, SnippetMap, TextEditor } from "@cursorless/common"; -import { mergeStrict, showError, type IDE } from "@cursorless/common"; -import { mergeSnippets, type Snippets } from "@cursorless/cursorless-engine"; +import type { TextEditor } from "@cursorless/common"; +import { type IDE } from "@cursorless/common"; +import { type Snippets } from "@cursorless/cursorless-engine"; import { walkFiles } from "@cursorless/node-common"; -import { max } from "lodash-es"; -import { open, readFile, stat } from "node:fs/promises"; +import { open } from "node:fs/promises"; import { join } from "node:path"; -export const CURSORLESS_SNIPPETS_SUFFIX = ".cursorless-snippets"; -const SNIPPET_DIR_REFRESH_INTERVAL_MS = 1000; +// DEPRECATED @ 2025-02-01 -interface DirectoryErrorMessage { - directory: string; - errorMessage: string; -} +export const CURSORLESS_SNIPPETS_SUFFIX = ".cursorless-snippets"; /** * Handles all cursorless snippets, including core, third-party and @@ -20,236 +15,29 @@ interface DirectoryErrorMessage { * name. */ export class VscodeSnippets implements Snippets { - private coreSnippets!: SnippetMap; - private thirdPartySnippets: Record = {}; - private userSnippets!: SnippetMap[]; - - private mergedSnippets!: SnippetMap; - private userSnippetsDir?: string; - /** - * The maximum modification time of any snippet in user snippets dir. - * - * This variable will be set to -1 if no user snippets have yet been read or - * if the user snippets path has changed. - * - * This variable will be set to 0 if the user has no snippets dir configured and - * we've already set userSnippets to {}. - */ - private maxSnippetMtimeMs: number = -1; - - /** - * If the user has misconfigured their snippet dir, then we keep track of it - * so that we can show them the error message if we can't find a snippet - * later, and so that we don't show them the same error message every time - * we try to poll the directory. - */ - private directoryErrorMessage: DirectoryErrorMessage | null | undefined = - null; - constructor(private ide: IDE) { this.updateUserSnippetsPath(); - this.updateUserSnippets = this.updateUserSnippets.bind(this); - this.registerThirdPartySnippets = - this.registerThirdPartySnippets.bind(this); - - const timer = setInterval( - this.updateUserSnippets, - SNIPPET_DIR_REFRESH_INTERVAL_MS, - ); - this.ide.disposeOnExit( - this.ide.configuration.onDidChangeConfiguration(() => { - if (this.updateUserSnippetsPath()) { - void this.updateUserSnippets(); - } - }), - { - dispose() { - clearInterval(timer); - }, - }, - ); - } - - async init() { - const extensionPath = this.ide.assetsRoot; - const snippetsDir = join(extensionPath, "cursorless-snippets"); - const snippetFiles = await this.getSnippetPaths(snippetsDir); - this.coreSnippets = mergeStrict( - ...(await Promise.all( - snippetFiles.map(async (path) => - JSON.parse(await readFile(path, "utf8")), - ), - )), + this.ide.configuration.onDidChangeConfiguration(() => + this.updateUserSnippetsPath(), + ), ); - await this.updateUserSnippets(); } - /** - * Updates the userSnippetsDir field if it has change, returning a boolean - * indicating whether there was an update. If there was an update, resets the - * maxSnippetMtime to -1 to ensure snippet update. - * @returns Boolean indicating whether path has changed - */ - private updateUserSnippetsPath(): boolean { - const newUserSnippetsDir = this.ide.configuration.getOwnConfiguration( + private updateUserSnippetsPath() { + this.userSnippetsDir = this.ide.configuration.getOwnConfiguration( "experimental.snippetsDir", ); - - if (newUserSnippetsDir === this.userSnippetsDir) { - return false; - } - - // Reset mtime to -1 so that next time we'll update the snippets - this.maxSnippetMtimeMs = -1; - - this.userSnippetsDir = newUserSnippetsDir; - - return true; - } - - async updateUserSnippets() { - let snippetFiles: string[]; - try { - snippetFiles = this.userSnippetsDir - ? await this.getSnippetPaths(this.userSnippetsDir) - : []; - } catch (err) { - if (this.directoryErrorMessage?.directory !== this.userSnippetsDir) { - // NB: We suppress error messages once we've shown it the first time - // because we poll the directory every second and want to make sure we - // don't show the same error message repeatedly - const errorMessage = `Error with cursorless snippets dir "${ - this.userSnippetsDir - }": ${(err as Error).message}`; - - void showError(this.ide.messages, "snippetsDirError", errorMessage); - - this.directoryErrorMessage = { - directory: this.userSnippetsDir!, - errorMessage, - }; - } - - this.userSnippets = []; - this.mergeSnippets(); - - return; - } - - this.directoryErrorMessage = null; - - const maxSnippetMtime = - max( - (await Promise.all(snippetFiles.map((file) => stat(file)))).map( - (stat) => stat.mtimeMs, - ), - ) ?? 0; - - if (maxSnippetMtime <= this.maxSnippetMtimeMs) { - return; - } - - this.maxSnippetMtimeMs = maxSnippetMtime; - - this.userSnippets = await Promise.all( - snippetFiles.map(async (path) => { - try { - const content = await readFile(path, "utf8"); - - if (content.length === 0) { - // Gracefully handle an empty file - return {}; - } - - return JSON.parse(content); - } catch (err) { - void showError( - this.ide.messages, - "snippetsFileError", - `Error with cursorless snippets file "${path}": ${ - (err as Error).message - }`, - ); - - // We don't want snippets from all files to stop working if there is - // a parse error in one file, so we just effectively ignore this file - // once we've shown an error message - return {}; - } - }), - ); - - this.mergeSnippets(); - } - - /** - * Allows extensions to register third-party snippets. Calling this function - * twice with the same extensionId will replace the older snippets. - * - * Note that third-party snippets take precedence over core snippets, but - * user snippets take precedence over both. - * @param extensionId The id of the extension registering the snippets. - * @param snippets The snippets to be registered. - */ - registerThirdPartySnippets(extensionId: string, snippets: SnippetMap) { - this.thirdPartySnippets[extensionId] = snippets; - this.mergeSnippets(); - } - - /** - * Merge core, third-party, and user snippets, with precedence user > third - * party > core. - */ - private mergeSnippets() { - this.mergedSnippets = mergeSnippets( - this.coreSnippets, - this.thirdPartySnippets, - this.userSnippets, - ); - } - - /** - * Looks in merged collection of snippets for a snippet with key - * `snippetName`. Throws an exception if the snippet of the given name could - * not be found - * @param snippetName The name of the snippet to look up - * @returns The named snippet - */ - getSnippetStrict(snippetName: string): Snippet { - const snippet = this.mergedSnippets[snippetName]; - - if (snippet == null) { - let errorMessage = `Couldn't find snippet ${snippetName}. `; - - if (this.directoryErrorMessage != null) { - errorMessage += `This could be due to: ${this.directoryErrorMessage.errorMessage}.`; - } - - throw Error(errorMessage); - } - - return snippet; } async openNewSnippetFile( snippetName: string, - directory?: string, + directory: string, ): Promise { - const path = (() => { - if (directory != null) { - return join(directory, `${snippetName}.snippet`); - } - - return join( - this.getUserDirectoryStrict(), - `${snippetName}.cursorless-snippets`, - ); - })(); - + const path = join(directory, `${snippetName}.snippet`); await touch(path); return this.ide.openTextDocument(path); } diff --git a/packages/cursorless-vscode/src/extension.ts b/packages/cursorless-vscode/src/extension.ts index a3995a33ce..3873024ac0 100644 --- a/packages/cursorless-vscode/src/extension.ts +++ b/packages/cursorless-vscode/src/extension.ts @@ -217,10 +217,6 @@ export async function activate( vscodeTutorial, ) : undefined, - - experimental: { - registerThirdPartySnippets: snippets.registerThirdPartySnippets, - }, }; } diff --git a/packages/vscode-common/src/getExtensionApi.ts b/packages/vscode-common/src/getExtensionApi.ts index 4aefc4a6e0..2549c52ac0 100644 --- a/packages/vscode-common/src/getExtensionApi.ts +++ b/packages/vscode-common/src/getExtensionApi.ts @@ -1,17 +1,10 @@ -import type { CommandServerApi, SnippetMap } from "@cursorless/common"; +import type { CommandServerApi } from "@cursorless/common"; import * as vscode from "vscode"; import type { Language, SyntaxNode, Tree } from "web-tree-sitter"; import type { VscodeTestHelpers } from "./TestHelpers"; export interface CursorlessApi { testHelpers: VscodeTestHelpers | undefined; - - experimental: { - registerThirdPartySnippets: ( - extensionId: string, - snippets: SnippetMap, - ) => void; - }; } export interface ParseTreeApi { From a060a8a0b9dc84a8037d9e0bbeb5dea36daca6f0 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 1 Feb 2025 05:13:37 +0100 Subject: [PATCH 03/38] More migrations --- cursorless-talon/src/snippet_types.py | 2 +- cursorless-talon/src/snippets.py | 2 +- packages/common/src/index.ts | 1 - packages/common/src/types/snippet.types.ts | 3 +- packages/common/src/util/textFormatters.ts | 35 ----- .../cursorless-engine/src/CommandHistory.ts | 9 +- .../src/actions/InsertSnippet.ts | 115 +++------------ .../src/actions/WrapWithSnippet.ts | 71 +++------- .../src/actions/actions.types.ts | 10 +- .../core/commandRunner/CommandRunnerImpl.ts | 2 + .../src/core/compareSnippetDefinitions.ts | 8 +- .../src/core/getPreferredSnippet.ts | 63 +++++++++ packages/cursorless-engine/src/index.ts | 1 - .../cursorless-engine/src/snippets/snippet.ts | 131 ------------------ packages/cursorless-vscode/src/extension.ts | 3 - 15 files changed, 125 insertions(+), 331 deletions(-) delete mode 100644 packages/common/src/util/textFormatters.ts create mode 100644 packages/cursorless-engine/src/core/getPreferredSnippet.ts diff --git a/cursorless-talon/src/snippet_types.py b/cursorless-talon/src/snippet_types.py index 2a03ac43a3..a0c9195bac 100644 --- a/cursorless-talon/src/snippet_types.py +++ b/cursorless-talon/src/snippet_types.py @@ -15,7 +15,7 @@ class ScopeType: class CustomInsertionSnippet: name = "custom" body: str - scopesTypes: list[ScopeType] | None = None + scopeTypes: list[ScopeType] | None = None languages: list[str] | None = None substitutions: dict[str, str] | None = None diff --git a/cursorless-talon/src/snippets.py b/cursorless-talon/src/snippets.py index 8ffde069bd..c81516bd47 100644 --- a/cursorless-talon/src/snippets.py +++ b/cursorless-talon/src/snippets.py @@ -131,7 +131,7 @@ def private_cursorless_insert_community_snippet( insert_community_snippet( name, None, # substitutions - ImplicitDestination(), + destination, ) def private_cursorless_wrap_with_community_snippet( diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts index fbc17884d0..49599e44f2 100644 --- a/packages/common/src/index.ts +++ b/packages/common/src/index.ts @@ -109,7 +109,6 @@ export * from "./util/regex"; export * from "./util/selectionsEqual"; export * from "./util/serializedMarksToTokenHats"; export * from "./util/splitKey"; -export * from "./util/textFormatters"; export * from "./util/toPlainObject"; export * from "./util/type"; export * from "./util/typeUtils"; diff --git a/packages/common/src/types/snippet.types.ts b/packages/common/src/types/snippet.types.ts index 4262e13736..88777ae9de 100644 --- a/packages/common/src/types/snippet.types.ts +++ b/packages/common/src/types/snippet.types.ts @@ -1,4 +1,3 @@ -import type { TextFormatterName } from "../util/textFormatters"; import type { SimpleScopeTypeType } from "./command/PartialTargetDescriptor.types"; export interface SnippetScope { @@ -58,7 +57,7 @@ export interface SnippetVariable { /** * Format text inserted into this variable using the given formatter */ - formatter?: TextFormatterName; + formatter?: string; } export interface Snippet { diff --git a/packages/common/src/util/textFormatters.ts b/packages/common/src/util/textFormatters.ts deleted file mode 100644 index d5e6dc9581..0000000000 --- a/packages/common/src/util/textFormatters.ts +++ /dev/null @@ -1,35 +0,0 @@ -type TextFormatter = (tokens: string[]) => string; - -export const textFormatters: Record = { - camelCase(tokens: string[]) { - if (tokens.length === 0) { - return ""; - } - - const [first, ...rest] = tokens; - - return first + rest.map(capitalizeToken).join(""); - }, - - snakeCase(tokens: string[]) { - return tokens.join("_"); - }, - - upperSnakeCase(tokens: string[]) { - return tokens.map((token) => token.toUpperCase()).join("_"); - }, - - pascalCase(tokens: string[]) { - return tokens.map(capitalizeToken).join(""); - }, -}; - -function capitalizeToken(token: string): string { - return token.length === 0 ? "" : token[0].toUpperCase() + token.substr(1); -} - -export type TextFormatterName = - | "camelCase" - | "pascalCase" - | "snakeCase" - | "upperSnakeCase"; diff --git a/packages/cursorless-engine/src/CommandHistory.ts b/packages/cursorless-engine/src/CommandHistory.ts index 4162f03b3a..b1f83a0a15 100644 --- a/packages/cursorless-engine/src/CommandHistory.ts +++ b/packages/cursorless-engine/src/CommandHistory.ts @@ -114,9 +114,16 @@ function sanitizeActionInPlace(action: ActionDescriptor): void { // Remove substitutions and custom body case "insertSnippet": - delete action.snippetDescription.substitutions; if (action.snippetDescription.type === "custom") { action.snippetDescription.body = ""; + delete action.snippetDescription.substitutions; + } else if (action.snippetDescription.type === "list") { + for (const snippet of action.snippetDescription.snippets) { + snippet.body = ""; + delete snippet.substitutions; + } + } else { + delete action.snippetDescription.substitutions; } break; diff --git a/packages/cursorless-engine/src/actions/InsertSnippet.ts b/packages/cursorless-engine/src/actions/InsertSnippet.ts index 82ccc80d62..f891804997 100644 --- a/packages/cursorless-engine/src/actions/InsertSnippet.ts +++ b/packages/cursorless-engine/src/actions/InsertSnippet.ts @@ -1,24 +1,15 @@ -import type { - CustomInsertSnippetArg, - InsertSnippetArg, - ScopeType, - Snippet, - SnippetDefinition, -} from "@cursorless/common"; -import { RangeExpansionBehavior, textFormatters } from "@cursorless/common"; +import type { InsertSnippetArg } from "@cursorless/common"; +import { RangeExpansionBehavior } from "@cursorless/common"; import type { Snippets } from "../core/Snippets"; +import { getPreferredSnippet } from "../core/getPreferredSnippet"; import type { RangeUpdater } from "../core/updateSelections/RangeUpdater"; import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; import type { ModifierStageFactory } from "../processTargets/ModifierStageFactory"; import { ModifyIfUntypedExplicitStage } from "../processTargets/modifiers/ConditionalModifierStages"; -import { UntypedTarget } from "../processTargets/targets"; import { ide } from "../singletons/ide.singleton"; -import { - findMatchingSnippetDefinitionStrict, - transformSnippetVariables, -} from "../snippets/snippet"; +import { transformSnippetVariables } from "../snippets/snippet"; import { SnippetParser } from "../snippets/vendor/vscodeSnippet/snippetParser"; -import type { Destination, Target } from "../typings/target.types"; +import type { Destination } from "../typings/target.types"; import { ensureSingleEditor } from "../util/targetUtils"; import type { Actions } from "./Actions"; import type { ActionReturnValue } from "./actions.types"; @@ -35,12 +26,16 @@ export default class InsertSnippet { this.run = this.run.bind(this); } - getFinalStages(snippetDescription: InsertSnippetArg) { - const snippets = getSnippets(snippetDescription); - const defaultScopeTypes = snippets.flatMap( - (snippetDescription) => snippetDescription.scopeTypes ?? [], + getFinalStages( + destinations: Destination[], + snippetDescription: InsertSnippetArg, + ) { + const editor = ensureSingleEditor(destinations); + const snippet = getPreferredSnippet( + snippetDescription, + editor.document.languageId, ); - + const defaultScopeTypes = snippet.scopeTypes ?? []; return defaultScopeTypes.length === 0 ? [] : [ @@ -61,35 +56,19 @@ export default class InsertSnippet { const editor = ide().getEditableTextEditor( ensureSingleEditor(destinations), ); - const snippets = getSnippets(snippetDescription); - - await this.actions.editNew.run(destinations); - - const { body, formatSubstitutions } = this.getSnippetInfo( + const snippet = getPreferredSnippet( snippetDescription, - // Use new selection locations instead of original targets because - // that's where we'll be doing the snippet insertion - editor.selections.map( - (selection) => - new UntypedTarget({ - editor, - contentRange: selection, - isReversed: false, - hasExplicitRange: true, - }), - ), + editor.document.languageId, ); - const parsedSnippet = this.snippetParser.parse(body); + const parsedSnippet = this.snippetParser.parse(snippet.body); - transformSnippetVariables( - parsedSnippet, - null, - formatSubstitutions(snippetDescription.substitutions), - ); + transformSnippetVariables(parsedSnippet, null, snippet.substitutions); const snippetString = parsedSnippet.toTextmateString(); + await this.actions.editNew.run(destinations); + const { editorSelections: updatedThatSelections } = await performEditsAndUpdateSelections({ rangeUpdater: this.rangeUpdater, @@ -112,57 +91,3 @@ export default class InsertSnippet { }; } } - -/** - * Applies the appropriate formatters to the given variable substitution values - * in {@link substitutions} based on the formatter specified for the given - * variables as defined in {@link snippet} and {@link definition}. - * @param snippet The full snippet info - * @param definition The specific definition chosen for the given target context - * @param substitutions The original unformatted substitution strings - * @returns A new map of substitution strings with the values formatted - */ -function formatSubstitutions( - snippet: Snippet, - definition: SnippetDefinition, - substitutions: Record, -): Record { - return Object.fromEntries( - Object.entries(substitutions).map(([variableName, value]) => { - // We prefer the variable formatters from the contextually relevant - // snippet definition if they exist, otherwise we fall back to the - // global definitions for the given snippet. - const formatterName = - (definition.variables ?? {})[variableName]?.formatter ?? - (snippet.variables ?? {})[variableName]?.formatter; - - if (formatterName == null) { - return [variableName, value]; - } - - const formatter = textFormatters[formatterName]; - - if (formatter == null) { - throw new Error( - `Couldn't find formatter ${formatterName} for variable ${variableName}`, - ); - } - - return [variableName, formatter(value.split(" "))]; - }), - ); -} - -function getSnippets( - snippetDescription: InsertSnippetArg, -): CustomInsertSnippetArg[] { - if (snippetDescription.type === "named") { - throw new Error( - "Cursorless snippets are deprecated. Please use community snippets.", - ); - } - if (snippetDescription.type === "custom") { - return [snippetDescription]; - } - return snippetDescription.snippets; -} diff --git a/packages/cursorless-engine/src/actions/WrapWithSnippet.ts b/packages/cursorless-engine/src/actions/WrapWithSnippet.ts index 07c33d3f91..afd162f256 100644 --- a/packages/cursorless-engine/src/actions/WrapWithSnippet.ts +++ b/packages/cursorless-engine/src/actions/WrapWithSnippet.ts @@ -1,15 +1,13 @@ -import type { ScopeType, WrapWithSnippetArg } from "@cursorless/common"; +import type { WrapWithSnippetArg } from "@cursorless/common"; import { FlashStyle } from "@cursorless/common"; import type { Snippets } from "../core/Snippets"; +import { getPreferredSnippet } from "../core/getPreferredSnippet"; import type { RangeUpdater } from "../core/updateSelections/RangeUpdater"; import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; import type { ModifierStageFactory } from "../processTargets/ModifierStageFactory"; import { ModifyIfUntypedStage } from "../processTargets/modifiers/ConditionalModifierStages"; import { ide } from "../singletons/ide.singleton"; -import { - findMatchingSnippetDefinitionStrict, - transformSnippetVariables, -} from "../snippets/snippet"; +import { transformSnippetVariables } from "../snippets/snippet"; import { SnippetParser } from "../snippets/vendor/vscodeSnippet/snippetParser"; import type { Target } from "../typings/target.types"; import { ensureSingleEditor, flashTargets } from "../util/targetUtils"; @@ -26,10 +24,14 @@ export default class WrapWithSnippet { this.run = this.run.bind(this); } - getFinalStages(snippet: WrapWithSnippetArg) { - const defaultScopeType = this.getScopeType(snippet); + getFinalStages(targets: Target[], snippetDescription: WrapWithSnippetArg) { + const editor = ensureSingleEditor(targets); + const snippet = getPreferredSnippet( + snippetDescription, + editor.document.languageId, + ); - if (defaultScopeType == null) { + if (snippet.scopeType == null) { return []; } @@ -38,64 +40,25 @@ export default class WrapWithSnippet { type: "modifyIfUntyped", modifier: { type: "containingScope", - scopeType: defaultScopeType, + scopeType: snippet.scopeType, }, }), ]; } - private getScopeType( - snippetDescription: WrapWithSnippetArg, - ): ScopeType | undefined { - if (snippetDescription.type === "named") { - const { name, variableName } = snippetDescription; - - const snippet = this.snippets.getSnippetStrict(name); - - const variables = snippet.variables ?? {}; - const scopeTypeType = variables[variableName]?.wrapperScopeType; - return scopeTypeType == null - ? undefined - : { - type: scopeTypeType, - }; - } else { - return snippetDescription.scopeType; - } - } - - private getBody( - snippetDescription: WrapWithSnippetArg, - targets: Target[], - ): string { - if (snippetDescription.type === "named") { - const { name } = snippetDescription; - - const snippet = this.snippets.getSnippetStrict(name); - - const definition = findMatchingSnippetDefinitionStrict( - this.modifierStageFactory, - targets, - snippet.definitions, - ); - - return definition.body.join("\n"); - } else { - return snippetDescription.body; - } - } - async run( targets: Target[], snippetDescription: WrapWithSnippetArg, ): Promise { const editor = ide().getEditableTextEditor(ensureSingleEditor(targets)); + const snippet = getPreferredSnippet( + snippetDescription, + editor.document.languageId, + ); - const body = this.getBody(snippetDescription, targets); - - const parsedSnippet = this.snippetParser.parse(body); + const parsedSnippet = this.snippetParser.parse(snippet.body); - transformSnippetVariables(parsedSnippet, snippetDescription.variableName); + transformSnippetVariables(parsedSnippet, snippet.variableName); const snippetString = parsedSnippet.toTextmateString(); diff --git a/packages/cursorless-engine/src/actions/actions.types.ts b/packages/cursorless-engine/src/actions/actions.types.ts index a0eeef4810..e1c93967c0 100644 --- a/packages/cursorless-engine/src/actions/actions.types.ts +++ b/packages/cursorless-engine/src/actions/actions.types.ts @@ -136,7 +136,10 @@ export interface ActionRecord extends Record { destinations: Destination[], snippetDescription: InsertSnippetArg, ): Promise; - getFinalStages(snippetDescription: InsertSnippetArg): ModifierStage[]; + getFinalStages( + destinations: Destination[], + snippetDescription: InsertSnippetArg, + ): ModifierStage[]; }; wrapWithSnippet: { @@ -144,7 +147,10 @@ export interface ActionRecord extends Record { targets: Target[], snippetDescription: WrapWithSnippetArg, ): Promise; - getFinalStages(snippetDescription: WrapWithSnippetArg): ModifierStage[]; + getFinalStages( + targets: Target[], + snippetDescription: WrapWithSnippetArg, + ): ModifierStage[]; }; editNew: { diff --git a/packages/cursorless-engine/src/core/commandRunner/CommandRunnerImpl.ts b/packages/cursorless-engine/src/core/commandRunner/CommandRunnerImpl.ts index ede4ea49c4..812359dcbf 100644 --- a/packages/cursorless-engine/src/core/commandRunner/CommandRunnerImpl.ts +++ b/packages/cursorless-engine/src/core/commandRunner/CommandRunnerImpl.ts @@ -175,6 +175,7 @@ export class CommandRunnerImpl implements CommandRunner { case "insertSnippet": this.finalStages = this.actions.insertSnippet.getFinalStages( + this.getDestinations(actionDescriptor.destination), actionDescriptor.snippetDescription, ); return this.actions.insertSnippet.run( @@ -184,6 +185,7 @@ export class CommandRunnerImpl implements CommandRunner { case "wrapWithSnippet": this.finalStages = this.actions.wrapWithSnippet.getFinalStages( + this.getTargets(actionDescriptor.target), actionDescriptor.snippetDescription, ); return this.actions.wrapWithSnippet.run( diff --git a/packages/cursorless-engine/src/core/compareSnippetDefinitions.ts b/packages/cursorless-engine/src/core/compareSnippetDefinitions.ts index d20d29a3bd..1b167f0ae7 100644 --- a/packages/cursorless-engine/src/core/compareSnippetDefinitions.ts +++ b/packages/cursorless-engine/src/core/compareSnippetDefinitions.ts @@ -22,12 +22,12 @@ export function compareSnippetDefinitions< } function getScopeFromSnippetDescription( - snippetDescription: CustomInsertSnippetArg | CustomWrapWithSnippetArg, + snippet: CustomInsertSnippetArg | CustomWrapWithSnippetArg, ): SnippetScope | undefined { - if (snippetDescription.languages != null) { + if (snippet.languages != null) { return { - langIds: snippetDescription.languages, - // Note what is called scopeTypes in the snippet description is the + langIds: snippet.languages, + // Note what is called scopeTypes in the snippet arg is the // insertion scope. Not scope to match against like with the // function/method snippet example. }; diff --git a/packages/cursorless-engine/src/core/getPreferredSnippet.ts b/packages/cursorless-engine/src/core/getPreferredSnippet.ts new file mode 100644 index 0000000000..9e11ab72fd --- /dev/null +++ b/packages/cursorless-engine/src/core/getPreferredSnippet.ts @@ -0,0 +1,63 @@ +import type { + CustomInsertSnippetArg, + CustomWrapWithSnippetArg, + InsertSnippetArg, + WrapWithSnippetArg, +} from "@cursorless/common"; +import { compareSnippetDefinitions } from "./compareSnippetDefinitions"; + +export function getPreferredSnippet( + snippetDescription: InsertSnippetArg, + languageId: string, +): CustomInsertSnippetArg; + +export function getPreferredSnippet( + snippetDescription: WrapWithSnippetArg, + languageId: string, +): CustomWrapWithSnippetArg; + +export function getPreferredSnippet( + snippetDescription: InsertSnippetArg | WrapWithSnippetArg, + languageId: string, +) { + const allSnippets = getSnippets(snippetDescription); + const filteredSnippets = filterSnippetDefinitions(allSnippets, languageId); + filteredSnippets.sort(compareSnippetDefinitions); + const preferredSnippet = filteredSnippets[0]; + + if (preferredSnippet == null) { + throw new Error("No snippet available for the current language"); + } + + return preferredSnippet; +} + +function getSnippets( + snippetDescription: InsertSnippetArg | WrapWithSnippetArg, +) { + if (snippetDescription.type === "named") { + throw new Error( + "Cursorless snippets are deprecated. Please use community snippets.", + ); + } + if (snippetDescription.type === "custom") { + return [snippetDescription]; + } + return snippetDescription.snippets; +} + +/** + * Filter snippet definitions by language. + * @param snippetDescriptions The snippets to filter + * @returns The snippets that are relevant to the current language + */ +function filterSnippetDefinitions< + T extends CustomInsertSnippetArg | CustomWrapWithSnippetArg, +>(snippetDescriptions: T[], languageId: string): T[] { + return snippetDescriptions.filter((snippetDescription) => { + if (snippetDescription.languages == null) { + return true; + } + return snippetDescription.languages.includes(languageId); + }); +} diff --git a/packages/cursorless-engine/src/index.ts b/packages/cursorless-engine/src/index.ts index 0fde5045ea..e00aaf5fce 100644 --- a/packages/cursorless-engine/src/index.ts +++ b/packages/cursorless-engine/src/index.ts @@ -3,7 +3,6 @@ export * from "./CommandHistory"; export * from "./CommandHistoryAnalyzer"; export * from "./CommandRunner"; export * from "./core/commandVersionUpgrades/canonicalizeAndValidateCommand"; -export * from "./core/mergeSnippets"; export * from "./core/Snippets"; export * from "./core/StoredTargets"; export * from "./cursorlessEngine"; diff --git a/packages/cursorless-engine/src/snippets/snippet.ts b/packages/cursorless-engine/src/snippets/snippet.ts index 5502a6a21f..2087a176ec 100644 --- a/packages/cursorless-engine/src/snippets/snippet.ts +++ b/packages/cursorless-engine/src/snippets/snippet.ts @@ -1,8 +1,3 @@ -import type { - SimpleScopeTypeType, - SnippetDefinition, -} from "@cursorless/common"; -import type { Target } from "../typings/target.types"; import type { TextmateSnippet } from "./vendor/vscodeSnippet/snippetParser"; import { Placeholder, @@ -10,7 +5,6 @@ import { Variable, } from "./vendor/vscodeSnippet/snippetParser"; import { KnownSnippetVariableNames } from "./vendor/vscodeSnippet/snippetVariables"; -import type { ModifierStageFactory } from "../processTargets/ModifierStageFactory"; /** * Replaces the snippet variable with name `placeholderName` with @@ -80,128 +74,3 @@ function getMaxPlaceholderIndex(parsedSnippet: TextmateSnippet): number { }); return placeholderIndex; } - -/** - * Based on the context determined by {@link targets} (eg the file's language - * id and containing scope), finds the first snippet definition that matches the - * given context. Throws an error if different snippet definitions match for - * different targets or if matching snippet definition could not be found - * @param targets The target that defines the context to use for finding the - * right snippet definition - * @param definitions The list of snippet definitions to search - * @returns The snippet definition that matches the given context - */ -export function findMatchingSnippetDefinitionStrict( - modifierStageFactory: ModifierStageFactory, - targets: Target[], - definitions: SnippetDefinition[], -): SnippetDefinition { - const definitionIndices = targets.map((target) => - findMatchingSnippetDefinitionForSingleTarget( - modifierStageFactory, - target, - definitions, - ), - ); - - const definitionIndex = definitionIndices[0]; - - if (!definitionIndices.every((index) => index === definitionIndex)) { - throw new Error("Multiple snippet definitions match the given context"); - } - - if (definitionIndex === -1) { - throw new Error("Couldn't find matching snippet definition"); - } - - return definitions[definitionIndex]; -} - -/** - * Based on the context determined by {@link target} (eg the file's language id - * and containing scope), finds the best snippet definition that matches the - * given context. Returns -1 if no matching snippet definition could be found. - * - * We assume that the definitions are sorted in precedence order, so we just - * return the first match we find. - * - * @param modifierStageFactory For creating containing scope modifiers - * @param target The target to find a matching snippet definition for - * @param definitions The list of snippet definitions to search - * @returns The index of the best snippet definition that matches the given - * target, or -1 if no matching snippet definition could be found - */ -function findMatchingSnippetDefinitionForSingleTarget( - modifierStageFactory: ModifierStageFactory, - target: Target, - definitions: SnippetDefinition[], -): number { - const languageId = target.editor.document.languageId; - - // We want to find the first definition that matches the given context. - // Note that we just use the first match we find because the definitions are - // guaranteed to come sorted in precedence order. - return definitions.findIndex(({ scope }) => { - if (scope == null) { - return true; - } - - const { langIds, scopeTypes, excludeDescendantScopeTypes } = scope; - - if (langIds != null && !langIds.includes(languageId)) { - return false; - } - - if (scopeTypes != null) { - const allScopeTypes = scopeTypes.concat( - excludeDescendantScopeTypes ?? [], - ); - let matchingTarget: Target | undefined = undefined; - let matchingScopeType: SimpleScopeTypeType | undefined = undefined; - for (const scopeTypeType of allScopeTypes) { - try { - let containingTarget = modifierStageFactory - .create({ - type: "containingScope", - scopeType: { type: scopeTypeType }, - }) - .run(target)[0]; - - if (target.contentRange.isRangeEqual(containingTarget.contentRange)) { - // Skip this scope if the target is exactly the same as the - // containing scope, otherwise wrapping won't work, because we're - // really outside the containing scope when we're wrapping - containingTarget = modifierStageFactory - .create({ - type: "containingScope", - scopeType: { type: scopeTypeType }, - ancestorIndex: 1, - }) - .run(target)[0]; - } - - if ( - matchingTarget == null || - matchingTarget.contentRange.contains(containingTarget.contentRange) - ) { - matchingTarget = containingTarget; - matchingScopeType = scopeTypeType; - } - } catch (_e) { - continue; - } - } - - if (matchingScopeType == null) { - return false; - } - - return ( - matchingTarget != null && - !(excludeDescendantScopeTypes ?? []).includes(matchingScopeType) - ); - } - - return true; - }); -} diff --git a/packages/cursorless-vscode/src/extension.ts b/packages/cursorless-vscode/src/extension.ts index 3873024ac0..d6ff7f83cd 100644 --- a/packages/cursorless-vscode/src/extension.ts +++ b/packages/cursorless-vscode/src/extension.ts @@ -97,10 +97,7 @@ export async function activate( const treeSitter = createTreeSitter(parseTreeApi); const talonSpokenForms = new FileSystemTalonSpokenForms(fileSystem); - // NOTE: do not await on snippet loading and hats initialization because we don't want to - // block extension activation const snippets = new VscodeSnippets(normalizedIde); - void snippets.init(); const treeSitterQueryProvider = new FileSystemRawTreeSitterQueryProvider( normalizedIde, From 70fde64d8d1ebef0a6329a50f5b93c6abea5c193 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 1 Feb 2025 05:14:51 +0100 Subject: [PATCH 04/38] Rename --- cursorless-talon/src/snippets.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cursorless-talon/src/snippets.py b/cursorless-talon/src/snippets.py index c81516bd47..d8b2fc147b 100644 --- a/cursorless-talon/src/snippets.py +++ b/cursorless-talon/src/snippets.py @@ -53,7 +53,7 @@ def insert_community_snippet( [ CustomInsertionSnippet( s.body, - to_scope_type(s.scopes), + to_scope_types(s.scopes), s.languages, substitutions, ) @@ -102,7 +102,7 @@ def cursorless_insert_snippet( """Cursorless: Insert custom snippet """ snippet = CustomInsertionSnippet( body, - to_scope_type(scope_type), + to_scope_types(scope_type), None, # languages None, # substitutions ) @@ -142,11 +142,11 @@ def private_cursorless_wrap_with_community_snippet( insert_community_wrapper_snippet(name, target) -def to_scope_type(scope_type: str | list[str] | None) -> list[ScopeType] | None: - if isinstance(scope_type, str): - return [ScopeType(scope_type)] - elif scope_type is not None: - return [ScopeType(st) for st in scope_type] +def to_scope_types(scope_types: str | list[str] | None) -> list[ScopeType] | None: + if isinstance(scope_types, str): + return [ScopeType(scope_types)] + elif scope_types is not None: + return [ScopeType(st) for st in scope_types] return None From 46b936433e11e5b69bb0707ba1a0e8450ef4779f Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 1 Feb 2025 05:21:42 +0100 Subject: [PATCH 05/38] Check if language field exists --- cursorless-talon/src/snippets.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cursorless-talon/src/snippets.py b/cursorless-talon/src/snippets.py index d8b2fc147b..1fdbf84c5e 100644 --- a/cursorless-talon/src/snippets.py +++ b/cursorless-talon/src/snippets.py @@ -54,7 +54,8 @@ def insert_community_snippet( CustomInsertionSnippet( s.body, to_scope_types(s.scopes), - s.languages, + # languages will be missing if the user has an older version of community + s.languages if hasattr(s, "languages") else None, substitutions, ) for s in snippets @@ -71,7 +72,7 @@ def insert_community_wrapper_snippet(name: str, target: CursorlessTarget): s.body, s.variable_name, ScopeType(s.scope) if s.scope else None, - s.languages, + s.languages if hasattr(s, "languages") else None, ) for s in snippets ], From adeb4c7552082c3032aa809d27956bd27f06b184 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 1 Feb 2025 05:31:22 +0100 Subject: [PATCH 06/38] Added substitutions to list snippet --- cursorless-talon/src/snippet_types.py | 13 +++++++------ cursorless-talon/src/snippets.py | 3 ++- .../common/src/types/command/ActionDescriptor.ts | 1 + .../cursorless-engine/src/actions/InsertSnippet.ts | 5 ++++- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/cursorless-talon/src/snippet_types.py b/cursorless-talon/src/snippet_types.py index a0c9195bac..73377a84d7 100644 --- a/cursorless-talon/src/snippet_types.py +++ b/cursorless-talon/src/snippet_types.py @@ -15,14 +15,15 @@ class ScopeType: class CustomInsertionSnippet: name = "custom" body: str - scopeTypes: list[ScopeType] | None = None - languages: list[str] | None = None - substitutions: dict[str, str] | None = None + scopeTypes: list[ScopeType] | None + languages: list[str] | None + substitutions: dict[str, str] | None @dataclass class ListInsertionSnippet: name = "list" + substitutions: dict[str, str] | None snippets: list[CustomInsertionSnippet] @@ -40,9 +41,9 @@ class InsertSnippetAction: class CustomWrapperSnippet: name = "custom" body: str - variableName: str | None = None - scopeType: ScopeType | None = None - languages: list[str] | None = None + variableName: str | None + scopeType: ScopeType | None + languages: list[str] | None @dataclass diff --git a/cursorless-talon/src/snippets.py b/cursorless-talon/src/snippets.py index 1fdbf84c5e..5dded04716 100644 --- a/cursorless-talon/src/snippets.py +++ b/cursorless-talon/src/snippets.py @@ -50,13 +50,14 @@ def insert_community_snippet( ): snippets: list[CommunityInsertionSnippet] = get_insertion_snippets(name) snippet = ListInsertionSnippet( + substitutions, [ CustomInsertionSnippet( s.body, to_scope_types(s.scopes), # languages will be missing if the user has an older version of community s.languages if hasattr(s, "languages") else None, - substitutions, + None, # substitutions ) for s in snippets ], diff --git a/packages/common/src/types/command/ActionDescriptor.ts b/packages/common/src/types/command/ActionDescriptor.ts index d3f5c0c906..ca9741ff77 100644 --- a/packages/common/src/types/command/ActionDescriptor.ts +++ b/packages/common/src/types/command/ActionDescriptor.ts @@ -157,6 +157,7 @@ export interface CustomInsertSnippetArg { interface ListInsertSnippetArg { type: "list"; + substitutions?: Record; snippets: CustomInsertSnippetArg[]; } diff --git a/packages/cursorless-engine/src/actions/InsertSnippet.ts b/packages/cursorless-engine/src/actions/InsertSnippet.ts index f891804997..040b7c5dbc 100644 --- a/packages/cursorless-engine/src/actions/InsertSnippet.ts +++ b/packages/cursorless-engine/src/actions/InsertSnippet.ts @@ -63,7 +63,10 @@ export default class InsertSnippet { const parsedSnippet = this.snippetParser.parse(snippet.body); - transformSnippetVariables(parsedSnippet, null, snippet.substitutions); + const substitutions = + snippet.substitutions ?? snippetDescription.substitutions; + + transformSnippetVariables(parsedSnippet, null, substitutions); const snippetString = parsedSnippet.toTextmateString(); From bf9e84aa39649b0ba329c66e34676d4c64e15d2f Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 1 Feb 2025 05:39:46 +0100 Subject: [PATCH 07/38] Support placeholder substitution --- packages/cursorless-engine/src/snippets/snippet.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/cursorless-engine/src/snippets/snippet.ts b/packages/cursorless-engine/src/snippets/snippet.ts index 2087a176ec..f8f213715c 100644 --- a/packages/cursorless-engine/src/snippets/snippet.ts +++ b/packages/cursorless-engine/src/snippets/snippet.ts @@ -53,6 +53,13 @@ export function transformSnippetVariables( } else if (candidate instanceof Placeholder) { if (candidate.index.toString() === placeholderName) { candidate.parent.replace(candidate, [new Variable("TM_SELECTED_TEXT")]); + } else if ( + substitutions != null && + Object.prototype.hasOwnProperty.call(substitutions, candidate.index) + ) { + candidate.parent.replace(candidate, [ + new Text(substitutions[candidate.index]), + ]); } } return true; From 37b48f5fa287aca77b075408e54b7a11cae01ffe Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 1 Feb 2025 05:42:24 +0100 Subject: [PATCH 08/38] Cleanup --- packages/cursorless-engine/src/actions/WrapWithSnippet.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/cursorless-engine/src/actions/WrapWithSnippet.ts b/packages/cursorless-engine/src/actions/WrapWithSnippet.ts index afd162f256..936909ad89 100644 --- a/packages/cursorless-engine/src/actions/WrapWithSnippet.ts +++ b/packages/cursorless-engine/src/actions/WrapWithSnippet.ts @@ -66,14 +66,11 @@ export default class WrapWithSnippet { const targetSelections = targets.map((target) => target.contentSelection); - const callback = () => - editor.insertSnippet(snippetString, targetSelections); - const { targetSelections: updatedTargetSelections } = await performEditsAndUpdateSelections({ rangeUpdater: this.rangeUpdater, editor, - callback, + callback: () => editor.insertSnippet(snippetString, targetSelections), preserveCursorSelections: true, selections: { targetSelections, From 0c6c9e0cd2e581faa7f92be2ca4372b408acf9dc Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 1 Feb 2025 06:21:43 +0100 Subject: [PATCH 09/38] Update types --- cursorless-talon/src/snippet_types.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cursorless-talon/src/snippet_types.py b/cursorless-talon/src/snippet_types.py index 73377a84d7..eb1f36a090 100644 --- a/cursorless-talon/src/snippet_types.py +++ b/cursorless-talon/src/snippet_types.py @@ -73,5 +73,5 @@ class CommunityInsertionSnippet: class CommunityWrapperSnippet: body: str variable_name: str - languages: list[str] | None = None - scope: str | None = None + languages: list[str] | None + scope: str | None From 207175928c9af476253f9bac76317fef5d01734f Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 1 Feb 2025 07:35:41 +0100 Subject: [PATCH 10/38] Migrating tests --- .../actions/snippets/customInsert.yml | 2 +- .../snippets/customInsertAfterWhale.yml | 2 +- .../snippets/customInsertAfterWhale2.yml | 2 +- .../snippets/customInsertHelloWorld.yml | 2 +- .../actions/snippets/customWrapHarp.yml | 2 +- .../actions/snippets/customWrapLine.yml | 2 +- .../actions/snippets/customWrapLine2.yml | 2 +- .../snippets/duplicatedDuplicatedWrapThis.yml | 4 +- .../snippets/duplicatedUniqueWrapThis.yml | 4 +- .../recorded/actions/snippets/ifWrapCap.yml | 2 +- .../snippets/snipDuplicatedDuplicated.yml | 4 +- .../snipDuplicatedDuplicatedHelloWorld.yml | 10 +++-- .../snipDuplicatedUniqueHelloWorld.yml | 11 +++-- .../recorded/actions/snippets/snipFunk.yml | 29 ------------ .../recorded/actions/snippets/snipFunk2.yml | 30 ------------- .../recorded/actions/snippets/snipFunk3.yml | 35 --------------- .../recorded/actions/snippets/snipFunk4.yml | 39 ---------------- .../recorded/actions/snippets/snipFunk5.yml | 39 ---------------- .../recorded/actions/snippets/snipFunk6.yml | 43 ------------------ .../actions/snippets/snipFunkAfterThis5.yml | 23 +--------- .../actions/snippets/snipFunkToClass.yml | 40 ----------------- .../actions/snippets/snipFunkToThis.yml | 42 ------------------ .../recorded/actions/snippets/snipIf.yml | 35 --------------- .../actions/snippets/snipSpaghetti.yml | 28 ------------ .../snippets/snipSpaghettiGraceHopper.yml | 31 ------------- .../snippets/spaghettiWrapPastGust.yml | 38 ---------------- .../recorded/actions/snippets/tryWrapThis.yml | 34 -------------- .../languages/cpp/elseStateWrapThis.yml | 27 ------------ .../recorded/languages/cpp/ifElseWrapThis.yml | 27 ------------ .../languages/cpp/ifStateWrapThis.yml | 25 ----------- .../languages/cpp/tryCatchWrapThis.yml | 27 ------------ .../languages/cpp/tryCatchWrapThis2.yml | 44 ------------------- .../languages/csharp/elseStateWrapThis.yml | 27 ------------ .../languages/csharp/ifElseWrapThis.yml | 27 ------------ .../languages/csharp/ifStateWrapThis.yml | 25 ----------- .../languages/csharp/tryCatchWrapThis.yml | 27 ------------ .../languages/csharp/tryCatchWrapThis2.yml | 44 ------------------- .../languages/java/elseStateWrapThis.yml | 27 ------------ .../languages/java/ifElseWrapThis.yml | 27 ------------ .../languages/java/ifStateWrapThis.yml | 25 ----------- .../languages/java/tryCatchWrapThis.yml | 27 ------------ .../languages/java/tryCatchWrapThis2.yml | 44 ------------------- .../recorded/languages/php/elseWrapThis.yml | 14 +----- .../recorded/languages/php/ifElseWrapThis.yml | 14 +----- .../recorded/languages/php/ifWrapThis.yml | 12 +---- .../recorded/languages/php/tryWrapThis.yml | 14 +----- .../recorded/languages/php/tryWrapThis2.yml | 24 +--------- .../languages/python/elseStateWrapThis.yml | 26 ----------- .../languages/python/ifElseWrapThis.yml | 26 ----------- .../languages/python/ifStateWrapThis.yml | 24 ---------- .../languages/python/tryCatchWrapThis.yml | 26 ----------- .../languages/python/tryCatchWrapThis2.yml | 40 ----------------- .../typescript/elseStateWrapThis.yml | 27 ------------ .../languages/typescript/ifElseWrapThis.yml | 27 ------------ .../languages/typescript/ifStateWrapThis.yml | 25 ----------- .../languages/typescript/tryCatchWrapThis.yml | 27 ------------ .../typescript/tryCatchWrapThis2.yml | 44 ------------------- .../src/actions/InsertSnippet.ts | 2 +- .../src/actions/WrapWithSnippet.ts | 2 +- ...nippet.ts => transformSnippetVariables.ts} | 0 60 files changed, 41 insertions(+), 1318 deletions(-) delete mode 100644 data/fixtures/recorded/actions/snippets/snipFunk.yml delete mode 100644 data/fixtures/recorded/actions/snippets/snipFunk2.yml delete mode 100644 data/fixtures/recorded/actions/snippets/snipFunk3.yml delete mode 100644 data/fixtures/recorded/actions/snippets/snipFunk4.yml delete mode 100644 data/fixtures/recorded/actions/snippets/snipFunk5.yml delete mode 100644 data/fixtures/recorded/actions/snippets/snipFunk6.yml delete mode 100644 data/fixtures/recorded/actions/snippets/snipFunkToClass.yml delete mode 100644 data/fixtures/recorded/actions/snippets/snipFunkToThis.yml delete mode 100644 data/fixtures/recorded/actions/snippets/snipIf.yml delete mode 100644 data/fixtures/recorded/actions/snippets/snipSpaghetti.yml delete mode 100644 data/fixtures/recorded/actions/snippets/snipSpaghettiGraceHopper.yml delete mode 100644 data/fixtures/recorded/actions/snippets/spaghettiWrapPastGust.yml delete mode 100644 data/fixtures/recorded/actions/snippets/tryWrapThis.yml delete mode 100644 data/fixtures/recorded/languages/cpp/elseStateWrapThis.yml delete mode 100644 data/fixtures/recorded/languages/cpp/ifElseWrapThis.yml delete mode 100644 data/fixtures/recorded/languages/cpp/ifStateWrapThis.yml delete mode 100644 data/fixtures/recorded/languages/cpp/tryCatchWrapThis.yml delete mode 100644 data/fixtures/recorded/languages/cpp/tryCatchWrapThis2.yml delete mode 100644 data/fixtures/recorded/languages/csharp/elseStateWrapThis.yml delete mode 100644 data/fixtures/recorded/languages/csharp/ifElseWrapThis.yml delete mode 100644 data/fixtures/recorded/languages/csharp/ifStateWrapThis.yml delete mode 100644 data/fixtures/recorded/languages/csharp/tryCatchWrapThis.yml delete mode 100644 data/fixtures/recorded/languages/csharp/tryCatchWrapThis2.yml delete mode 100644 data/fixtures/recorded/languages/java/elseStateWrapThis.yml delete mode 100644 data/fixtures/recorded/languages/java/ifElseWrapThis.yml delete mode 100644 data/fixtures/recorded/languages/java/ifStateWrapThis.yml delete mode 100644 data/fixtures/recorded/languages/java/tryCatchWrapThis.yml delete mode 100644 data/fixtures/recorded/languages/java/tryCatchWrapThis2.yml delete mode 100644 data/fixtures/recorded/languages/python/elseStateWrapThis.yml delete mode 100644 data/fixtures/recorded/languages/python/ifElseWrapThis.yml delete mode 100644 data/fixtures/recorded/languages/python/ifStateWrapThis.yml delete mode 100644 data/fixtures/recorded/languages/python/tryCatchWrapThis.yml delete mode 100644 data/fixtures/recorded/languages/python/tryCatchWrapThis2.yml delete mode 100644 data/fixtures/recorded/languages/typescript/elseStateWrapThis.yml delete mode 100644 data/fixtures/recorded/languages/typescript/ifElseWrapThis.yml delete mode 100644 data/fixtures/recorded/languages/typescript/ifStateWrapThis.yml delete mode 100644 data/fixtures/recorded/languages/typescript/tryCatchWrapThis.yml delete mode 100644 data/fixtures/recorded/languages/typescript/tryCatchWrapThis2.yml rename packages/cursorless-engine/src/snippets/{snippet.ts => transformSnippetVariables.ts} (100%) diff --git a/data/fixtures/recorded/actions/snippets/customInsert.yml b/data/fixtures/recorded/actions/snippets/customInsert.yml index 50b82a4dd2..4648ba14cd 100644 --- a/data/fixtures/recorded/actions/snippets/customInsert.yml +++ b/data/fixtures/recorded/actions/snippets/customInsert.yml @@ -7,7 +7,7 @@ command: snippetDescription: {type: custom, body: 'dummy snippet hole1: ($hole1), hole2: ($hole2)'} destination: {type: implicit} usePrePhraseSnapshot: true -spokenFormError: Custom insertion snippet +spokenFormError: custom insertion snippet initialState: documentContents: "" selections: diff --git a/data/fixtures/recorded/actions/snippets/customInsertAfterWhale.yml b/data/fixtures/recorded/actions/snippets/customInsertAfterWhale.yml index aecd21b1db..0895eb3b23 100644 --- a/data/fixtures/recorded/actions/snippets/customInsertAfterWhale.yml +++ b/data/fixtures/recorded/actions/snippets/customInsertAfterWhale.yml @@ -12,7 +12,7 @@ command: type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: w} usePrePhraseSnapshot: true -spokenFormError: Custom insertion snippet +spokenFormError: custom insertion snippet initialState: documentContents: hello world selections: diff --git a/data/fixtures/recorded/actions/snippets/customInsertAfterWhale2.yml b/data/fixtures/recorded/actions/snippets/customInsertAfterWhale2.yml index fc02893614..aa352d2e02 100644 --- a/data/fixtures/recorded/actions/snippets/customInsertAfterWhale2.yml +++ b/data/fixtures/recorded/actions/snippets/customInsertAfterWhale2.yml @@ -16,7 +16,7 @@ command: type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: w} usePrePhraseSnapshot: true -spokenFormError: Custom insertion snippet +spokenFormError: custom insertion snippet initialState: documentContents: hello world selections: diff --git a/data/fixtures/recorded/actions/snippets/customInsertHelloWorld.yml b/data/fixtures/recorded/actions/snippets/customInsertHelloWorld.yml index 7d85bdc525..25015f5205 100644 --- a/data/fixtures/recorded/actions/snippets/customInsertHelloWorld.yml +++ b/data/fixtures/recorded/actions/snippets/customInsertHelloWorld.yml @@ -10,7 +10,7 @@ command: substitutions: {hole2: hello world} destination: {type: implicit} usePrePhraseSnapshot: true -spokenFormError: Custom insertion snippet +spokenFormError: custom insertion snippet initialState: documentContents: "" selections: diff --git a/data/fixtures/recorded/actions/snippets/customWrapHarp.yml b/data/fixtures/recorded/actions/snippets/customWrapHarp.yml index 02c26c8a23..ea856689bd 100644 --- a/data/fixtures/recorded/actions/snippets/customWrapHarp.yml +++ b/data/fixtures/recorded/actions/snippets/customWrapHarp.yml @@ -13,7 +13,7 @@ command: type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: h} usePrePhraseSnapshot: true -spokenFormError: Custom wrap with snippet +spokenFormError: custom wrap with snippet initialState: documentContents: | hello world diff --git a/data/fixtures/recorded/actions/snippets/customWrapLine.yml b/data/fixtures/recorded/actions/snippets/customWrapLine.yml index 4e016823c1..e26290d238 100644 --- a/data/fixtures/recorded/actions/snippets/customWrapLine.yml +++ b/data/fixtures/recorded/actions/snippets/customWrapLine.yml @@ -11,7 +11,7 @@ command: - type: containingScope scopeType: {type: line} usePrePhraseSnapshot: true -spokenFormError: Custom wrap with snippet +spokenFormError: custom wrap with snippet initialState: documentContents: hello world selections: diff --git a/data/fixtures/recorded/actions/snippets/customWrapLine2.yml b/data/fixtures/recorded/actions/snippets/customWrapLine2.yml index 22a4900bca..f681a363ae 100644 --- a/data/fixtures/recorded/actions/snippets/customWrapLine2.yml +++ b/data/fixtures/recorded/actions/snippets/customWrapLine2.yml @@ -11,7 +11,7 @@ command: - type: containingScope scopeType: {type: line} usePrePhraseSnapshot: true -spokenFormError: Custom wrap with snippet +spokenFormError: custom wrap with snippet initialState: documentContents: hello world selections: diff --git a/data/fixtures/recorded/actions/snippets/duplicatedDuplicatedWrapThis.yml b/data/fixtures/recorded/actions/snippets/duplicatedDuplicatedWrapThis.yml index b635ff16cc..04425e9bea 100644 --- a/data/fixtures/recorded/actions/snippets/duplicatedDuplicatedWrapThis.yml +++ b/data/fixtures/recorded/actions/snippets/duplicatedDuplicatedWrapThis.yml @@ -4,12 +4,12 @@ command: spokenForm: duplicated duplicated wrap this action: name: wrapWithSnippet - snippetDescription: {type: named, name: duplicatedVariableTest, variableName: duplicated} + snippetDescription: {type: custom, variableName: duplicated, body: 'This variable: ''$duplicated'' is duplicated here: ''$duplicated'', but ''$unique'' is unique!'} target: type: primitive mark: {type: cursor} usePrePhraseSnapshot: true -spokenFormError: Named wrap with snippet 'duplicatedVariableTest.duplicated' +spokenFormError: custom wrap with snippet initialState: documentContents: Hello world selections: diff --git a/data/fixtures/recorded/actions/snippets/duplicatedUniqueWrapThis.yml b/data/fixtures/recorded/actions/snippets/duplicatedUniqueWrapThis.yml index b58d8875dc..37cf7d3509 100644 --- a/data/fixtures/recorded/actions/snippets/duplicatedUniqueWrapThis.yml +++ b/data/fixtures/recorded/actions/snippets/duplicatedUniqueWrapThis.yml @@ -4,12 +4,12 @@ command: spokenForm: duplicated unique wrap this action: name: wrapWithSnippet - snippetDescription: {type: named, name: duplicatedVariableTest, variableName: unique} + snippetDescription: {type: custom, variableName: unique, body: 'This variable: ''$duplicated'' is duplicated here: ''$duplicated'', but ''$unique'' is unique!'} target: type: primitive mark: {type: cursor} usePrePhraseSnapshot: true -spokenFormError: Named wrap with snippet 'duplicatedVariableTest.unique' +spokenFormError: custom wrap with snippet initialState: documentContents: Hello world selections: diff --git a/data/fixtures/recorded/actions/snippets/ifWrapCap.yml b/data/fixtures/recorded/actions/snippets/ifWrapCap.yml index dcdbd5eaee..b747cb1221 100644 --- a/data/fixtures/recorded/actions/snippets/ifWrapCap.yml +++ b/data/fixtures/recorded/actions/snippets/ifWrapCap.yml @@ -13,7 +13,7 @@ command: type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: c} usePrePhraseSnapshot: true -spokenFormError: Custom wrap with snippet +spokenFormError: custom wrap with snippet initialState: documentContents: const value = 2; selections: diff --git a/data/fixtures/recorded/actions/snippets/snipDuplicatedDuplicated.yml b/data/fixtures/recorded/actions/snippets/snipDuplicatedDuplicated.yml index 4f9c0c86fa..0e4ae2bcc2 100644 --- a/data/fixtures/recorded/actions/snippets/snipDuplicatedDuplicated.yml +++ b/data/fixtures/recorded/actions/snippets/snipDuplicatedDuplicated.yml @@ -4,10 +4,10 @@ command: spokenForm: snippet duplicated duplicated action: name: insertSnippet - snippetDescription: {type: named, name: duplicatedVariableTest} + snippetDescription: {type: custom, body: 'This variable: ''$duplicated'' is duplicated here: ''$duplicated'', but ''$unique'' is unique!'} destination: {type: implicit} usePrePhraseSnapshot: true -spokenFormError: Named insertion snippet 'duplicatedVariableTest' +spokenFormError: custom insertion snippet initialState: documentContents: "" selections: diff --git a/data/fixtures/recorded/actions/snippets/snipDuplicatedDuplicatedHelloWorld.yml b/data/fixtures/recorded/actions/snippets/snipDuplicatedDuplicatedHelloWorld.yml index 5a36d7daf9..da2c15d73d 100644 --- a/data/fixtures/recorded/actions/snippets/snipDuplicatedDuplicatedHelloWorld.yml +++ b/data/fixtures/recorded/actions/snippets/snipDuplicatedDuplicatedHelloWorld.yml @@ -5,12 +5,14 @@ command: action: name: insertSnippet snippetDescription: - type: named - name: duplicatedVariableTest - substitutions: {duplicated: hello world} + type: custom + substitutions: {duplicated: hello_world} + body: >- + This variable: '$duplicated' is duplicated here: '$duplicated', but + '$unique' is unique! destination: {type: implicit} usePrePhraseSnapshot: true -spokenFormError: Named insertion snippet 'duplicatedVariableTest' +spokenFormError: custom insertion snippet initialState: documentContents: "" selections: diff --git a/data/fixtures/recorded/actions/snippets/snipDuplicatedUniqueHelloWorld.yml b/data/fixtures/recorded/actions/snippets/snipDuplicatedUniqueHelloWorld.yml index dc7108f9de..3264a39935 100644 --- a/data/fixtures/recorded/actions/snippets/snipDuplicatedUniqueHelloWorld.yml +++ b/data/fixtures/recorded/actions/snippets/snipDuplicatedUniqueHelloWorld.yml @@ -5,12 +5,15 @@ command: action: name: insertSnippet snippetDescription: - type: named - name: duplicatedVariableTest - substitutions: {unique: hello world} + type: custom + substitutions: {unique: helloWorld} + Name: duplicated + body: >- + This variable: '$duplicated' is duplicated here: '$duplicated', but + '$unique' is unique! destination: {type: implicit} usePrePhraseSnapshot: true -spokenFormError: Named insertion snippet 'duplicatedVariableTest' +spokenFormError: custom insertion snippet initialState: documentContents: "" selections: diff --git a/data/fixtures/recorded/actions/snippets/snipFunk.yml b/data/fixtures/recorded/actions/snippets/snipFunk.yml deleted file mode 100644 index f5fb9aebd5..0000000000 --- a/data/fixtures/recorded/actions/snippets/snipFunk.yml +++ /dev/null @@ -1,29 +0,0 @@ -languageId: typescript -command: - version: 6 - spokenForm: snippet funk - action: - name: insertSnippet - snippetDescription: {type: named, name: functionDeclaration} - destination: {type: implicit} - usePrePhraseSnapshot: false -initialState: - documentContents: "" - selections: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} -finalState: - documentContents: |- - function () { - - } - selections: - - anchor: {line: 0, character: 9} - active: {line: 0, character: 9} - thatMark: - - type: UntypedTarget - contentRange: - start: {line: 0, character: 0} - end: {line: 2, character: 1} - isReversed: false - hasExplicitRange: true diff --git a/data/fixtures/recorded/actions/snippets/snipFunk2.yml b/data/fixtures/recorded/actions/snippets/snipFunk2.yml deleted file mode 100644 index 4d8ccb35c3..0000000000 --- a/data/fixtures/recorded/actions/snippets/snipFunk2.yml +++ /dev/null @@ -1,30 +0,0 @@ -languageId: typescript -command: - version: 6 - spokenForm: snippet funk - action: - name: insertSnippet - snippetDescription: {type: named, name: functionDeclaration} - destination: {type: implicit} - usePrePhraseSnapshot: true -initialState: - documentContents: "" - selections: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} - marks: {} -finalState: - documentContents: |- - function () { - - } - selections: - - anchor: {line: 0, character: 9} - active: {line: 0, character: 9} - thatMark: - - type: UntypedTarget - contentRange: - start: {line: 0, character: 0} - end: {line: 2, character: 1} - isReversed: false - hasExplicitRange: true diff --git a/data/fixtures/recorded/actions/snippets/snipFunk3.yml b/data/fixtures/recorded/actions/snippets/snipFunk3.yml deleted file mode 100644 index 4e2bf78d42..0000000000 --- a/data/fixtures/recorded/actions/snippets/snipFunk3.yml +++ /dev/null @@ -1,35 +0,0 @@ -languageId: typescript -command: - version: 6 - spokenForm: snippet funk - action: - name: insertSnippet - snippetDescription: {type: named, name: functionDeclaration} - destination: {type: implicit} - usePrePhraseSnapshot: true -initialState: - documentContents: |- - class Aaa { - - } - selections: - - anchor: {line: 1, character: 4} - active: {line: 1, character: 4} - marks: {} -finalState: - documentContents: |- - class Aaa { - () { - - } - } - selections: - - anchor: {line: 1, character: 4} - active: {line: 1, character: 4} - thatMark: - - type: UntypedTarget - contentRange: - start: {line: 1, character: 4} - end: {line: 3, character: 5} - isReversed: false - hasExplicitRange: true diff --git a/data/fixtures/recorded/actions/snippets/snipFunk4.yml b/data/fixtures/recorded/actions/snippets/snipFunk4.yml deleted file mode 100644 index db9ac84ca2..0000000000 --- a/data/fixtures/recorded/actions/snippets/snipFunk4.yml +++ /dev/null @@ -1,39 +0,0 @@ -languageId: typescript -command: - version: 6 - spokenForm: snippet funk - action: - name: insertSnippet - snippetDescription: {type: named, name: functionDeclaration} - destination: {type: implicit} - usePrePhraseSnapshot: true -initialState: - documentContents: |- - class Aaa { - bbb() { - - } - } - selections: - - anchor: {line: 2, character: 8} - active: {line: 2, character: 8} - marks: {} -finalState: - documentContents: |- - class Aaa { - bbb() { - function () { - - } - } - } - selections: - - anchor: {line: 2, character: 17} - active: {line: 2, character: 17} - thatMark: - - type: UntypedTarget - contentRange: - start: {line: 2, character: 8} - end: {line: 4, character: 9} - isReversed: false - hasExplicitRange: true diff --git a/data/fixtures/recorded/actions/snippets/snipFunk5.yml b/data/fixtures/recorded/actions/snippets/snipFunk5.yml deleted file mode 100644 index 5059994512..0000000000 --- a/data/fixtures/recorded/actions/snippets/snipFunk5.yml +++ /dev/null @@ -1,39 +0,0 @@ -languageId: typescript -command: - version: 6 - spokenForm: snippet funk - action: - name: insertSnippet - snippetDescription: {type: named, name: functionDeclaration} - destination: {type: implicit} - usePrePhraseSnapshot: true -initialState: - documentContents: |- - function aaa() { - class Bbb { - - } - } - selections: - - anchor: {line: 2, character: 8} - active: {line: 2, character: 8} - marks: {} -finalState: - documentContents: |- - function aaa() { - class Bbb { - () { - - } - } - } - selections: - - anchor: {line: 2, character: 8} - active: {line: 2, character: 8} - thatMark: - - type: UntypedTarget - contentRange: - start: {line: 2, character: 8} - end: {line: 4, character: 9} - isReversed: false - hasExplicitRange: true diff --git a/data/fixtures/recorded/actions/snippets/snipFunk6.yml b/data/fixtures/recorded/actions/snippets/snipFunk6.yml deleted file mode 100644 index 12a7187419..0000000000 --- a/data/fixtures/recorded/actions/snippets/snipFunk6.yml +++ /dev/null @@ -1,43 +0,0 @@ -languageId: typescript -command: - version: 6 - spokenForm: snippet funk - action: - name: insertSnippet - snippetDescription: {type: named, name: functionDeclaration} - destination: {type: implicit} - usePrePhraseSnapshot: true -initialState: - documentContents: |- - class Aaa { - bbb() { - class Bbb { - - } - } - } - selections: - - anchor: {line: 3, character: 12} - active: {line: 3, character: 12} - marks: {} -finalState: - documentContents: |- - class Aaa { - bbb() { - class Bbb { - () { - - } - } - } - } - selections: - - anchor: {line: 3, character: 12} - active: {line: 3, character: 12} - thatMark: - - type: UntypedTarget - contentRange: - start: {line: 3, character: 12} - end: {line: 5, character: 13} - isReversed: false - hasExplicitRange: true diff --git a/data/fixtures/recorded/actions/snippets/snipFunkAfterThis5.yml b/data/fixtures/recorded/actions/snippets/snipFunkAfterThis5.yml index aa8a47c57e..28ad811555 100644 --- a/data/fixtures/recorded/actions/snippets/snipFunkAfterThis5.yml +++ b/data/fixtures/recorded/actions/snippets/snipFunkAfterThis5.yml @@ -12,6 +12,7 @@ command: type: primitive mark: {type: cursor} usePrePhraseSnapshot: true +spokenFormError: named insertion snippet initialState: documentContents: |- class Aaa { @@ -23,24 +24,4 @@ initialState: - anchor: {line: 2, character: 8} active: {line: 2, character: 8} marks: {} -finalState: - documentContents: |- - class Aaa { - bbb() { - - } - - () { - - } - } - selections: - - anchor: {line: 5, character: 4} - active: {line: 5, character: 4} - thatMark: - - type: UntypedTarget - contentRange: - start: {line: 5, character: 4} - end: {line: 7, character: 5} - isReversed: false - hasExplicitRange: true +thrownError: {name: Error} diff --git a/data/fixtures/recorded/actions/snippets/snipFunkToClass.yml b/data/fixtures/recorded/actions/snippets/snipFunkToClass.yml deleted file mode 100644 index 67bf80cd09..0000000000 --- a/data/fixtures/recorded/actions/snippets/snipFunkToClass.yml +++ /dev/null @@ -1,40 +0,0 @@ -languageId: typescript -command: - version: 6 - spokenForm: snippet funk to class - action: - name: insertSnippet - snippetDescription: {type: named, name: functionDeclaration} - destination: - type: primitive - insertionMode: to - target: - type: primitive - modifiers: - - type: containingScope - scopeType: {type: class} - usePrePhraseSnapshot: true -initialState: - documentContents: |- - class Aaa { - - } - selections: - - anchor: {line: 1, character: 4} - active: {line: 1, character: 4} - marks: {} -finalState: - documentContents: |- - function () { - - } - selections: - - anchor: {line: 0, character: 9} - active: {line: 0, character: 9} - thatMark: - - type: UntypedTarget - contentRange: - start: {line: 0, character: 0} - end: {line: 2, character: 1} - isReversed: false - hasExplicitRange: true diff --git a/data/fixtures/recorded/actions/snippets/snipFunkToThis.yml b/data/fixtures/recorded/actions/snippets/snipFunkToThis.yml deleted file mode 100644 index cd540d7878..0000000000 --- a/data/fixtures/recorded/actions/snippets/snipFunkToThis.yml +++ /dev/null @@ -1,42 +0,0 @@ -languageId: typescript -command: - version: 6 - spokenForm: snippet funk to this - action: - name: insertSnippet - snippetDescription: {type: named, name: functionDeclaration} - destination: - type: primitive - insertionMode: to - target: - type: primitive - mark: {type: cursor} - usePrePhraseSnapshot: true -initialState: - documentContents: |- - class Aaa { - bbb() { - - } - } - selections: - - anchor: {line: 2, character: 8} - active: {line: 2, character: 8} - marks: {} -finalState: - documentContents: |- - class Aaa { - () { - - } - } - selections: - - anchor: {line: 1, character: 4} - active: {line: 1, character: 4} - thatMark: - - type: UntypedTarget - contentRange: - start: {line: 1, character: 4} - end: {line: 3, character: 5} - isReversed: false - hasExplicitRange: true diff --git a/data/fixtures/recorded/actions/snippets/snipIf.yml b/data/fixtures/recorded/actions/snippets/snipIf.yml deleted file mode 100644 index 37c6f597a7..0000000000 --- a/data/fixtures/recorded/actions/snippets/snipIf.yml +++ /dev/null @@ -1,35 +0,0 @@ -languageId: typescript -command: - version: 6 - spokenForm: snippet if - action: - name: insertSnippet - snippetDescription: {type: named, name: ifStatement} - destination: {type: implicit} - usePrePhraseSnapshot: false -initialState: - documentContents: |- - function whatever() { - - } - selections: - - anchor: {line: 1, character: 4} - active: {line: 1, character: 4} - marks: {} -finalState: - documentContents: |- - function whatever() { - if () { - - } - } - selections: - - anchor: {line: 1, character: 8} - active: {line: 1, character: 8} - thatMark: - - type: UntypedTarget - contentRange: - start: {line: 1, character: 4} - end: {line: 3, character: 5} - isReversed: false - hasExplicitRange: true diff --git a/data/fixtures/recorded/actions/snippets/snipSpaghetti.yml b/data/fixtures/recorded/actions/snippets/snipSpaghetti.yml deleted file mode 100644 index c7398e762f..0000000000 --- a/data/fixtures/recorded/actions/snippets/snipSpaghetti.yml +++ /dev/null @@ -1,28 +0,0 @@ -languageId: plaintext -command: - version: 6 - spokenForm: snippet spaghetti - action: - name: insertSnippet - snippetDescription: {type: named, name: spaghetti} - destination: {type: implicit} - usePrePhraseSnapshot: false -spokenFormError: Named insertion snippet 'spaghetti' -initialState: - documentContents: "" - selections: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} - marks: {} -finalState: - documentContents: My friend likes to eat spaghetti! - selections: - - anchor: {line: 0, character: 10} - active: {line: 0, character: 10} - thatMark: - - type: UntypedTarget - contentRange: - start: {line: 0, character: 0} - end: {line: 0, character: 34} - isReversed: false - hasExplicitRange: true diff --git a/data/fixtures/recorded/actions/snippets/snipSpaghettiGraceHopper.yml b/data/fixtures/recorded/actions/snippets/snipSpaghettiGraceHopper.yml deleted file mode 100644 index c2ec079a34..0000000000 --- a/data/fixtures/recorded/actions/snippets/snipSpaghettiGraceHopper.yml +++ /dev/null @@ -1,31 +0,0 @@ -languageId: plaintext -command: - version: 6 - spokenForm: snippet spaghetti grace hopper - action: - name: insertSnippet - snippetDescription: - type: named - name: spaghetti - substitutions: {foo: grace hopper} - destination: {type: implicit} - usePrePhraseSnapshot: false -spokenFormError: Named insertion snippet 'spaghetti' -initialState: - documentContents: "" - selections: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} - marks: {} -finalState: - documentContents: My friend grace_hopper likes to eat spaghetti! - selections: - - anchor: {line: 0, character: 46} - active: {line: 0, character: 46} - thatMark: - - type: UntypedTarget - contentRange: - start: {line: 0, character: 0} - end: {line: 0, character: 46} - isReversed: false - hasExplicitRange: true diff --git a/data/fixtures/recorded/actions/snippets/spaghettiWrapPastGust.yml b/data/fixtures/recorded/actions/snippets/spaghettiWrapPastGust.yml deleted file mode 100644 index a21370da14..0000000000 --- a/data/fixtures/recorded/actions/snippets/spaghettiWrapPastGust.yml +++ /dev/null @@ -1,38 +0,0 @@ -languageId: plaintext -command: - version: 6 - spokenForm: spaghetti wrap past gust - action: - name: wrapWithSnippet - snippetDescription: {type: named, name: spaghetti, variableName: foo} - target: - type: range - anchor: {type: implicit} - active: - type: primitive - mark: {type: decoratedSymbol, symbolColor: default, character: g} - excludeAnchor: false - excludeActive: false - usePrePhraseSnapshot: false -spokenFormError: Named wrap with snippet 'spaghetti.foo' -initialState: - documentContents: grace hopper - selections: - - anchor: {line: 0, character: 12} - active: {line: 0, character: 12} - marks: - default.g: - start: {line: 0, character: 0} - end: {line: 0, character: 5} -finalState: - documentContents: My friend grace hopper likes to eat spaghetti! - selections: - - anchor: {line: 0, character: 46} - active: {line: 0, character: 46} - thatMark: - - type: UntypedTarget - contentRange: - start: {line: 0, character: 0} - end: {line: 0, character: 46} - isReversed: true - hasExplicitRange: true diff --git a/data/fixtures/recorded/actions/snippets/tryWrapThis.yml b/data/fixtures/recorded/actions/snippets/tryWrapThis.yml deleted file mode 100644 index 3c1c4fe8de..0000000000 --- a/data/fixtures/recorded/actions/snippets/tryWrapThis.yml +++ /dev/null @@ -1,34 +0,0 @@ -languageId: typescript -command: - version: 6 - spokenForm: try wrap this - action: - name: wrapWithSnippet - snippetDescription: {type: named, name: tryCatchStatement, variableName: body} - target: - type: primitive - mark: {type: cursor} - usePrePhraseSnapshot: true -initialState: - documentContents: const foo = "bar"; - selections: - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} - marks: {} -finalState: - documentContents: |- - try { - const foo = "bar"; - } catch (err) { - - } - selections: - - anchor: {line: 3, character: 4} - active: {line: 3, character: 4} - thatMark: - - type: UntypedTarget - contentRange: - start: {line: 0, character: 0} - end: {line: 4, character: 1} - isReversed: false - hasExplicitRange: true diff --git a/data/fixtures/recorded/languages/cpp/elseStateWrapThis.yml b/data/fixtures/recorded/languages/cpp/elseStateWrapThis.yml deleted file mode 100644 index bc925fec3e..0000000000 --- a/data/fixtures/recorded/languages/cpp/elseStateWrapThis.yml +++ /dev/null @@ -1,27 +0,0 @@ -languageId: cpp -command: - version: 6 - spokenForm: else wrap this - action: - name: wrapWithSnippet - snippetDescription: {type: named, name: ifElseStatement, variableName: alternative} - target: - type: primitive - mark: {type: cursor} - usePrePhraseSnapshot: false -initialState: - documentContents: int foo = 0; - selections: - - anchor: {line: 0, character: 6} - active: {line: 0, character: 6} - marks: {} -finalState: - documentContents: |- - if () { - - } else { - int foo = 0; - } - selections: - - anchor: {line: 0, character: 4} - active: {line: 0, character: 4} diff --git a/data/fixtures/recorded/languages/cpp/ifElseWrapThis.yml b/data/fixtures/recorded/languages/cpp/ifElseWrapThis.yml deleted file mode 100644 index d1e44da734..0000000000 --- a/data/fixtures/recorded/languages/cpp/ifElseWrapThis.yml +++ /dev/null @@ -1,27 +0,0 @@ -languageId: cpp -command: - version: 6 - spokenForm: if else wrap this - action: - name: wrapWithSnippet - snippetDescription: {type: named, name: ifElseStatement, variableName: consequence} - target: - type: primitive - mark: {type: cursor} - usePrePhraseSnapshot: false -initialState: - documentContents: int foo = 0; - selections: - - anchor: {line: 0, character: 6} - active: {line: 0, character: 6} - marks: {} -finalState: - documentContents: |- - if () { - int foo = 0; - } else { - - } - selections: - - anchor: {line: 0, character: 4} - active: {line: 0, character: 4} diff --git a/data/fixtures/recorded/languages/cpp/ifStateWrapThis.yml b/data/fixtures/recorded/languages/cpp/ifStateWrapThis.yml deleted file mode 100644 index 7e2aabb36b..0000000000 --- a/data/fixtures/recorded/languages/cpp/ifStateWrapThis.yml +++ /dev/null @@ -1,25 +0,0 @@ -languageId: cpp -command: - version: 6 - spokenForm: if wrap this - action: - name: wrapWithSnippet - snippetDescription: {type: named, name: ifStatement, variableName: consequence} - target: - type: primitive - mark: {type: cursor} - usePrePhraseSnapshot: false -initialState: - documentContents: int foo = 0; - selections: - - anchor: {line: 0, character: 6} - active: {line: 0, character: 6} - marks: {} -finalState: - documentContents: |- - if () { - int foo = 0; - } - selections: - - anchor: {line: 0, character: 4} - active: {line: 0, character: 4} diff --git a/data/fixtures/recorded/languages/cpp/tryCatchWrapThis.yml b/data/fixtures/recorded/languages/cpp/tryCatchWrapThis.yml deleted file mode 100644 index 3dc87af8ac..0000000000 --- a/data/fixtures/recorded/languages/cpp/tryCatchWrapThis.yml +++ /dev/null @@ -1,27 +0,0 @@ -languageId: cpp -command: - version: 6 - spokenForm: try wrap this - action: - name: wrapWithSnippet - snippetDescription: {type: named, name: tryCatchStatement, variableName: body} - target: - type: primitive - mark: {type: cursor} - usePrePhraseSnapshot: false -initialState: - documentContents: int foo = 0; - selections: - - anchor: {line: 0, character: 6} - active: {line: 0, character: 6} - marks: {} -finalState: - documentContents: |- - try { - int foo = 0; - } catch () { - - } - selections: - - anchor: {line: 2, character: 9} - active: {line: 2, character: 9} diff --git a/data/fixtures/recorded/languages/cpp/tryCatchWrapThis2.yml b/data/fixtures/recorded/languages/cpp/tryCatchWrapThis2.yml deleted file mode 100644 index cdf200b099..0000000000 --- a/data/fixtures/recorded/languages/cpp/tryCatchWrapThis2.yml +++ /dev/null @@ -1,44 +0,0 @@ -languageId: cpp -command: - version: 6 - spokenForm: try wrap this - action: - name: wrapWithSnippet - snippetDescription: {type: named, name: tryCatchStatement, variableName: body} - target: - type: primitive - mark: {type: cursor} - usePrePhraseSnapshot: false -initialState: - documentContents: |- - if (true) { - int foo = 0; - } - - int bar = 1; - selections: - - anchor: {line: 4, character: 0} - active: {line: 4, character: 0} - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} - marks: {} -finalState: - documentContents: |- - try { - if (true) { - int foo = 0; - } - } catch () { - - } - - try { - int bar = 1; - } catch () { - - } - selections: - - anchor: {line: 10, character: 9} - active: {line: 10, character: 9} - - anchor: {line: 4, character: 9} - active: {line: 4, character: 9} diff --git a/data/fixtures/recorded/languages/csharp/elseStateWrapThis.yml b/data/fixtures/recorded/languages/csharp/elseStateWrapThis.yml deleted file mode 100644 index e6e550b326..0000000000 --- a/data/fixtures/recorded/languages/csharp/elseStateWrapThis.yml +++ /dev/null @@ -1,27 +0,0 @@ -languageId: csharp -command: - version: 6 - spokenForm: else wrap this - action: - name: wrapWithSnippet - snippetDescription: {type: named, name: ifElseStatement, variableName: alternative} - target: - type: primitive - mark: {type: cursor} - usePrePhraseSnapshot: false -initialState: - documentContents: int foo = 0; - selections: - - anchor: {line: 0, character: 6} - active: {line: 0, character: 6} - marks: {} -finalState: - documentContents: |- - if () { - - } else { - int foo = 0; - } - selections: - - anchor: {line: 0, character: 4} - active: {line: 0, character: 4} diff --git a/data/fixtures/recorded/languages/csharp/ifElseWrapThis.yml b/data/fixtures/recorded/languages/csharp/ifElseWrapThis.yml deleted file mode 100644 index 8acf803b31..0000000000 --- a/data/fixtures/recorded/languages/csharp/ifElseWrapThis.yml +++ /dev/null @@ -1,27 +0,0 @@ -languageId: csharp -command: - version: 6 - spokenForm: if else wrap this - action: - name: wrapWithSnippet - snippetDescription: {type: named, name: ifElseStatement, variableName: consequence} - target: - type: primitive - mark: {type: cursor} - usePrePhraseSnapshot: false -initialState: - documentContents: int foo = 0; - selections: - - anchor: {line: 0, character: 6} - active: {line: 0, character: 6} - marks: {} -finalState: - documentContents: |- - if () { - int foo = 0; - } else { - - } - selections: - - anchor: {line: 0, character: 4} - active: {line: 0, character: 4} diff --git a/data/fixtures/recorded/languages/csharp/ifStateWrapThis.yml b/data/fixtures/recorded/languages/csharp/ifStateWrapThis.yml deleted file mode 100644 index 26b6825557..0000000000 --- a/data/fixtures/recorded/languages/csharp/ifStateWrapThis.yml +++ /dev/null @@ -1,25 +0,0 @@ -languageId: csharp -command: - version: 6 - spokenForm: if wrap this - action: - name: wrapWithSnippet - snippetDescription: {type: named, name: ifStatement, variableName: consequence} - target: - type: primitive - mark: {type: cursor} - usePrePhraseSnapshot: false -initialState: - documentContents: int foo = 0; - selections: - - anchor: {line: 0, character: 6} - active: {line: 0, character: 6} - marks: {} -finalState: - documentContents: |- - if () { - int foo = 0; - } - selections: - - anchor: {line: 0, character: 4} - active: {line: 0, character: 4} diff --git a/data/fixtures/recorded/languages/csharp/tryCatchWrapThis.yml b/data/fixtures/recorded/languages/csharp/tryCatchWrapThis.yml deleted file mode 100644 index f0cdd28d08..0000000000 --- a/data/fixtures/recorded/languages/csharp/tryCatchWrapThis.yml +++ /dev/null @@ -1,27 +0,0 @@ -languageId: csharp -command: - version: 6 - spokenForm: try wrap this - action: - name: wrapWithSnippet - snippetDescription: {type: named, name: tryCatchStatement, variableName: body} - target: - type: primitive - mark: {type: cursor} - usePrePhraseSnapshot: false -initialState: - documentContents: int foo = 0; - selections: - - anchor: {line: 0, character: 6} - active: {line: 0, character: 6} - marks: {} -finalState: - documentContents: |- - try { - int foo = 0; - } catch () { - - } - selections: - - anchor: {line: 2, character: 9} - active: {line: 2, character: 9} diff --git a/data/fixtures/recorded/languages/csharp/tryCatchWrapThis2.yml b/data/fixtures/recorded/languages/csharp/tryCatchWrapThis2.yml deleted file mode 100644 index 4c61de1dde..0000000000 --- a/data/fixtures/recorded/languages/csharp/tryCatchWrapThis2.yml +++ /dev/null @@ -1,44 +0,0 @@ -languageId: csharp -command: - version: 6 - spokenForm: try wrap this - action: - name: wrapWithSnippet - snippetDescription: {type: named, name: tryCatchStatement, variableName: body} - target: - type: primitive - mark: {type: cursor} - usePrePhraseSnapshot: false -initialState: - documentContents: |- - if (true) { - int foo = 0; - } - - int bar = 1; - selections: - - anchor: {line: 4, character: 0} - active: {line: 4, character: 0} - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} - marks: {} -finalState: - documentContents: |- - try { - if (true) { - int foo = 0; - } - } catch () { - - } - - try { - int bar = 1; - } catch () { - - } - selections: - - anchor: {line: 10, character: 9} - active: {line: 10, character: 9} - - anchor: {line: 4, character: 9} - active: {line: 4, character: 9} diff --git a/data/fixtures/recorded/languages/java/elseStateWrapThis.yml b/data/fixtures/recorded/languages/java/elseStateWrapThis.yml deleted file mode 100644 index c1a5e476bf..0000000000 --- a/data/fixtures/recorded/languages/java/elseStateWrapThis.yml +++ /dev/null @@ -1,27 +0,0 @@ -languageId: java -command: - version: 6 - spokenForm: else wrap this - action: - name: wrapWithSnippet - snippetDescription: {type: named, name: ifElseStatement, variableName: alternative} - target: - type: primitive - mark: {type: cursor} - usePrePhraseSnapshot: false -initialState: - documentContents: int foo = 0; - selections: - - anchor: {line: 0, character: 6} - active: {line: 0, character: 6} - marks: {} -finalState: - documentContents: |- - if () { - - } else { - int foo = 0; - } - selections: - - anchor: {line: 0, character: 4} - active: {line: 0, character: 4} diff --git a/data/fixtures/recorded/languages/java/ifElseWrapThis.yml b/data/fixtures/recorded/languages/java/ifElseWrapThis.yml deleted file mode 100644 index e042e38aec..0000000000 --- a/data/fixtures/recorded/languages/java/ifElseWrapThis.yml +++ /dev/null @@ -1,27 +0,0 @@ -languageId: java -command: - version: 6 - spokenForm: if else wrap this - action: - name: wrapWithSnippet - snippetDescription: {type: named, name: ifElseStatement, variableName: consequence} - target: - type: primitive - mark: {type: cursor} - usePrePhraseSnapshot: false -initialState: - documentContents: int foo = 0; - selections: - - anchor: {line: 0, character: 6} - active: {line: 0, character: 6} - marks: {} -finalState: - documentContents: |- - if () { - int foo = 0; - } else { - - } - selections: - - anchor: {line: 0, character: 4} - active: {line: 0, character: 4} diff --git a/data/fixtures/recorded/languages/java/ifStateWrapThis.yml b/data/fixtures/recorded/languages/java/ifStateWrapThis.yml deleted file mode 100644 index c183a7ea41..0000000000 --- a/data/fixtures/recorded/languages/java/ifStateWrapThis.yml +++ /dev/null @@ -1,25 +0,0 @@ -languageId: java -command: - version: 6 - spokenForm: if wrap this - action: - name: wrapWithSnippet - snippetDescription: {type: named, name: ifStatement, variableName: consequence} - target: - type: primitive - mark: {type: cursor} - usePrePhraseSnapshot: false -initialState: - documentContents: int foo = 0; - selections: - - anchor: {line: 0, character: 6} - active: {line: 0, character: 6} - marks: {} -finalState: - documentContents: |- - if () { - int foo = 0; - } - selections: - - anchor: {line: 0, character: 4} - active: {line: 0, character: 4} diff --git a/data/fixtures/recorded/languages/java/tryCatchWrapThis.yml b/data/fixtures/recorded/languages/java/tryCatchWrapThis.yml deleted file mode 100644 index db29bfdd6a..0000000000 --- a/data/fixtures/recorded/languages/java/tryCatchWrapThis.yml +++ /dev/null @@ -1,27 +0,0 @@ -languageId: java -command: - version: 6 - spokenForm: try wrap this - action: - name: wrapWithSnippet - snippetDescription: {type: named, name: tryCatchStatement, variableName: body} - target: - type: primitive - mark: {type: cursor} - usePrePhraseSnapshot: false -initialState: - documentContents: int foo = 0; - selections: - - anchor: {line: 0, character: 6} - active: {line: 0, character: 6} - marks: {} -finalState: - documentContents: |- - try { - int foo = 0; - } catch () { - - } - selections: - - anchor: {line: 2, character: 9} - active: {line: 2, character: 9} diff --git a/data/fixtures/recorded/languages/java/tryCatchWrapThis2.yml b/data/fixtures/recorded/languages/java/tryCatchWrapThis2.yml deleted file mode 100644 index d9534338f4..0000000000 --- a/data/fixtures/recorded/languages/java/tryCatchWrapThis2.yml +++ /dev/null @@ -1,44 +0,0 @@ -languageId: java -command: - version: 6 - spokenForm: try wrap this - action: - name: wrapWithSnippet - snippetDescription: {type: named, name: tryCatchStatement, variableName: body} - target: - type: primitive - mark: {type: cursor} - usePrePhraseSnapshot: false -initialState: - documentContents: |- - if (true) { - int foo = 0; - } - - int bar = 1; - selections: - - anchor: {line: 4, character: 0} - active: {line: 4, character: 0} - - anchor: {line: 0, character: 0} - active: {line: 0, character: 0} - marks: {} -finalState: - documentContents: |- - try { - if (true) { - int foo = 0; - } - } catch () { - - } - - try { - int bar = 1; - } catch () { - - } - selections: - - anchor: {line: 10, character: 9} - active: {line: 10, character: 9} - - anchor: {line: 4, character: 9} - active: {line: 4, character: 9} diff --git a/data/fixtures/recorded/languages/php/elseWrapThis.yml b/data/fixtures/recorded/languages/php/elseWrapThis.yml index ea60f4b585..eaec9e2593 100644 --- a/data/fixtures/recorded/languages/php/elseWrapThis.yml +++ b/data/fixtures/recorded/languages/php/elseWrapThis.yml @@ -9,6 +9,7 @@ command: type: primitive mark: {type: cursor} usePrePhraseSnapshot: false +spokenFormError: named wrap with snippet initialState: documentContents: |- Date: Sat, 1 Feb 2025 07:48:19 +0100 Subject: [PATCH 11/38] Update test --- data/fixtures/recorded/actions/snippets/funkWrapClass.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/data/fixtures/recorded/actions/snippets/funkWrapClass.yml b/data/fixtures/recorded/actions/snippets/funkWrapClass.yml index 326f31f954..de61136506 100644 --- a/data/fixtures/recorded/actions/snippets/funkWrapClass.yml +++ b/data/fixtures/recorded/actions/snippets/funkWrapClass.yml @@ -4,13 +4,14 @@ command: spokenForm: funk wrap class action: name: wrapWithSnippet - snippetDescription: {type: named, name: functionDeclaration, variableName: body} + snippetDescription: {type: custom, variableName: body, body: "def $name($parameterList):\n\t$body"} target: type: primitive modifiers: - type: containingScope scopeType: {type: class} usePrePhraseSnapshot: true +spokenFormError: custom wrap with snippet initialState: documentContents: |- class Aaa: From 18d504bbea253023a81c92d8d5d46252a423ad76 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 1 Feb 2025 08:39:37 +0100 Subject: [PATCH 12/38] Update more tests --- .../actions/snippets/snipFunkAfterClass.yml | 3 +- .../snippets/snipFunkAfterFineAndZip.yml | 7 ++- .../snipFunkAfterMadeAndBeforeFineAndZip.yml | 7 ++- .../actions/snippets/snipFunkAfterThis.yml | 7 ++- .../actions/snippets/snipFunkAfterThis2.yml | 7 ++- .../actions/snippets/snipFunkAfterThis3.yml | 8 +++- .../actions/snippets/snipFunkAfterThis4.yml | 7 ++- .../snipFunkAfterZipAndBeforeFine.yml | 7 ++- .../actions/snippets/snipFunkBeforeClass.yml | 7 ++- .../actions/snippets/snipFunkBeforeThis.yml | 7 ++- .../actions/snippets/snipFunkBeforeThis2.yml | 7 ++- .../actions/snippets/snipFunkBeforeThis3.yml | 7 ++- .../actions/snippets/snipFunkBeforeThis4.yml | 14 ++++-- .../actions/snippets/snipFunkCelloWorld.yml | 15 ++++--- .../actions/snippets/snipFunkHelloWorld.yml | 9 ++-- .../actions/snippets/snipFunkHelloWorld2.yml | 18 +++++--- .../actions/snippets/snipFunkHelloWorld3.yml | 9 ++-- .../actions/snippets/snipMakeFunk.yml | 45 +++++++------------ .../actions/snippets/snipMakeState.yml | 39 ++++++---------- .../actions/snippets/snipPrintAfterPit.yml | 2 +- .../actions/snippets/testSnippetMakeLine.yml | 37 +++++---------- 21 files changed, 153 insertions(+), 116 deletions(-) diff --git a/data/fixtures/recorded/actions/snippets/snipFunkAfterClass.yml b/data/fixtures/recorded/actions/snippets/snipFunkAfterClass.yml index 7bc740df73..b89d65130d 100644 --- a/data/fixtures/recorded/actions/snippets/snipFunkAfterClass.yml +++ b/data/fixtures/recorded/actions/snippets/snipFunkAfterClass.yml @@ -4,7 +4,7 @@ command: spokenForm: snippet funk after class action: name: insertSnippet - snippetDescription: {type: named, name: functionDeclaration} + snippetDescription: {type: custom, body: "function $name($parameterList) {\n\t$body\n}"} destination: type: primitive insertionMode: after @@ -14,6 +14,7 @@ command: - type: containingScope scopeType: {type: class} usePrePhraseSnapshot: true +spokenFormError: custom insertion snippet initialState: documentContents: |- class Aaa { diff --git a/data/fixtures/recorded/actions/snippets/snipFunkAfterFineAndZip.yml b/data/fixtures/recorded/actions/snippets/snipFunkAfterFineAndZip.yml index 7c5b951b54..a4b4ddc614 100644 --- a/data/fixtures/recorded/actions/snippets/snipFunkAfterFineAndZip.yml +++ b/data/fixtures/recorded/actions/snippets/snipFunkAfterFineAndZip.yml @@ -4,7 +4,11 @@ command: spokenForm: snippet funk after fine and zip action: name: insertSnippet - snippetDescription: {type: named, name: functionDeclaration} + snippetDescription: + type: custom + body: "function $name($parameterList) {\n\t$body\n}" + scopeTypes: + - {type: statement} destination: type: primitive insertionMode: after @@ -16,6 +20,7 @@ command: - type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: z} usePrePhraseSnapshot: true +spokenFormError: custom insertion snippet initialState: documentContents: |- const foo = "bar"; diff --git a/data/fixtures/recorded/actions/snippets/snipFunkAfterMadeAndBeforeFineAndZip.yml b/data/fixtures/recorded/actions/snippets/snipFunkAfterMadeAndBeforeFineAndZip.yml index cb83372b77..eda4cc3bfb 100644 --- a/data/fixtures/recorded/actions/snippets/snipFunkAfterMadeAndBeforeFineAndZip.yml +++ b/data/fixtures/recorded/actions/snippets/snipFunkAfterMadeAndBeforeFineAndZip.yml @@ -4,7 +4,11 @@ command: spokenForm: snippet funk after made and before fine and zip action: name: insertSnippet - snippetDescription: {type: named, name: functionDeclaration} + snippetDescription: + type: custom + body: "function $name($parameterList) {\n\t$body\n}" + scopeTypes: + - {type: statement} destination: type: list destinations: @@ -23,6 +27,7 @@ command: - type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: z} usePrePhraseSnapshot: true +spokenFormError: custom insertion snippet initialState: documentContents: | const foo = "bar"; diff --git a/data/fixtures/recorded/actions/snippets/snipFunkAfterThis.yml b/data/fixtures/recorded/actions/snippets/snipFunkAfterThis.yml index 80146831cc..fef8f9bd59 100644 --- a/data/fixtures/recorded/actions/snippets/snipFunkAfterThis.yml +++ b/data/fixtures/recorded/actions/snippets/snipFunkAfterThis.yml @@ -4,7 +4,11 @@ command: spokenForm: snippet funk after this action: name: insertSnippet - snippetDescription: {type: named, name: functionDeclaration} + snippetDescription: + type: custom + body: "function $name($parameterList) {\n\t$body\n}" + scopeTypes: + - {type: statement} destination: type: primitive insertionMode: after @@ -12,6 +16,7 @@ command: type: primitive mark: {type: cursor} usePrePhraseSnapshot: true +spokenFormError: custom insertion snippet initialState: documentContents: " const foo = \"bar\";" selections: diff --git a/data/fixtures/recorded/actions/snippets/snipFunkAfterThis2.yml b/data/fixtures/recorded/actions/snippets/snipFunkAfterThis2.yml index 17338f69cc..d7af366172 100644 --- a/data/fixtures/recorded/actions/snippets/snipFunkAfterThis2.yml +++ b/data/fixtures/recorded/actions/snippets/snipFunkAfterThis2.yml @@ -4,7 +4,11 @@ command: spokenForm: snippet funk after this action: name: insertSnippet - snippetDescription: {type: named, name: functionDeclaration} + snippetDescription: + type: custom + body: "function $name($parameterList) {\n\t$body\n}" + scopeTypes: + - {type: statement} destination: type: primitive insertionMode: after @@ -12,6 +16,7 @@ command: type: primitive mark: {type: cursor} usePrePhraseSnapshot: true +spokenFormError: custom insertion snippet initialState: documentContents: const foo = "bar"; selections: diff --git a/data/fixtures/recorded/actions/snippets/snipFunkAfterThis3.yml b/data/fixtures/recorded/actions/snippets/snipFunkAfterThis3.yml index cac2137eeb..2b7129bda8 100644 --- a/data/fixtures/recorded/actions/snippets/snipFunkAfterThis3.yml +++ b/data/fixtures/recorded/actions/snippets/snipFunkAfterThis3.yml @@ -4,7 +4,12 @@ command: spokenForm: snippet funk after this action: name: insertSnippet - snippetDescription: {type: named, name: functionDeclaration} + snippetDescription: + type: custom + body: "function $name($parameterList) {\n\t$body\n}" + scopeTypes: + - {type: namedFunction} + - {type: statement} destination: type: primitive insertionMode: after @@ -12,6 +17,7 @@ command: type: primitive mark: {type: cursor} usePrePhraseSnapshot: true +spokenFormError: custom insertion snippet initialState: documentContents: |- function helloWorld() { diff --git a/data/fixtures/recorded/actions/snippets/snipFunkAfterThis4.yml b/data/fixtures/recorded/actions/snippets/snipFunkAfterThis4.yml index 99baeccc41..754366fbf1 100644 --- a/data/fixtures/recorded/actions/snippets/snipFunkAfterThis4.yml +++ b/data/fixtures/recorded/actions/snippets/snipFunkAfterThis4.yml @@ -4,7 +4,11 @@ command: spokenForm: snippet funk after this action: name: insertSnippet - snippetDescription: {type: named, name: functionDeclaration} + snippetDescription: + type: custom + body: "function $name($parameterList) {\n\t$body\n}" + scopeTypes: + - {type: statement} destination: type: primitive insertionMode: after @@ -12,6 +16,7 @@ command: type: primitive mark: {type: cursor} usePrePhraseSnapshot: false +spokenFormError: custom insertion snippet initialState: documentContents: const foo = "bar"; selections: diff --git a/data/fixtures/recorded/actions/snippets/snipFunkAfterZipAndBeforeFine.yml b/data/fixtures/recorded/actions/snippets/snipFunkAfterZipAndBeforeFine.yml index 268f9c53fb..604cb1b555 100644 --- a/data/fixtures/recorded/actions/snippets/snipFunkAfterZipAndBeforeFine.yml +++ b/data/fixtures/recorded/actions/snippets/snipFunkAfterZipAndBeforeFine.yml @@ -4,7 +4,11 @@ command: spokenForm: snippet funk after zip and before fine action: name: insertSnippet - snippetDescription: {type: named, name: functionDeclaration} + snippetDescription: + type: custom + body: "function $name($parameterList) {\n\t$body\n}" + scopeTypes: + - {type: statement} destination: type: list destinations: @@ -19,6 +23,7 @@ command: type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: f} usePrePhraseSnapshot: true +spokenFormError: custom insertion snippet initialState: documentContents: |- const foo = "bar"; diff --git a/data/fixtures/recorded/actions/snippets/snipFunkBeforeClass.yml b/data/fixtures/recorded/actions/snippets/snipFunkBeforeClass.yml index ee2e73118e..c7e451c64b 100644 --- a/data/fixtures/recorded/actions/snippets/snipFunkBeforeClass.yml +++ b/data/fixtures/recorded/actions/snippets/snipFunkBeforeClass.yml @@ -4,7 +4,11 @@ command: spokenForm: snippet funk before class action: name: insertSnippet - snippetDescription: {type: named, name: functionDeclaration} + snippetDescription: + type: custom + body: "function $name($parameterList) {\n\t$body\n}" + scopeTypes: + - {type: statement} destination: type: primitive insertionMode: before @@ -14,6 +18,7 @@ command: - type: containingScope scopeType: {type: class} usePrePhraseSnapshot: true +spokenFormError: custom insertion snippet initialState: documentContents: |- class Aaa { diff --git a/data/fixtures/recorded/actions/snippets/snipFunkBeforeThis.yml b/data/fixtures/recorded/actions/snippets/snipFunkBeforeThis.yml index 9adbfc936c..5a51ee1ec6 100644 --- a/data/fixtures/recorded/actions/snippets/snipFunkBeforeThis.yml +++ b/data/fixtures/recorded/actions/snippets/snipFunkBeforeThis.yml @@ -4,7 +4,11 @@ command: spokenForm: snippet funk before this action: name: insertSnippet - snippetDescription: {type: named, name: functionDeclaration} + snippetDescription: + type: custom + body: "function $name($parameterList) {\n\t$body\n}" + scopeTypes: + - {type: statement} destination: type: primitive insertionMode: before @@ -12,6 +16,7 @@ command: type: primitive mark: {type: cursor} usePrePhraseSnapshot: true +spokenFormError: custom insertion snippet initialState: documentContents: const foo = "bar"; selections: diff --git a/data/fixtures/recorded/actions/snippets/snipFunkBeforeThis2.yml b/data/fixtures/recorded/actions/snippets/snipFunkBeforeThis2.yml index 63bbf52fcf..7731e04161 100644 --- a/data/fixtures/recorded/actions/snippets/snipFunkBeforeThis2.yml +++ b/data/fixtures/recorded/actions/snippets/snipFunkBeforeThis2.yml @@ -4,7 +4,11 @@ command: spokenForm: snippet funk before this action: name: insertSnippet - snippetDescription: {type: named, name: functionDeclaration} + snippetDescription: + type: custom + body: "function $name($parameterList) {\n\t$body\n}" + scopeTypes: + - {type: statement} destination: type: primitive insertionMode: before @@ -12,6 +16,7 @@ command: type: primitive mark: {type: cursor} usePrePhraseSnapshot: true +spokenFormError: custom insertion snippet initialState: documentContents: " const foo = \"bar\";" selections: diff --git a/data/fixtures/recorded/actions/snippets/snipFunkBeforeThis3.yml b/data/fixtures/recorded/actions/snippets/snipFunkBeforeThis3.yml index 028d9ae24c..37bc03c0b6 100644 --- a/data/fixtures/recorded/actions/snippets/snipFunkBeforeThis3.yml +++ b/data/fixtures/recorded/actions/snippets/snipFunkBeforeThis3.yml @@ -4,7 +4,11 @@ command: spokenForm: snippet funk before this action: name: insertSnippet - snippetDescription: {type: named, name: functionDeclaration} + snippetDescription: + type: custom + body: "function $name($parameterList) {\n\t$body\n}" + scopeTypes: + - {type: statement} destination: type: primitive insertionMode: before @@ -12,6 +16,7 @@ command: type: primitive mark: {type: cursor} usePrePhraseSnapshot: true +spokenFormError: custom insertion snippet initialState: documentContents: const foo = "bar"; selections: diff --git a/data/fixtures/recorded/actions/snippets/snipFunkBeforeThis4.yml b/data/fixtures/recorded/actions/snippets/snipFunkBeforeThis4.yml index fe6f711972..ed05622b1d 100644 --- a/data/fixtures/recorded/actions/snippets/snipFunkBeforeThis4.yml +++ b/data/fixtures/recorded/actions/snippets/snipFunkBeforeThis4.yml @@ -4,7 +4,12 @@ command: spokenForm: snippet funk before this action: name: insertSnippet - snippetDescription: {type: named, name: functionDeclaration} + snippetDescription: + type: custom + body: "function $name($parameterList) {\n\t$body\n}" + scopeTypes: + - {type: namedFunction} + - {type: statement} destination: type: primitive insertionMode: before @@ -12,6 +17,7 @@ command: type: primitive mark: {type: cursor} usePrePhraseSnapshot: true +spokenFormError: custom insertion snippet initialState: documentContents: |- class Aaa { @@ -26,7 +32,7 @@ initialState: finalState: documentContents: |- class Aaa { - () { + function () { } @@ -35,8 +41,8 @@ finalState: } } selections: - - anchor: {line: 1, character: 4} - active: {line: 1, character: 4} + - anchor: {line: 1, character: 13} + active: {line: 1, character: 13} thatMark: - type: UntypedTarget contentRange: diff --git a/data/fixtures/recorded/actions/snippets/snipFunkCelloWorld.yml b/data/fixtures/recorded/actions/snippets/snipFunkCelloWorld.yml index 179fbeaebd..a0fd8a9390 100644 --- a/data/fixtures/recorded/actions/snippets/snipFunkCelloWorld.yml +++ b/data/fixtures/recorded/actions/snippets/snipFunkCelloWorld.yml @@ -5,11 +5,14 @@ command: action: name: insertSnippet snippetDescription: - type: named - name: functionDeclaration - substitutions: {name: cello world} + type: custom + body: "function $name($parameterList) {\n\t$body\n}" + scopeTypes: + - {type: statement} + substitutions: {name: celloWorld} destination: {type: implicit} usePrePhraseSnapshot: true +spokenFormError: custom insertion snippet initialState: documentContents: |- class Aaa { @@ -22,13 +25,13 @@ initialState: finalState: documentContents: |- class Aaa { - celloWorld() { + function celloWorld() { } } selections: - - anchor: {line: 1, character: 15} - active: {line: 1, character: 15} + - anchor: {line: 1, character: 24} + active: {line: 1, character: 24} thatMark: - type: UntypedTarget contentRange: diff --git a/data/fixtures/recorded/actions/snippets/snipFunkHelloWorld.yml b/data/fixtures/recorded/actions/snippets/snipFunkHelloWorld.yml index 7c51d5e316..be0eb3bf47 100644 --- a/data/fixtures/recorded/actions/snippets/snipFunkHelloWorld.yml +++ b/data/fixtures/recorded/actions/snippets/snipFunkHelloWorld.yml @@ -5,11 +5,14 @@ command: action: name: insertSnippet snippetDescription: - type: named - name: functionDeclaration - substitutions: {name: hello world} + type: custom + body: "function $name($parameterList) {\n\t$body\n}" + scopeTypes: + - {type: statement} + substitutions: {name: helloWorld} destination: {type: implicit} usePrePhraseSnapshot: false +spokenFormError: custom insertion snippet initialState: documentContents: "" selections: diff --git a/data/fixtures/recorded/actions/snippets/snipFunkHelloWorld2.yml b/data/fixtures/recorded/actions/snippets/snipFunkHelloWorld2.yml index 5f8c395a6a..e257a57a7a 100644 --- a/data/fixtures/recorded/actions/snippets/snipFunkHelloWorld2.yml +++ b/data/fixtures/recorded/actions/snippets/snipFunkHelloWorld2.yml @@ -5,11 +5,14 @@ command: action: name: insertSnippet snippetDescription: - type: named - name: functionDeclaration - substitutions: {name: hello world} + type: custom + body: "function $name($parameterList) {\n\t$body\n}" + scopeTypes: + - {type: statement} + substitutions: {name: hello_world} destination: {type: implicit} usePrePhraseSnapshot: false +spokenFormError: custom insertion snippet initialState: documentContents: "" selections: @@ -17,15 +20,16 @@ initialState: active: {line: 0, character: 0} finalState: documentContents: |- - def hello_world(): + function hello_world() { + } selections: - - anchor: {line: 0, character: 16} - active: {line: 0, character: 16} + - anchor: {line: 0, character: 21} + active: {line: 0, character: 21} thatMark: - type: UntypedTarget contentRange: start: {line: 0, character: 0} - end: {line: 1, character: 4} + end: {line: 2, character: 1} isReversed: false hasExplicitRange: true diff --git a/data/fixtures/recorded/actions/snippets/snipFunkHelloWorld3.yml b/data/fixtures/recorded/actions/snippets/snipFunkHelloWorld3.yml index 1018dcff70..c325d30959 100644 --- a/data/fixtures/recorded/actions/snippets/snipFunkHelloWorld3.yml +++ b/data/fixtures/recorded/actions/snippets/snipFunkHelloWorld3.yml @@ -5,11 +5,14 @@ command: action: name: insertSnippet snippetDescription: - type: named - name: functionDeclaration - substitutions: {name: hello world} + type: custom + body: "function $name($parameterList) {\n\t$body\n}" + scopeTypes: + - {type: statement} + substitutions: {name: helloWorld} destination: {type: implicit} usePrePhraseSnapshot: true +spokenFormError: custom insertion snippet initialState: documentContents: "" selections: diff --git a/data/fixtures/recorded/actions/snippets/snipMakeFunk.yml b/data/fixtures/recorded/actions/snippets/snipMakeFunk.yml index d56f3b0fc4..36f94a2e94 100644 --- a/data/fixtures/recorded/actions/snippets/snipMakeFunk.yml +++ b/data/fixtures/recorded/actions/snippets/snipMakeFunk.yml @@ -4,6 +4,7 @@ command: spokenForm: snippet make funk action: name: generateSnippet + directory: "" snippetName: snippetTest1 target: type: primitive @@ -28,37 +29,23 @@ initialState: active: {line: 5, character: 9} marks: {} finalState: - documentContents: |- - { - "snippetTest1": { - "definitions": [ - { - "scope": { - "langIds": [ - "typescript" - ] - }, - "body": [ - "function $variable1() {", - "\tconst whatever = \"hello\";", - "", - "\t$variable2", - "}" - ] - } - ], - "description": "", - "variables": { - "variable1": {}, - "variable2": {} - } - } + documentContents: | + name: snippetTest1 + language: typescript + phrase: + + $1.wrapperPhrase: + $0.wrapperPhrase: + - + function $1() { + const whatever = "hello"; + + $0 } + --- selections: - - anchor: {line: 10, character: 21} - active: {line: 10, character: 30} - - anchor: {line: 20, character: 7} - active: {line: 20, character: 16} + - anchor: {line: 2, character: 8} + active: {line: 2, character: 8} thatMark: - type: UntypedTarget contentRange: diff --git a/data/fixtures/recorded/actions/snippets/snipMakeState.yml b/data/fixtures/recorded/actions/snippets/snipMakeState.yml index c0503658af..d12dfc5a5d 100644 --- a/data/fixtures/recorded/actions/snippets/snipMakeState.yml +++ b/data/fixtures/recorded/actions/snippets/snipMakeState.yml @@ -4,6 +4,7 @@ command: spokenForm: snippet make state action: name: generateSnippet + directory: "" snippetName: snippetTest1 target: type: primitive @@ -22,34 +23,20 @@ initialState: active: {line: 0, character: 4} marks: {} finalState: - documentContents: |- - { - "snippetTest1": { - "definitions": [ - { - "scope": { - "langIds": [ - "typescript" - ] - }, - "body": [ - "if ($variable1) {", - "\tconsole.log(\"hello\")", - "}" - ] - } - ], - "description": "", - "variables": { - "variable1": {} - } - } + documentContents: | + name: snippetTest1 + language: typescript + phrase: + + $0.wrapperPhrase: + - + if ($0) { + console.log("hello") } + --- selections: - - anchor: {line: 10, character: 16} - active: {line: 10, character: 25} - - anchor: {line: 18, character: 7} - active: {line: 18, character: 16} + - anchor: {line: 2, character: 8} + active: {line: 2, character: 8} thatMark: - type: UntypedTarget contentRange: diff --git a/data/fixtures/recorded/actions/snippets/snipPrintAfterPit.yml b/data/fixtures/recorded/actions/snippets/snipPrintAfterPit.yml index 19c2f19ca9..5524e40cbe 100644 --- a/data/fixtures/recorded/actions/snippets/snipPrintAfterPit.yml +++ b/data/fixtures/recorded/actions/snippets/snipPrintAfterPit.yml @@ -17,7 +17,7 @@ command: type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: p} usePrePhraseSnapshot: true -spokenFormError: Custom insertion snippet +spokenFormError: custom insertion snippet initialState: documentContents: | def my_funk(): diff --git a/data/fixtures/recorded/actions/snippets/testSnippetMakeLine.yml b/data/fixtures/recorded/actions/snippets/testSnippetMakeLine.yml index 828d06aa2b..88ba687d97 100644 --- a/data/fixtures/recorded/actions/snippets/testSnippetMakeLine.yml +++ b/data/fixtures/recorded/actions/snippets/testSnippetMakeLine.yml @@ -4,6 +4,7 @@ command: spokenForm: test snippet make line action: name: generateSnippet + directory: "" snippetName: testSnippet target: type: primitive @@ -19,32 +20,18 @@ initialState: active: {line: 0, character: 12} marks: {} finalState: - documentContents: |- - { - "testSnippet": { - "definitions": [ - { - "scope": { - "langIds": [ - "plaintext" - ] - }, - "body": [ - "\\textbf{\\$$variable1}" - ] - } - ], - "description": "", - "variables": { - "variable1": {} - } - } - } + documentContents: | + name: testSnippet + language: plaintext + phrase: + + $0.wrapperPhrase: + - + \textbf{\$$0} + --- selections: - - anchor: {line: 10, character: 24} - active: {line: 10, character: 33} - - anchor: {line: 16, character: 7} - active: {line: 16, character: 16} + - anchor: {line: 2, character: 8} + active: {line: 2, character: 8} thatMark: - type: UntypedTarget contentRange: From db35ddf98b16183d9233d9bef815f07ee8d6b99a Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 1 Feb 2025 09:30:17 +0100 Subject: [PATCH 13/38] Updated more tests --- .../recorded/implicitExpansion/funkWrapPastInk.yml | 7 ++++++- data/fixtures/recorded/implicitExpansion/funkWrapThat.yml | 7 ++++++- .../fixtures/recorded/implicitExpansion/funkWrapThat2.yml | 7 ++++++- data/fixtures/recorded/implicitExpansion/funkWrapThis.yml | 7 ++++++- .../fixtures/recorded/implicitExpansion/funkWrapThis2.yml | 7 ++++++- .../fixtures/recorded/implicitExpansion/funkWrapToken.yml | 7 ++++++- .../fixtures/recorded/implicitExpansion/funkWrapWhale.yml | 7 ++++++- .../recorded/implicitExpansion/funkWrapWhalePastBat.yml | 7 ++++++- .../recorded/implicitExpansion/snipFunkAfterThat.yml | 8 +++++++- .../recorded/implicitExpansion/snipFunkAfterThat2.yml | 8 +++++++- .../recorded/implicitExpansion/snipFunkAfterThis.yml | 8 +++++++- .../recorded/implicitExpansion/snipFunkAfterThis2.yml | 8 +++++++- .../recorded/implicitExpansion/snipFunkAfterToken.yml | 8 +++++++- .../recorded/implicitExpansion/snipFunkAfterWhale.yml | 8 +++++++- .../recorded/implicitExpansion/snipFunkToAirPastWhale.yml | 8 +++++++- .../recorded/implicitExpansion/snipFunkToThisPastEach.yml | 8 +++++++- data/fixtures/recorded/inference/ifWrapTokenFine.yml | 7 ++++++- data/fixtures/recorded/positions/snipElseAfterThis.yml | 8 ++++++-- 18 files changed, 116 insertions(+), 19 deletions(-) diff --git a/data/fixtures/recorded/implicitExpansion/funkWrapPastInk.yml b/data/fixtures/recorded/implicitExpansion/funkWrapPastInk.yml index 8b4a728473..035506421d 100644 --- a/data/fixtures/recorded/implicitExpansion/funkWrapPastInk.yml +++ b/data/fixtures/recorded/implicitExpansion/funkWrapPastInk.yml @@ -4,7 +4,11 @@ command: spokenForm: funk wrap past sit action: name: wrapWithSnippet - snippetDescription: {type: named, name: functionDeclaration, variableName: body} + snippetDescription: + type: custom + variableName: body + scopeType: {type: statement} + body: "function $name($parameterList) {\n\t$body\n}" target: type: range anchor: {type: implicit} @@ -14,6 +18,7 @@ command: excludeAnchor: false excludeActive: false usePrePhraseSnapshot: true +spokenFormError: custom wrap with snippet initialState: documentContents: |- const whatever = "hello"; diff --git a/data/fixtures/recorded/implicitExpansion/funkWrapThat.yml b/data/fixtures/recorded/implicitExpansion/funkWrapThat.yml index bca75a3f8f..bcf931e2a3 100644 --- a/data/fixtures/recorded/implicitExpansion/funkWrapThat.yml +++ b/data/fixtures/recorded/implicitExpansion/funkWrapThat.yml @@ -4,11 +4,16 @@ command: spokenForm: funk wrap that action: name: wrapWithSnippet - snippetDescription: {type: named, name: functionDeclaration, variableName: body} + snippetDescription: + type: custom + variableName: body + scopeType: {type: statement} + body: "function $name($parameterList) {\n\t$body\n}" target: type: primitive mark: {type: that} usePrePhraseSnapshot: true +spokenFormError: custom wrap with snippet initialState: documentContents: | const whatever = "hello"; diff --git a/data/fixtures/recorded/implicitExpansion/funkWrapThat2.yml b/data/fixtures/recorded/implicitExpansion/funkWrapThat2.yml index a504308100..4f6923d8d7 100644 --- a/data/fixtures/recorded/implicitExpansion/funkWrapThat2.yml +++ b/data/fixtures/recorded/implicitExpansion/funkWrapThat2.yml @@ -4,11 +4,16 @@ command: spokenForm: funk wrap that action: name: wrapWithSnippet - snippetDescription: {type: named, name: functionDeclaration, variableName: body} + snippetDescription: + type: custom + variableName: body + scopeType: {type: statement} + body: "function $name($parameterList) {\n\t$body\n}" target: type: primitive mark: {type: that} usePrePhraseSnapshot: true +spokenFormError: custom wrap with snippet initialState: documentContents: | const whatever = "hello"; diff --git a/data/fixtures/recorded/implicitExpansion/funkWrapThis.yml b/data/fixtures/recorded/implicitExpansion/funkWrapThis.yml index 97ac715f4f..40ef4294e0 100644 --- a/data/fixtures/recorded/implicitExpansion/funkWrapThis.yml +++ b/data/fixtures/recorded/implicitExpansion/funkWrapThis.yml @@ -4,11 +4,16 @@ command: spokenForm: funk wrap this action: name: wrapWithSnippet - snippetDescription: {type: named, name: functionDeclaration, variableName: body} + snippetDescription: + type: custom + variableName: body + scopeType: {type: statement} + body: "function $name($parameterList) {\n\t$body\n}" target: type: primitive mark: {type: cursor} usePrePhraseSnapshot: true +spokenFormError: custom wrap with snippet initialState: documentContents: const whatever = "hello"; selections: diff --git a/data/fixtures/recorded/implicitExpansion/funkWrapThis2.yml b/data/fixtures/recorded/implicitExpansion/funkWrapThis2.yml index 16bcb03420..74ff0b6344 100644 --- a/data/fixtures/recorded/implicitExpansion/funkWrapThis2.yml +++ b/data/fixtures/recorded/implicitExpansion/funkWrapThis2.yml @@ -4,11 +4,16 @@ command: spokenForm: funk wrap this action: name: wrapWithSnippet - snippetDescription: {type: named, name: functionDeclaration, variableName: body} + snippetDescription: + type: custom + variableName: body + scopeType: {type: statement} + body: "function $name($parameterList) {\n\t$body\n}" target: type: primitive mark: {type: cursor} usePrePhraseSnapshot: true +spokenFormError: custom wrap with snippet initialState: documentContents: const whatever = "hello"; selections: diff --git a/data/fixtures/recorded/implicitExpansion/funkWrapToken.yml b/data/fixtures/recorded/implicitExpansion/funkWrapToken.yml index 2f306b0132..0b2fe517e8 100644 --- a/data/fixtures/recorded/implicitExpansion/funkWrapToken.yml +++ b/data/fixtures/recorded/implicitExpansion/funkWrapToken.yml @@ -4,13 +4,18 @@ command: spokenForm: funk wrap token action: name: wrapWithSnippet - snippetDescription: {type: named, name: functionDeclaration, variableName: body} + snippetDescription: + type: custom + variableName: body + scopeType: {type: statement} + body: "function $name($parameterList) {\n\t$body\n}" target: type: primitive modifiers: - type: containingScope scopeType: {type: token} usePrePhraseSnapshot: true +spokenFormError: custom wrap with snippet initialState: documentContents: const whatever = "hello"; selections: diff --git a/data/fixtures/recorded/implicitExpansion/funkWrapWhale.yml b/data/fixtures/recorded/implicitExpansion/funkWrapWhale.yml index c898c850a4..33928e80fb 100644 --- a/data/fixtures/recorded/implicitExpansion/funkWrapWhale.yml +++ b/data/fixtures/recorded/implicitExpansion/funkWrapWhale.yml @@ -4,11 +4,16 @@ command: spokenForm: funk wrap whale action: name: wrapWithSnippet - snippetDescription: {type: named, name: functionDeclaration, variableName: body} + snippetDescription: + type: custom + variableName: body + scopeType: {type: statement} + body: "function $name($parameterList) {\n\t$body\n}" target: type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: w} usePrePhraseSnapshot: true +spokenFormError: custom wrap with snippet initialState: documentContents: | const whatever = "hello"; diff --git a/data/fixtures/recorded/implicitExpansion/funkWrapWhalePastBat.yml b/data/fixtures/recorded/implicitExpansion/funkWrapWhalePastBat.yml index 74f5834c2d..ca5059557d 100644 --- a/data/fixtures/recorded/implicitExpansion/funkWrapWhalePastBat.yml +++ b/data/fixtures/recorded/implicitExpansion/funkWrapWhalePastBat.yml @@ -4,7 +4,11 @@ command: spokenForm: funk wrap whale past bat action: name: wrapWithSnippet - snippetDescription: {type: named, name: functionDeclaration, variableName: body} + snippetDescription: + type: custom + variableName: body + scopeType: {type: statement} + body: "function $name($parameterList) {\n\t$body\n}" target: type: range anchor: @@ -16,6 +20,7 @@ command: excludeAnchor: false excludeActive: false usePrePhraseSnapshot: true +spokenFormError: custom wrap with snippet initialState: documentContents: | const whatever = "hello"; diff --git a/data/fixtures/recorded/implicitExpansion/snipFunkAfterThat.yml b/data/fixtures/recorded/implicitExpansion/snipFunkAfterThat.yml index f6263bd0c1..0ca28adaee 100644 --- a/data/fixtures/recorded/implicitExpansion/snipFunkAfterThat.yml +++ b/data/fixtures/recorded/implicitExpansion/snipFunkAfterThat.yml @@ -4,7 +4,12 @@ command: spokenForm: snippet funk after that action: name: insertSnippet - snippetDescription: {type: named, name: functionDeclaration} + snippetDescription: + type: custom + body: "function $name($parameterList) {\n\t$body\n}" + scopeTypes: + - {type: namedFunction} + - {type: statement} destination: type: primitive insertionMode: after @@ -12,6 +17,7 @@ command: type: primitive mark: {type: that} usePrePhraseSnapshot: true +spokenFormError: custom insertion snippet initialState: documentContents: | function myFunction() { diff --git a/data/fixtures/recorded/implicitExpansion/snipFunkAfterThat2.yml b/data/fixtures/recorded/implicitExpansion/snipFunkAfterThat2.yml index b234a12c98..9c3a50fc2f 100644 --- a/data/fixtures/recorded/implicitExpansion/snipFunkAfterThat2.yml +++ b/data/fixtures/recorded/implicitExpansion/snipFunkAfterThat2.yml @@ -4,7 +4,12 @@ command: spokenForm: snippet funk after that action: name: insertSnippet - snippetDescription: {type: named, name: functionDeclaration} + snippetDescription: + type: custom + body: "function $name($parameterList) {\n\t$body\n}" + scopeTypes: + - {type: namedFunction} + - {type: statement} destination: type: primitive insertionMode: after @@ -12,6 +17,7 @@ command: type: primitive mark: {type: that} usePrePhraseSnapshot: true +spokenFormError: custom insertion snippet initialState: documentContents: |- function whatever() { diff --git a/data/fixtures/recorded/implicitExpansion/snipFunkAfterThis.yml b/data/fixtures/recorded/implicitExpansion/snipFunkAfterThis.yml index 229979cf89..a2975cf354 100644 --- a/data/fixtures/recorded/implicitExpansion/snipFunkAfterThis.yml +++ b/data/fixtures/recorded/implicitExpansion/snipFunkAfterThis.yml @@ -4,7 +4,12 @@ command: spokenForm: snippet funk after this action: name: insertSnippet - snippetDescription: {type: named, name: functionDeclaration} + snippetDescription: + type: custom + body: "function $name($parameterList) {\n\t$body\n}" + scopeTypes: + - {type: namedFunction} + - {type: statement} destination: type: primitive insertionMode: after @@ -12,6 +17,7 @@ command: type: primitive mark: {type: cursor} usePrePhraseSnapshot: true +spokenFormError: custom insertion snippet initialState: documentContents: |+ function myFunction() { diff --git a/data/fixtures/recorded/implicitExpansion/snipFunkAfterThis2.yml b/data/fixtures/recorded/implicitExpansion/snipFunkAfterThis2.yml index 7407d87130..1ec65d4ef2 100644 --- a/data/fixtures/recorded/implicitExpansion/snipFunkAfterThis2.yml +++ b/data/fixtures/recorded/implicitExpansion/snipFunkAfterThis2.yml @@ -4,7 +4,12 @@ command: spokenForm: snippet funk after this action: name: insertSnippet - snippetDescription: {type: named, name: functionDeclaration} + snippetDescription: + type: custom + body: "function $name($parameterList) {\n\t$body\n}" + scopeTypes: + - {type: namedFunction} + - {type: statement} destination: type: primitive insertionMode: after @@ -12,6 +17,7 @@ command: type: primitive mark: {type: cursor} usePrePhraseSnapshot: true +spokenFormError: custom insertion snippet initialState: documentContents: |+ function myFunction() { diff --git a/data/fixtures/recorded/implicitExpansion/snipFunkAfterToken.yml b/data/fixtures/recorded/implicitExpansion/snipFunkAfterToken.yml index 24b8e0df7e..e31f4b9bbd 100644 --- a/data/fixtures/recorded/implicitExpansion/snipFunkAfterToken.yml +++ b/data/fixtures/recorded/implicitExpansion/snipFunkAfterToken.yml @@ -4,7 +4,12 @@ command: spokenForm: snippet funk after token action: name: insertSnippet - snippetDescription: {type: named, name: functionDeclaration} + snippetDescription: + type: custom + body: "function $name($parameterList) {\n\t$body\n}" + scopeTypes: + - {type: namedFunction} + - {type: statement} destination: type: primitive insertionMode: after @@ -14,6 +19,7 @@ command: - type: containingScope scopeType: {type: token} usePrePhraseSnapshot: true +spokenFormError: custom insertion snippet initialState: documentContents: |+ function myFunction() { diff --git a/data/fixtures/recorded/implicitExpansion/snipFunkAfterWhale.yml b/data/fixtures/recorded/implicitExpansion/snipFunkAfterWhale.yml index cac59a6e92..65676b2878 100644 --- a/data/fixtures/recorded/implicitExpansion/snipFunkAfterWhale.yml +++ b/data/fixtures/recorded/implicitExpansion/snipFunkAfterWhale.yml @@ -4,7 +4,12 @@ command: spokenForm: snippet funk after whale action: name: insertSnippet - snippetDescription: {type: named, name: functionDeclaration} + snippetDescription: + type: custom + body: "function $name($parameterList) {\n\t$body\n}" + scopeTypes: + - {type: namedFunction} + - {type: statement} destination: type: primitive insertionMode: after @@ -12,6 +17,7 @@ command: type: primitive mark: {type: decoratedSymbol, symbolColor: default, character: w} usePrePhraseSnapshot: true +spokenFormError: custom insertion snippet initialState: documentContents: |+ function myFunction() { diff --git a/data/fixtures/recorded/implicitExpansion/snipFunkToAirPastWhale.yml b/data/fixtures/recorded/implicitExpansion/snipFunkToAirPastWhale.yml index 6921751272..24bee9eb56 100644 --- a/data/fixtures/recorded/implicitExpansion/snipFunkToAirPastWhale.yml +++ b/data/fixtures/recorded/implicitExpansion/snipFunkToAirPastWhale.yml @@ -4,7 +4,12 @@ command: spokenForm: snippet funk to air past whale action: name: insertSnippet - snippetDescription: {type: named, name: functionDeclaration} + snippetDescription: + type: custom + body: "function $name($parameterList) {\n\t$body\n}" + scopeTypes: + - {type: namedFunction} + - {type: statement} destination: type: primitive insertionMode: to @@ -19,6 +24,7 @@ command: excludeAnchor: false excludeActive: false usePrePhraseSnapshot: true +spokenFormError: custom insertion snippet initialState: documentContents: |+ function myFunction() { diff --git a/data/fixtures/recorded/implicitExpansion/snipFunkToThisPastEach.yml b/data/fixtures/recorded/implicitExpansion/snipFunkToThisPastEach.yml index b7609a3210..d4e5fdc204 100644 --- a/data/fixtures/recorded/implicitExpansion/snipFunkToThisPastEach.yml +++ b/data/fixtures/recorded/implicitExpansion/snipFunkToThisPastEach.yml @@ -4,7 +4,12 @@ command: spokenForm: snippet funk to this past each action: name: insertSnippet - snippetDescription: {type: named, name: functionDeclaration} + snippetDescription: + type: custom + body: "function $name($parameterList) {\n\t$body\n}" + scopeTypes: + - {type: namedFunction} + - {type: statement} destination: type: primitive insertionMode: to @@ -19,6 +24,7 @@ command: excludeAnchor: false excludeActive: false usePrePhraseSnapshot: true +spokenFormError: custom insertion snippet initialState: documentContents: |- function whatever() { diff --git a/data/fixtures/recorded/inference/ifWrapTokenFine.yml b/data/fixtures/recorded/inference/ifWrapTokenFine.yml index 885ba79886..05b0435411 100644 --- a/data/fixtures/recorded/inference/ifWrapTokenFine.yml +++ b/data/fixtures/recorded/inference/ifWrapTokenFine.yml @@ -4,7 +4,11 @@ command: spokenForm: if wrap token fine action: name: wrapWithSnippet - snippetDescription: {type: named, name: ifStatement, variableName: consequence} + snippetDescription: + type: custom + variableName: consequence + body: "if ($condition) {\n\t$consequence\n}" + scopeType: {type: statement} target: type: primitive modifiers: @@ -12,6 +16,7 @@ command: scopeType: {type: token} mark: {type: decoratedSymbol, symbolColor: default, character: f} usePrePhraseSnapshot: false +spokenFormError: custom wrap with snippet initialState: documentContents: | const foo = "hello"; diff --git a/data/fixtures/recorded/positions/snipElseAfterThis.yml b/data/fixtures/recorded/positions/snipElseAfterThis.yml index 38af380687..ba44a8d6ba 100644 --- a/data/fixtures/recorded/positions/snipElseAfterThis.yml +++ b/data/fixtures/recorded/positions/snipElseAfterThis.yml @@ -4,7 +4,11 @@ command: spokenForm: snippet else after this action: name: insertSnippet - snippetDescription: {type: named, name: elseStatement} + snippetDescription: + type: custom + body: "else:\n\t$body" + scopeTypes: + - {type: branch} destination: type: primitive insertionMode: after @@ -12,7 +16,7 @@ command: type: primitive mark: {type: cursor} usePrePhraseSnapshot: true -spokenFormError: Named insertion snippet 'elseStatement' +spokenFormError: custom insertion snippet initialState: documentContents: | if True: From 35b4d3aaab5d67c23231868d4594f7d252239085 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 1 Feb 2025 09:38:29 +0100 Subject: [PATCH 14/38] Updated test --- .../wrapWithSnippetAcrossSplit.vscode.test.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/cursorless-vscode-e2e/src/suite/wrapWithSnippetAcrossSplit.vscode.test.ts b/packages/cursorless-vscode-e2e/src/suite/wrapWithSnippetAcrossSplit.vscode.test.ts index 7cffec5001..413b80b7e9 100644 --- a/packages/cursorless-vscode-e2e/src/suite/wrapWithSnippetAcrossSplit.vscode.test.ts +++ b/packages/cursorless-vscode-e2e/src/suite/wrapWithSnippetAcrossSplit.vscode.test.ts @@ -25,10 +25,15 @@ async function runTest() { await hatTokenMap.allocateHats(); await runCursorlessCommand({ - version: 4, - action: { name: "wrapWithSnippet", args: ["spaghetti.foo"] }, - targets: [ - { + version: 7, + action: { + name: "wrapWithSnippet", + snippetDescription: { + type: "custom", + body: "My friend $foo likes to eat spaghetti!", + variableName: "foo", + }, + target: { type: "primitive", mark: { type: "decoratedSymbol", @@ -36,7 +41,7 @@ async function runTest() { character: "h", }, }, - ], + }, usePrePhraseSnapshot: false, }); From 93bb50970826cf754388beae2a11b501379b8066 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 1 Feb 2025 09:47:08 +0100 Subject: [PATCH 15/38] Rename name field to type --- cursorless-talon/src/snippet_types.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cursorless-talon/src/snippet_types.py b/cursorless-talon/src/snippet_types.py index eb1f36a090..3107bf040d 100644 --- a/cursorless-talon/src/snippet_types.py +++ b/cursorless-talon/src/snippet_types.py @@ -13,7 +13,7 @@ class ScopeType: @dataclass class CustomInsertionSnippet: - name = "custom" + type = "custom" body: str scopeTypes: list[ScopeType] | None languages: list[str] | None @@ -22,7 +22,7 @@ class CustomInsertionSnippet: @dataclass class ListInsertionSnippet: - name = "list" + type = "list" substitutions: dict[str, str] | None snippets: list[CustomInsertionSnippet] @@ -39,7 +39,7 @@ class InsertSnippetAction: @dataclass class CustomWrapperSnippet: - name = "custom" + type = "custom" body: str variableName: str | None scopeType: ScopeType | None @@ -48,7 +48,7 @@ class CustomWrapperSnippet: @dataclass class ListWrapperSnippet: - name = "list" + type = "list" snippets: list[CustomWrapperSnippet] From 854375bf4a864e828ca8d8c13b098281efffc5b7 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 1 Feb 2025 09:55:12 +0100 Subject: [PATCH 16/38] More tests --- .../recorded/actions/snippets/snipCode.yml | 34 +++++++++++++ .../recorded/actions/snippets/snipIf.yml | 48 +++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 data/fixtures/recorded/actions/snippets/snipCode.yml create mode 100644 data/fixtures/recorded/actions/snippets/snipIf.yml diff --git a/data/fixtures/recorded/actions/snippets/snipCode.yml b/data/fixtures/recorded/actions/snippets/snipCode.yml new file mode 100644 index 0000000000..cc85d58c03 --- /dev/null +++ b/data/fixtures/recorded/actions/snippets/snipCode.yml @@ -0,0 +1,34 @@ +languageId: plaintext +command: + version: 7 + spokenForm: snip code + action: + name: insertSnippet + snippetDescription: + type: list + snippets: + - {type: custom, body: "```\n$0\n```"} + destination: {type: implicit} + usePrePhraseSnapshot: false +spokenFormError: list insertion snippet +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: + - type: UntypedTarget + contentRange: + start: {line: 0, character: 0} + end: {line: 2, character: 3} + isReversed: false + hasExplicitRange: true diff --git a/data/fixtures/recorded/actions/snippets/snipIf.yml b/data/fixtures/recorded/actions/snippets/snipIf.yml new file mode 100644 index 0000000000..dc78b01315 --- /dev/null +++ b/data/fixtures/recorded/actions/snippets/snipIf.yml @@ -0,0 +1,48 @@ +languageId: typescript +command: + version: 7 + spokenForm: snip if + action: + name: insertSnippet + snippetDescription: + type: list + snippets: + - type: custom + body: "if ($1) {\n\t$0\n}" + scopeTypes: + - {type: statement} + languages: [c, cpp, csharp, java, javascript, typescript, javascriptreact, typescriptreact] + - type: custom + body: "if $1:\n\t$0" + scopeTypes: + - {type: statement} + languages: [python] + - type: custom + body: "if $1 then\n\t$0\nend" + scopeTypes: + - {type: statement} + languages: [lua] + destination: {type: implicit} + usePrePhraseSnapshot: false +spokenFormError: list insertion snippet +initialState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: {} +finalState: + documentContents: |- + if () { + + } + selections: + - anchor: {line: 0, character: 4} + active: {line: 0, character: 4} + thatMark: + - type: UntypedTarget + contentRange: + start: {line: 0, character: 0} + end: {line: 2, character: 1} + isReversed: false + hasExplicitRange: true From de41e41cc40c55ab523ccb16904f91d7384eba94 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 1 Feb 2025 10:20:57 +0100 Subject: [PATCH 17/38] Added test --- .../snippets/snipIfAfterAirAndBatt.yml | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 data/fixtures/recorded/actions/snippets/snipIfAfterAirAndBatt.yml diff --git a/data/fixtures/recorded/actions/snippets/snipIfAfterAirAndBatt.yml b/data/fixtures/recorded/actions/snippets/snipIfAfterAirAndBatt.yml new file mode 100644 index 0000000000..d416b6d909 --- /dev/null +++ b/data/fixtures/recorded/actions/snippets/snipIfAfterAirAndBatt.yml @@ -0,0 +1,83 @@ +languageId: typescript +command: + version: 7 + spokenForm: snip if after air and batt + action: + name: insertSnippet + snippetDescription: + type: list + snippets: + - type: custom + body: "if ($1) {\n\t$0\n}" + scopeTypes: + - {type: statement} + - {type: line} + languages: [c, cpp, csharp, java, javascript, typescript, javascriptreact, typescriptreact] + - type: custom + body: "if $1:\n\t$0" + scopeTypes: + - {type: statement} + - {type: line} + languages: [python] + - type: custom + body: "if $1 then\n\t$0\nend" + scopeTypes: + - {type: statement} + - {type: line} + languages: [lua] + destination: + type: primitive + insertionMode: after + target: + type: list + elements: + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: a} + - type: primitive + mark: {type: decoratedSymbol, symbolColor: default, character: b} + usePrePhraseSnapshot: false +spokenFormError: list insertion snippet +initialState: + documentContents: | + const aaa = 2; + + // bbb + selections: + - anchor: {line: 3, character: 0} + active: {line: 3, character: 0} + marks: + default.a: + start: {line: 0, character: 6} + end: {line: 0, character: 9} + default.b: + start: {line: 2, character: 3} + end: {line: 2, character: 6} +finalState: + documentContents: | + const aaa = 2; + if () { + + } + + // bbb + if () { + + } + selections: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} + - anchor: {line: 6, character: 4} + active: {line: 6, character: 4} + thatMark: + - type: UntypedTarget + contentRange: + start: {line: 1, character: 0} + end: {line: 3, character: 1} + isReversed: false + hasExplicitRange: true + - type: UntypedTarget + contentRange: + start: {line: 6, character: 0} + end: {line: 8, character: 1} + isReversed: false + hasExplicitRange: true From 28d3d657d29b7452d64a27555b6c4d5ad3a4d793 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 1 Feb 2025 10:45:44 +0100 Subject: [PATCH 18/38] Update test fixtures --- .../actions/snippets/snipFunkAfterThis4.yml | 8 ++--- .../actions/snippets/snipFunkAfterThis5.yml | 29 +++++++++++++++++-- .../actions/snippets/snipFunkCelloWorld.yml | 8 ++--- .../actions/snippets/snipFunkHelloWorld2.yml | 11 ++++--- .../recorded/languages/php/elseWrapThis.yml | 22 -------------- .../recorded/languages/php/ifElseWrapThis.yml | 22 -------------- .../recorded/languages/php/ifWrapThis.yml | 22 -------------- .../recorded/languages/php/tryWrapThis.yml | 22 -------------- .../recorded/languages/php/tryWrapThis2.yml | 28 ------------------ 9 files changed, 39 insertions(+), 133 deletions(-) delete mode 100644 data/fixtures/recorded/languages/php/elseWrapThis.yml delete mode 100644 data/fixtures/recorded/languages/php/ifElseWrapThis.yml delete mode 100644 data/fixtures/recorded/languages/php/ifWrapThis.yml delete mode 100644 data/fixtures/recorded/languages/php/tryWrapThis.yml delete mode 100644 data/fixtures/recorded/languages/php/tryWrapThis2.yml diff --git a/data/fixtures/recorded/actions/snippets/snipFunkAfterThis4.yml b/data/fixtures/recorded/actions/snippets/snipFunkAfterThis4.yml index 754366fbf1..f2ed02d936 100644 --- a/data/fixtures/recorded/actions/snippets/snipFunkAfterThis4.yml +++ b/data/fixtures/recorded/actions/snippets/snipFunkAfterThis4.yml @@ -6,7 +6,7 @@ command: name: insertSnippet snippetDescription: type: custom - body: "function $name($parameterList) {\n\t$body\n}" + body: "$name($parameterList) {\n\t$body\n}" scopeTypes: - {type: statement} destination: @@ -25,12 +25,12 @@ initialState: finalState: documentContents: |- const foo = "bar"; - function () { + () { } selections: - - anchor: {line: 1, character: 9} - active: {line: 1, character: 9} + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} thatMark: - type: UntypedTarget contentRange: diff --git a/data/fixtures/recorded/actions/snippets/snipFunkAfterThis5.yml b/data/fixtures/recorded/actions/snippets/snipFunkAfterThis5.yml index 28ad811555..407dc1db95 100644 --- a/data/fixtures/recorded/actions/snippets/snipFunkAfterThis5.yml +++ b/data/fixtures/recorded/actions/snippets/snipFunkAfterThis5.yml @@ -4,7 +4,11 @@ command: spokenForm: snippet funk after this action: name: insertSnippet - snippetDescription: {type: named, name: functionDeclaration} + snippetDescription: + type: custom + body: "$name($parameterList) {\n\t$body\n}" + scopeTypes: + - {type: statement} destination: type: primitive insertionMode: after @@ -12,7 +16,7 @@ command: type: primitive mark: {type: cursor} usePrePhraseSnapshot: true -spokenFormError: named insertion snippet +spokenFormError: custom insertion snippet initialState: documentContents: |- class Aaa { @@ -24,4 +28,23 @@ initialState: - anchor: {line: 2, character: 8} active: {line: 2, character: 8} marks: {} -thrownError: {name: Error} +finalState: + documentContents: |- + class Aaa { + bbb() { + + } + () { + + } + } + selections: + - anchor: {line: 4, character: 4} + active: {line: 4, character: 4} + thatMark: + - type: UntypedTarget + contentRange: + start: {line: 4, character: 4} + end: {line: 6, character: 5} + isReversed: false + hasExplicitRange: true diff --git a/data/fixtures/recorded/actions/snippets/snipFunkCelloWorld.yml b/data/fixtures/recorded/actions/snippets/snipFunkCelloWorld.yml index a0fd8a9390..46fc3370de 100644 --- a/data/fixtures/recorded/actions/snippets/snipFunkCelloWorld.yml +++ b/data/fixtures/recorded/actions/snippets/snipFunkCelloWorld.yml @@ -6,7 +6,7 @@ command: name: insertSnippet snippetDescription: type: custom - body: "function $name($parameterList) {\n\t$body\n}" + body: "$name($parameterList) {\n\t$body\n}" scopeTypes: - {type: statement} substitutions: {name: celloWorld} @@ -25,13 +25,13 @@ initialState: finalState: documentContents: |- class Aaa { - function celloWorld() { + celloWorld() { } } selections: - - anchor: {line: 1, character: 24} - active: {line: 1, character: 24} + - anchor: {line: 1, character: 15} + active: {line: 1, character: 15} thatMark: - type: UntypedTarget contentRange: diff --git a/data/fixtures/recorded/actions/snippets/snipFunkHelloWorld2.yml b/data/fixtures/recorded/actions/snippets/snipFunkHelloWorld2.yml index e257a57a7a..925e671338 100644 --- a/data/fixtures/recorded/actions/snippets/snipFunkHelloWorld2.yml +++ b/data/fixtures/recorded/actions/snippets/snipFunkHelloWorld2.yml @@ -6,7 +6,7 @@ command: name: insertSnippet snippetDescription: type: custom - body: "function $name($parameterList) {\n\t$body\n}" + body: "def $name($parameterList):\n\t$body" scopeTypes: - {type: statement} substitutions: {name: hello_world} @@ -20,16 +20,15 @@ initialState: active: {line: 0, character: 0} finalState: documentContents: |- - function hello_world() { + def hello_world(): - } selections: - - anchor: {line: 0, character: 21} - active: {line: 0, character: 21} + - anchor: {line: 0, character: 16} + active: {line: 0, character: 16} thatMark: - type: UntypedTarget contentRange: start: {line: 0, character: 0} - end: {line: 2, character: 1} + end: {line: 1, character: 4} isReversed: false hasExplicitRange: true diff --git a/data/fixtures/recorded/languages/php/elseWrapThis.yml b/data/fixtures/recorded/languages/php/elseWrapThis.yml deleted file mode 100644 index eaec9e2593..0000000000 --- a/data/fixtures/recorded/languages/php/elseWrapThis.yml +++ /dev/null @@ -1,22 +0,0 @@ -languageId: php -command: - version: 6 - spokenForm: else wrap this - action: - name: wrapWithSnippet - snippetDescription: {type: named, name: ifElseStatement, variableName: alternative} - target: - type: primitive - mark: {type: cursor} - usePrePhraseSnapshot: false -spokenFormError: named wrap with snippet -initialState: - documentContents: |- - Date: Sat, 1 Feb 2025 10:54:54 +0100 Subject: [PATCH 19/38] Updated more tests --- .../recorded/actions/snippets/snipFunkAfterThis4.yml | 8 ++++---- .../recorded/actions/snippets/snipFunkAfterThis5.yml | 10 ++++++---- .../recorded/actions/snippets/snipFunkBeforeThis4.yml | 8 ++++---- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/data/fixtures/recorded/actions/snippets/snipFunkAfterThis4.yml b/data/fixtures/recorded/actions/snippets/snipFunkAfterThis4.yml index f2ed02d936..754366fbf1 100644 --- a/data/fixtures/recorded/actions/snippets/snipFunkAfterThis4.yml +++ b/data/fixtures/recorded/actions/snippets/snipFunkAfterThis4.yml @@ -6,7 +6,7 @@ command: name: insertSnippet snippetDescription: type: custom - body: "$name($parameterList) {\n\t$body\n}" + body: "function $name($parameterList) {\n\t$body\n}" scopeTypes: - {type: statement} destination: @@ -25,12 +25,12 @@ initialState: finalState: documentContents: |- const foo = "bar"; - () { + function () { } selections: - - anchor: {line: 1, character: 0} - active: {line: 1, character: 0} + - anchor: {line: 1, character: 9} + active: {line: 1, character: 9} thatMark: - type: UntypedTarget contentRange: diff --git a/data/fixtures/recorded/actions/snippets/snipFunkAfterThis5.yml b/data/fixtures/recorded/actions/snippets/snipFunkAfterThis5.yml index 407dc1db95..75d7eadce1 100644 --- a/data/fixtures/recorded/actions/snippets/snipFunkAfterThis5.yml +++ b/data/fixtures/recorded/actions/snippets/snipFunkAfterThis5.yml @@ -8,6 +8,7 @@ command: type: custom body: "$name($parameterList) {\n\t$body\n}" scopeTypes: + - {type: namedFunction} - {type: statement} destination: type: primitive @@ -34,17 +35,18 @@ finalState: bbb() { } + () { } } selections: - - anchor: {line: 4, character: 4} - active: {line: 4, character: 4} + - anchor: {line: 5, character: 4} + active: {line: 5, character: 4} thatMark: - type: UntypedTarget contentRange: - start: {line: 4, character: 4} - end: {line: 6, character: 5} + start: {line: 5, character: 4} + end: {line: 7, character: 5} isReversed: false hasExplicitRange: true diff --git a/data/fixtures/recorded/actions/snippets/snipFunkBeforeThis4.yml b/data/fixtures/recorded/actions/snippets/snipFunkBeforeThis4.yml index ed05622b1d..aa74af2eca 100644 --- a/data/fixtures/recorded/actions/snippets/snipFunkBeforeThis4.yml +++ b/data/fixtures/recorded/actions/snippets/snipFunkBeforeThis4.yml @@ -6,7 +6,7 @@ command: name: insertSnippet snippetDescription: type: custom - body: "function $name($parameterList) {\n\t$body\n}" + body: "$name($parameterList) {\n\t$body\n}" scopeTypes: - {type: namedFunction} - {type: statement} @@ -32,7 +32,7 @@ initialState: finalState: documentContents: |- class Aaa { - function () { + () { } @@ -41,8 +41,8 @@ finalState: } } selections: - - anchor: {line: 1, character: 13} - active: {line: 1, character: 13} + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} thatMark: - type: UntypedTarget contentRange: From 7f5d4f68f5bd67b6645ee3db5b6212ac5a80064b Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 1 Feb 2025 11:01:19 +0100 Subject: [PATCH 20/38] Added tests --- .../recorded/actions/snippets/snipFunk.yml | 30 +++++++++++++ .../recorded/actions/snippets/snipFunk2.yml | 31 +++++++++++++ .../recorded/actions/snippets/snipFunk3.yml | 36 +++++++++++++++ .../recorded/actions/snippets/snipFunk4.yml | 40 +++++++++++++++++ .../recorded/actions/snippets/snipFunk5.yml | 40 +++++++++++++++++ .../recorded/actions/snippets/snipFunk6.yml | 44 +++++++++++++++++++ 6 files changed, 221 insertions(+) create mode 100644 data/fixtures/recorded/actions/snippets/snipFunk.yml create mode 100644 data/fixtures/recorded/actions/snippets/snipFunk2.yml create mode 100644 data/fixtures/recorded/actions/snippets/snipFunk3.yml create mode 100644 data/fixtures/recorded/actions/snippets/snipFunk4.yml create mode 100644 data/fixtures/recorded/actions/snippets/snipFunk5.yml create mode 100644 data/fixtures/recorded/actions/snippets/snipFunk6.yml diff --git a/data/fixtures/recorded/actions/snippets/snipFunk.yml b/data/fixtures/recorded/actions/snippets/snipFunk.yml new file mode 100644 index 0000000000..272c890bb3 --- /dev/null +++ b/data/fixtures/recorded/actions/snippets/snipFunk.yml @@ -0,0 +1,30 @@ +languageId: typescript +command: + version: 6 + spokenForm: snippet funk + action: + name: insertSnippet + snippetDescription: {type: custom, body: "function $name($parameterList) {\n\t$body\n}"} + destination: {type: implicit} + usePrePhraseSnapshot: false +spokenFormError: custom insertion snippet +initialState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} +finalState: + documentContents: |- + function () { + + } + selections: + - anchor: {line: 0, character: 9} + active: {line: 0, character: 9} + thatMark: + - type: UntypedTarget + contentRange: + start: {line: 0, character: 0} + end: {line: 2, character: 1} + isReversed: false + hasExplicitRange: true diff --git a/data/fixtures/recorded/actions/snippets/snipFunk2.yml b/data/fixtures/recorded/actions/snippets/snipFunk2.yml new file mode 100644 index 0000000000..639d045f95 --- /dev/null +++ b/data/fixtures/recorded/actions/snippets/snipFunk2.yml @@ -0,0 +1,31 @@ +languageId: typescript +command: + version: 6 + spokenForm: snippet funk + action: + name: insertSnippet + snippetDescription: {type: custom, body: "function $name($parameterList) {\n\t$body\n}"} + destination: {type: implicit} + usePrePhraseSnapshot: true +spokenFormError: custom insertion snippet +initialState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: {} +finalState: + documentContents: |- + function () { + + } + selections: + - anchor: {line: 0, character: 9} + active: {line: 0, character: 9} + thatMark: + - type: UntypedTarget + contentRange: + start: {line: 0, character: 0} + end: {line: 2, character: 1} + isReversed: false + hasExplicitRange: true diff --git a/data/fixtures/recorded/actions/snippets/snipFunk3.yml b/data/fixtures/recorded/actions/snippets/snipFunk3.yml new file mode 100644 index 0000000000..91e662020a --- /dev/null +++ b/data/fixtures/recorded/actions/snippets/snipFunk3.yml @@ -0,0 +1,36 @@ +languageId: typescript +command: + version: 6 + spokenForm: snippet funk + action: + name: insertSnippet + snippetDescription: {type: custom, body: "$name($parameterList) {\n\t$body\n}"} + destination: {type: implicit} + usePrePhraseSnapshot: true +spokenFormError: custom insertion snippet +initialState: + documentContents: |- + class Aaa { + + } + selections: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} + marks: {} +finalState: + documentContents: |- + class Aaa { + () { + + } + } + selections: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} + thatMark: + - type: UntypedTarget + contentRange: + start: {line: 1, character: 4} + end: {line: 3, character: 5} + isReversed: false + hasExplicitRange: true diff --git a/data/fixtures/recorded/actions/snippets/snipFunk4.yml b/data/fixtures/recorded/actions/snippets/snipFunk4.yml new file mode 100644 index 0000000000..40b288fa3e --- /dev/null +++ b/data/fixtures/recorded/actions/snippets/snipFunk4.yml @@ -0,0 +1,40 @@ +languageId: typescript +command: + version: 6 + spokenForm: snippet funk + action: + name: insertSnippet + snippetDescription: {type: custom, body: "function $name($parameterList) {\n\t$body\n}"} + destination: {type: implicit} + usePrePhraseSnapshot: true +spokenFormError: custom insertion snippet +initialState: + documentContents: |- + class Aaa { + bbb() { + + } + } + selections: + - anchor: {line: 2, character: 8} + active: {line: 2, character: 8} + marks: {} +finalState: + documentContents: |- + class Aaa { + bbb() { + function () { + + } + } + } + selections: + - anchor: {line: 2, character: 17} + active: {line: 2, character: 17} + thatMark: + - type: UntypedTarget + contentRange: + start: {line: 2, character: 8} + end: {line: 4, character: 9} + isReversed: false + hasExplicitRange: true diff --git a/data/fixtures/recorded/actions/snippets/snipFunk5.yml b/data/fixtures/recorded/actions/snippets/snipFunk5.yml new file mode 100644 index 0000000000..e8186e8124 --- /dev/null +++ b/data/fixtures/recorded/actions/snippets/snipFunk5.yml @@ -0,0 +1,40 @@ +languageId: typescript +command: + version: 6 + spokenForm: snippet funk + action: + name: insertSnippet + snippetDescription: {type: custom, body: "$name($parameterList) {\n\t$body\n}"} + destination: {type: implicit} + usePrePhraseSnapshot: true +spokenFormError: custom insertion snippet +initialState: + documentContents: |- + function aaa() { + class Bbb { + + } + } + selections: + - anchor: {line: 2, character: 8} + active: {line: 2, character: 8} + marks: {} +finalState: + documentContents: |- + function aaa() { + class Bbb { + () { + + } + } + } + selections: + - anchor: {line: 2, character: 8} + active: {line: 2, character: 8} + thatMark: + - type: UntypedTarget + contentRange: + start: {line: 2, character: 8} + end: {line: 4, character: 9} + isReversed: false + hasExplicitRange: true diff --git a/data/fixtures/recorded/actions/snippets/snipFunk6.yml b/data/fixtures/recorded/actions/snippets/snipFunk6.yml new file mode 100644 index 0000000000..7f4bebe005 --- /dev/null +++ b/data/fixtures/recorded/actions/snippets/snipFunk6.yml @@ -0,0 +1,44 @@ +languageId: typescript +command: + version: 6 + spokenForm: snippet funk + action: + name: insertSnippet + snippetDescription: {type: custom, body: "$name($parameterList) {\n\t$body\n}"} + destination: {type: implicit} + usePrePhraseSnapshot: true +spokenFormError: custom insertion snippet +initialState: + documentContents: |- + class Aaa { + bbb() { + class Bbb { + + } + } + } + selections: + - anchor: {line: 3, character: 12} + active: {line: 3, character: 12} + marks: {} +finalState: + documentContents: |- + class Aaa { + bbb() { + class Bbb { + () { + + } + } + } + } + selections: + - anchor: {line: 3, character: 12} + active: {line: 3, character: 12} + thatMark: + - type: UntypedTarget + contentRange: + start: {line: 3, character: 12} + end: {line: 5, character: 13} + isReversed: false + hasExplicitRange: true From 415945a131882954ca43ecbdcd22417eb8c63a8b Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 1 Feb 2025 14:31:13 +0100 Subject: [PATCH 21/38] More snippet cleanup --- cursorless-talon-dev/src/spoken_form_test.py | 16 ------- .../src/actions/generate_snippet.py | 18 +------- .../fixtures/communitySnippets.fixture.ts | 4 +- .../src/test/fixtures/spokenFormTest.ts | 13 ------ .../src/test/spokenForms.talon.test.ts | 45 ++++++------------- 5 files changed, 15 insertions(+), 81 deletions(-) diff --git a/cursorless-talon-dev/src/spoken_form_test.py b/cursorless-talon-dev/src/spoken_form_test.py index 275c8c3a7e..6c531ef2c2 100644 --- a/cursorless-talon-dev/src/spoken_form_test.py +++ b/cursorless-talon-dev/src/spoken_form_test.py @@ -39,8 +39,6 @@ mockedGetValue = "" -community_snippets_tag_name = "user.cursorless_use_community_snippets" - @ctx.action_class("user") class UserActions: @@ -99,20 +97,6 @@ def private_cursorless_spoken_form_test_mode(enable: bool): # pyright: ignore [ "Cursorless spoken form tests are done. Talon microphone is re-enabled." ) - def private_cursorless_use_community_snippets(enable: bool): # pyright: ignore [reportGeneralTypeIssues] - """Enable/disable cursorless community snippets in test mode""" - if enable: - tags = set(ctx.tags) - tags.add(community_snippets_tag_name) - ctx.tags = list(tags) - else: - tags = set(ctx.tags) - tags.remove(community_snippets_tag_name) - ctx.tags = list(tags) - # Note: Test harness hangs if we don't print anything because it's - # waiting for stdout - print(f"Set community snippet enablement to {enable}") - def private_cursorless_spoken_form_test( phrase: str, # pyright: ignore [reportGeneralTypeIssues] mockedGetValue_: Optional[str], diff --git a/cursorless-talon/src/actions/generate_snippet.py b/cursorless-talon/src/actions/generate_snippet.py index 54835bd66f..7d9b66a4f3 100644 --- a/cursorless-talon/src/actions/generate_snippet.py +++ b/cursorless-talon/src/actions/generate_snippet.py @@ -1,17 +1,12 @@ import glob from pathlib import Path -from talon import Context, Module, actions, registry, settings +from talon import Module, actions, registry, settings from ..targets.target_types import CursorlessExplicitTarget mod = Module() -ctx = Context() -ctx.matches = r""" -tag: user.cursorless_use_community_snippets -""" - @mod.action_class class Actions: @@ -33,17 +28,6 @@ def private_cursorless_migrate_snippets(): def private_cursorless_generate_snippet_action(target: CursorlessExplicitTarget): # pyright: ignore [reportGeneralTypeIssues] """Generate a snippet from the given target""" - actions.user.private_cursorless_command_no_wait( - { - "name": "generateSnippet", - "target": target, - } - ) - - -@ctx.action_class("user") -class UserActions: - def private_cursorless_generate_snippet_action(target: CursorlessExplicitTarget): # pyright: ignore [reportGeneralTypeIssues] actions.user.private_cursorless_command_no_wait( { "name": "generateSnippet", diff --git a/packages/cursorless-engine/src/test/fixtures/communitySnippets.fixture.ts b/packages/cursorless-engine/src/test/fixtures/communitySnippets.fixture.ts index d9ccddd191..d71edb32e4 100644 --- a/packages/cursorless-engine/src/test/fixtures/communitySnippets.fixture.ts +++ b/packages/cursorless-engine/src/test/fixtures/communitySnippets.fixture.ts @@ -27,7 +27,5 @@ const verticalRangeAction: ActionDescriptor = { * Talon tests by relying on our recorded test fixtures alone. */ export const communitySnippetsSpokenFormsFixture = [ - spokenFormTest("snippet code after air", verticalRangeAction, undefined, { - useCommunitySnippets: true, - }), + spokenFormTest("snippet code after air", verticalRangeAction, undefined), ]; diff --git a/packages/cursorless-engine/src/test/fixtures/spokenFormTest.ts b/packages/cursorless-engine/src/test/fixtures/spokenFormTest.ts index fc12a4b850..4394cf0a66 100644 --- a/packages/cursorless-engine/src/test/fixtures/spokenFormTest.ts +++ b/packages/cursorless-engine/src/test/fixtures/spokenFormTest.ts @@ -23,24 +23,17 @@ export interface SpokenFormTest { * {@link spokenForm} is spoken. */ commands: CommandV6[]; - - /** - * If `true`, use community snippets instead of Cursorless snippets - */ - useCommunitySnippets: boolean; } export function spokenFormTest( spokenForm: string, action: ActionDescriptor, mockedGetValue?: unknown, - { useCommunitySnippets = false }: SpokenFormTestOpts = {}, ): SpokenFormTest { return { spokenForm, mockedGetValue: wrapMockedGetValue(mockedGetValue), commands: [command(spokenForm, action)], - useCommunitySnippets, }; } @@ -48,13 +41,11 @@ export function multiActionSpokenFormTest( spokenForm: string, actions: ActionDescriptor[], mockedGetValue?: unknown, - { useCommunitySnippets = false }: SpokenFormTestOpts = {}, ): SpokenFormTest { return { spokenForm, mockedGetValue: wrapMockedGetValue(mockedGetValue), commands: actions.map((action) => command(spokenForm, action)), - useCommunitySnippets, }; } @@ -72,7 +63,3 @@ function command(spokenForm: string, action: ActionDescriptor): CommandV6 { action, }; } - -export interface SpokenFormTestOpts { - useCommunitySnippets?: boolean; -} diff --git a/packages/cursorless-engine/src/test/spokenForms.talon.test.ts b/packages/cursorless-engine/src/test/spokenForms.talon.test.ts index ccadecb3d8..e4a494d4ec 100644 --- a/packages/cursorless-engine/src/test/spokenForms.talon.test.ts +++ b/packages/cursorless-engine/src/test/spokenForms.talon.test.ts @@ -13,7 +13,6 @@ import { getHatMapCommand } from "../generateSpokenForm/getHatMapCommand"; import { TalonRepl } from "../testUtil/TalonRepl"; import { communitySnippetsSpokenFormsFixture } from "./fixtures/communitySnippets.fixture"; import { multiActionFixture } from "./fixtures/multiAction.fixture"; -import type { SpokenFormTestOpts } from "./fixtures/spokenFormTest"; import { synonymousSpokenFormsFixture } from "./fixtures/synonymousSpokenForms.fixture"; import { talonApiFixture } from "./fixtures/talonApi.fixture"; @@ -45,12 +44,8 @@ suite("Talon spoken forms", async function () { ...talonApiFixture, ...multiActionFixture, ...communitySnippetsSpokenFormsFixture, - ].forEach(({ spokenForm, commands, mockedGetValue, useCommunitySnippets }) => - test(spokenForm, () => - runTest(repl, spokenForm, commands, mockedGetValue, { - useCommunitySnippets, - }), - ), + ].forEach(({ spokenForm, commands, mockedGetValue }) => + test(spokenForm, () => runTest(repl, spokenForm, commands, mockedGetValue)), ); }); @@ -83,7 +78,6 @@ async function runTest( spokenForm: string, commandsLegacy: Command[], mockedGetValue?: unknown, - { useCommunitySnippets = false }: SpokenFormTestOpts = {}, ) { const commandsExpected = commandsLegacy.map((command) => ({ ...canonicalizeAndValidateCommand(command), @@ -109,37 +103,24 @@ async function runTest( ? "None" : JSON.stringify(JSON.stringify(mockedGetValue)); - if (useCommunitySnippets) { - await repl.action(`user.private_cursorless_use_community_snippets(True)`); - } + const result = await repl.action( + `user.private_cursorless_spoken_form_test("${spokenForm}", ${mockedGetValueString})`, + ); - try { - const result = await repl.action( - `user.private_cursorless_spoken_form_test("${spokenForm}", ${mockedGetValueString})`, - ); - - const commandsActual = (() => { - try { - return JSON.parse(result); - } catch (_e) { - throw Error(result); - } - })(); - - assert.deepStrictEqual(commandsActual, commandsExpected); - } finally { - if (useCommunitySnippets) { - await repl.action( - `user.private_cursorless_use_community_snippets(False)`, - ); + const commandsActual = (() => { + try { + return JSON.parse(result); + } catch (_e) { + throw Error(result); } - } + })(); + + assert.deepStrictEqual(commandsActual, commandsExpected); } async function setTestMode(repl: TalonRepl, enabled: boolean) { const arg = enabled ? "True" : "False"; await repl.action(`user.private_cursorless_spoken_form_test_mode(${arg})`); - await repl.action(`user.private_cursorless_use_community_snippets(False)`); // If you have warnings in your talon user files, they will be printed to the // repl when you run the above action. We need to eat them so that they don't From afdea94ac72395f656fcd04b062a24c42f010d92 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sat, 1 Feb 2025 14:38:41 +0100 Subject: [PATCH 22/38] Update Talon grammar tests --- .../src/cursorless_test.talon | 4 --- .../fixtures/communitySnippets.fixture.ts | 9 +++++-- .../src/test/fixtures/talonApi.fixture.ts | 25 ------------------- 3 files changed, 7 insertions(+), 31 deletions(-) diff --git a/cursorless-talon-dev/src/cursorless_test.talon b/cursorless-talon-dev/src/cursorless_test.talon index 561d620ee0..339c642110 100644 --- a/cursorless-talon-dev/src/cursorless_test.talon +++ b/cursorless-talon-dev/src/cursorless_test.talon @@ -25,12 +25,8 @@ test api insert snippet: user.cursorless_insert_snippet("Hello, $foo! My name is $bar!") test api insert snippet : user.cursorless_insert_snippet("Hello, $foo! My name is $bar!", cursorless_destination, "statement") -test api insert snippet by name: - user.cursorless_insert_snippet_by_name("functionDeclaration") test api wrap with snippet : user.cursorless_wrap_with_snippet("Hello, $foo! My name is $bar!", cursorless_target, "foo", "statement") -test api wrap with snippet by name : - user.cursorless_wrap_with_snippet_by_name("functionDeclaration", "body", cursorless_target) test api extract decorated marks : user.private_cursorless_test_extract_decorated_marks(cursorless_target) test api alternate highlight nothing: diff --git a/packages/cursorless-engine/src/test/fixtures/communitySnippets.fixture.ts b/packages/cursorless-engine/src/test/fixtures/communitySnippets.fixture.ts index d71edb32e4..afbb3fa78c 100644 --- a/packages/cursorless-engine/src/test/fixtures/communitySnippets.fixture.ts +++ b/packages/cursorless-engine/src/test/fixtures/communitySnippets.fixture.ts @@ -16,8 +16,13 @@ const verticalRangeAction: ActionDescriptor = { }, }, snippetDescription: { - body: "```\n$0\n```", - type: "custom", + type: "list", + snippets: [ + { + type: "custom", + body: "```\n$0\n```", + }, + ], }, }; diff --git a/packages/cursorless-engine/src/test/fixtures/talonApi.fixture.ts b/packages/cursorless-engine/src/test/fixtures/talonApi.fixture.ts index fac4504e5d..71a8c17d57 100644 --- a/packages/cursorless-engine/src/test/fixtures/talonApi.fixture.ts +++ b/packages/cursorless-engine/src/test/fixtures/talonApi.fixture.ts @@ -60,14 +60,6 @@ const insertSnippetWithScopeAction: ActionDescriptor = { scopeTypes: [{ type: "statement" }], }, }; -const insertSnippetByNameAction: ActionDescriptor = { - name: "insertSnippet", - destination: { type: "implicit" }, - snippetDescription: { - type: "named", - name: "functionDeclaration", - }, -}; const wrapWithSnippetAction: ActionDescriptor = { name: "wrapWithSnippet", target: { @@ -81,18 +73,6 @@ const wrapWithSnippetAction: ActionDescriptor = { scopeType: { type: "statement" }, }, }; -const wrapWithSnippetByNameAction: ActionDescriptor = { - name: "wrapWithSnippet", - target: { - type: "primitive", - mark: { type: "cursor" }, - }, - snippetDescription: { - type: "named", - name: "functionDeclaration", - variableName: "body", - }, -}; const alternateHighlightAirAndBatAction: ActionDescriptor = { name: "highlight", target: { @@ -212,12 +192,7 @@ export const talonApiFixture = [ "test api insert snippet after air", insertSnippetWithScopeAction, ), - spokenFormTest("test api insert snippet by name", insertSnippetByNameAction), spokenFormTest("test api wrap with snippet this", wrapWithSnippetAction), - spokenFormTest( - "test api wrap with snippet by name this", - wrapWithSnippetByNameAction, - ), spokenFormTest( "test api get text air", getTextAction({ showDecorations: true, ensureSingleTarget: true }), From 036117bc88b29a5364832275808c9d6d951af5c6 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 4 Feb 2025 19:31:41 +0100 Subject: [PATCH 23/38] Rename fixture --- .../src/test/fixtures/communitySnippets.fixture.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/cursorless-engine/src/test/fixtures/communitySnippets.fixture.ts b/packages/cursorless-engine/src/test/fixtures/communitySnippets.fixture.ts index afbb3fa78c..d205429c71 100644 --- a/packages/cursorless-engine/src/test/fixtures/communitySnippets.fixture.ts +++ b/packages/cursorless-engine/src/test/fixtures/communitySnippets.fixture.ts @@ -1,7 +1,7 @@ import type { ActionDescriptor } from "@cursorless/common"; import { spokenFormTest } from "./spokenFormTest"; -const verticalRangeAction: ActionDescriptor = { +const snippetAfterAction: ActionDescriptor = { name: "insertSnippet", destination: { type: "primitive", @@ -32,5 +32,5 @@ const verticalRangeAction: ActionDescriptor = { * Talon tests by relying on our recorded test fixtures alone. */ export const communitySnippetsSpokenFormsFixture = [ - spokenFormTest("snippet code after air", verticalRangeAction, undefined), + spokenFormTest("snippet code after air", snippetAfterAction, undefined), ]; From e3f4297268e4ac3e4455817edb4c480ff9fafb11 Mon Sep 17 00:00:00 2001 From: Phillip Cohen Date: Tue, 4 Feb 2025 10:37:39 -0800 Subject: [PATCH 24/38] fix --- packages/cursorless-vscode/src/VscodeSnippets.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/cursorless-vscode/src/VscodeSnippets.ts b/packages/cursorless-vscode/src/VscodeSnippets.ts index 89ae362387..7ea83f8c93 100644 --- a/packages/cursorless-vscode/src/VscodeSnippets.ts +++ b/packages/cursorless-vscode/src/VscodeSnippets.ts @@ -6,7 +6,6 @@ import { open } from "node:fs/promises"; import { join } from "node:path"; // DEPRECATED @ 2025-02-01 - export const CURSORLESS_SNIPPETS_SUFFIX = ".cursorless-snippets"; /** From c8d2ed1aa49a0191cfb680ee071780dd0314afb5 Mon Sep 17 00:00:00 2001 From: Phil Cohen Date: Tue, 4 Feb 2025 10:43:53 -0800 Subject: [PATCH 25/38] Update cursorless-talon/src/snippets.py --- cursorless-talon/src/snippets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cursorless-talon/src/snippets.py b/cursorless-talon/src/snippets.py index 5dded04716..e915de344e 100644 --- a/cursorless-talon/src/snippets.py +++ b/cursorless-talon/src/snippets.py @@ -105,8 +105,8 @@ def cursorless_insert_snippet( snippet = CustomInsertionSnippet( body, to_scope_types(scope_type), - None, # languages - None, # substitutions + languages=None, + substitutions=None, ) insert_snippet(snippet, destination) From 835d0d37af43f2e344b429fa16f6d05d75aa76b4 Mon Sep 17 00:00:00 2001 From: Phil Cohen Date: Tue, 4 Feb 2025 10:44:23 -0800 Subject: [PATCH 26/38] Update cursorless-talon/src/snippets.py --- cursorless-talon/src/snippets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cursorless-talon/src/snippets.py b/cursorless-talon/src/snippets.py index e915de344e..1a3906cd6d 100644 --- a/cursorless-talon/src/snippets.py +++ b/cursorless-talon/src/snippets.py @@ -121,7 +121,7 @@ def cursorless_wrap_with_snippet( body, variable_name, ScopeType(scope) if scope else None, - None, # languages + languages=None, ) wrap_with_snippet(snippet, target) From c21678ce5c894215d70a9222929854b58bfa3a79 Mon Sep 17 00:00:00 2001 From: Phil Cohen Date: Tue, 4 Feb 2025 10:45:13 -0800 Subject: [PATCH 27/38] Update cursorless-talon/src/snippets.py --- cursorless-talon/src/snippets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cursorless-talon/src/snippets.py b/cursorless-talon/src/snippets.py index 1a3906cd6d..3c4acaec6e 100644 --- a/cursorless-talon/src/snippets.py +++ b/cursorless-talon/src/snippets.py @@ -57,7 +57,7 @@ def insert_community_snippet( to_scope_types(s.scopes), # languages will be missing if the user has an older version of community s.languages if hasattr(s, "languages") else None, - None, # substitutions + substitutions=None, ) for s in snippets ], From 1966999baec582cc0a9f14c86e369c2408cd9190 Mon Sep 17 00:00:00 2001 From: Phillip Cohen Date: Tue, 4 Feb 2025 10:47:11 -0800 Subject: [PATCH 28/38] fix --- cursorless-talon/src/snippets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cursorless-talon/src/snippets.py b/cursorless-talon/src/snippets.py index 3c4acaec6e..e4f3600ecc 100644 --- a/cursorless-talon/src/snippets.py +++ b/cursorless-talon/src/snippets.py @@ -132,8 +132,8 @@ def private_cursorless_insert_community_snippet( """Cursorless: Insert community snippet """ insert_community_snippet( name, - None, # substitutions - destination, + substitutions=None, + destination=destination, ) def private_cursorless_wrap_with_community_snippet( From f12c7f428abff4c0bf873a335826e39e4a9f8a32 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 4 Feb 2025 19:47:14 +0100 Subject: [PATCH 29/38] Clean up --- cursorless-talon/src/snippets.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cursorless-talon/src/snippets.py b/cursorless-talon/src/snippets.py index 3c4acaec6e..f922032150 100644 --- a/cursorless-talon/src/snippets.py +++ b/cursorless-talon/src/snippets.py @@ -149,7 +149,6 @@ def to_scope_types(scope_types: str | list[str] | None) -> list[ScopeType] | Non return [ScopeType(scope_types)] elif scope_types is not None: return [ScopeType(st) for st in scope_types] - return None def get_insertion_snippets(name: str) -> list[CommunityInsertionSnippet]: From 6730477346a3c1af58a1ab723d2bd03fea86c1ca Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 4 Feb 2025 19:48:10 +0100 Subject: [PATCH 30/38] Fix --- cursorless-talon/src/snippets.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cursorless-talon/src/snippets.py b/cursorless-talon/src/snippets.py index 8266232161..e21170ee7c 100644 --- a/cursorless-talon/src/snippets.py +++ b/cursorless-talon/src/snippets.py @@ -132,8 +132,8 @@ def private_cursorless_insert_community_snippet( """Cursorless: Insert community snippet """ insert_community_snippet( name, - substitutions=None, - destination=destination, + None, # substitutions + destination, ) def private_cursorless_wrap_with_community_snippet( @@ -149,6 +149,7 @@ def to_scope_types(scope_types: str | list[str] | None) -> list[ScopeType] | Non return [ScopeType(scope_types)] elif scope_types is not None: return [ScopeType(st) for st in scope_types] + return None def get_insertion_snippets(name: str) -> list[CommunityInsertionSnippet]: From 725cd1f4c03b6cf4806ef37519eade913e64595b Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 4 Feb 2025 19:50:40 +0100 Subject: [PATCH 31/38] Keyword argument --- cursorless-talon/src/snippets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cursorless-talon/src/snippets.py b/cursorless-talon/src/snippets.py index e21170ee7c..9ef9211f5c 100644 --- a/cursorless-talon/src/snippets.py +++ b/cursorless-talon/src/snippets.py @@ -132,8 +132,8 @@ def private_cursorless_insert_community_snippet( """Cursorless: Insert community snippet """ insert_community_snippet( name, - None, # substitutions - destination, + substitutions=None, + destination=destination, ) def private_cursorless_wrap_with_community_snippet( From 8c5f44a278a6204704dbe4473fdc108ad4eb92cb Mon Sep 17 00:00:00 2001 From: Phillip Cohen Date: Tue, 4 Feb 2025 11:14:58 -0800 Subject: [PATCH 32/38] fix --- .../{snipIfAfterAirAndBatt.yml => snipIfAfterAirAndBat.yml} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename data/fixtures/recorded/actions/snippets/{snipIfAfterAirAndBatt.yml => snipIfAfterAirAndBat.yml} (98%) diff --git a/data/fixtures/recorded/actions/snippets/snipIfAfterAirAndBatt.yml b/data/fixtures/recorded/actions/snippets/snipIfAfterAirAndBat.yml similarity index 98% rename from data/fixtures/recorded/actions/snippets/snipIfAfterAirAndBatt.yml rename to data/fixtures/recorded/actions/snippets/snipIfAfterAirAndBat.yml index d416b6d909..93398664d8 100644 --- a/data/fixtures/recorded/actions/snippets/snipIfAfterAirAndBatt.yml +++ b/data/fixtures/recorded/actions/snippets/snipIfAfterAirAndBat.yml @@ -1,7 +1,7 @@ languageId: typescript command: version: 7 - spokenForm: snip if after air and batt + spokenForm: snip if after air and bat action: name: insertSnippet snippetDescription: From 2d6bf5fbd573872796de499ec89f394ab76127bc Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 4 Feb 2025 20:16:48 +0100 Subject: [PATCH 33/38] Update snippet --- .../recorded/actions/snippets/tryWrapThis.yml | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 data/fixtures/recorded/actions/snippets/tryWrapThis.yml diff --git a/data/fixtures/recorded/actions/snippets/tryWrapThis.yml b/data/fixtures/recorded/actions/snippets/tryWrapThis.yml new file mode 100644 index 0000000000..52995cd804 --- /dev/null +++ b/data/fixtures/recorded/actions/snippets/tryWrapThis.yml @@ -0,0 +1,40 @@ +languageId: typescript +command: + version: 6 + spokenForm: try wrap this + action: + name: wrapWithSnippet + snippetDescription: + type: custom + body: "try {\n\t$1\n} catch (err) {\n\t$0\n}\n" + scopeTypes: + - {type: statement} + target: + type: primitive + mark: {type: cursor} + usePrePhraseSnapshot: true +spokenFormError: custom wrap with snippet +initialState: + documentContents: const foo = "bar"; + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: {} +finalState: + documentContents: |- + try { + + } catch (err) { + + } + foo = "bar"; + selections: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} + thatMark: + - type: UntypedTarget + contentRange: + start: {line: 0, character: 0} + end: {line: 5, character: 0} + isReversed: false + hasExplicitRange: true From 6de2e62c22984453a611f9f059bcf72b260bc624 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 4 Feb 2025 20:18:56 +0100 Subject: [PATCH 34/38] Update test --- .../recorded/actions/snippets/tryWrapThis.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/data/fixtures/recorded/actions/snippets/tryWrapThis.yml b/data/fixtures/recorded/actions/snippets/tryWrapThis.yml index 52995cd804..c2153c172d 100644 --- a/data/fixtures/recorded/actions/snippets/tryWrapThis.yml +++ b/data/fixtures/recorded/actions/snippets/tryWrapThis.yml @@ -6,7 +6,8 @@ command: name: wrapWithSnippet snippetDescription: type: custom - body: "try {\n\t$1\n} catch (err) {\n\t$0\n}\n" + variableName: try + body: "try {\n\t$try\n} catch (err) {\n\tcatch\n}" scopeTypes: - {type: statement} target: @@ -23,18 +24,17 @@ initialState: finalState: documentContents: |- try { - + const } catch (err) { - - } - foo = "bar"; + catch + } foo = "bar"; selections: - - anchor: {line: 1, character: 4} - active: {line: 1, character: 4} + - anchor: {line: 4, character: 1} + active: {line: 4, character: 1} thatMark: - type: UntypedTarget contentRange: start: {line: 0, character: 0} - end: {line: 5, character: 0} + end: {line: 4, character: 1} isReversed: false hasExplicitRange: true From 5d9d5fc8e789c2e20bef394713e1d65261eaa98f Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 4 Feb 2025 20:21:44 +0100 Subject: [PATCH 35/38] Properly fixed test --- .../recorded/actions/snippets/tryWrapThis.yml | 22 ++++++------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/data/fixtures/recorded/actions/snippets/tryWrapThis.yml b/data/fixtures/recorded/actions/snippets/tryWrapThis.yml index c2153c172d..26b2ec3145 100644 --- a/data/fixtures/recorded/actions/snippets/tryWrapThis.yml +++ b/data/fixtures/recorded/actions/snippets/tryWrapThis.yml @@ -7,9 +7,8 @@ command: snippetDescription: type: custom variableName: try - body: "try {\n\t$try\n} catch (err) {\n\tcatch\n}" - scopeTypes: - - {type: statement} + body: "try {\n\t$try\n} catch (err) {\n\t$catch\n}" + scopeType: {type: statement} target: type: primitive mark: {type: cursor} @@ -24,17 +23,10 @@ initialState: finalState: documentContents: |- try { - const + const foo = "bar"; } catch (err) { - catch - } foo = "bar"; + + } selections: - - anchor: {line: 4, character: 1} - active: {line: 4, character: 1} - thatMark: - - type: UntypedTarget - contentRange: - start: {line: 0, character: 0} - end: {line: 4, character: 1} - isReversed: false - hasExplicitRange: true + - anchor: {line: 3, character: 4} + active: {line: 3, character: 4} From 372ff5de9e6f07cce8160e44e987fa29e6041a3c Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 4 Feb 2025 20:23:48 +0100 Subject: [PATCH 36/38] Added that mark --- .../recorded/implicitExpansion/funkWrapPastInk.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/data/fixtures/recorded/implicitExpansion/funkWrapPastInk.yml b/data/fixtures/recorded/implicitExpansion/funkWrapPastInk.yml index 035506421d..6c1d62fb5a 100644 --- a/data/fixtures/recorded/implicitExpansion/funkWrapPastInk.yml +++ b/data/fixtures/recorded/implicitExpansion/funkWrapPastInk.yml @@ -39,3 +39,11 @@ finalState: selections: - anchor: {line: 0, character: 9} active: {line: 0, character: 9} + thatMark: + - type: UntypedTarget + contentRange: + start: {line: 0, character: 0} + end: {line: 4, character: 1} + isReversed: false + hasExplicitRange: true + From 8bca281a9361eb2959bc16008028557cef839200 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 4 Feb 2025 20:43:00 +0100 Subject: [PATCH 37/38] Update test --- data/fixtures/recorded/implicitExpansion/funkWrapPastInk.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/data/fixtures/recorded/implicitExpansion/funkWrapPastInk.yml b/data/fixtures/recorded/implicitExpansion/funkWrapPastInk.yml index 6c1d62fb5a..6a2a40c6f9 100644 --- a/data/fixtures/recorded/implicitExpansion/funkWrapPastInk.yml +++ b/data/fixtures/recorded/implicitExpansion/funkWrapPastInk.yml @@ -43,7 +43,6 @@ finalState: - type: UntypedTarget contentRange: start: {line: 0, character: 0} - end: {line: 4, character: 1} + end: {line: 3, character: 1} isReversed: false hasExplicitRange: true - From 67cf59dac7a51d03a00d19bae0ed9d4dfc991218 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Tue, 4 Feb 2025 20:43:45 +0100 Subject: [PATCH 38/38] Removed that --- .../recorded/implicitExpansion/funkWrapPastInk.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/data/fixtures/recorded/implicitExpansion/funkWrapPastInk.yml b/data/fixtures/recorded/implicitExpansion/funkWrapPastInk.yml index 6a2a40c6f9..035506421d 100644 --- a/data/fixtures/recorded/implicitExpansion/funkWrapPastInk.yml +++ b/data/fixtures/recorded/implicitExpansion/funkWrapPastInk.yml @@ -39,10 +39,3 @@ finalState: selections: - anchor: {line: 0, character: 9} active: {line: 0, character: 9} - thatMark: - - type: UntypedTarget - contentRange: - start: {line: 0, character: 0} - end: {line: 3, character: 1} - isReversed: false - hasExplicitRange: true