diff --git a/src/languages/clojure.ts b/src/languages/clojure.ts new file mode 100644 index 0000000000..52ff55324f --- /dev/null +++ b/src/languages/clojure.ts @@ -0,0 +1,192 @@ +import { + cascadingMatcher, + chainedMatcher, + createPatternMatchers, + matcher, + patternMatcher, +} from "../util/nodeMatchers"; +import { + ScopeType, + NodeMatcherAlternative, + NodeFinder, +} from "../typings/Types"; +import { SyntaxNode } from "web-tree-sitter"; +import { delimitedSelector } from "../util/nodeSelectors"; +import { flow, identity } from "lodash"; +import { getChildNodesForFieldName } from "../util/treeSitterUtils"; +import { patternFinder } from "../util/nodeFinders"; + +/** + * Picks a node by rounding down and using the given parity. This function is + * useful for picking the picking eg the key in a sequence of key-value pairs + * @param parentFinder The finder to use to determine whether the parent is a + * match + * @param parity The parity that we're looking for + * @returns A node finder + */ +function parityNodeFinder(parentFinder: NodeFinder, parity: 0 | 1) { + return indexNodeFinder( + parentFinder, + (nodeIndex: number) => Math.floor(nodeIndex / 2) * 2 + parity + ); +} + +function mapParityNodeFinder(parity: 0 | 1) { + return parityNodeFinder(patternFinder("map_lit"), parity); +} + +/** + * Creates a node finder which will apply a transformation to the index of a + * value node and return the node at the given index of the nodes parent + * @param parentFinder A finder which will be applied to the parent to determine + * whether it is a match + * @param indexTransform A function that will be applied to the index of the + * value node. The node at the given index will be used instead of the node + * itself + * @returns A node finder based on the given description + */ +function indexNodeFinder( + parentFinder: NodeFinder, + indexTransform: (index: number) => number +) { + return (node: SyntaxNode) => { + const parent = node.parent; + + if (parent == null || parentFinder(parent) == null) { + return null; + } + + const valueNodes = getValueNodes(parent); + + const nodeIndex = valueNodes.findIndex(({ id }) => id === node.id); + + if (nodeIndex === -1) { + // TODO: In the future we might conceivably try to handle saying "take + // item" when the selection is inside a comment between the key and value + return null; + } + + const desiredIndex = indexTransform(nodeIndex); + + if (desiredIndex === -1) { + return null; + } + + return valueNodes[desiredIndex]; + }; +} + +function itemFinder() { + return indexNodeFinder( + (node) => node, + (nodeIndex: number) => nodeIndex + ); +} + +/** + * Return the "value" node children of a given node. These are the items in a list + * @param node The node whose children to get + * @returns A list of the value node children of the given node + */ +const getValueNodes = (node: SyntaxNode) => + getChildNodesForFieldName(node, "value"); + +// A function call is a list literal which is not quoted +const functionCallPattern = "~quoting_lit.list_lit!"; +const functionCallFinder = patternFinder(functionCallPattern); + +/** + * Matches a function call if the name of the function is one of the given names + * @param names The acceptable function names + * @returns The function call node if the name matches otherwise null + */ +function functionNameBasedFinder(...names: string[]) { + return (node: SyntaxNode) => { + const functionCallNode = functionCallFinder(node); + if (functionCallNode == null) { + return null; + } + + const functionNode = getValueNodes(functionCallNode)[0]; + + return names.includes(functionNode?.text) ? functionCallNode : null; + }; +} + +function functionNameBasedMatcher(...names: string[]) { + return matcher(functionNameBasedFinder(...names)); +} + +const functionFinder = functionNameBasedFinder("defn", "defmacro"); + +const functionNameMatcher = chainedMatcher([ + functionFinder, + (functionNode) => getValueNodes(functionNode)[1], +]); + +const ifStatementFinder = functionNameBasedFinder( + "if", + "if-let", + "when", + "when-let" +); + +const ifStatementMatcher = matcher(ifStatementFinder); + +const nodeMatchers: Partial> = { + comment: "comment", + map: "map_lit", + + collectionKey: matcher(mapParityNodeFinder(0)), + collectionItem: cascadingMatcher( + // Treat each key value pair as a single item if we're in a map + matcher( + mapParityNodeFinder(0), + delimitedSelector( + (node) => node.type === "{" || node.type === "}", + ", ", + identity, + mapParityNodeFinder(1) as (node: SyntaxNode) => SyntaxNode + ) + ), + + // Otherwise just treat every item within a list as an item + matcher(itemFinder()) + ), + value: matcher(mapParityNodeFinder(1)), + + // TODO: Handle formal parameters + argumentOrParameter: matcher( + indexNodeFinder(patternFinder(functionCallPattern), (nodeIndex: number) => + nodeIndex !== 0 ? nodeIndex : -1 + ) + ), + + // A list is either a vector literal or a quoted list literal + list: ["vec_lit", "quoting_lit.list_lit"], + + string: "str_lit", + + functionCall: functionCallPattern, + + namedFunction: matcher(functionFinder), + + functionName: functionNameMatcher, + + // TODO: Handle `let` declarations, defs, etc + name: functionNameMatcher, + + anonymousFunction: cascadingMatcher( + functionNameBasedMatcher("fn"), + patternMatcher("anon_fn_lit") + ), + + ifStatement: ifStatementMatcher, + + condition: chainedMatcher([ + ifStatementFinder, + (node) => getValueNodes(node)[1], + ]), +}; + +export default createPatternMatchers(nodeMatchers); diff --git a/src/languages/constants.ts b/src/languages/constants.ts index 2ead5eb26e..86bc029c1e 100644 --- a/src/languages/constants.ts +++ b/src/languages/constants.ts @@ -1,5 +1,6 @@ export const supportedLanguageIds = [ "c", + "clojure", "cpp", "csharp", "java", diff --git a/src/languages/csharp.ts b/src/languages/csharp.ts index e9e7f77f4a..4d91f3a473 100644 --- a/src/languages/csharp.ts +++ b/src/languages/csharp.ts @@ -1,7 +1,7 @@ import { SyntaxNode } from "web-tree-sitter"; import { cascadingMatcher, - composedMatcher, + chainedMatcher, createPatternMatchers, matcher, trailingMatcher, @@ -162,26 +162,26 @@ const makeDelimitedSelector = (leftType: string, rightType: string) => const getMapMatchers = { map: cascadingMatcher( - composedMatcher([ + chainedMatcher([ typedNodeFinder(...OBJECT_TYPES_WITH_INITIALIZERS_AS_CHILDREN), getChildInitializerNode, ]), - composedMatcher([ + chainedMatcher([ typedNodeFinder("object_creation_expression"), getInitializerNode, ]) ), - collectionKey: composedMatcher([ + collectionKey: chainedMatcher([ typedNodeFinder("assignment_expression"), (node: SyntaxNode) => node.childForFieldName("left"), ]), value: matcher((node: SyntaxNode) => node.childForFieldName("right")), list: cascadingMatcher( - composedMatcher([ + chainedMatcher([ typedNodeFinder(...LIST_TYPES_WITH_INITIALIZERS_AS_CHILDREN), getChildInitializerNode, ]), - composedMatcher([ + chainedMatcher([ typedNodeFinder("object_creation_expression"), (node: SyntaxNode) => node.childForFieldName("initializer"), ]) diff --git a/src/languages/getNodeMatcher.ts b/src/languages/getNodeMatcher.ts index 85ddb7ab84..830790c2b5 100644 --- a/src/languages/getNodeMatcher.ts +++ b/src/languages/getNodeMatcher.ts @@ -8,10 +8,11 @@ import { SelectionWithEditor, } from "../typings/Types"; import cpp from "./cpp"; +import clojure from "./clojure"; import csharp from "./csharp"; import { patternMatchers as json } from "./json"; import { patternMatchers as typescript } from "./typescript"; -import { patternMatchers as java } from "./java"; +import java from "./java"; import python from "./python"; import { UnsupportedLanguageError } from "../errors"; import { SupportedLanguageId } from "./constants"; @@ -45,7 +46,8 @@ const languageMatchers: Record< Record > = { c: cpp, - cpp: cpp, + clojure, + cpp, csharp: csharp, java, javascript: typescript, diff --git a/src/languages/getTextFragmentExtractor.ts b/src/languages/getTextFragmentExtractor.ts index 2ca609667a..1c955c04d7 100644 --- a/src/languages/getTextFragmentExtractor.ts +++ b/src/languages/getTextFragmentExtractor.ts @@ -1,7 +1,6 @@ import { SyntaxNode } from "web-tree-sitter"; import { SelectionWithEditor } from "../typings/Types"; import { stringTextFragmentExtractor as jsonStringTextFragmentExtractor } from "./json"; -import { stringTextFragmentExtractor as javaStringTextFragmentExtractor } from "./java"; import { stringTextFragmentExtractor as typescriptStringTextFragmentExtractor } from "./typescript"; import { UnsupportedLanguageError } from "../errors"; import { Range } from "vscode"; @@ -67,6 +66,33 @@ function constructDefaultStringTextFragmentExtractor( }; } +/** + * Extracts string text fragments in languages that don't have quotation mark + * tokens as children of string tokens, but instead include them in the text of + * the string. + * + * This is a hack. Rather than letting the parse tree handle the quotation marks + * in java, we instead just let the textual surround handle them by letting it + * see the quotation marks. In other languages we prefer to let the parser + * handle the quotation marks in case they are more than one character long. + * @param node The node which might be a string node + * @param selection The selection from which to expand + * @returns The range of the string text or null if the node is not a string + */ +function constructHackedStringTextFragmentExtractor( + languageId: SupportedLanguageId +) { + const stringNodeMatcher = getNodeMatcher(languageId, "string", false); + + return (node: SyntaxNode, selection: SelectionWithEditor) => { + if (stringNodeMatcher(selection, node) != null) { + return getNodeRange(node); + } + + return null; + }; +} + /** * Returns a function which can be used to extract the range of a text fragment * from within a parsed language. This function should only return a nominal @@ -94,11 +120,15 @@ const textFragmentExtractors: Record< TextFragmentExtractor > = { c: constructDefaultTextFragmentExtractor("c"), + clojure: constructDefaultTextFragmentExtractor( + "clojure", + constructHackedStringTextFragmentExtractor("clojure") + ), cpp: constructDefaultTextFragmentExtractor("cpp"), csharp: constructDefaultTextFragmentExtractor("csharp"), java: constructDefaultTextFragmentExtractor( "java", - javaStringTextFragmentExtractor + constructHackedStringTextFragmentExtractor("java") ), javascript: constructDefaultTextFragmentExtractor( "javascript", diff --git a/src/languages/java.ts b/src/languages/java.ts index be406a45c8..f137cd0fcd 100644 --- a/src/languages/java.ts +++ b/src/languages/java.ts @@ -5,13 +5,7 @@ import { conditionMatcher, trailingMatcher, } from "../util/nodeMatchers"; -import { - NodeMatcherAlternative, - ScopeType, - SelectionWithEditor, -} from "../typings/Types"; -import { getNodeRange } from "../util/nodeSelectors"; -import { SyntaxNode } from "web-tree-sitter"; +import { NodeMatcherAlternative, ScopeType } from "../typings/Types"; // Generated by the following command: // > curl https://raw.githubusercontent.com/tree-sitter/tree-sitter-java/master/src/node-types.json | jq '[.[] | select(.type == "statement" or .type == "declaration") | .subtypes[].type]' @@ -78,28 +72,4 @@ const nodeMatchers: Partial> = { argumentOrParameter: argumentMatcher("formal_parameters", "argument_list"), }; -export const patternMatchers = createPatternMatchers(nodeMatchers); - -/** - * Extracts string text fragments in java. - * - * This is a hack to deal with the fact that java doesn't have - * quotation mark tokens as children of the string. Rather than letting - * the parse tree handle the quotation marks in java, we instead just - * let the textual surround handle them by letting it see the quotation - * marks. In other languages we prefer to let the parser handle the - * quotation marks in case they are more than one character long. - * @param node The node which might be a string node - * @param selection The selection from which to expand - * @returns The range of the string text or null if the node is not a string - */ -export function stringTextFragmentExtractor( - node: SyntaxNode, - selection: SelectionWithEditor -) { - if (node.type === "string_literal") { - return getNodeRange(node); - } - - return null; -} +export default createPatternMatchers(nodeMatchers); diff --git a/src/test/suite/fixtures/recorded/languages/clojure/chuckItemFine.yml b/src/test/suite/fixtures/recorded/languages/clojure/chuckItemFine.yml new file mode 100644 index 0000000000..f681967189 --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/chuckItemFine.yml @@ -0,0 +1,36 @@ +languageId: clojure +command: + version: 0 + spokenForm: chuck item fine + action: remove + targets: + - type: primitive + modifier: {type: containingScope, scopeType: collectionItem, includeSiblings: false} + mark: {type: decoratedSymbol, symbolColor: default, character: f, usePrePhraseSnapshot: true} +initialState: + documentContents: |- + { + :foo "bar", + ;; hello + :baz "whatever", + } + selections: + - anchor: {line: 4, character: 1} + active: {line: 4, character: 1} + marks: + default.f: + start: {line: 1, character: 5} + end: {line: 1, character: 8} +finalState: + documentContents: |- + { + ;; hello + :baz "whatever", + } + selections: + - anchor: {line: 3, character: 1} + active: {line: 3, character: 1} + thatMark: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: f, usePrePhraseSnapshot: true}, selectionType: token, position: contents, insideOutsideType: outside, modifier: {type: containingScope, scopeType: collectionItem, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/chuckItemFine2.yml b/src/test/suite/fixtures/recorded/languages/clojure/chuckItemFine2.yml new file mode 100644 index 0000000000..1a0800288e --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/chuckItemFine2.yml @@ -0,0 +1,34 @@ +languageId: clojure +command: + version: 0 + spokenForm: chuck item fine + action: remove + targets: + - type: primitive + modifier: {type: containingScope, scopeType: collectionItem, includeSiblings: false} + mark: {type: decoratedSymbol, symbolColor: default, character: f, usePrePhraseSnapshot: true} +initialState: + documentContents: |- + { + :foo "bar", + :baz "whatever", + } + selections: + - anchor: {line: 3, character: 1} + active: {line: 3, character: 1} + marks: + default.f: + start: {line: 1, character: 5} + end: {line: 1, character: 8} +finalState: + documentContents: |- + { + :baz "whatever", + } + selections: + - anchor: {line: 2, character: 1} + active: {line: 2, character: 1} + thatMark: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: f, usePrePhraseSnapshot: true}, selectionType: token, position: contents, insideOutsideType: outside, modifier: {type: containingScope, scopeType: collectionItem, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/chuckItemZip.yml b/src/test/suite/fixtures/recorded/languages/clojure/chuckItemZip.yml new file mode 100644 index 0000000000..56537e57ba --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/chuckItemZip.yml @@ -0,0 +1,37 @@ +languageId: clojure +command: + version: 0 + spokenForm: chuck item zip + action: remove + targets: + - type: primitive + modifier: {type: containingScope, scopeType: collectionItem, includeSiblings: false} + mark: {type: decoratedSymbol, symbolColor: default, character: z, usePrePhraseSnapshot: true} +initialState: + documentContents: |- + { + :foo "bar", + ;; hello + :baz "whatever", + } + selections: + - anchor: {line: 4, character: 1} + active: {line: 4, character: 1} + marks: + default.z: + start: {line: 3, character: 5} + end: {line: 3, character: 8} +finalState: + documentContents: |- + { + :foo "bar", + ;; hello + , + } + selections: + - anchor: {line: 4, character: 1} + active: {line: 4, character: 1} + thatMark: + - anchor: {line: 3, character: 0} + active: {line: 3, character: 0} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: z, usePrePhraseSnapshot: true}, selectionType: token, position: contents, insideOutsideType: outside, modifier: {type: containingScope, scopeType: collectionItem, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/chuckItemZip2.yml b/src/test/suite/fixtures/recorded/languages/clojure/chuckItemZip2.yml new file mode 100644 index 0000000000..669fe853e1 --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/chuckItemZip2.yml @@ -0,0 +1,34 @@ +languageId: clojure +command: + version: 0 + spokenForm: chuck item zip + action: remove + targets: + - type: primitive + modifier: {type: containingScope, scopeType: collectionItem, includeSiblings: false} + mark: {type: decoratedSymbol, symbolColor: default, character: z, usePrePhraseSnapshot: true} +initialState: + documentContents: |- + { + :foo "bar", + :baz "whatever", + } + selections: + - anchor: {line: 3, character: 1} + active: {line: 3, character: 1} + marks: + default.z: + start: {line: 2, character: 5} + end: {line: 2, character: 8} +finalState: + documentContents: |- + { + :foo "bar", + } + selections: + - anchor: {line: 2, character: 1} + active: {line: 2, character: 1} + thatMark: + - anchor: {line: 1, character: 14} + active: {line: 1, character: 14} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: z, usePrePhraseSnapshot: true}, selectionType: token, position: contents, insideOutsideType: outside, modifier: {type: containingScope, scopeType: collectionItem, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearArgue.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearArgue.yml new file mode 100644 index 0000000000..e0fef982b3 --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearArgue.yml @@ -0,0 +1,43 @@ +languageId: clojure +command: + version: 1 + spokenForm: clear argue + action: clearAndSetSelection + targets: + - type: primitive + modifier: + { + type: containingScope, + scopeType: argumentOrParameter, + includeSiblings: false, + } +initialState: + documentContents: (foo :bar) + selections: + - anchor: { line: 0, character: 6 } + active: { line: 0, character: 6 } + marks: {} +finalState: + documentContents: (foo ) + selections: + - anchor: { line: 0, character: 5 } + active: { line: 0, character: 5 } + thatMark: + - anchor: { line: 0, character: 5 } + active: { line: 0, character: 5 } +fullTargets: + [ + { + type: primitive, + mark: { type: cursor }, + selectionType: token, + position: contents, + insideOutsideType: inside, + modifier: + { + type: containingScope, + scopeType: argumentOrParameter, + includeSiblings: false, + }, + }, + ] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearArgue2.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearArgue2.yml new file mode 100644 index 0000000000..0ec0032a5f --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearArgue2.yml @@ -0,0 +1,23 @@ +languageId: clojure +command: + version: 1 + spokenForm: clear argue + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: argumentOrParameter, includeSiblings: false} +initialState: + documentContents: (hello (foo :bar)) + selections: + - anchor: {line: 0, character: 10} + active: {line: 0, character: 10} + marks: {} +finalState: + documentContents: (hello ) + selections: + - anchor: {line: 0, character: 7} + active: {line: 0, character: 7} + thatMark: + - anchor: {line: 0, character: 7} + active: {line: 0, character: 7} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: argumentOrParameter, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearArgue3.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearArgue3.yml new file mode 100644 index 0000000000..aaa1788ed1 --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearArgue3.yml @@ -0,0 +1,23 @@ +languageId: clojure +command: + version: 1 + spokenForm: clear argue + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: argumentOrParameter, includeSiblings: false} +initialState: + documentContents: (foo '(hello there)) + selections: + - anchor: {line: 0, character: 17} + active: {line: 0, character: 17} + marks: {} +finalState: + documentContents: (foo ) + selections: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} + thatMark: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: argumentOrParameter, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearCall.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearCall.yml new file mode 100644 index 0000000000..5e5717b25c --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearCall.yml @@ -0,0 +1,23 @@ +languageId: clojure +command: + version: 0 + spokenForm: clear call + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: functionCall, includeSiblings: false} +initialState: + documentContents: (hello) + 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} + thatMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: functionCall, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearCall2.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearCall2.yml new file mode 100644 index 0000000000..30bafe20ec --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearCall2.yml @@ -0,0 +1,23 @@ +languageId: clojure +command: + version: 0 + spokenForm: clear call + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: functionCall, includeSiblings: false} +initialState: + documentContents: (foo '(bar)) + selections: + - anchor: {line: 0, character: 9} + active: {line: 0, character: 9} + marks: {} +finalState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: functionCall, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearComment.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearComment.yml new file mode 100644 index 0000000000..d56eaa5b67 --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearComment.yml @@ -0,0 +1,23 @@ +languageId: clojure +command: + version: 0 + spokenForm: clear comment + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: comment, includeSiblings: false} +initialState: + documentContents: ;; hello + selections: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 6} + marks: {} +finalState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: comment, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearCondition.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearCondition.yml new file mode 100644 index 0000000000..95c1224bea --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearCondition.yml @@ -0,0 +1,23 @@ +languageId: clojure +command: + version: 1 + spokenForm: clear condition + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: condition, includeSiblings: false} +initialState: + documentContents: (if true "hello") + selections: + - anchor: {line: 0, character: 14} + active: {line: 0, character: 14} + marks: {} +finalState: + documentContents: (if "hello") + selections: + - anchor: {line: 0, character: 4} + active: {line: 0, character: 4} + thatMark: + - anchor: {line: 0, character: 4} + active: {line: 0, character: 4} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: condition, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearEveryItem.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearEveryItem.yml new file mode 100644 index 0000000000..1b44562896 --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearEveryItem.yml @@ -0,0 +1,39 @@ +languageId: clojure +command: + version: 0 + spokenForm: clear every item + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: collectionItem, includeSiblings: true} +initialState: + documentContents: |- + + { + :foo "bar", + ;; hello + :baz "whatever", + } + selections: + - anchor: {line: 4, character: 13} + active: {line: 4, character: 13} + marks: {} +finalState: + documentContents: |- + + { + , + ;; hello + , + } + selections: + - anchor: {line: 2, character: 4} + active: {line: 2, character: 4} + - anchor: {line: 4, character: 4} + active: {line: 4, character: 4} + thatMark: + - anchor: {line: 2, character: 4} + active: {line: 2, character: 4} + - anchor: {line: 4, character: 4} + active: {line: 4, character: 4} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: collectionItem, includeSiblings: true}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearEveryKey.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearEveryKey.yml new file mode 100644 index 0000000000..4b90516c91 --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearEveryKey.yml @@ -0,0 +1,39 @@ +languageId: clojure +command: + version: 0 + spokenForm: clear every key + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: collectionKey, includeSiblings: true} +initialState: + documentContents: |- + + { + :foo "bar", + ;; hello + :baz "whatever", + } + selections: + - anchor: {line: 4, character: 13} + active: {line: 4, character: 13} + marks: {} +finalState: + documentContents: |- + + { + "bar", + ;; hello + "whatever", + } + selections: + - anchor: {line: 2, character: 4} + active: {line: 2, character: 4} + - anchor: {line: 4, character: 4} + active: {line: 4, character: 4} + thatMark: + - anchor: {line: 2, character: 4} + active: {line: 2, character: 4} + - anchor: {line: 4, character: 4} + active: {line: 4, character: 4} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: collectionKey, includeSiblings: true}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearEveryValue.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearEveryValue.yml new file mode 100644 index 0000000000..8f7660574c --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearEveryValue.yml @@ -0,0 +1,39 @@ +languageId: clojure +command: + version: 0 + spokenForm: clear every value + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: value, includeSiblings: true} +initialState: + documentContents: |- + + { + :foo "bar", + ;; hello + :baz "whatever", + } + selections: + - anchor: {line: 4, character: 13} + active: {line: 4, character: 13} + marks: {} +finalState: + documentContents: |- + + { + :foo , + ;; hello + :baz , + } + selections: + - anchor: {line: 2, character: 9} + active: {line: 2, character: 9} + - anchor: {line: 4, character: 9} + active: {line: 4, character: 9} + thatMark: + - anchor: {line: 2, character: 9} + active: {line: 2, character: 9} + - anchor: {line: 4, character: 9} + active: {line: 4, character: 9} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: value, includeSiblings: true}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearFunk.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearFunk.yml new file mode 100644 index 0000000000..c84e629bd3 --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearFunk.yml @@ -0,0 +1,26 @@ +languageId: clojure +command: + version: 1 + spokenForm: clear funk + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: namedFunction, includeSiblings: false} +initialState: + documentContents: |- + (defn say-hello + [name] + (println (str "Hello, " name))) + selections: + - anchor: {line: 2, character: 4} + active: {line: 2, character: 4} + marks: {} +finalState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: namedFunction, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearFunk2.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearFunk2.yml new file mode 100644 index 0000000000..a63eb4e510 --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearFunk2.yml @@ -0,0 +1,23 @@ +languageId: clojure +command: + version: 1 + spokenForm: clear funk + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: namedFunction, includeSiblings: false} +initialState: + documentContents: (defmacro foo [bar] "baz" (bongo)) + selections: + - anchor: {line: 0, character: 30} + active: {line: 0, character: 30} + marks: {} +finalState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: namedFunction, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearIfState.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearIfState.yml new file mode 100644 index 0000000000..8161fb3c4b --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearIfState.yml @@ -0,0 +1,23 @@ +languageId: clojure +command: + version: 1 + spokenForm: clear if state + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: ifStatement, includeSiblings: false} +initialState: + documentContents: (if true "hello") + selections: + - anchor: {line: 0, character: 14} + active: {line: 0, character: 14} + marks: {} +finalState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: ifStatement, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearItem.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearItem.yml new file mode 100644 index 0000000000..2ecf967339 --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearItem.yml @@ -0,0 +1,33 @@ +languageId: clojure +command: + version: 0 + spokenForm: clear item + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: collectionItem, includeSiblings: false} +initialState: + documentContents: |- + { + :bongo { + :foo "bar", + ;; hello + :baz "whatever", + } + } + selections: + - anchor: {line: 3, character: 13} + active: {line: 3, character: 13} + marks: {} +finalState: + documentContents: |- + { + + } + selections: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} + thatMark: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: collectionItem, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearItem2.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearItem2.yml new file mode 100644 index 0000000000..e5e37e6457 --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearItem2.yml @@ -0,0 +1,23 @@ +languageId: clojure +command: + version: 1 + spokenForm: clear item + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: collectionItem, includeSiblings: false} +initialState: + documentContents: (foo :bar) + selections: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 6} + marks: {} +finalState: + documentContents: (foo ) + selections: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} + thatMark: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: collectionItem, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearItem3.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearItem3.yml new file mode 100644 index 0000000000..0114c2c0d7 --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearItem3.yml @@ -0,0 +1,23 @@ +languageId: clojure +command: + version: 1 + spokenForm: clear item + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: collectionItem, includeSiblings: false} +initialState: + documentContents: (foo) + selections: + - anchor: {line: 0, character: 3} + active: {line: 0, character: 3} + marks: {} +finalState: + documentContents: () + selections: + - anchor: {line: 0, character: 1} + active: {line: 0, character: 1} + thatMark: + - anchor: {line: 0, character: 1} + active: {line: 0, character: 1} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: collectionItem, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearItem4.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearItem4.yml new file mode 100644 index 0000000000..b71ffc8a78 --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearItem4.yml @@ -0,0 +1,23 @@ +languageId: clojure +command: + version: 1 + spokenForm: clear item + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: collectionItem, includeSiblings: false} +initialState: + documentContents: (foo (hello there)) + selections: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} + marks: {} +finalState: + documentContents: (foo ) + selections: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} + thatMark: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: collectionItem, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearItem5.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearItem5.yml new file mode 100644 index 0000000000..e0b5b48cad --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearItem5.yml @@ -0,0 +1,23 @@ +languageId: clojure +command: + version: 1 + spokenForm: clear item + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: collectionItem, includeSiblings: false} +initialState: + documentContents: "'(foo bar)" + selections: + - anchor: {line: 0, character: 3} + active: {line: 0, character: 3} + marks: {} +finalState: + documentContents: "'( bar)" + selections: + - anchor: {line: 0, character: 2} + active: {line: 0, character: 2} + thatMark: + - anchor: {line: 0, character: 2} + active: {line: 0, character: 2} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: collectionItem, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearItem6.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearItem6.yml new file mode 100644 index 0000000000..fc7311c5b4 --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearItem6.yml @@ -0,0 +1,23 @@ +languageId: clojure +command: + version: 1 + spokenForm: clear item + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: collectionItem, includeSiblings: false} +initialState: + documentContents: "[foo :bar]" + selections: + - anchor: {line: 0, character: 7} + active: {line: 0, character: 7} + marks: {} +finalState: + documentContents: "[foo ]" + selections: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} + thatMark: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: collectionItem, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearItemBat.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearItemBat.yml new file mode 100644 index 0000000000..681632ab9e --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearItemBat.yml @@ -0,0 +1,35 @@ +languageId: clojure +command: + version: 0 + spokenForm: clear item bat + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: collectionItem, includeSiblings: false} + mark: {type: decoratedSymbol, symbolColor: default, character: b, usePrePhraseSnapshot: true} +initialState: + documentContents: |- + { + :baz + ;; hello + "whatever", + } + selections: + - anchor: {line: 4, character: 1} + active: {line: 4, character: 1} + marks: + default.b: + start: {line: 1, character: 5} + end: {line: 1, character: 8} +finalState: + documentContents: |- + { + , + } + selections: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} + thatMark: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: b, usePrePhraseSnapshot: true}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: collectionItem, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearItemBatClearItemBat.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearItemBatClearItemBat.yml new file mode 100644 index 0000000000..4d69bb45a8 --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearItemBatClearItemBat.yml @@ -0,0 +1,27 @@ +languageId: clojure +command: + version: 0 + spokenForm: clear item bat clear item bat + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: collectionItem, includeSiblings: false} + mark: {type: decoratedSymbol, symbolColor: default, character: b, usePrePhraseSnapshot: true} +initialState: + documentContents: "{:foo \"bar\"}" + selections: + - anchor: {line: 0, character: 12} + active: {line: 0, character: 12} + marks: + default.b: + start: {line: 0, character: 7} + end: {line: 0, character: 10} +finalState: + documentContents: "{}" + selections: + - anchor: {line: 0, character: 1} + active: {line: 0, character: 1} + thatMark: + - anchor: {line: 0, character: 1} + active: {line: 0, character: 1} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: b, usePrePhraseSnapshot: true}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: collectionItem, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearItemFine.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearItemFine.yml new file mode 100644 index 0000000000..8c92e6f215 --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearItemFine.yml @@ -0,0 +1,27 @@ +languageId: clojure +command: + version: 0 + spokenForm: clear item fine + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: collectionItem, includeSiblings: false} + mark: {type: decoratedSymbol, symbolColor: default, character: f, usePrePhraseSnapshot: true} +initialState: + documentContents: "{:foo \"bar\" :baz \"whatever\"}" + selections: + - anchor: {line: 0, character: 28} + active: {line: 0, character: 28} + marks: + default.f: + start: {line: 0, character: 2} + end: {line: 0, character: 5} +finalState: + documentContents: "{ :baz \"whatever\"}" + selections: + - anchor: {line: 0, character: 1} + active: {line: 0, character: 1} + thatMark: + - anchor: {line: 0, character: 1} + active: {line: 0, character: 1} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: f, usePrePhraseSnapshot: true}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: collectionItem, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearItemWhale.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearItemWhale.yml new file mode 100644 index 0000000000..6518d1b4c6 --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearItemWhale.yml @@ -0,0 +1,27 @@ +languageId: clojure +command: + version: 0 + spokenForm: clear item whale + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: collectionItem, includeSiblings: false} + mark: {type: decoratedSymbol, symbolColor: default, character: w, usePrePhraseSnapshot: true} +initialState: + documentContents: "{:foo \"bar\", :baz \"whatever\"}" + selections: + - anchor: {line: 0, character: 29} + active: {line: 0, character: 29} + marks: + default.w: + start: {line: 0, character: 19} + end: {line: 0, character: 27} +finalState: + documentContents: "{:foo \"bar\", }" + selections: + - anchor: {line: 0, character: 13} + active: {line: 0, character: 13} + thatMark: + - anchor: {line: 0, character: 13} + active: {line: 0, character: 13} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: w, usePrePhraseSnapshot: true}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: collectionItem, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearItemZip.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearItemZip.yml new file mode 100644 index 0000000000..70353e8d4a --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearItemZip.yml @@ -0,0 +1,27 @@ +languageId: clojure +command: + version: 0 + spokenForm: clear item zip + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: collectionItem, includeSiblings: false} + mark: {type: decoratedSymbol, symbolColor: default, character: z, usePrePhraseSnapshot: true} +initialState: + documentContents: "{:foo \"bar\", :baz \"whatever\"}" + selections: + - anchor: {line: 0, character: 29} + active: {line: 0, character: 29} + marks: + default.z: + start: {line: 0, character: 14} + end: {line: 0, character: 17} +finalState: + documentContents: "{:foo \"bar\", }" + selections: + - anchor: {line: 0, character: 13} + active: {line: 0, character: 13} + thatMark: + - anchor: {line: 0, character: 13} + active: {line: 0, character: 13} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: z, usePrePhraseSnapshot: true}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: collectionItem, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearKey.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearKey.yml new file mode 100644 index 0000000000..79fc5686ca --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearKey.yml @@ -0,0 +1,23 @@ +languageId: clojure +command: + version: 0 + spokenForm: clear key + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: collectionKey, includeSiblings: false} +initialState: + documentContents: "{:baz {:foo \"bar\"}}" + selections: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 6} + marks: {} +finalState: + documentContents: "{ {:foo \"bar\"}}" + selections: + - anchor: {line: 0, character: 1} + active: {line: 0, character: 1} + thatMark: + - anchor: {line: 0, character: 1} + active: {line: 0, character: 1} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: collectionKey, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearKeyWhale.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearKeyWhale.yml new file mode 100644 index 0000000000..2152b29266 --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearKeyWhale.yml @@ -0,0 +1,27 @@ +languageId: clojure +command: + version: 0 + spokenForm: clear key whale + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: collectionKey, includeSiblings: false} + mark: {type: decoratedSymbol, symbolColor: default, character: w, usePrePhraseSnapshot: true} +initialState: + documentContents: "{:foo \"bar\", :baz \"whatever\"}" + selections: + - anchor: {line: 0, character: 29} + active: {line: 0, character: 29} + marks: + default.w: + start: {line: 0, character: 19} + end: {line: 0, character: 27} +finalState: + documentContents: "{:foo \"bar\", \"whatever\"}" + selections: + - anchor: {line: 0, character: 13} + active: {line: 0, character: 13} + thatMark: + - anchor: {line: 0, character: 13} + active: {line: 0, character: 13} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: w, usePrePhraseSnapshot: true}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: collectionKey, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearKeyWhale2.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearKeyWhale2.yml new file mode 100644 index 0000000000..1af0ab879c --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearKeyWhale2.yml @@ -0,0 +1,37 @@ +languageId: clojure +command: + version: 0 + spokenForm: clear key whale + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: collectionKey, includeSiblings: false} + mark: {type: decoratedSymbol, symbolColor: default, character: w, usePrePhraseSnapshot: true} +initialState: + documentContents: |- + { + :baz + ;; hello + "whatever", + } + selections: + - anchor: {line: 4, character: 1} + active: {line: 4, character: 1} + marks: + default.w: + start: {line: 3, character: 5} + end: {line: 3, character: 13} +finalState: + documentContents: |- + { + + ;; hello + "whatever", + } + selections: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} + thatMark: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: w, usePrePhraseSnapshot: true}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: collectionKey, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearKeyZip.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearKeyZip.yml new file mode 100644 index 0000000000..6ad296d569 --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearKeyZip.yml @@ -0,0 +1,27 @@ +languageId: clojure +command: + version: 0 + spokenForm: clear key zip + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: collectionKey, includeSiblings: false} + mark: {type: decoratedSymbol, symbolColor: default, character: z, usePrePhraseSnapshot: true} +initialState: + documentContents: "{:foo \"bar\", :baz \"whatever\"}" + selections: + - anchor: {line: 0, character: 29} + active: {line: 0, character: 29} + marks: + default.z: + start: {line: 0, character: 14} + end: {line: 0, character: 17} +finalState: + documentContents: "{:foo \"bar\", \"whatever\"}" + selections: + - anchor: {line: 0, character: 13} + active: {line: 0, character: 13} + thatMark: + - anchor: {line: 0, character: 13} + active: {line: 0, character: 13} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: z, usePrePhraseSnapshot: true}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: collectionKey, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearKeyZip2.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearKeyZip2.yml new file mode 100644 index 0000000000..4d348209ce --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearKeyZip2.yml @@ -0,0 +1,37 @@ +languageId: clojure +command: + version: 0 + spokenForm: clear key zip + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: collectionKey, includeSiblings: false} + mark: {type: decoratedSymbol, symbolColor: default, character: z, usePrePhraseSnapshot: true} +initialState: + documentContents: |- + { + :foo "bar", + ;; hello + :baz "whatever", + } + selections: + - anchor: {line: 4, character: 1} + active: {line: 4, character: 1} + marks: + default.z: + start: {line: 3, character: 5} + end: {line: 3, character: 8} +finalState: + documentContents: |- + { + :foo "bar", + ;; hello + "whatever", + } + selections: + - anchor: {line: 3, character: 4} + active: {line: 3, character: 4} + thatMark: + - anchor: {line: 3, character: 4} + active: {line: 3, character: 4} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: z, usePrePhraseSnapshot: true}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: collectionKey, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearLambda.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearLambda.yml new file mode 100644 index 0000000000..c45ff257b5 --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearLambda.yml @@ -0,0 +1,23 @@ +languageId: clojure +command: + version: 1 + spokenForm: clear lambda + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: anonymousFunction, includeSiblings: false} +initialState: + documentContents: (fn [] (println "Hello world")) + selections: + - anchor: {line: 0, character: 12} + active: {line: 0, character: 12} + marks: {} +finalState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: anonymousFunction, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearLambda2.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearLambda2.yml new file mode 100644 index 0000000000..2d1beed854 --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearLambda2.yml @@ -0,0 +1,23 @@ +languageId: clojure +command: + version: 1 + spokenForm: clear lambda + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: anonymousFunction, includeSiblings: false} +initialState: + documentContents: "#(+ 1 1)" + selections: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 6} + marks: {} +finalState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: anonymousFunction, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearList.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearList.yml new file mode 100644 index 0000000000..9871b5b06f --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearList.yml @@ -0,0 +1,23 @@ +languageId: clojure +command: + version: 0 + spokenForm: clear list + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: list, includeSiblings: false} +initialState: + documentContents: "'(hello)" + selections: + - anchor: {line: 0, character: 3} + active: {line: 0, character: 3} + marks: {} +finalState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: list, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearList2.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearList2.yml new file mode 100644 index 0000000000..2d534b67d2 --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearList2.yml @@ -0,0 +1,23 @@ +languageId: clojure +command: + version: 0 + spokenForm: clear list + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: list, includeSiblings: false} +initialState: + documentContents: "[hello]" + selections: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} + marks: {} +finalState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: list, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearMap.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearMap.yml new file mode 100644 index 0000000000..fbd9601141 --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearMap.yml @@ -0,0 +1,23 @@ +languageId: clojure +command: + version: 0 + spokenForm: clear map + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: map, includeSiblings: false} +initialState: + documentContents: "{:foo \"bar\"}" + selections: + - anchor: {line: 0, character: 9} + active: {line: 0, character: 9} + marks: {} +finalState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: map, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearName.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearName.yml new file mode 100644 index 0000000000..85b8629c99 --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearName.yml @@ -0,0 +1,29 @@ +languageId: clojure +command: + version: 1 + spokenForm: clear name + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: name, includeSiblings: false} +initialState: + documentContents: |- + (defn say-hello + [name] + (println (str "Hello, " name))) + selections: + - anchor: {line: 2, character: 4} + active: {line: 2, character: 4} + marks: {} +finalState: + documentContents: |- + (defn + [name] + (println (str "Hello, " name))) + selections: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 6} + thatMark: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 6} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: name, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearName2.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearName2.yml new file mode 100644 index 0000000000..e512e0951b --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearName2.yml @@ -0,0 +1,23 @@ +languageId: clojure +command: + version: 1 + spokenForm: clear name + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: name, includeSiblings: false} +initialState: + documentContents: (defmacro foo [bar] "baz" (bongo)) + selections: + - anchor: {line: 0, character: 30} + active: {line: 0, character: 30} + marks: {} +finalState: + documentContents: (defmacro [bar] "baz" (bongo)) + selections: + - anchor: {line: 0, character: 10} + active: {line: 0, character: 10} + thatMark: + - anchor: {line: 0, character: 10} + active: {line: 0, character: 10} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: name, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearValueBat.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearValueBat.yml new file mode 100644 index 0000000000..cb579acc6a --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearValueBat.yml @@ -0,0 +1,37 @@ +languageId: clojure +command: + version: 0 + spokenForm: clear value bat + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: value, includeSiblings: false} + mark: {type: decoratedSymbol, symbolColor: default, character: b, usePrePhraseSnapshot: true} +initialState: + documentContents: |- + { + :baz + ;; hello + "whatever", + } + selections: + - anchor: {line: 4, character: 1} + active: {line: 4, character: 1} + marks: + default.b: + start: {line: 1, character: 5} + end: {line: 1, character: 8} +finalState: + documentContents: |- + { + :baz + ;; hello + , + } + selections: + - anchor: {line: 3, character: 4} + active: {line: 3, character: 4} + thatMark: + - anchor: {line: 3, character: 4} + active: {line: 3, character: 4} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: b, usePrePhraseSnapshot: true}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: value, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/clearValueZip.yml b/src/test/suite/fixtures/recorded/languages/clojure/clearValueZip.yml new file mode 100644 index 0000000000..58aaf055f3 --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/clearValueZip.yml @@ -0,0 +1,37 @@ +languageId: clojure +command: + version: 0 + spokenForm: clear value zip + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: value, includeSiblings: false} + mark: {type: decoratedSymbol, symbolColor: default, character: z, usePrePhraseSnapshot: true} +initialState: + documentContents: |- + { + :foo "bar", + ;; hello + :baz "whatever", + } + selections: + - anchor: {line: 4, character: 1} + active: {line: 4, character: 1} + marks: + default.z: + start: {line: 3, character: 5} + end: {line: 3, character: 8} +finalState: + documentContents: |- + { + :foo "bar", + ;; hello + :baz , + } + selections: + - anchor: {line: 3, character: 9} + active: {line: 3, character: 9} + thatMark: + - anchor: {line: 3, character: 9} + active: {line: 3, character: 9} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: z, usePrePhraseSnapshot: true}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: value, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/takeValue.yml b/src/test/suite/fixtures/recorded/languages/clojure/takeValue.yml new file mode 100644 index 0000000000..ddb7fb6d41 --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/takeValue.yml @@ -0,0 +1,23 @@ +languageId: clojure +command: + version: 0 + spokenForm: take value + action: setSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: value, includeSiblings: false} +initialState: + documentContents: "{:bar {:foo \"bar\"}}" + selections: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 6} + marks: {} +finalState: + documentContents: "{:bar {:foo \"bar\"}}" + selections: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 18} + thatMark: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 18} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: value, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/takeValueBat.yml b/src/test/suite/fixtures/recorded/languages/clojure/takeValueBat.yml new file mode 100644 index 0000000000..9f9ead1f01 --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/takeValueBat.yml @@ -0,0 +1,27 @@ +languageId: clojure +command: + version: 0 + spokenForm: take value bat + action: setSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: value, includeSiblings: false} + mark: {type: decoratedSymbol, symbolColor: default, character: b, usePrePhraseSnapshot: true} +initialState: + documentContents: "{:foo \"bar\", :baz \"whatever\"}" + selections: + - anchor: {line: 0, character: 29} + active: {line: 0, character: 29} + marks: + default.b: + start: {line: 0, character: 7} + end: {line: 0, character: 10} +finalState: + documentContents: "{:foo \"bar\", :baz \"whatever\"}" + selections: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 11} + thatMark: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 11} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: b, usePrePhraseSnapshot: true}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: value, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/takeValueBat2.yml b/src/test/suite/fixtures/recorded/languages/clojure/takeValueBat2.yml new file mode 100644 index 0000000000..74bcf78854 --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/takeValueBat2.yml @@ -0,0 +1,27 @@ +languageId: clojure +command: + version: 0 + spokenForm: take value bat + action: setSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: value, includeSiblings: false} + mark: {type: decoratedSymbol, symbolColor: default, character: b, usePrePhraseSnapshot: true} +initialState: + documentContents: "{:foo \"bar\"}" + selections: + - anchor: {line: 0, character: 12} + active: {line: 0, character: 12} + marks: + default.b: + start: {line: 0, character: 7} + end: {line: 0, character: 10} +finalState: + documentContents: "{:foo \"bar\"}" + selections: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 11} + thatMark: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 11} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: b, usePrePhraseSnapshot: true}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: value, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/takeValueFine.yml b/src/test/suite/fixtures/recorded/languages/clojure/takeValueFine.yml new file mode 100644 index 0000000000..eda182cdf0 --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/takeValueFine.yml @@ -0,0 +1,27 @@ +languageId: clojure +command: + version: 0 + spokenForm: take value fine + action: setSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: value, includeSiblings: false} + mark: {type: decoratedSymbol, symbolColor: default, character: f, usePrePhraseSnapshot: true} +initialState: + documentContents: "{:foo \"bar\", :baz \"whatever\"}" + selections: + - anchor: {line: 0, character: 29} + active: {line: 0, character: 29} + marks: + default.f: + start: {line: 0, character: 2} + end: {line: 0, character: 5} +finalState: + documentContents: "{:foo \"bar\", :baz \"whatever\"}" + selections: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 11} + thatMark: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 11} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: f, usePrePhraseSnapshot: true}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: value, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/takeValueFine2.yml b/src/test/suite/fixtures/recorded/languages/clojure/takeValueFine2.yml new file mode 100644 index 0000000000..46e34546c1 --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/takeValueFine2.yml @@ -0,0 +1,27 @@ +languageId: clojure +command: + version: 0 + spokenForm: take value fine + action: setSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: value, includeSiblings: false} + mark: {type: decoratedSymbol, symbolColor: default, character: f, usePrePhraseSnapshot: true} +initialState: + documentContents: "{:foo \"bar\"}" + selections: + - anchor: {line: 0, character: 12} + active: {line: 0, character: 12} + marks: + default.f: + start: {line: 0, character: 2} + end: {line: 0, character: 5} +finalState: + documentContents: "{:foo \"bar\"}" + selections: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 11} + thatMark: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 11} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: f, usePrePhraseSnapshot: true}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: value, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/takeValueWhale.yml b/src/test/suite/fixtures/recorded/languages/clojure/takeValueWhale.yml new file mode 100644 index 0000000000..5fcfd485e1 --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/takeValueWhale.yml @@ -0,0 +1,27 @@ +languageId: clojure +command: + version: 0 + spokenForm: take value whale + action: setSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: value, includeSiblings: false} + mark: {type: decoratedSymbol, symbolColor: default, character: w, usePrePhraseSnapshot: true} +initialState: + documentContents: "{:foo \"bar\", :baz \"whatever\"}" + selections: + - anchor: {line: 0, character: 29} + active: {line: 0, character: 29} + marks: + default.w: + start: {line: 0, character: 19} + end: {line: 0, character: 27} +finalState: + documentContents: "{:foo \"bar\", :baz \"whatever\"}" + selections: + - anchor: {line: 0, character: 18} + active: {line: 0, character: 28} + thatMark: + - anchor: {line: 0, character: 18} + active: {line: 0, character: 28} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: w, usePrePhraseSnapshot: true}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: value, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/takeValueZip.yml b/src/test/suite/fixtures/recorded/languages/clojure/takeValueZip.yml new file mode 100644 index 0000000000..823f42f27a --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/takeValueZip.yml @@ -0,0 +1,27 @@ +languageId: clojure +command: + version: 0 + spokenForm: take value zip + action: setSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: value, includeSiblings: false} + mark: {type: decoratedSymbol, symbolColor: default, character: z, usePrePhraseSnapshot: true} +initialState: + documentContents: "{:foo \"bar\", :baz \"whatever\"}" + selections: + - anchor: {line: 0, character: 29} + active: {line: 0, character: 29} + marks: + default.z: + start: {line: 0, character: 14} + end: {line: 0, character: 17} +finalState: + documentContents: "{:foo \"bar\", :baz \"whatever\"}" + selections: + - anchor: {line: 0, character: 18} + active: {line: 0, character: 28} + thatMark: + - anchor: {line: 0, character: 18} + active: {line: 0, character: 28} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: z, usePrePhraseSnapshot: true}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: value, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/languages/clojure/takeValueZip2.yml b/src/test/suite/fixtures/recorded/languages/clojure/takeValueZip2.yml new file mode 100644 index 0000000000..c7153a500c --- /dev/null +++ b/src/test/suite/fixtures/recorded/languages/clojure/takeValueZip2.yml @@ -0,0 +1,27 @@ +languageId: clojure +command: + version: 0 + spokenForm: take value zip + action: setSelection + targets: + - type: primitive + modifier: {type: containingScope, scopeType: value, includeSiblings: false} + mark: {type: decoratedSymbol, symbolColor: default, character: z, usePrePhraseSnapshot: true} +initialState: + documentContents: "{:baz {:foo \"bar\"}}" + selections: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 6} + marks: + default.z: + start: {line: 0, character: 2} + end: {line: 0, character: 5} +finalState: + documentContents: "{:baz {:foo \"bar\"}}" + selections: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 18} + thatMark: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 18} +fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: z, usePrePhraseSnapshot: true}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: value, includeSiblings: false}}] diff --git a/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearBound.yml b/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearBound.yml new file mode 100644 index 0000000000..fa14465411 --- /dev/null +++ b/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearBound.yml @@ -0,0 +1,27 @@ +languageId: clojure +command: + version: 0 + spokenForm: clear bound + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: surroundingPair, delimiter: any, delimiterInclusion: excludeInterior} +initialState: + documentContents: (hello) + selections: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} + marks: {} +finalState: + documentContents: hello + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} + thatMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: surroundingPair, delimiter: any, delimiterInclusion: excludeInterior}}] diff --git a/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearCore.yml b/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearCore.yml new file mode 100644 index 0000000000..64a6d7a07d --- /dev/null +++ b/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearCore.yml @@ -0,0 +1,23 @@ +languageId: clojure +command: + version: 0 + spokenForm: clear core + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: surroundingPair, delimiter: any, delimiterInclusion: interiorOnly} +initialState: + documentContents: (hello) + selections: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} + marks: {} +finalState: + documentContents: () + selections: + - anchor: {line: 0, character: 1} + active: {line: 0, character: 1} + thatMark: + - anchor: {line: 0, character: 1} + active: {line: 0, character: 1} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: surroundingPair, delimiter: any, delimiterInclusion: interiorOnly}}] diff --git a/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearCore2.yml b/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearCore2.yml new file mode 100644 index 0000000000..182e2415d5 --- /dev/null +++ b/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearCore2.yml @@ -0,0 +1,23 @@ +languageId: clojure +command: + version: 0 + spokenForm: clear core + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: surroundingPair, delimiter: any, delimiterInclusion: interiorOnly} +initialState: + documentContents: "\"hello\"" + selections: + - anchor: {line: 0, character: 4} + active: {line: 0, character: 4} + marks: {} +finalState: + documentContents: "\"\"" + selections: + - anchor: {line: 0, character: 1} + active: {line: 0, character: 1} + thatMark: + - anchor: {line: 0, character: 1} + active: {line: 0, character: 1} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: surroundingPair, delimiter: any, delimiterInclusion: interiorOnly}}] diff --git a/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearPair.yml b/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearPair.yml new file mode 100644 index 0000000000..fee3c533d3 --- /dev/null +++ b/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearPair.yml @@ -0,0 +1,23 @@ +languageId: clojure +command: + version: 0 + spokenForm: clear pair + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: surroundingPair, delimiter: any} +initialState: + documentContents: ;; (hello) + selections: + - anchor: {line: 0, character: 7} + active: {line: 0, character: 7} + marks: {} +finalState: + documentContents: ";; " + selections: + - anchor: {line: 0, character: 3} + active: {line: 0, character: 3} + thatMark: + - anchor: {line: 0, character: 3} + active: {line: 0, character: 3} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: surroundingPair, delimiter: any}}] diff --git a/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearPair2.yml b/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearPair2.yml new file mode 100644 index 0000000000..2d507b9f18 --- /dev/null +++ b/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearPair2.yml @@ -0,0 +1,23 @@ +languageId: clojure +command: + version: 0 + spokenForm: clear pair + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: surroundingPair, delimiter: any} +initialState: + documentContents: (hello) + selections: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} + marks: {} +finalState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: surroundingPair, delimiter: any}}] diff --git a/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearPair3.yml b/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearPair3.yml new file mode 100644 index 0000000000..4d17cdb09d --- /dev/null +++ b/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearPair3.yml @@ -0,0 +1,23 @@ +languageId: clojure +command: + version: 0 + spokenForm: clear pair + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: surroundingPair, delimiter: any} +initialState: + documentContents: "\"hello\"" + selections: + - anchor: {line: 0, character: 4} + active: {line: 0, character: 4} + marks: {} +finalState: + documentContents: "" + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: surroundingPair, delimiter: any}}] diff --git a/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearPair4.yml b/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearPair4.yml new file mode 100644 index 0000000000..0268532496 --- /dev/null +++ b/src/test/suite/fixtures/recorded/surroundingPair/parseTree/clojure/clearPair4.yml @@ -0,0 +1,23 @@ +languageId: clojure +command: + version: 0 + spokenForm: clear pair + action: clearAndSetSelection + targets: + - type: primitive + modifier: {type: surroundingPair, delimiter: any} +initialState: + documentContents: "\"(hello)\"" + selections: + - anchor: {line: 0, character: 6} + active: {line: 0, character: 6} + marks: {} +finalState: + documentContents: "\"\"" + selections: + - anchor: {line: 0, character: 1} + active: {line: 0, character: 1} + thatMark: + - anchor: {line: 0, character: 1} + active: {line: 0, character: 1} +fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: surroundingPair, delimiter: any}}] diff --git a/src/util/nodeFinders.ts b/src/util/nodeFinders.ts index 02550b83d1..dc0aabd9a6 100644 --- a/src/util/nodeFinders.ts +++ b/src/util/nodeFinders.ts @@ -10,6 +10,27 @@ export const nodeFinder = ( }; }; +/** + * Given a list of node finders returns a new node finder which applies them in + * sequence returning null if any of the sequence returns null otherwise + * returning the output of the final node finder + * @param nodeFinders A list of node finders to apply in sequence + * @returns A node finder which is a chain of the input node finders + */ +export function chainedNodeFinder(...nodeFinders: NodeFinder[]) { + return (node: SyntaxNode) => { + let currentNode: SyntaxNode | null = node; + for (const nodeFinder of nodeFinders) { + currentNode = nodeFinder(currentNode); + if (currentNode == null) { + return null; + } + } + + return currentNode; + }; +} + export const typedNodeFinder = (...typeNames: string[]): NodeFinder => { return nodeFinder((node) => typeNames.includes(node.type)); }; diff --git a/src/util/nodeMatchers.ts b/src/util/nodeMatchers.ts index dee1d700e9..f58363ac74 100644 --- a/src/util/nodeMatchers.ts +++ b/src/util/nodeMatchers.ts @@ -18,6 +18,7 @@ import { typedNodeFinder, patternFinder, argumentNodeFinder, + chainedNodeFinder, } from "./nodeFinders"; export function matcher( @@ -37,19 +38,27 @@ export function matcher( }; } -export function composedMatcher( +/** + * Given a list of node finders returns a matcher which applies them in + * sequence returning null if any of the sequence returns null otherwise + * returning the output of the final node finder + * @param nodeFinders A list of node finders to apply in sequence + * @param selector The selector to apply to the final node + * @returns A matcher which is a chain of the input node finders + */ +export function chainedMatcher( finders: NodeFinder[], selector: SelectionExtractor = simpleSelectionExtractor ): NodeMatcher { + const nodeFinder = chainedNodeFinder(...finders); + return function (selection: SelectionWithEditor, initialNode: SyntaxNode) { - let returnNode: SyntaxNode = initialNode; - for (const finder of finders) { - const foundNode = finder(returnNode, selection.selection); - if (foundNode == null) { - return null; - } - returnNode = foundNode; + const returnNode = nodeFinder(initialNode); + + if (returnNode == null) { + return null; } + return [ { node: returnNode, diff --git a/src/util/nodeSelectors.ts b/src/util/nodeSelectors.ts index 5405d38c77..8c1541e216 100644 --- a/src/util/nodeSelectors.ts +++ b/src/util/nodeSelectors.ts @@ -1,6 +1,7 @@ import { SyntaxNode, Point } from "web-tree-sitter"; import { Position, Range, Selection, TextEditor } from "vscode"; import { SelectionWithContext, SelectionExtractor } from "../typings/Types"; +import { identity } from "lodash"; export function makeRangeFromPositions( startPosition: Point, @@ -221,24 +222,44 @@ export function delimitersSelector(...delimiters: string[]) { return delimitedSelector((node) => delimiters.includes(node.type), ", "); } +/** + * Creates a selector which can be used to automatically clean up after elements + * in a list by removing leading or trailing delimiters + * @param isDelimiterNode A function used to determine whether a given node is a + * delimiter node + * @param defaultDelimiter The default list separator to use if we can't + * determine it by looking before or after the given node + * @param getStartNode A function to be applied to the node to determine which + * node is the start node if we really want to expand to a sequence of nodes + * @param getEndNode A function to be applied to the node to determine which + * node is the end node if we really want to expand to a sequence of nodes + * @returns A selection extractor + */ export function delimitedSelector( isDelimiterNode: (node: SyntaxNode) => boolean, - defaultDelimiter: string + defaultDelimiter: string, + getStartNode: (node: SyntaxNode) => SyntaxNode = identity, + getEndNode: (node: SyntaxNode) => SyntaxNode = identity ): SelectionExtractor { return (editor: TextEditor, node: SyntaxNode) => { let containingListDelimiter: string | null = null; let leadingDelimiterRange: Range | null = null; let trailingDelimiterRange: Range | null = null; + const startNode = getStartNode(node); + const endNode = getEndNode(node); - const nextNonDelimiterNode = getNextNonDelimiterNode(node, isDelimiterNode); + const nextNonDelimiterNode = getNextNonDelimiterNode( + endNode, + isDelimiterNode + ); const previousNonDelimiterNode = getPreviousNonDelimiterNode( - node, + startNode, isDelimiterNode ); if (nextNonDelimiterNode != null) { trailingDelimiterRange = makeRangeFromPositions( - node.endPosition, + endNode.endPosition, nextNonDelimiterNode.startPosition ); @@ -248,7 +269,7 @@ export function delimitedSelector( if (previousNonDelimiterNode != null) { leadingDelimiterRange = makeRangeFromPositions( previousNonDelimiterNode.endPosition, - node.startPosition + startNode.startPosition ); if (containingListDelimiter == null) { @@ -263,7 +284,13 @@ export function delimitedSelector( } return { - ...simpleSelectionExtractor(editor, node), + selection: new Selection( + new Position( + startNode.startPosition.row, + startNode.startPosition.column + ), + new Position(endNode.endPosition.row, endNode.endPosition.column) + ), context: { isInDelimitedList: true, containingListDelimiter, diff --git a/src/util/treeSitterUtils.ts b/src/util/treeSitterUtils.ts index 4509d31e22..478823814a 100644 --- a/src/util/treeSitterUtils.ts +++ b/src/util/treeSitterUtils.ts @@ -14,3 +14,25 @@ export const getDefinitionNode = (node: SyntaxNode) => export const getDeclarationNode = (node: SyntaxNode) => node.childForFieldName("declarator"); + +export function getChildNodesForFieldName( + node: SyntaxNode, + fieldName: string +): SyntaxNode[] { + const treeCursor = node.walk(); + treeCursor.gotoFirstChild(); + + const ret = []; + + let hasNext = true; + + while (hasNext) { + if (treeCursor.currentFieldName() === fieldName) { + ret.push(treeCursor.currentNode()); + } + + hasNext = treeCursor.gotoNextSibling(); + } + + return ret; +}