From 8dedf7e0661d61aed94abb48c8a348eaa8cc9630 Mon Sep 17 00:00:00 2001 From: fidgetingbits Date: Thu, 9 Nov 2023 09:55:57 +0800 Subject: [PATCH 1/2] Add language overrides for delimiter maps --- .../findSurroundingPairParseTreeBased.ts | 5 ++- .../findSurroundingPairTextBased.ts | 5 ++- .../{delimiterMaps.ts => getDelimiterMaps.ts} | 39 ++++++++++++++++++- .../getIndividualDelimiters.ts | 4 +- .../modifiers/surroundingPair/index.ts | 2 +- 5 files changed, 50 insertions(+), 5 deletions(-) rename packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/{delimiterMaps.ts => getDelimiterMaps.ts} (57%) diff --git a/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts b/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts index ccc756ea06..27e9ab3756 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/findSurroundingPairParseTreeBased.ts @@ -66,7 +66,10 @@ export function findSurroundingPairParseTreeBased( ) { const document: TextDocument = editor.document; - const individualDelimiters = getIndividualDelimiters(delimiters); + const individualDelimiters = getIndividualDelimiters( + document.languageId, + delimiters, + ); const delimiterTextToDelimiterInfoMap = Object.fromEntries( individualDelimiters.map((individualDelimiter) => [ diff --git a/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts b/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts index d0be1d0398..e221903c03 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts @@ -74,7 +74,10 @@ export function findSurroundingPairTextBased( const document: TextDocument = editor.document; const fullRange = allowableRange ?? document.range; - const individualDelimiters = getIndividualDelimiters(delimiters); + const individualDelimiters = getIndividualDelimiters( + document.languageId, + delimiters, + ); const delimiterTextToDelimiterInfoMap = Object.fromEntries( individualDelimiters.map((individualDelimiter) => [ diff --git a/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/delimiterMaps.ts b/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/getDelimiterMaps.ts similarity index 57% rename from packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/delimiterMaps.ts rename to packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/getDelimiterMaps.ts index b8e54be1fe..b826e0715e 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/delimiterMaps.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/getDelimiterMaps.ts @@ -5,7 +5,7 @@ import { type IndividualDelimiterText = string | string[]; -export const delimiterToText: Record< +const delimiterToText: Record< SimpleSurroundingPairName, [IndividualDelimiterText, IndividualDelimiterText] > = { @@ -25,6 +25,22 @@ export const delimiterToText: Record< squareBrackets: ["[", "]"], }; +const delimiterToTextNix: Record< + SimpleSurroundingPairName, + [IndividualDelimiterText, IndividualDelimiterText] +> = { + ...delimiterToText, + singleQuotes: ["''", "''"], +}; + +const delimiterToTextLua: Record< + SimpleSurroundingPairName, + [IndividualDelimiterText, IndividualDelimiterText] +> = { + ...delimiterToText, + // FIXME: Add [[ ]] somewhere +}; + export const leftToRightMap: Record = Object.fromEntries( Object.values(delimiterToText), ); @@ -46,3 +62,24 @@ export const complexDelimiterMap: Record< "angleBrackets", ], }; + +/** + * Given a language id, returns a list of all possible delimiters + * for that language. + * @param languageId The language id + * @returns A list of all possible delimiters for that language + */ +export function getSimpleDelimiterMap( + languageId: string, +): Record< + SimpleSurroundingPairName, + [IndividualDelimiterText, IndividualDelimiterText] +> { + if (languageId == "nix") { + return delimiterToTextNix; + } else if (languageId == "lua") { + return delimiterToTextLua; + } else { + return delimiterToText; + } +} diff --git a/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/getIndividualDelimiters.ts b/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/getIndividualDelimiters.ts index 16420cbf7a..f8f97a2ac8 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/getIndividualDelimiters.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/getIndividualDelimiters.ts @@ -1,6 +1,6 @@ import { SimpleSurroundingPairName } from "@cursorless/common"; import { IndividualDelimiter } from "./types"; -import { delimiterToText } from "./delimiterMaps"; +import { getSimpleDelimiterMap } from "./getDelimiterMaps"; import { concat, uniq } from "lodash"; import { isString } from "../../../util/type"; @@ -13,8 +13,10 @@ import { isString } from "../../../util/type"; * @returns A list of information about all possible left / right delimiter instances */ export function getIndividualDelimiters( + languageId: string, delimiters: SimpleSurroundingPairName[], ): IndividualDelimiter[] { + const delimiterToText = getSimpleDelimiterMap(languageId); return delimiters.flatMap((delimiter) => { const [leftDelimiter, rightDelimiter] = delimiterToText[delimiter]; diff --git a/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/index.ts b/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/index.ts index 52898d6e88..92f4452b67 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/index.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/index.ts @@ -9,7 +9,7 @@ import getTextFragmentExtractor from "../../../languages/getTextFragmentExtracto import { Target } from "../../../typings/target.types"; import { SurroundingPairTarget } from "../../targets"; import { getContainingScopeTarget } from "../getContainingScopeTarget"; -import { complexDelimiterMap } from "./delimiterMaps"; +import { complexDelimiterMap } from "./getDelimiterMaps"; import { SurroundingPairInfo } from "./extractSelectionFromSurroundingPairOffsets"; import { findSurroundingPairParseTreeBased } from "./findSurroundingPairParseTreeBased"; import { findSurroundingPairTextBased } from "./findSurroundingPairTextBased"; From e82832f4922c328290f61aed6ca7554807c44dd0 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Wed, 12 Jun 2024 21:24:57 +0100 Subject: [PATCH 2/2] Tweaks --- .../recorded/languages/lua/changeString2.yml | 23 +++++++ .../{getDelimiterMaps.ts => delimiterMaps.ts} | 65 ++++++++++++------- .../findSurroundingPairTextBased.ts | 5 +- .../getIndividualDelimiters.ts | 8 ++- .../modifiers/surroundingPair/index.ts | 2 +- 5 files changed, 70 insertions(+), 33 deletions(-) create mode 100644 data/fixtures/recorded/languages/lua/changeString2.yml rename packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/{getDelimiterMaps.ts => delimiterMaps.ts} (53%) diff --git a/data/fixtures/recorded/languages/lua/changeString2.yml b/data/fixtures/recorded/languages/lua/changeString2.yml new file mode 100644 index 0000000000..6bd5692747 --- /dev/null +++ b/data/fixtures/recorded/languages/lua/changeString2.yml @@ -0,0 +1,23 @@ +languageId: lua +command: + version: 7 + spokenForm: change string + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - type: containingScope + scopeType: {type: surroundingPair, delimiter: string} + usePrePhraseSnapshot: true +initialState: + documentContents: "[[aaa]]" + selections: + - anchor: {line: 0, character: 2} + active: {line: 0, character: 2} + marks: {} +finalState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} diff --git a/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/getDelimiterMaps.ts b/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/delimiterMaps.ts similarity index 53% rename from packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/getDelimiterMaps.ts rename to packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/delimiterMaps.ts index aa3ee76df0..bdea535cb6 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/getDelimiterMaps.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/delimiterMaps.ts @@ -6,10 +6,12 @@ import { unsafeKeys } from "../../../util/object"; type IndividualDelimiterText = string | string[]; -const delimiterToText: Record< +type DelimiterMap = Record< SimpleSurroundingPairName, [IndividualDelimiterText, IndividualDelimiterText] -> = Object.freeze({ +>; + +const delimiterToText: DelimiterMap = Object.freeze({ angleBrackets: [ ["", "/>"], @@ -26,20 +28,22 @@ const delimiterToText: Record< squareBrackets: ["[", "]"], }); -const delimiterToTextNix: Record< - SimpleSurroundingPairName, - [IndividualDelimiterText, IndividualDelimiterText] -> = { - ...delimiterToText, - singleQuotes: ["''", "''"], -}; +// FIXME: Probably remove these as part of +// https://github.com/cursorless-dev/cursorless/issues/1812#issuecomment-1691493746 +const delimiterToTextOverrides: Record> = { + nix: { + singleQuotes: ["''", "''"], + }, -const delimiterToTextLua: Record< - SimpleSurroundingPairName, - [IndividualDelimiterText, IndividualDelimiterText] -> = { - ...delimiterToText, - // FIXME: Add [[ ]] somewhere + lua: { + // FIXME: Add special double square brackets + // see https://github.com/cursorless-dev/cursorless/pull/2012#issuecomment-1808214409 + // see also https://github.com/cursorless-dev/cursorless/issues/1812#issuecomment-1691493746 + doubleQuotes: [ + ['"', "[["], + ['"', "]]"], + ], + }, }; export const leftToRightMap: Record = Object.fromEntries( @@ -65,22 +69,33 @@ export const complexDelimiterMap: Record< }; /** - * Given a language id, returns a list of all possible delimiters - * for that language. - * @param languageId The language id + * Given a language id, returns a list of all possible delimiters for that + * language. + * + * Allows us to support languages where the parse tree gives type names to nodes + * that don't correspond to the actual delimiter. + * + * Note that we pass in `undefined` if we are in a text fragment, because then + * we won't be using a parse tree. + * + * FIXME: Probably remove these as part of + * https://github.com/cursorless-dev/cursorless/issues/1812#issuecomment-1691493746 + * + * @param languageId The language id, or `undefined` if in a text fragment * @returns A list of all possible delimiters for that language */ export function getSimpleDelimiterMap( - languageId: string, + languageId: string | undefined, ): Record< SimpleSurroundingPairName, [IndividualDelimiterText, IndividualDelimiterText] > { - if (languageId == "nix") { - return delimiterToTextNix; - } else if (languageId == "lua") { - return delimiterToTextLua; - } else { - return delimiterToText; + if (languageId != null && languageId in delimiterToTextOverrides) { + return { + ...delimiterToText, + ...delimiterToTextOverrides[languageId], + }; } + + return delimiterToText; } diff --git a/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts b/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts index e221903c03..1b24505dce 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/findSurroundingPairTextBased.ts @@ -74,10 +74,7 @@ export function findSurroundingPairTextBased( const document: TextDocument = editor.document; const fullRange = allowableRange ?? document.range; - const individualDelimiters = getIndividualDelimiters( - document.languageId, - delimiters, - ); + const individualDelimiters = getIndividualDelimiters(undefined, delimiters); const delimiterTextToDelimiterInfoMap = Object.fromEntries( individualDelimiters.map((individualDelimiter) => [ diff --git a/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/getIndividualDelimiters.ts b/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/getIndividualDelimiters.ts index 4bfb13760f..e63a8a8d69 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/getIndividualDelimiters.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/getIndividualDelimiters.ts @@ -1,6 +1,6 @@ import { SimpleSurroundingPairName, isString } from "@cursorless/common"; import { IndividualDelimiter } from "./types"; -import { getSimpleDelimiterMap } from "./getDelimiterMaps"; +import { getSimpleDelimiterMap } from "./delimiterMaps"; import { concat, uniq } from "lodash"; /** @@ -8,11 +8,13 @@ import { concat, uniq } from "lodash"; * a single right or left delimiter. Each item contains information such as a * reference to delimiter name, the text to expect, etc. * + * @param languageId The language id, or `undefined` if in a text fragment * @param delimiters The delimiter names - * @returns A list of information about all possible left / right delimiter instances + * @returns A list of information about all possible left / right delimiter + * instances */ export function getIndividualDelimiters( - languageId: string, + languageId: string | undefined, delimiters: SimpleSurroundingPairName[], ): IndividualDelimiter[] { const delimiterToText = getSimpleDelimiterMap(languageId); diff --git a/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/index.ts b/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/index.ts index d92c16848f..f81ef8ebab 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/index.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/surroundingPair/index.ts @@ -7,7 +7,7 @@ import { LanguageDefinitions } from "../../../languages/LanguageDefinitions"; import { Target } from "../../../typings/target.types"; import { SurroundingPairTarget } from "../../targets"; import { getContainingScopeTarget } from "../getContainingScopeTarget"; -import { complexDelimiterMap } from "./getDelimiterMaps"; +import { complexDelimiterMap } from "./delimiterMaps"; import { SurroundingPairInfo } from "./extractSelectionFromSurroundingPairOffsets"; import { findSurroundingPairParseTreeBased } from "./findSurroundingPairParseTreeBased"; import { findSurroundingPairTextBased } from "./findSurroundingPairTextBased";