diff --git a/docs/parse-tree-patterns.md b/docs/parse-tree-patterns.md
index b82baf3b19..f9d362fd5a 100644
--- a/docs/parse-tree-patterns.md
+++ b/docs/parse-tree-patterns.md
@@ -11,6 +11,7 @@ We have a small domain-specific language that we use to define patterns to look
| TYPE | Match node type
`node.type` |
| Dot operator(`.`) | Type hierarchy between parent and child |
| Wildcard op(`*`) | Match any type |
+| Negation op(`~`) | Match any type other than what is specified after `~` |
| Important op(`!`) | Use this node as result instead of parent.
By default the leftmost/top node is used |
| Optional op(`?`) | Node is optional. Will match if available. |
| Field op(`[field]`) | Get child field node for resulting node.
Only evaluated on the resulting node at the end.
`node.childForFieldName(field)` |
diff --git a/src/extension.ts b/src/extension.ts
index 1a71b2176f..8cf689afc2 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -199,9 +199,10 @@ export async function activate(context: vscode.ExtensionContext) {
// const processedTargets = processTargets(navigationMap!, targets);
} catch (e) {
- vscode.window.showErrorMessage(e.message);
- console.trace(e.message);
- throw e;
+ const err = e as Error;
+ vscode.window.showErrorMessage(err.message);
+ console.trace(err.message);
+ throw err;
}
}
);
diff --git a/src/languages/python.ts b/src/languages/python.ts
index 64e16fae1d..063bef283b 100644
--- a/src/languages/python.ts
+++ b/src/languages/python.ts
@@ -55,7 +55,7 @@ const nodeMatchers: Partial> = {
className: "class_definition[name]",
namedFunction: "decorated_definition?.function_definition",
functionName: "function_definition[name]",
- type: ["function_definition[return_type]", "*[type]"],
+ type: valueMatcher("function_definition[return_type]", "*[type]"),
name: [
"assignment[left]",
"typed_parameter.identifier!",
@@ -63,7 +63,7 @@ const nodeMatchers: Partial> = {
"*[name]",
],
collectionItem: argumentMatcher(...dictionaryTypes, ...listTypes),
- value: valueMatcher("assignment[right]", "pair[value].*", "*[value]"),
+ value: valueMatcher("assignment[right]", "~subscript[value]"),
argumentOrParameter: argumentMatcher("parameters", "argument_list"),
};
diff --git a/src/test/suite/fixtures/recorded/languages/python/chuckType.yml b/src/test/suite/fixtures/recorded/languages/python/chuckType.yml
new file mode 100644
index 0000000000..1a30b6846f
--- /dev/null
+++ b/src/test/suite/fixtures/recorded/languages/python/chuckType.yml
@@ -0,0 +1,23 @@
+spokenForm: chuck type
+languageId: python
+command:
+ actionName: remove
+ partialTargets:
+ - type: primitive
+ modifier: {type: containingScope, scopeType: type, includeSiblings: false}
+ extraArgs: []
+marks: {}
+initialState:
+ documentContents: "foo: str = 'hello'"
+ selections:
+ - anchor: {line: 0, character: 1}
+ active: {line: 0, character: 1}
+finalState:
+ documentContents: foo = 'hello'
+ selections:
+ - anchor: {line: 0, character: 1}
+ active: {line: 0, character: 1}
+ thatMark:
+ - anchor: {line: 0, character: 3}
+ active: {line: 0, character: 3}
+fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: outside, modifier: {type: containingScope, scopeType: type, includeSiblings: false}}]
diff --git a/src/test/suite/fixtures/recorded/languages/python/chuckValue.yml b/src/test/suite/fixtures/recorded/languages/python/chuckValue.yml
new file mode 100644
index 0000000000..1eef01799f
--- /dev/null
+++ b/src/test/suite/fixtures/recorded/languages/python/chuckValue.yml
@@ -0,0 +1,23 @@
+spokenForm: chuck value
+languageId: python
+command:
+ actionName: remove
+ partialTargets:
+ - type: primitive
+ modifier: {type: containingScope, scopeType: value, includeSiblings: false}
+ extraArgs: []
+marks: {}
+initialState:
+ documentContents: "foo: str = \"hello\""
+ selections:
+ - anchor: {line: 0, character: 2}
+ active: {line: 0, character: 2}
+finalState:
+ documentContents: "foo: str "
+ selections:
+ - anchor: {line: 0, character: 2}
+ active: {line: 0, character: 2}
+ thatMark:
+ - anchor: {line: 0, character: 9}
+ active: {line: 0, character: 9}
+fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: outside, modifier: {type: containingScope, scopeType: value, includeSiblings: false}}]
diff --git a/src/test/suite/fixtures/recorded/languages/python/clearEveryValue.yml b/src/test/suite/fixtures/recorded/languages/python/clearEveryValue.yml
new file mode 100644
index 0000000000..03813cfe61
--- /dev/null
+++ b/src/test/suite/fixtures/recorded/languages/python/clearEveryValue.yml
@@ -0,0 +1,35 @@
+spokenForm: clear every value
+languageId: python
+command:
+ actionName: clearAndSetSelection
+ partialTargets:
+ - type: primitive
+ modifier: {type: containingScope, scopeType: value, includeSiblings: true}
+ extraArgs: []
+marks: {}
+initialState:
+ documentContents: |-
+ {
+ "foo": "bar",
+ "baz": "bongo",
+ }
+ selections:
+ - anchor: {line: 1, character: 13}
+ active: {line: 1, character: 13}
+finalState:
+ documentContents: |-
+ {
+ "foo": ,
+ "baz": ,
+ }
+ selections:
+ - anchor: {line: 1, character: 11}
+ active: {line: 1, character: 11}
+ - anchor: {line: 2, character: 11}
+ active: {line: 2, character: 11}
+ thatMark:
+ - anchor: {line: 1, character: 11}
+ active: {line: 1, character: 11}
+ - anchor: {line: 2, character: 11}
+ active: {line: 2, character: 11}
+fullTargets: [{type: primitive, mark: {type: cursor}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: containingScope, scopeType: value, includeSiblings: true}}]
diff --git a/src/util/nodeFinders.ts b/src/util/nodeFinders.ts
index c0d36001a4..02550b83d1 100644
--- a/src/util/nodeFinders.ts
+++ b/src/util/nodeFinders.ts
@@ -228,13 +228,17 @@ class Pattern {
isOptional: boolean = false;
constructor(pattern: string) {
- this.type = pattern.match(/^[\w*]+/)![0];
+ this.type = pattern.match(/^[\w*~]+/)![0];
this.fields = [...pattern.matchAll(/(?<=\[).+?(?=\])/g)].map((m) => m[0]);
this.isImportant = pattern.indexOf("!") > -1;
this.isOptional = pattern.indexOf("?") > -1;
}
typeEquals(node: SyntaxNode) {
- return this.type === node.type || this.type === "*";
+ return (
+ this.type === node.type ||
+ this.type === "*" ||
+ (this.type.startsWith("~") && this.type.slice(1) !== node.type)
+ );
}
}