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:
)
+ 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
;;! ^^^^^ ^^^^^^