@@ -165,7 +165,7 @@ function generateScopesExclusive(
165165}
166166
167167/**
168- * Gets the interior scope range(s) within the containing scope of
168+ * Gets the scope range(s) within the containing scope of
169169 * {@link initialPosition} that should be used to exclude next / previous
170170 * scopes.
171171 *
@@ -194,114 +194,101 @@ function getExcludedInteriorRanges(
194194 initialPosition : Position ,
195195 direction : Direction ,
196196) : Range [ ] {
197- const interiorTargets =
198- scopeHandler . scopeType ?. type === "surroundingPair"
199- ? getSurroundingPairInteriorTargets (
200- scopeHandler ,
201- editor ,
202- initialPosition ,
203- direction ,
204- )
205- : getLanguageInteriorTargets (
206- scopeHandlerFactory ,
207- scopeHandler ,
208- editor ,
209- initialPosition ,
210- direction ,
211- ) ;
212-
213- // Interiors containing the initial position are excluded. This happens when
214- // you are in the body of an if statement and use `next state` and in that
215- // case we don't want to exclude scopes within the same interior.
216- return interiorTargets
217- . map ( ( t ) =>
218- t instanceof InteriorTarget ? t . fullInteriorRange : t . contentRange ,
219- )
220- . filter ( ( r ) => ! r . contains ( initialPosition ) ) ;
221- }
222-
223- function getSurroundingPairInteriorTargets (
224- scopeHandler : ScopeHandler ,
225- editor : TextEditor ,
226- initialPosition : Position ,
227- direction : Direction ,
228- ) : Target [ ] {
229- const containingScope = getContainingScope (
197+ const containingScopeTarget = getContainingScopeTarget (
230198 scopeHandler ,
231199 editor ,
232200 initialPosition ,
233201 direction ,
234202 ) ;
235203
236- if ( containingScope == null ) {
204+ // No containing scope, nothing to exclude.
205+ if ( containingScopeTarget == null ) {
237206 return [ ] ;
238207 }
239208
240- return containingScope
241- . getTargets ( false )
242- . flatMap ( ( t ) => t . getInterior ( ) ?? [ ] ) ;
243- }
209+ const containingInteriorTargets = containingScopeTarget . getInterior ( ) ;
244210
245- function getLanguageInteriorTargets (
246- scopeHandlerFactory : ScopeHandlerFactory ,
247- scopeHandler : ScopeHandler ,
248- editor : TextEditor ,
249- initialPosition : Position ,
250- direction : Direction ,
251- ) : Target [ ] {
211+ // Containing target already has an interior. eg a surrounding pair scope.
212+ if ( containingInteriorTargets != null ) {
213+ return getFilteredInteriorRanges (
214+ containingInteriorTargets ,
215+ initialPosition ,
216+ ) ;
217+ }
218+
219+ // Fallback to language specific interior scope handler
252220 const interiorScopeHandler = scopeHandlerFactory . maybeCreate (
253221 { type : "interior" } ,
254222 editor . document . languageId ,
255223 ) ;
256224
225+ // No interior scope handler, nothing to exclude.
226+ // For languages that hasn't defined the interior scope handler yet we default
227+ // to NOT excluding anything.
257228 if ( interiorScopeHandler == null ) {
258229 return [ ] ;
259230 }
260231
261- const containingScope = getContainingScope (
262- scopeHandler ,
263- editor ,
264- initialPosition ,
232+ const containingPositions = getPositions (
233+ containingScopeTarget . contentRange ,
265234 direction ,
266235 ) ;
267236
268- if ( containingScope == null ) {
269- return [ ] ;
270- }
271-
272- const containingInitialPosition =
273- direction === "forward"
274- ? containingScope . domain . start
275- : containingScope . domain . end ;
276- const containingDistalPosition =
277- direction === "forward"
278- ? containingScope . domain . end
279- : containingScope . domain . start ;
280-
281237 const interiorScopes = interiorScopeHandler . generateScopes (
282238 editor ,
283- containingInitialPosition ,
239+ containingPositions . initial ,
284240 direction ,
285241 {
286242 skipAncestorScopes : true ,
287- distalPosition : containingDistalPosition ,
243+ distalPosition : containingPositions . distal ,
288244 } ,
289245 ) ;
290246
291- return Array . from ( interiorScopes ) . flatMap ( ( s ) => s . getTargets ( false ) ) ;
247+ const interiorTargets = Array . from ( interiorScopes ) . flatMap ( ( s ) =>
248+ s . getTargets ( false ) ,
249+ ) ;
250+
251+ if ( interiorTargets . length > 0 ) {
252+ return getFilteredInteriorRanges ( interiorTargets , initialPosition ) ;
253+ }
254+
255+ // This containing scope has no interior.
256+ // Default to excluding the entire containing scope.
257+ return [ containingScopeTarget . contentRange ] ;
258+ }
259+
260+ function getPositions ( range : Range , direction : Direction ) {
261+ return direction === "forward"
262+ ? { initial : range . start , distal : range . end }
263+ : { initial : range . end , distal : range . start } ;
264+ }
265+
266+ function getFilteredInteriorRanges (
267+ interiorTargets : Target [ ] ,
268+ initialPosition : Position ,
269+ ) {
270+ // Interiors containing the initial position are excluded. This happens when
271+ // you are in the body of an if statement and use `next state` and in that
272+ // case we don't want to exclude scopes within the same interior.
273+ return interiorTargets
274+ . map ( ( t ) =>
275+ t instanceof InteriorTarget ? t . fullInteriorRange : t . contentRange ,
276+ )
277+ . filter ( ( r ) => ! r . contains ( initialPosition ) ) ;
292278}
293279
294- function getContainingScope (
280+ function getContainingScopeTarget (
295281 scopeHandler : ScopeHandler ,
296282 editor : TextEditor ,
297283 initialPosition : Position ,
298284 direction : Direction ,
299- ) : TargetScope | undefined {
300- return find (
285+ ) : Target | undefined {
286+ const containingScope = find (
301287 scopeHandler . generateScopes ( editor , initialPosition , direction , {
302288 containment : "required" ,
303289 allowAdjacentScopes : true ,
304290 skipAncestorScopes : true ,
305291 } ) ,
306292 ) ;
293+ return containingScope ?. getTargets ( false ) [ 0 ] ;
307294}
0 commit comments