diff --git a/cursorless-talon/src/spoken_forms.py b/cursorless-talon/src/spoken_forms.py index 5d66e1ffc1..044978b95e 100644 --- a/cursorless-talon/src/spoken_forms.py +++ b/cursorless-talon/src/spoken_forms.py @@ -161,6 +161,7 @@ def handle_new_values(csv_name: str, values: list[SpokenFormEntry]): "textFragment", "disqualifyDelimiter", "pairDelimiter", + "interior", ], default_list_name="scope_type", ), diff --git a/data/fixtures/recorded/implicitExpansion/clearCoreToken.yml b/data/fixtures/recorded/implicitExpansion/clearCoreToken.yml index 0c5670ce0a..42794a31e2 100644 --- a/data/fixtures/recorded/implicitExpansion/clearCoreToken.yml +++ b/data/fixtures/recorded/implicitExpansion/clearCoreToken.yml @@ -17,8 +17,4 @@ initialState: - anchor: {line: 0, character: 1} active: {line: 0, character: 1} marks: {} -finalState: - documentContents: () - selections: - - anchor: {line: 0, character: 1} - active: {line: 0, character: 1} +thrownError: {name: NoContainingScopeError} diff --git a/data/fixtures/recorded/modifiers/changeInside.yml b/data/fixtures/recorded/modifiers/changeInside.yml new file mode 100644 index 0000000000..32454197af --- /dev/null +++ b/data/fixtures/recorded/modifiers/changeInside.yml @@ -0,0 +1,26 @@ +languageId: python +command: + version: 7 + spokenForm: change inside + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - {type: interiorOnly} + usePrePhraseSnapshot: false +initialState: + documentContents: |- + def testing(): + pass + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: {} +finalState: + documentContents: |- + def testing(): + + selections: + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} diff --git a/data/fixtures/recorded/modifiers/interior/changeInside.yml b/data/fixtures/recorded/modifiers/interior/changeInside.yml new file mode 100644 index 0000000000..f8c61d871c --- /dev/null +++ b/data/fixtures/recorded/modifiers/interior/changeInside.yml @@ -0,0 +1,22 @@ +languageId: html +command: + version: 7 + spokenForm: change inside + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - {type: interiorOnly} + usePrePhraseSnapshot: false +initialState: + documentContents:
content
+ selections: + - anchor: {line: 0, character: 1} + active: {line: 0, character: 1} + marks: {} +finalState: + documentContents: <>content + selections: + - anchor: {line: 0, character: 1} + active: {line: 0, character: 1} diff --git a/data/fixtures/recorded/modifiers/interior/changeInside2.yml b/data/fixtures/recorded/modifiers/interior/changeInside2.yml new file mode 100644 index 0000000000..ef90304905 --- /dev/null +++ b/data/fixtures/recorded/modifiers/interior/changeInside2.yml @@ -0,0 +1,22 @@ +languageId: html +command: + version: 7 + spokenForm: change inside + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - {type: interiorOnly} + usePrePhraseSnapshot: false +initialState: + documentContents:
content
+ selections: + - anchor: {line: 0, character: 9} + active: {line: 0, character: 9} + marks: {} +finalState: + documentContents:
+ selections: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} diff --git a/data/fixtures/recorded/modifiers/interior/changeInside3.yml b/data/fixtures/recorded/modifiers/interior/changeInside3.yml new file mode 100644 index 0000000000..aa0638a03f --- /dev/null +++ b/data/fixtures/recorded/modifiers/interior/changeInside3.yml @@ -0,0 +1,22 @@ +languageId: plaintext +command: + version: 7 + spokenForm: change inside + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - {type: interiorOnly} + usePrePhraseSnapshot: false +initialState: + documentContents: (hello) + 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} diff --git a/data/fixtures/recorded/modifiers/interior/changeInside4.yml b/data/fixtures/recorded/modifiers/interior/changeInside4.yml new file mode 100644 index 0000000000..362d8c265c --- /dev/null +++ b/data/fixtures/recorded/modifiers/interior/changeInside4.yml @@ -0,0 +1,22 @@ +languageId: html +command: + version: 7 + spokenForm: change inside + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - {type: interiorOnly} + usePrePhraseSnapshot: false +initialState: + documentContents:
content
(hello) + selections: + - anchor: {line: 0, character: 8} + active: {line: 0, character: 23} + marks: {} +finalState: + documentContents:
) + selections: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} diff --git a/data/fixtures/recorded/modifiers/interior/changeInsideElement.yml b/data/fixtures/recorded/modifiers/interior/changeInsideElement.yml new file mode 100644 index 0000000000..07635004f1 --- /dev/null +++ b/data/fixtures/recorded/modifiers/interior/changeInsideElement.yml @@ -0,0 +1,24 @@ +languageId: html +command: + version: 7 + spokenForm: change inside element + action: + name: clearAndSetSelection + target: + type: primitive + modifiers: + - {type: interiorOnly} + - type: containingScope + scopeType: {type: xmlElement} + usePrePhraseSnapshot: false +initialState: + documentContents:
content
+ selections: + - anchor: {line: 0, character: 1} + active: {line: 0, character: 1} + marks: {} +finalState: + documentContents:
+ selections: + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} diff --git a/data/fixtures/scopes/html/element.scope b/data/fixtures/scopes/html/element.scope index 23ebb42694..7fce7e4f9f 100644 --- a/data/fixtures/scopes/html/element.scope +++ b/data/fixtures/scopes/html/element.scope @@ -1,14 +1,10 @@ -
+
text
--- [Content] = [Removal] = -[Domain] = 0:0-0:21 - >---------------------< -0|
- -[Interior] = 0:15-0:15 - >< -0|
+[Domain] = 0:0-0:25 + >-------------------------< +0|
text
[Insertion delimiter] = "\n" diff --git a/data/fixtures/scopes/html/interior.element.scope b/data/fixtures/scopes/html/interior.element.scope new file mode 100644 index 0000000000..9682fcd74b --- /dev/null +++ b/data/fixtures/scopes/html/interior.element.scope @@ -0,0 +1,40 @@ +
text
+--- + +[#1 Content] = +[#1 Removal] = 0:1-0:4 + >---< +0|
text
+ +[#1 Domain] = 0:0-0:5 + >-----< +0|
text
+ +[#1 Insertion delimiter] = " " + + +[#2 Content] = 0:6-0:10 + >----< +0|
text
+ +[#2 Removal] = 0:5-0:11 + >------< +0|
text
+ +[#2 Domain] = 0:0-0:17 + >-----------------< +0|
text
+ +[#2 Insertion delimiter] = " " + + +[#3 Content] = +[#3 Removal] = 0:13-0:16 + >---< +0|
text
+ +[#3 Domain] = 0:11-0:17 + >------< +0|
text
+ +[#3 Insertion delimiter] = " " diff --git a/data/fixtures/scopes/javascript.jsx/element.scope b/data/fixtures/scopes/javascript.jsx/element.scope index 23ebb42694..7fce7e4f9f 100644 --- a/data/fixtures/scopes/javascript.jsx/element.scope +++ b/data/fixtures/scopes/javascript.jsx/element.scope @@ -1,14 +1,10 @@ -
+
text
--- [Content] = [Removal] = -[Domain] = 0:0-0:21 - >---------------------< -0|
- -[Interior] = 0:15-0:15 - >< -0|
+[Domain] = 0:0-0:25 + >-------------------------< +0|
text
[Insertion delimiter] = "\n" diff --git a/data/fixtures/scopes/javascript.jsx/interior.element.scope b/data/fixtures/scopes/javascript.jsx/interior.element.scope new file mode 100644 index 0000000000..9682fcd74b --- /dev/null +++ b/data/fixtures/scopes/javascript.jsx/interior.element.scope @@ -0,0 +1,40 @@ +
text
+--- + +[#1 Content] = +[#1 Removal] = 0:1-0:4 + >---< +0|
text
+ +[#1 Domain] = 0:0-0:5 + >-----< +0|
text
+ +[#1 Insertion delimiter] = " " + + +[#2 Content] = 0:6-0:10 + >----< +0|
text
+ +[#2 Removal] = 0:5-0:11 + >------< +0|
text
+ +[#2 Domain] = 0:0-0:17 + >-----------------< +0|
text
+ +[#2 Insertion delimiter] = " " + + +[#3 Content] = +[#3 Removal] = 0:13-0:16 + >---< +0|
text
+ +[#3 Domain] = 0:11-0:17 + >------< +0|
text
+ +[#3 Insertion delimiter] = " " diff --git a/data/fixtures/scopes/latex/element.scope b/data/fixtures/scopes/latex/element.scope index ce63430e4d..8d938b3d62 100644 --- a/data/fixtures/scopes/latex/element.scope +++ b/data/fixtures/scopes/latex/element.scope @@ -12,14 +12,4 @@ 2| \end{quote} -----------< -[Interior: Content] = 1:4-1:9 - >-----< -1| Hello -[Interior: Removal] = 0:13-2:0 - > -0| \begin{quote} -1| Hello -2| \end{quote} - < - [Insertion delimiter] = "\n" diff --git a/data/fixtures/scopes/latex/environment.scope b/data/fixtures/scopes/latex/environment.scope index ce63430e4d..8d938b3d62 100644 --- a/data/fixtures/scopes/latex/environment.scope +++ b/data/fixtures/scopes/latex/environment.scope @@ -12,14 +12,4 @@ 2| \end{quote} -----------< -[Interior: Content] = 1:4-1:9 - >-----< -1| Hello -[Interior: Removal] = 0:13-2:0 - > -0| \begin{quote} -1| Hello -2| \end{quote} - < - [Insertion delimiter] = "\n" diff --git a/data/fixtures/scopes/latex/interior.element.scope b/data/fixtures/scopes/latex/interior.element.scope new file mode 100644 index 0000000000..a3235c56a0 --- /dev/null +++ b/data/fixtures/scopes/latex/interior.element.scope @@ -0,0 +1,48 @@ +\begin{quote} + Hello +\end{quote} +--- + +[#1 Content] = 1:4-1:9 + >-----< +1| Hello + +[#1 Removal] = 0:13-2:0 + > +0| \begin{quote} +1| Hello +2| \end{quote} + < + +[#1 Domain] = 0:0-2:11 + >------------- +0| \begin{quote} +1| Hello +2| \end{quote} + -----------< + +[#1 Insertion delimiter] = " " + + +[#2 Content] = +[#2 Removal] = 0:7-0:12 + >-----< +0| \begin{quote} + +[#2 Domain] = 0:6-0:13 + >-------< +0| \begin{quote} + +[#2 Insertion delimiter] = " " + + +[#3 Content] = +[#3 Removal] = 2:5-2:10 + >-----< +2| \end{quote} + +[#3 Domain] = 2:4-2:11 + >-------< +2| \end{quote} + +[#3 Insertion delimiter] = " " diff --git a/data/fixtures/scopes/lua/branch.if.scope b/data/fixtures/scopes/lua/branch.if.scope index 606863122e..3f35d2c647 100644 --- a/data/fixtures/scopes/lua/branch.if.scope +++ b/data/fixtures/scopes/lua/branch.if.scope @@ -21,10 +21,6 @@ end 2| elseif x > y then < -[#1 Interior] = 1:4-1:29 - >-------------------------< -1| print("x is less than y") - [#1 Insertion delimiter] = "\n" @@ -42,10 +38,6 @@ end 4| else < -[#2 Interior] = 3:4-3:32 - >----------------------------< -3| print("x is greater than y") - [#2 Insertion delimiter] = "\n" @@ -63,8 +55,4 @@ end 6| end < -[#3 Interior] = 5:4-5:28 - >------------------------< -5| print("x is equal to y") - [#3 Insertion delimiter] = "\n" diff --git a/data/fixtures/scopes/lua/interior.branch.scope b/data/fixtures/scopes/lua/interior.branch.scope new file mode 100644 index 0000000000..2ce1cb35f8 --- /dev/null +++ b/data/fixtures/scopes/lua/interior.branch.scope @@ -0,0 +1,49 @@ +if x < y then + a = 1 +elseif x > y then + a = 2 +else + a = 3 +end +--- + +[#1 Content] = +[#1 Removal] = 1:4-1:9 + >-----< +1| a = 1 + +[#1 Domain] = 0:0-1:9 + >------------- +0| if x < y then +1| a = 1 + ---------< + +[#1 Insertion delimiter] = " " + + +[#2 Content] = +[#2 Removal] = 3:4-3:9 + >-----< +3| a = 2 + +[#2 Domain] = 2:0-3:9 + >----------------- +2| elseif x > y then +3| a = 2 + ---------< + +[#2 Insertion delimiter] = " " + + +[#3 Content] = +[#3 Removal] = 5:4-5:9 + >-----< +5| a = 3 + +[#3 Domain] = 4:0-5:9 + >---- +4| else +5| a = 3 + ---------< + +[#3 Insertion delimiter] = " " diff --git a/data/fixtures/scopes/lua/interior.function.scope b/data/fixtures/scopes/lua/interior.function.scope new file mode 100644 index 0000000000..4880d538f5 --- /dev/null +++ b/data/fixtures/scopes/lua/interior.function.scope @@ -0,0 +1,30 @@ +function makeCounter() + local count = 0 +end +--- + +[#1 Content] = +[#1 Removal] = 1:4-1:19 + >---------------< +1| local count = 0 + +[#1 Domain] = 0:0-2:3 + >---------------------- +0| function makeCounter() +1| local count = 0 +2| end + ---< + +[#1 Insertion delimiter] = " " + + +[#2 Content] = +[#2 Removal] = 0:21-0:21 + >< +0| function makeCounter() + +[#2 Domain] = 0:20-0:22 + >--< +0| function makeCounter() + +[#2 Insertion delimiter] = " " diff --git a/data/fixtures/scopes/lua/map.scope b/data/fixtures/scopes/lua/map.scope index cbb86ec2a4..afca7544f1 100644 --- a/data/fixtures/scopes/lua/map.scope +++ b/data/fixtures/scopes/lua/map.scope @@ -14,11 +14,4 @@ foo = { bar = "a", baz = "b" } >-< 0| foo = { bar = "a", baz = "b" } -[Interior: Content] = 0:8-0:28 - >--------------------< -0| foo = { bar = "a", baz = "b" } -[Interior: Removal] = 0:7-0:29 - >----------------------< -0| foo = { bar = "a", baz = "b" } - [Insertion delimiter] = " " diff --git a/data/fixtures/scopes/lua/namedFunction.scope b/data/fixtures/scopes/lua/namedFunction.scope index a869646a86..d14715737a 100644 --- a/data/fixtures/scopes/lua/namedFunction.scope +++ b/data/fixtures/scopes/lua/namedFunction.scope @@ -20,13 +20,4 @@ end 6| end ---< -[Interior] = 1:4-5:7 - >--------------- -1| local count = 0 -2| return function() -3| count = count + 1 -4| return count -5| end - -------< - [Insertion delimiter] = "\n\n" diff --git a/data/fixtures/scopes/markdown/interior.cell.scope b/data/fixtures/scopes/markdown/interior.cell.scope new file mode 100644 index 0000000000..9bf5718ecd --- /dev/null +++ b/data/fixtures/scopes/markdown/interior.cell.scope @@ -0,0 +1,116 @@ +```python +def foo(): + pass +``` + +``` +hello +``` + +--- + +[#1 Content] = 0:3-2:8 + >------ +0| ```python +1| def foo(): +2| pass + --------< + +[#1 Removal] = 0:3-3:0 + >------ +0| ```python +1| def foo(): +2| pass +3| ``` + < + +[#1 Domain] = 0:0-3:3 + >--------- +0| ```python +1| def foo(): +2| pass +3| ``` + ---< + +[#1 Insertion delimiter] = " " + + +[#2 Content] = 1:0-2:8 + >---------- +1| def foo(): +2| pass + --------< + +[#2 Removal] = 0:9-3:0 + > +0| ```python +1| def foo(): +2| pass +3| ``` + < + +[#2 Domain] = 0:0-4:0 + >--------- +0| ```python +1| def foo(): +2| pass +3| ``` +4| + < + +[#2 Insertion delimiter] = " " + + +[#3 Content] = +[#3 Removal] = 1:8-1:8 + >< +1| def foo(): + +[#3 Domain] = 1:7-1:9 + >--< +1| def foo(): + +[#3 Insertion delimiter] = " " + + +[#4 Content] = 6:0-6:5 + >-----< +6| hello + +[#4 Removal] = 5:3-7:0 + > +5| ``` +6| hello +7| ``` + < + +[#4 Domain] = 5:0-7:3 + >--- +5| ``` +6| hello +7| ``` + ---< + +[#4 Insertion delimiter] = " " + + +[#5 Content] = 6:0-6:5 + >-----< +6| hello + +[#5 Removal] = 5:3-7:0 + > +5| ``` +6| hello +7| ``` + < + +[#5 Domain] = 5:0-8:0 + >--- +5| ``` +6| hello +7| ``` +8| + < + +[#5 Insertion delimiter] = " " diff --git a/data/fixtures/scopes/markdown/notebookCell.scope b/data/fixtures/scopes/markdown/notebookCell.scope index 60b0eb34be..5493342751 100644 --- a/data/fixtures/scopes/markdown/notebookCell.scope +++ b/data/fixtures/scopes/markdown/notebookCell.scope @@ -28,19 +28,6 @@ hello 5| ``` < -[#1 Interior: Content] = 1:0-2:8 - >---------- -1| def foo(): -2| pass - --------< -[#1 Interior: Removal] = 0:9-3:0 - > -0| ```python -1| def foo(): -2| pass -3| ``` - < - [#1 Insertion delimiter] = "\n\n" @@ -61,14 +48,4 @@ hello 8| < -[#2 Interior: Content] = 6:0-6:5 - >-----< -6| hello -[#2 Interior: Removal] = 5:3-7:0 - > -5| ``` -6| hello -7| ``` - < - [#2 Insertion delimiter] = "\n\n" diff --git a/data/fixtures/scopes/python/anonymousFunction.scope b/data/fixtures/scopes/python/anonymousFunction.scope index bfb98d9a04..4e5afbda7e 100644 --- a/data/fixtures/scopes/python/anonymousFunction.scope +++ b/data/fixtures/scopes/python/anonymousFunction.scope @@ -7,8 +7,4 @@ lambda: pass >------------< 0| lambda: pass -[Interior] = 0:8-0:12 - >----< -0| lambda: pass - [Insertion delimiter] = "\n" diff --git a/data/fixtures/scopes/python/anonymousFunction2.scope b/data/fixtures/scopes/python/anonymousFunction2.scope index 0f251e1fb7..78b05442a5 100644 --- a/data/fixtures/scopes/python/anonymousFunction2.scope +++ b/data/fixtures/scopes/python/anonymousFunction2.scope @@ -7,8 +7,4 @@ lambda x: x >-----------< 0| lambda x: x -[Interior] = 0:10-0:11 - >-< -0| lambda x: x - [Insertion delimiter] = "\n" diff --git a/data/fixtures/scopes/python/class.scope b/data/fixtures/scopes/python/class.scope new file mode 100644 index 0000000000..4463b9d47c --- /dev/null +++ b/data/fixtures/scopes/python/class.scope @@ -0,0 +1,13 @@ +class MyClass: + pass +--- + +[Content] = +[Removal] = +[Domain] = 0:0-1:8 + >-------------- +0| class MyClass: +1| pass + --------< + +[Insertion delimiter] = "\n\n" diff --git a/data/fixtures/scopes/python/interior.class.scope b/data/fixtures/scopes/python/interior.class.scope new file mode 100644 index 0000000000..0248108e3e --- /dev/null +++ b/data/fixtures/scopes/python/interior.class.scope @@ -0,0 +1,16 @@ +class MyClass: + pass +--- + +[Content] = +[Removal] = 1:4-1:8 + >----< +1| pass + +[Domain] = 0:0-1:8 + >-------------- +0| class MyClass: +1| pass + --------< + +[Insertion delimiter] = " " diff --git a/data/fixtures/scopes/python/interior.function.scope b/data/fixtures/scopes/python/interior.function.scope new file mode 100644 index 0000000000..9acf9a45a3 --- /dev/null +++ b/data/fixtures/scopes/python/interior.function.scope @@ -0,0 +1,28 @@ +def foo(): + pass +--- + +[#1 Content] = +[#1 Removal] = 1:4-1:8 + >----< +1| pass + +[#1 Domain] = 0:0-1:8 + >---------- +0| def foo(): +1| pass + --------< + +[#1 Insertion delimiter] = " " + + +[#2 Content] = +[#2 Removal] = 0:8-0:8 + >< +0| def foo(): + +[#2 Domain] = 0:7-0:9 + >--< +0| def foo(): + +[#2 Insertion delimiter] = " " diff --git a/data/fixtures/scopes/python/interior.function2.scope b/data/fixtures/scopes/python/interior.function2.scope new file mode 100644 index 0000000000..d3b7564582 --- /dev/null +++ b/data/fixtures/scopes/python/interior.function2.scope @@ -0,0 +1,30 @@ +@foo +def bar(value: string) -> str: + return value +--- + +[#1 Content] = +[#1 Removal] = 2:4-2:16 + >------------< +2| return value + +[#1 Domain] = 0:0-2:16 + >---- +0| @foo +1| def bar(value: string) -> str: +2| return value + ----------------< + +[#1 Insertion delimiter] = " " + + +[#2 Content] = +[#2 Removal] = 1:8-1:21 + >-------------< +1| def bar(value: string) -> str: + +[#2 Domain] = 1:7-1:22 + >---------------< +1| def bar(value: string) -> str: + +[#2 Insertion delimiter] = " " diff --git a/data/fixtures/scopes/python/interior.lambda.scope b/data/fixtures/scopes/python/interior.lambda.scope new file mode 100644 index 0000000000..a889bc2430 --- /dev/null +++ b/data/fixtures/scopes/python/interior.lambda.scope @@ -0,0 +1,13 @@ +lambda: pass +--- + +[Content] = +[Removal] = 0:8-0:12 + >----< +0| lambda: pass + +[Domain] = 0:0-0:12 + >------------< +0| lambda: pass + +[Insertion delimiter] = " " diff --git a/data/fixtures/scopes/python/interior.lambda2.scope b/data/fixtures/scopes/python/interior.lambda2.scope new file mode 100644 index 0000000000..af724a71b6 --- /dev/null +++ b/data/fixtures/scopes/python/interior.lambda2.scope @@ -0,0 +1,13 @@ +lambda x: x +--- + +[Content] = +[Removal] = 0:10-0:11 + >-< +0| lambda x: x + +[Domain] = 0:0-0:11 + >-----------< +0| lambda x: x + +[Insertion delimiter] = " " diff --git a/data/fixtures/scopes/python/namedFunction.scope b/data/fixtures/scopes/python/namedFunction.scope index abcd7da01a..ca7c1ce6ef 100644 --- a/data/fixtures/scopes/python/namedFunction.scope +++ b/data/fixtures/scopes/python/namedFunction.scope @@ -10,8 +10,4 @@ def foo(): 1| pass --------< -[Interior] = 1:4-1:8 - >----< -1| pass - [Insertion delimiter] = "\n\n" diff --git a/data/fixtures/scopes/python/namedFunction2.scope b/data/fixtures/scopes/python/namedFunction2.scope index 18ce418ab6..bb85d94947 100644 --- a/data/fixtures/scopes/python/namedFunction2.scope +++ b/data/fixtures/scopes/python/namedFunction2.scope @@ -12,8 +12,4 @@ def bar(value: string) -> str: 2| return value ----------------< -[Interior] = 2:4-2:16 - >------------< -2| return value - [Insertion delimiter] = "\n\n" diff --git a/data/fixtures/scopes/talon/command.scope b/data/fixtures/scopes/talon/command.scope index a9db1a7118..7f114b88bb 100644 --- a/data/fixtures/scopes/talon/command.scope +++ b/data/fixtures/scopes/talon/command.scope @@ -10,8 +10,4 @@ press {user.key}: 1| key(key) ------------< -[Interior] = 1:4-1:12 - >--------< -1| key(key) - [Insertion delimiter] = "\n" diff --git a/data/fixtures/scopes/talon/interior.command.scope b/data/fixtures/scopes/talon/interior.command.scope new file mode 100644 index 0000000000..3b1f340e92 --- /dev/null +++ b/data/fixtures/scopes/talon/interior.command.scope @@ -0,0 +1,16 @@ +do something: + a = 2 +--- + +[Content] = +[Removal] = 1:4-1:9 + >-----< +1| a = 2 + +[Domain] = 0:0-1:9 + >------------- +0| do something: +1| a = 2 + ---------< + +[Insertion delimiter] = " " diff --git a/data/fixtures/scopes/textual/interior.surroundingPair.scope b/data/fixtures/scopes/textual/interior.surroundingPair.scope new file mode 100644 index 0000000000..24f970f757 --- /dev/null +++ b/data/fixtures/scopes/textual/interior.surroundingPair.scope @@ -0,0 +1,16 @@ +( text ) +--- + +[Content] = 0:2-0:6 + >----< +0| ( text ) + +[Removal] = 0:1-0:7 + >------< +0| ( text ) + +[Domain] = 0:0-0:8 + >--------< +0| ( text ) + +[Insertion delimiter] = " " diff --git a/packages/common/src/scopeSupportFacets/html.ts b/packages/common/src/scopeSupportFacets/html.ts index 9380d91003..68ae5e7779 100644 --- a/packages/common/src/scopeSupportFacets/html.ts +++ b/packages/common/src/scopeSupportFacets/html.ts @@ -12,6 +12,7 @@ export const htmlScopeSupport: LanguageScopeSupportFacetMap = { "key.attribute": supported, "value.attribute": supported, "comment.block": supported, + "interior.element": supported, "argument.actual": notApplicable, "argument.actual.iteration": notApplicable, diff --git a/packages/common/src/scopeSupportFacets/javascript.ts b/packages/common/src/scopeSupportFacets/javascript.ts index ad79065b1f..30eafa68b5 100644 --- a/packages/common/src/scopeSupportFacets/javascript.ts +++ b/packages/common/src/scopeSupportFacets/javascript.ts @@ -125,6 +125,7 @@ export const javascriptJsxScopeSupport: LanguageScopeSupportFacetMap = { attribute: supported, "key.attribute": supported, "value.attribute": supported, + "interior.element": supported, }; export const javascriptScopeSupport: LanguageScopeSupportFacetMap = { diff --git a/packages/common/src/scopeSupportFacets/latex.ts b/packages/common/src/scopeSupportFacets/latex.ts index db73bc677b..64d72b34e3 100644 --- a/packages/common/src/scopeSupportFacets/latex.ts +++ b/packages/common/src/scopeSupportFacets/latex.ts @@ -13,4 +13,5 @@ export const latexScopeSupport: LanguageScopeSupportFacetMap = { tags: supported, environment: supported, disqualifyDelimiter: supported, + "interior.element": supported, }; diff --git a/packages/common/src/scopeSupportFacets/lua.ts b/packages/common/src/scopeSupportFacets/lua.ts index 5b515b1aff..601d8c8d6d 100644 --- a/packages/common/src/scopeSupportFacets/lua.ts +++ b/packages/common/src/scopeSupportFacets/lua.ts @@ -15,4 +15,6 @@ export const luaScopeSupport: LanguageScopeSupportFacetMap = { "branch.if": supported, namedFunction: supported, disqualifyDelimiter: supported, + "interior.function": supported, + "interior.branch": supported, }; diff --git a/packages/common/src/scopeSupportFacets/markdown.ts b/packages/common/src/scopeSupportFacets/markdown.ts index 52867e06f8..171bdf51f9 100644 --- a/packages/common/src/scopeSupportFacets/markdown.ts +++ b/packages/common/src/scopeSupportFacets/markdown.ts @@ -13,5 +13,6 @@ export const markdownScopeSupport: LanguageScopeSupportFacetMap = { "section.iteration.parent": supported, notebookCell: supported, + "interior.cell": supported, "collectionItem.unenclosed": supported, }; diff --git a/packages/common/src/scopeSupportFacets/python.ts b/packages/common/src/scopeSupportFacets/python.ts index 7df0aa9c71..b46466c93f 100644 --- a/packages/common/src/scopeSupportFacets/python.ts +++ b/packages/common/src/scopeSupportFacets/python.ts @@ -38,6 +38,12 @@ export const pythonScopeSupport: LanguageScopeSupportFacetMap = { "branch.try": supported, "branch.loop": supported, + class: supported, + + "interior.class": supported, + "interior.function": supported, + "interior.lambda": supported, + element: notApplicable, tags: notApplicable, attribute: notApplicable, diff --git a/packages/common/src/scopeSupportFacets/scopeSupportFacetInfos.ts b/packages/common/src/scopeSupportFacets/scopeSupportFacetInfos.ts index 21c42943ca..f39280ee06 100644 --- a/packages/common/src/scopeSupportFacets/scopeSupportFacetInfos.ts +++ b/packages/common/src/scopeSupportFacets/scopeSupportFacetInfos.ts @@ -705,6 +705,35 @@ export const scopeSupportFacetInfos: Record< isIteration: true, }, + "interior.class": { + description: "The body of a class", + scopeType: { type: "interior" }, + }, + "interior.function": { + description: "The body of a function", + scopeType: { type: "interior" }, + }, + "interior.lambda": { + description: "The body of a lambda/anonymous function", + scopeType: { type: "interior" }, + }, + "interior.branch": { + description: "The body of an if/elif/else branch", + scopeType: { type: "interior" }, + }, + "interior.element": { + description: "The interior/children of an XML element", + scopeType: { type: "interior" }, + }, + "interior.command": { + description: "The body of a Talon command", + scopeType: { type: "interior" }, + }, + "interior.cell": { + description: "The body of a code cell in markdown", + scopeType: { type: "interior" }, + }, + notebookCell: { description: "A cell in a notebook or a markdown code block", scopeType: "notebookCell", diff --git a/packages/common/src/scopeSupportFacets/scopeSupportFacets.types.ts b/packages/common/src/scopeSupportFacets/scopeSupportFacets.types.ts index 669c27b49f..e40b157f32 100644 --- a/packages/common/src/scopeSupportFacets/scopeSupportFacets.types.ts +++ b/packages/common/src/scopeSupportFacets/scopeSupportFacets.types.ts @@ -174,6 +174,14 @@ export const scopeSupportFacets = [ "type.typeArgument", "type.typeArgument.iteration", + "interior.class", + "interior.function", + "interior.lambda", + "interior.branch", + "interior.element", + "interior.command", + "interior.cell", + "notebookCell", // FIXME: Still in legacy @@ -213,6 +221,7 @@ export type TextualScopeSupportFacet = | "url" | "surroundingPair" | "surroundingPair.iteration" + | "interior.surroundingPair" | "collectionItem.textual" | "collectionItem.textual.iteration"; diff --git a/packages/common/src/scopeSupportFacets/talon.ts b/packages/common/src/scopeSupportFacets/talon.ts index c5728874ff..c2fc3e46fe 100644 --- a/packages/common/src/scopeSupportFacets/talon.ts +++ b/packages/common/src/scopeSupportFacets/talon.ts @@ -5,6 +5,7 @@ const { supported } = ScopeSupportFacetLevel; export const talonScopeSupport: LanguageScopeSupportFacetMap = { command: supported, + "interior.command": supported, "name.field": supported, "value.field": supported, }; diff --git a/packages/common/src/scopeSupportFacets/textualScopeSupportFacetInfos.ts b/packages/common/src/scopeSupportFacets/textualScopeSupportFacetInfos.ts index 86c34b5abf..8fe3e2de83 100644 --- a/packages/common/src/scopeSupportFacets/textualScopeSupportFacetInfos.ts +++ b/packages/common/src/scopeSupportFacets/textualScopeSupportFacetInfos.ts @@ -83,6 +83,12 @@ export const textualScopeSupportFacetInfos: Record< }, isIteration: true, }, + "interior.surroundingPair": { + description: "The interior scope of a surrounding pair", + scopeType: { + type: "interior", + }, + }, "collectionItem.textual": { description: "A text based collection item", scopeType: { diff --git a/packages/common/src/types/command/PartialTargetDescriptor.types.ts b/packages/common/src/types/command/PartialTargetDescriptor.types.ts index af7b98cadb..8ee0a2ed3c 100644 --- a/packages/common/src/types/command/PartialTargetDescriptor.types.ts +++ b/packages/common/src/types/command/PartialTargetDescriptor.types.ts @@ -227,6 +227,13 @@ export interface CustomRegexScopeType { flags?: string; } +export interface InteriorScopeType { + type: "interior"; + + // The user has specified a scope type. eg "inside element". + explicitScopeType?: boolean; +} + export type SurroundingPairDirection = "left" | "right"; export interface SurroundingPairScopeType { @@ -270,6 +277,7 @@ export type ScopeType = | SurroundingPairScopeType | SurroundingPairInteriorScopeType | CustomRegexScopeType + | InteriorScopeType | OneOfScopeType | GlyphScopeType; diff --git a/packages/cursorless-engine/src/generateSpokenForm/primitiveTargetToSpokenForm.ts b/packages/cursorless-engine/src/generateSpokenForm/primitiveTargetToSpokenForm.ts index a2046e7838..9b657aedb8 100644 --- a/packages/cursorless-engine/src/generateSpokenForm/primitiveTargetToSpokenForm.ts +++ b/packages/cursorless-engine/src/generateSpokenForm/primitiveTargetToSpokenForm.ts @@ -267,6 +267,9 @@ export class PrimitiveTargetSpokenFormGenerator { } ); + case "interior": + return this.spokenFormMap.simpleModifier.interiorOnly; + default: return this.spokenFormMap.simpleScopeTypeType[scopeType.type]; } diff --git a/packages/cursorless-engine/src/languages/TreeSitterQuery/validateQueryCaptures.test.ts b/packages/cursorless-engine/src/languages/TreeSitterQuery/validateQueryCaptures.test.ts index 535c330d40..08c54a7e92 100644 --- a/packages/cursorless-engine/src/languages/TreeSitterQuery/validateQueryCaptures.test.ts +++ b/packages/cursorless-engine/src/languages/TreeSitterQuery/validateQueryCaptures.test.ts @@ -7,12 +7,12 @@ const testCases: { name: string; isOk: boolean; content: string }[] = [ { name: "Scope captures", isOk: true, - content: "(if_statement) @statement @ifStatement @comment", + content: "(if_statement) @statement @ifStatement @comment @interior", }, { name: "Relationships", isOk: true, - content: "(if_statement) @statement.domain @statement.interior @_.removal", + content: "(if_statement) @statement.domain @_.removal", }, { name: "Position captures", @@ -24,7 +24,7 @@ const testCases: { name: string; isOk: boolean; content: string }[] = [ name: "Range captures", isOk: true, content: - "(if_statement) @statement.start @statement.start.endOf @statement.removal.start @statement.interior.start.endOf", + "(if_statement) @statement.start @statement.start.endOf @statement.removal.start", }, { name: "Dummy capture", diff --git a/packages/cursorless-engine/src/languages/TreeSitterQuery/validateQueryCaptures.ts b/packages/cursorless-engine/src/languages/TreeSitterQuery/validateQueryCaptures.ts index 4f2b8f4db9..594b755129 100644 --- a/packages/cursorless-engine/src/languages/TreeSitterQuery/validateQueryCaptures.ts +++ b/packages/cursorless-engine/src/languages/TreeSitterQuery/validateQueryCaptures.ts @@ -2,7 +2,7 @@ import { showError, simpleScopeTypeTypes } from "@cursorless/common"; import { ide } from "../../singletons/ide.singleton"; const wildcard = "_"; -const captureNames = [wildcard, ...simpleScopeTypeTypes]; +const captureNames = [wildcard, "interior", ...simpleScopeTypeTypes]; const positionRelationships = ["prefix", "leading", "trailing"]; const positionSuffixes = [ @@ -17,7 +17,6 @@ const positionSuffixes = [ const rangeRelationships = [ "domain", "removal", - "interior", "iteration", "iteration.domain", ]; diff --git a/packages/cursorless-engine/src/processTargets/modifiers/ContainingScopeStage.ts b/packages/cursorless-engine/src/processTargets/modifiers/ContainingScopeStage.ts index bf74445f54..dff36ba8a7 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/ContainingScopeStage.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/ContainingScopeStage.ts @@ -52,7 +52,7 @@ export class ContainingScopeStage implements ModifierStage { ); if (containingScopes == null) { - throw new NoContainingScopeError(this.modifier.scopeType.type); + throw new NoContainingScopeError(scopeType.type); } return containingScopes; diff --git a/packages/cursorless-engine/src/processTargets/modifiers/InteriorStage.ts b/packages/cursorless-engine/src/processTargets/modifiers/InteriorStage.ts index ec1c37508f..3ae2d9899b 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/InteriorStage.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/InteriorStage.ts @@ -8,20 +8,27 @@ import type { ModifierStage } from "../PipelineStages.types"; import { ModifyIfConditionStage } from "./ConditionalModifierStages"; export class InteriorOnlyStage implements ModifierStage { - private containingSurroundingPairIfNoInteriorStage: ModifierStage; - constructor( - private modifierStageFactory: ModifierStageFactory, + private modifierHandlerFactory: ModifierStageFactory, private modifier: InteriorOnlyModifier, - ) { - this.containingSurroundingPairIfNoInteriorStage = - getContainingSurroundingPairIfNoInteriorStage(this.modifierStageFactory); - } + ) {} run(target: Target): Target[] { - return this.containingSurroundingPairIfNoInteriorStage - .run(target) - .flatMap((target) => target.getInterior()!); + const interior = target.getInterior(); + + if (interior != null) { + return interior; + } + + const containingModifier = this.modifierHandlerFactory.create({ + type: "containingScope", + scopeType: { + type: "interior", + explicitScopeType: target.hasExplicitScopeType, + }, + }); + + return containingModifier.run(target); } } @@ -43,19 +50,6 @@ export class ExcludeInteriorStage implements ModifierStage { } } -function getContainingSurroundingPairIfNoInteriorStage( - modifierStageFactory: ModifierStageFactory, -): ModifierStage { - return new ModifyIfConditionStage( - modifierStageFactory, - { - type: "containingScope", - scopeType: { type: "surroundingPair", delimiter: "any" }, - }, - (target) => target.getInterior() == null, - ); -} - export function getContainingSurroundingPairIfNoBoundaryStage( modifierStageFactory: ModifierStageFactory, ): ModifierStage { diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/FallbackScopeHandler.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/FallbackScopeHandler.ts index 869d4993b3..911bfaafe9 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/FallbackScopeHandler.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/FallbackScopeHandler.ts @@ -18,32 +18,39 @@ export class FallbackScopeHandler extends BaseScopeHandler { public scopeType = undefined; protected isHierarchical = true; - get iterationScopeType(): ScopeType { - throw new NoContainingScopeError( - "Iteration scope for FallbackScopeHandler", + static create( + scopeHandlerFactory: ScopeHandlerFactory, + scopeType: FallbackScopeType, + languageId: string, + ): ScopeHandler { + const scopeHandlers: ScopeHandler[] = scopeType.scopeTypes.map( + (scopeType) => scopeHandlerFactory.create(scopeType, languageId), ); + + return this.createFromScopeHandlers(scopeHandlers); } - constructor( - public scopeHandlerFactory: ScopeHandlerFactory, - private fallbackScopeType: FallbackScopeType, - private languageId: string, - ) { + static createFromScopeHandlers(scopeHandlers: ScopeHandler[]): ScopeHandler { + return new FallbackScopeHandler(scopeHandlers); + } + + private constructor(private scopeHandlers: ScopeHandler[]) { super(); } + get iterationScopeType(): ScopeType { + throw new NoContainingScopeError( + "Iteration scope for FallbackScopeHandler", + ); + } + *generateScopeCandidates( editor: TextEditor, position: Position, direction: Direction, hints: ScopeIteratorRequirements, ): Iterable { - const scopeHandlers: ScopeHandler[] = this.fallbackScopeType.scopeTypes.map( - (scopeType) => - this.scopeHandlerFactory.create(scopeType, this.languageId), - ); - - for (const scopeHandler of scopeHandlers) { + for (const scopeHandler of this.scopeHandlers) { yield* scopeHandler.generateScopes(editor, position, direction, hints); } } diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ScopeHandlerFactoryImpl.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ScopeHandlerFactoryImpl.ts index 50152f21ef..8c9dc3c46d 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ScopeHandlerFactoryImpl.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ScopeHandlerFactoryImpl.ts @@ -20,15 +20,16 @@ import { NonWhitespaceSequenceScopeHandler, UrlScopeHandler, } from "./RegexScopeHandler"; +import type { ComplexScopeType, ScopeHandler } from "./scopeHandler.types"; import type { ScopeHandlerFactory } from "./ScopeHandlerFactory"; import { SentenceScopeHandler } from "./SentenceScopeHandler/SentenceScopeHandler"; import { SurroundingPairInteriorScopeHandler, SurroundingPairScopeHandler, } from "./SurroundingPairScopeHandler"; +import { InteriorScopeHandler } from "./SurroundingPairScopeHandler/InteriorScopeHandler"; import { TokenScopeHandler } from "./TokenScopeHandler"; import { WordScopeHandler } from "./WordScopeHandler/WordScopeHandler"; -import type { ComplexScopeType, ScopeHandler } from "./scopeHandler.types"; /** * Returns a scope handler for the given scope type and language id, or @@ -119,12 +120,19 @@ export class ScopeHandlerFactoryImpl implements ScopeHandlerFactory { scopeType, languageId, ); + case "interior": + return new InteriorScopeHandler( + this, + this.languageDefinitions, + scopeType, + languageId, + ); case "custom": return scopeType.scopeHandler; case "oneOf": return OneOfScopeHandler.create(this, scopeType, languageId); case "fallback": - return new FallbackScopeHandler(this, scopeType, languageId); + return FallbackScopeHandler.create(this, scopeType, languageId); case "conditional": return new ConditionalScopeHandler(this, scopeType, languageId); case "instance": diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/SurroundingPairScopeHandler/InteriorScopeHandler.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/SurroundingPairScopeHandler/InteriorScopeHandler.ts new file mode 100644 index 0000000000..56406abec3 --- /dev/null +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/SurroundingPairScopeHandler/InteriorScopeHandler.ts @@ -0,0 +1,140 @@ +import { + NoContainingScopeError, + Range, + type Direction, + type InteriorScopeType, + type Position, + type ScopeType, + type TextEditor, +} from "@cursorless/common"; +import type { LanguageDefinitions } from "../../../../languages/LanguageDefinitions"; +import type { Target } from "../../../../typings/target.types"; +import { InteriorTarget } from "../../../targets"; +import { BaseScopeHandler } from "../BaseScopeHandler"; +import { FallbackScopeHandler } from "../FallbackScopeHandler"; +import { OneOfScopeHandler } from "../OneOfScopeHandler"; +import type { TargetScope } from "../scope.types"; +import type { + ComplexScopeType, + ScopeIteratorRequirements, +} from "../scopeHandler.types"; +import { type ScopeHandler } from "../scopeHandler.types"; +import type { ScopeHandlerFactory } from "../ScopeHandlerFactory"; + +export class InteriorScopeHandler extends BaseScopeHandler { + protected isHierarchical = true; + + constructor( + private scopeHandlerFactory: ScopeHandlerFactory, + private languageDefinitions: LanguageDefinitions, + public readonly scopeType: InteriorScopeType, + private languageId: string, + ) { + super(); + } + + get iterationScopeType(): ScopeType | ComplexScopeType { + throw new NoContainingScopeError( + "Iteration scope for InteriorScopeHandler", + ); + } + + *generateScopeCandidates( + editor: TextEditor, + position: Position, + direction: Direction, + hints: ScopeIteratorRequirements, + ): Iterable { + const targetDomain = new Range(position, hints.distalPosition); + const scopeHandler = this.getScopeHandler(); + + if (scopeHandler == null) { + return; + } + + const scopes = scopeHandler.generateScopes( + editor, + position, + direction, + hints, + ); + + for (const scope of scopes) { + if (this.shouldYield(targetDomain, scope)) { + yield createInteriorScope(scope); + } + } + } + + private getScopeHandler(): ScopeHandler | undefined { + const languageScopeHandler = this.languageDefinitions + .get(this.languageId) + ?.getScopeHandler(this.scopeType); + + const pairScopeHandler = this.scopeHandlerFactory.create( + { + type: "surroundingPair", + delimiter: "any", + }, + this.languageId, + ); + + // If the scope type is explicit (ie, the user has specified a scope + // type), then we want to prioritize language scopes. For example, + // if the user says "inside element" inside a `
` tag, the angle + // brackets of the tag are also a surrounding pair which should have + // lower priority. + if (this.scopeType.explicitScopeType) { + if (languageScopeHandler == null) { + return pairScopeHandler; + } + return FallbackScopeHandler.createFromScopeHandlers([ + languageScopeHandler, + pairScopeHandler, + ]); + } + + if (languageScopeHandler == null) { + return pairScopeHandler; + } + + return OneOfScopeHandler.createFromScopeHandlers( + this.scopeHandlerFactory, + this.languageId, + [languageScopeHandler, pairScopeHandler], + ); + } + + private shouldYield(targetDomain: Range, scope: TargetScope): boolean { + // For an explicit scope type we only yield scopes that are contained within + // the target domain. For example, if the user said "inside token", we don't + // want to yield scopes that are larger than the token. + return ( + !this.scopeType.explicitScopeType || targetDomain.contains(scope.domain) + ); + } +} + +function createInteriorScope(scope: TargetScope): TargetScope { + return { + editor: scope.editor, + domain: scope.domain, + getTargets(isReversed) { + return scope.getTargets(isReversed).flatMap(createInteriorTargets); + }, + }; +} + +function createInteriorTargets(target: Target): Target[] { + const interior = target.getInterior(); + if (interior != null) { + return interior; + } + return [ + new InteriorTarget({ + editor: target.editor, + isReversed: target.isReversed, + fullInteriorRange: target.contentRange, + }), + ]; +} diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/TreeSitterScopeHandler/TreeSitterScopeHandler.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/TreeSitterScopeHandler/TreeSitterScopeHandler.ts index 5ce6141817..1fead109cd 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/TreeSitterScopeHandler/TreeSitterScopeHandler.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/TreeSitterScopeHandler/TreeSitterScopeHandler.ts @@ -53,13 +53,6 @@ export class TreeSitterScopeHandler extends BaseTreeSitterScopeHandler { const domain = getRelatedRange(match, scopeTypeType, "domain", true) ?? contentRange; - const interiorRange = getRelatedRange( - match, - scopeTypeType, - "interior", - true, - ); - const prefixRange = getRelatedRange( match, scopeTypeType, @@ -111,7 +104,6 @@ export class TreeSitterScopeHandler extends BaseTreeSitterScopeHandler { removalRange, leadingDelimiterRange, trailingDelimiterRange, - interiorRange, insertionDelimiter, }), ], diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeTypeStages/LegacyContainingSyntaxScopeStage.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeTypeStages/LegacyContainingSyntaxScopeStage.ts index d3ba647c4a..e3beaa6f02 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeTypeStages/LegacyContainingSyntaxScopeStage.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeTypeStages/LegacyContainingSyntaxScopeStage.ts @@ -65,7 +65,6 @@ export class LegacyContainingSyntaxScopeStage implements ModifierStage { leadingDelimiterRange, trailingDelimiterRange, removalRange, - interiorRange, } = scope.context; if ( @@ -85,7 +84,6 @@ export class LegacyContainingSyntaxScopeStage implements ModifierStage { isReversed: target.isReversed, contentRange: contentSelection, removalRange: removalRange, - interiorRange: interiorRange, insertionDelimiter: containingListDelimiter, leadingDelimiterRange, trailingDelimiterRange, diff --git a/packages/cursorless-engine/src/processTargets/targets/InteriorTarget.ts b/packages/cursorless-engine/src/processTargets/targets/InteriorTarget.ts index d7a38da9ef..afdcc3f9b3 100644 --- a/packages/cursorless-engine/src/processTargets/targets/InteriorTarget.ts +++ b/packages/cursorless-engine/src/processTargets/targets/InteriorTarget.ts @@ -1,8 +1,7 @@ import type { Range } from "@cursorless/common"; +import { shrinkRangeToFitContent } from "../../util/selectionUtils"; import type { MinimumTargetParameters } from "./BaseTarget"; import { BaseTarget } from "./BaseTarget"; -import { shrinkRangeToFitContent } from "../../util/selectionUtils"; -import { createContinuousRangeFromRanges } from "./util/createContinuousRange"; export interface InteriorTargetParameters extends MinimumTargetParameters { readonly fullInteriorRange: Range; @@ -42,11 +41,8 @@ export class InteriorTarget extends BaseTarget { return new InteriorTarget({ ...this.getCloneParameters(), isReversed, - fullInteriorRange: createContinuousRangeFromRanges( - this.fullInteriorRange, + fullInteriorRange: this.fullInteriorRange.union( endTarget.fullInteriorRange, - true, - true, ), }); } diff --git a/packages/cursorless-engine/src/processTargets/targets/ScopeTypeTarget.ts b/packages/cursorless-engine/src/processTargets/targets/ScopeTypeTarget.ts index f3a3712e4b..cf74c9854d 100644 --- a/packages/cursorless-engine/src/processTargets/targets/ScopeTypeTarget.ts +++ b/packages/cursorless-engine/src/processTargets/targets/ScopeTypeTarget.ts @@ -7,12 +7,7 @@ import type { Target } from "../../typings/target.types"; import { toGeneralizedRange } from "../../util/targetUtils"; import type { CommonTargetParameters } from "./BaseTarget"; import { BaseTarget } from "./BaseTarget"; -import { InteriorTarget } from "./InteriorTarget"; import { PlainTarget } from "./PlainTarget"; -import { - createContinuousRange, - createContinuousRangeFromRanges, -} from "./util/createContinuousRange"; import { getDelimitedSequenceRemovalRange } from "./util/insertionRemovalBehaviors/DelimitedSequenceInsertionRemovalBehavior"; import { getTokenLeadingDelimiterTarget, @@ -25,7 +20,6 @@ export interface ScopeTypeTargetParameters extends CommonTargetParameters { readonly insertionDelimiter?: string; readonly prefixRange?: Range; readonly removalRange?: Range; - readonly interiorRange?: Range; readonly leadingDelimiterRange?: Range; readonly trailingDelimiterRange?: Range; } @@ -34,7 +28,6 @@ export class ScopeTypeTarget extends BaseTarget { type = "ScopeTypeTarget"; private scopeTypeType_: SimpleScopeTypeType; private removalRange_?: Range; - private interiorRange_?: Range; private leadingDelimiterRange_?: Range; private trailingDelimiterRange_?: Range; private hasDelimiterRange_: boolean; @@ -45,7 +38,6 @@ export class ScopeTypeTarget extends BaseTarget { super(parameters); this.scopeTypeType_ = parameters.scopeTypeType; this.removalRange_ = parameters.removalRange; - this.interiorRange_ = parameters.interiorRange; this.leadingDelimiterRange_ = parameters.leadingDelimiterRange; this.trailingDelimiterRange_ = parameters.trailingDelimiterRange; this.prefixRange = parameters.prefixRange; @@ -84,19 +76,6 @@ export class ScopeTypeTarget extends BaseTarget { return undefined; } - getInterior() { - if (this.interiorRange_ == null) { - return super.getInterior(); - } - return [ - new InteriorTarget({ - editor: this.editor, - isReversed: this.isReversed, - fullInteriorRange: this.interiorRange_, - }), - ]; - } - getRemovalRange(): Range { if (this.removalRange_ != null) { return this.removalRange_; @@ -127,11 +106,8 @@ export class ScopeTypeTarget extends BaseTarget { const contentRemovalRange = this.removalRange_ != null || endTarget.removalRange_ != null - ? createContinuousRangeFromRanges( - this.removalRange_ ?? this.contentRange, + ? (this.removalRange_ ?? this.contentRange).union( endTarget.removalRange_ ?? endTarget.contentRange, - true, - true, ) : undefined; @@ -141,7 +117,7 @@ export class ScopeTypeTarget extends BaseTarget { leadingDelimiterRange: this.leadingDelimiterRange_, trailingDelimiterRange: endTarget.trailingDelimiterRange_, removalRange: contentRemovalRange, - contentRange: createContinuousRange(this, endTarget, true, true), + contentRange: this.contentRange.union(endTarget.contentRange), }); } diff --git a/packages/cursorless-engine/src/processTargets/targets/util/createContinuousRange.ts b/packages/cursorless-engine/src/processTargets/targets/util/createContinuousRange.ts index 02a2777f34..f9a904bf32 100644 --- a/packages/cursorless-engine/src/processTargets/targets/util/createContinuousRange.ts +++ b/packages/cursorless-engine/src/processTargets/targets/util/createContinuousRange.ts @@ -15,7 +15,7 @@ export function createContinuousRange( ); } -export function createContinuousRangeFromRanges( +function createContinuousRangeFromRanges( startRange: Range, endRange: Range, includeStart: boolean, diff --git a/packages/cursorless-engine/src/scopeProviders/ScopeInfoProvider.ts b/packages/cursorless-engine/src/scopeProviders/ScopeInfoProvider.ts index a1b982a5cd..4ca19be2c2 100644 --- a/packages/cursorless-engine/src/scopeProviders/ScopeInfoProvider.ts +++ b/packages/cursorless-engine/src/scopeProviders/ScopeInfoProvider.ts @@ -126,6 +126,7 @@ function isLanguageSpecific(scopeType: ScopeType): boolean { case "functionName": case "ifStatement": case "instance": + case "interior": case "list": case "map": case "name": diff --git a/queries/go.scm b/queries/go.scm index 73a0315319..598ce90fa4 100644 --- a/queries/go.scm +++ b/queries/go.scm @@ -202,11 +202,11 @@ name: (_) @functionName body: (block . - "{" @namedFunction.interior.start.endOf - "}" @namedFunction.interior.end.startOf + "{" @interior.start.endOf + "}" @interior.end.startOf . )? -) @namedFunction @functionName.domain +) @namedFunction @functionName.domain @interior.domain ;; method declaration ;; func (X) foo() {} @@ -214,21 +214,21 @@ name: (_) @functionName body: (block . - "{" @namedFunction.interior.start.endOf - "}" @namedFunction.interior.end.startOf + "{" @interior.start.endOf + "}" @interior.end.startOf . ) -) @namedFunction @functionName.domain +) @namedFunction @functionName.domain @interior.domain ;; func literal (func_literal body: (block . - "{" @anonymousFunction.interior.start.endOf @namedFunction.interior.start.endOf - "}" @anonymousFunction.interior.end.startOf @namedFunction.interior.end.startOf + "{" @interior.start.endOf + "}" @interior.end.startOf . ) -) @anonymousFunction @namedFunction +) @anonymousFunction @namedFunction @interior.domain ;; switch-based branch diff --git a/queries/html.scm b/queries/html.scm index 70b457e14c..3559b325dc 100644 --- a/queries/html.scm +++ b/queries/html.scm @@ -68,9 +68,9 @@ ;;! ^^^^^^^^^^^^^^^ ;;! ^^^^ (_ - (start_tag) @xmlElement.interior.start.endOf - (end_tag) @xmlElement.interior.end.startOf -) @xmlElement + (start_tag) @interior.start.endOf + (end_tag) @interior.end.startOf +) @xmlElement @interior.domain ;;!! text ;;! ^^^^^ ^^^^^^ diff --git a/queries/javascript.jsx.scm b/queries/javascript.jsx.scm index 6cad71af0d..2825fcff08 100644 --- a/queries/javascript.jsx.scm +++ b/queries/javascript.jsx.scm @@ -3,9 +3,12 @@ ;;! ### ;;! *** ( - (jsx_element) @xmlElement @_.interior @_.iteration - (#child-range! @_.interior 0 -1 true true) - (#child-range! @_.iteration 0 -1 true true) + (jsx_element) @xmlElement @interior @interior.domain + (#child-range! @interior 0 -1 true true) +) +( + (jsx_element) @xmlElement.iteration + (#child-range! @xmlElement.iteration 0 -1 true true) ) ;;!! bar diff --git a/queries/latex.scm b/queries/latex.scm index a67decdc20..2b044cd777 100644 --- a/queries/latex.scm +++ b/queries/latex.scm @@ -16,8 +16,8 @@ (subparagraph) @subParagraph (_ - (begin) @xmlStartTag @environment.interior.start.endOf @xmlElement.interior.start.endOf - (end) @xmlEndTag @environment.interior.end.startOf @xmlElement.interior.end.startOf + (begin) @xmlStartTag @interior.start.endOf + (end) @xmlEndTag @interior.end.startOf ) @environment @xmlElement @_.domain (_ diff --git a/queries/lua.scm b/queries/lua.scm index 19ba91145f..0a5a728a7e 100644 --- a/queries/lua.scm +++ b/queries/lua.scm @@ -77,8 +77,8 @@ ;;!! (if_statement - "if" @branch.start - consequence: (_) @branch.end @branch.interior + "if" @branch.start @interior.domain.start + consequence: (_) @branch.end @interior @interior.domain.end ) @ifStatement @branch.iteration @condition.iteration ;;!! if x < y then @@ -90,12 +90,12 @@ ;;!! end [ (elseif_statement - consequence: (_) @branch.interior + consequence: (_) @interior ) (else_statement - body: (_) @branch.interior + body: (_) @interior ) -] @branch @_.domain +] @branch @interior.domain ;;!! while i <= 5 do ;;! ^^^^^^ @@ -115,12 +115,19 @@ ;; Lists and maps (table_constructor - "{" @_.interior.start.endOf @value.iteration.start.endOf @collectionKey.iteration.start.endOf (field name: (_) ) - "}" @_.interior.end.startOf @value.iteration.end.startOf @collectionKey.iteration.end.startOf ) @map + +(table_constructor + "{" @value.iteration.start.endOf @collectionKey.iteration.start.endOf + (field + name: (_) + ) + "}" @value.iteration.end.startOf @collectionKey.iteration.end.startOf +) + ;;!! a = { foo = "bar" } ;;! ^^^-------- ;;! xxxxxx----- @@ -137,11 +144,9 @@ ;;!! a = { "1", "2", "3" } ;;! ^^^^^^^^^^^^^^^^^ (table_constructor - "{" @_.interior.start.endOf (field !name ) - "}" @_.interior.end.startOf ) @list ;; Strings @@ -215,8 +220,8 @@ ;;! ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (function_declaration name: (_) @functionName - body: (_)? @namedFunction.interior -) @functionName.domain @namedFunction + body: (_)? @interior +) @namedFunction @_.domain ;; inside lambda: ;;!! __add = function(a, b) return a + b end @@ -226,8 +231,8 @@ ;;! ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (function_definition !name - body: (_)? @_.interior -) @anonymousFunction + body: (_)? @interior +) @anonymousFunction @interior.domain ;; Names and values diff --git a/queries/markdown.scm b/queries/markdown.scm index aa1af86613..e81ecc9e9c 100644 --- a/queries/markdown.scm +++ b/queries/markdown.scm @@ -48,11 +48,11 @@ ;;! ^^^ ( (fenced_code_block - (fenced_code_block_delimiter) @_.interior.start.endOf + (fenced_code_block_delimiter) @interior.start.endOf . (block_continuation) - (fenced_code_block_delimiter) @_.interior.end.startOf - ) @notebookCell + (fenced_code_block_delimiter) @interior.end.startOf + ) @notebookCell @interior.domain (#trim-end! @notebookCell) (#insertion-delimiter! @notebookCell "\n\n") ) @@ -66,9 +66,9 @@ ;;! ^^^ ( (fenced_code_block - (info_string) @_.interior.start.endOf - (fenced_code_block_delimiter) @_.interior.end.startOf - ) @notebookCell + (info_string) @interior.start.endOf + (fenced_code_block_delimiter) @interior.end.startOf + ) @notebookCell @interior.domain (#trim-end! @notebookCell) (#insertion-delimiter! @notebookCell "\n\n") ) diff --git a/queries/python.scm b/queries/python.scm index 9fd7f53697..26ffbdc567 100644 --- a/queries/python.scm +++ b/queries/python.scm @@ -282,30 +282,30 @@ ( (function_definition name: (_) @functionName - body: (_) @namedFunction.interior - ) @namedFunction @functionName.domain + body: (_) @interior + ) @namedFunction @functionName.domain @interior.domain (#not-parent-type? @namedFunction decorated_definition) ) (decorated_definition (function_definition name: (_) @functionName - body: (_) @namedFunction.interior + body: (_) @interior ) -) @namedFunction @functionName.domain +) @namedFunction @functionName.domain @interior.domain ( (class_definition name: (_) @className - body: (_) @class.interior - ) @class @className.domain + body: (_) @interior + ) @class @className.domain @interior.domain (#not-parent-type? @class decorated_definition) ) (decorated_definition (class_definition name: (_) @className - body: (_) @class.interior + body: (_) @interior ) -) @class @className.domain +) @class @className.domain @interior.domain (module) @className.iteration @class.iteration (module) @statement.iteration @@ -362,8 +362,8 @@ ;;!! lambda _: pass ;;! ^^^^^^^^^^^^^^ (lambda - body: (_) @anonymousFunction.interior -) @anonymousFunction + body: (_) @interior +) @anonymousFunction @interior.domain ;;!! match value: ;;! ^^^^^ diff --git a/queries/talon.scm b/queries/talon.scm index d9c7dc54f4..da5a8b68d4 100644 --- a/queries/talon.scm +++ b/queries/talon.scm @@ -122,8 +122,8 @@ ;;! ^^^^^^^^^^^^^^^^ ( (command_declaration - right: (_) @_.interior - ) @command + right: (_) @interior + ) @command @interior.domain (#insertion-delimiter! @command "\n") ) diff --git a/queries/xml.scm b/queries/xml.scm index ec7b93628b..e509419245 100644 --- a/queries/xml.scm +++ b/queries/xml.scm @@ -45,9 +45,9 @@ ;;! ^^^^^^^^^^^^^^^ ;;! ^^^^ (element - (STag) @xmlElement.interior.start.endOf - (ETag) @xmlElement.interior.end.startOf -) @xmlElement + (STag) @interior.start.endOf + (ETag) @interior.end.startOf +) @xmlElement @interior.domain ;;!! text ;;! ^^^^^ ^^^^^^