diff --git a/data/playground/python/values.py b/data/playground/python/values.py new file mode 100644 index 0000000000..e20b579375 --- /dev/null +++ b/data/playground/python/values.py @@ -0,0 +1,64 @@ +# Useful commands: +# "visualize value" +# "visualize value iteration" +# "take value" +# "chuck value" +# "chuck every value" + +# the argument value "True" that is part of "b=True" +# is "value" scope +def func(b=True, c=True): + # the returned value "1" that is part of "return 1" + # is "value" scope + if b is True: + return 1 + else: + return 0 + +# the argument value "False" that is part of "b=False" +# is "value" scope +func(b=False) +# but here, there is no "value" scope for "False" since no argument +func(False) + +# both "1.5" and "25" are "value" scope +val = 1.5 +val /= 25 + +val1, val2 = 0, 5 +val1 = 0, val2 = 5 +val1 = val2 + +def my_funk(value: str) -> str: + print(value) + +def my_funk(value: str = "hello", other: bool=False) -> str: + print(value) + +# we can say "change every value" to allow modifying all the values in one go +def foo(): + a = 0 + b = 1 + c = 2 + +# But we don't support outside of a function yet +a = 0 +b = 1 +c = 2 + +# values of a Python "dictionary" are "value" scope +# we can say "chuck every value" to convert the dict into a set +d1 = {"a": 1, "b": 2, "c": 3} + +_ = {value: key for (key, value) in d1.items()} + +# complex ones +_ = {{"a": 1, "b": 2, "c": 3}: 1, d1: 2} +_ = {{1, 2, 3}: 1, {2, 3, 4}: 2} + +# we don't want the access to a a Python "dictionary" +# value to be of "value" scope so we have it here +# to be sure we ignore it +d1["a"] + +value = "hello world" diff --git a/packages/cursorless-engine/src/languages/python.ts b/packages/cursorless-engine/src/languages/python.ts index d20bea22f5..4ee79dd2cb 100644 --- a/packages/cursorless-engine/src/languages/python.ts +++ b/packages/cursorless-engine/src/languages/python.ts @@ -80,28 +80,6 @@ const nodeMatchers: Partial< "parameters.identifier!", "*[name]", ], - value: cascadingMatcher( - leadingMatcher( - ["assignment[right]", "augmented_assignment[right]", "~subscript[value]"], - [ - ":", - "=", - "+=", - "-=", - "*=", - "/=", - "%=", - "//=", - "**=", - "&=", - "|=", - "^=", - "<<=", - ">>=", - ], - ), - patternMatcher("return_statement.~return!"), - ), argumentOrParameter: cascadingMatcher( argumentMatcher("parameters", "argument_list"), matcher(patternFinder("call.generator_expression!"), childRangeSelector()), diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/python/changeValue.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/python/changeValue.yml new file mode 100644 index 0000000000..927da9ad05 --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/python/changeValue.yml @@ -0,0 +1,27 @@ +languageId: python +command: + version: 6 + spokenForm: change value + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - type: containingScope + scopeType: {type: value} + usePrePhraseSnapshot: true +initialState: + documentContents: |- + if (x := 0) < 1: + pass + selections: + - anchor: {line: 0, character: 4} + active: {line: 0, character: 4} + marks: {} +finalState: + documentContents: |- + if (x := ) < 1: + pass + selections: + - anchor: {line: 0, character: 9} + active: {line: 0, character: 9} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/python/changeValue2.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/python/changeValue2.yml new file mode 100644 index 0000000000..8c766129bc --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/python/changeValue2.yml @@ -0,0 +1,29 @@ +languageId: python +command: + version: 6 + spokenForm: change value + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - type: containingScope + scopeType: {type: value} + usePrePhraseSnapshot: true +initialState: + documentContents: |- + match aaa: + case {"bbb": ccc}: + pass + selections: + - anchor: {line: 1, character: 10} + active: {line: 1, character: 10} + marks: {} +finalState: + documentContents: |- + match aaa: + case {"bbb": }: + pass + selections: + - anchor: {line: 1, character: 17} + active: {line: 1, character: 17} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/python/chuckValue4.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/python/chuckValue4.yml new file mode 100644 index 0000000000..4841de5b97 --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/python/chuckValue4.yml @@ -0,0 +1,27 @@ +languageId: python +command: + version: 6 + spokenForm: chuck value + action: + name: remove + target: + type: primitive + modifiers: + - type: containingScope + scopeType: {type: value} + usePrePhraseSnapshot: true +initialState: + documentContents: |- + if (x := 0) < 1: + pass + selections: + - anchor: {line: 0, character: 4} + active: {line: 0, character: 4} + marks: {} +finalState: + documentContents: |- + if (x) < 1: + pass + selections: + - anchor: {line: 0, character: 4} + active: {line: 0, character: 4} diff --git a/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/python/chuckValue5.yml b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/python/chuckValue5.yml new file mode 100644 index 0000000000..6bd67dc98e --- /dev/null +++ b/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/python/chuckValue5.yml @@ -0,0 +1,29 @@ +languageId: python +command: + version: 6 + spokenForm: chuck value + action: + name: remove + target: + type: primitive + modifiers: + - type: containingScope + scopeType: {type: value} + usePrePhraseSnapshot: true +initialState: + documentContents: |- + match aaa: + case {"bbb": ccc}: + pass + selections: + - anchor: {line: 1, character: 10} + active: {line: 1, character: 10} + marks: {} +finalState: + documentContents: |- + match aaa: + case {"bbb"}: + pass + selections: + - anchor: {line: 1, character: 10} + active: {line: 1, character: 10} diff --git a/pyproject.toml b/pyproject.toml index a345db38d9..b1327e6966 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,8 +1,9 @@ [tool.black] target-version = ["py39"] +force-exclude = ["vendor", "data/playground"] [tool.ruff] select = ["E", "F", "C4", "I001", "UP", "SIM"] ignore = ["E501", "SIM105", "UP035"] target-version = "py39" -extend-exclude = ["vendor"] +extend-exclude = ["vendor", "data/playground/**/*.py"] diff --git a/queries/python.scm b/queries/python.scm index 7566194e9a..094f916174 100644 --- a/queries/python.scm +++ b/queries/python.scm @@ -27,6 +27,58 @@ (with_statement) ] @statement +;;!! a = 25 +;;! ^^ +;;! xxxxx +;;! ------ +(assignment + (_) @_.leading.start.endOf + . + right: (_) @value @_.leading.end.startOf +) @_.domain + +;;!! a /= 25 +;;! ^^ +;;! xxxxxx +;;! ------- +(augmented_assignment + (_) @_.leading.start.endOf + . + right: (_) @value @_.leading.end.startOf +) @_.domain + +;;!! d = {"a": 1234} +;;! ^^^^ +;;! xxxxxx +;;! --------- +;;!! {value: key for (key, value) in d1.items()} +;;! ^^^ +;;! xxxxx +;;! ---------- +;;!! def func(value: str = ""): +;;! ^^ +;;! xxxxx +;;! --------------- +( + (_ + (_) @_.leading.start.endOf + . + value: (_) @value @_.leading.end.startOf + ) @_.domain + (#not-type? @_.domain subscript) +) + +;;!! return 1 +;;! ^ +;;! xx +;;! -------- +;; +;; NOTE: in tree-sitter, both "return" and the "1" are children of `return_statement` +;; but "return" is anonymous whereas "1" is named node, so no need to exclude explicitly +(return_statement + (_) @value +) @_.domain + (comment) @comment @textFragment (string @@ -77,6 +129,26 @@ (module) @statement.iteration (module) @namedFunction.iteration @functionName.iteration (class_definition) @namedFunction.iteration @functionName.iteration -(_ - body: (_) @statement.iteration + +;;!! def foo(): +;;!! a = 0 +;;! <***** +;;!! b = 1 +;;! ***** +;;!! c = 2 +;;! *****> +(block) @statement.iteration @value.iteration + +;;!! {"a": 1, "b": 2, "c": 3} +;;! ********************** +(dictionary + "{" @value.iteration.start.endOf + "}" @value.iteration.end.startOf +) + +;;!! def func(a=0, b=1): +;;! ******** +(parameters + "(" @value.iteration.start.endOf + ")" @value.iteration.end.startOf )