@@ -381,6 +381,7 @@ impl MappableCommand {
381
381
rotate_selection_contents_backward, "Rotate selections contents backward" ,
382
382
expand_selection, "Expand selection to parent syntax node" ,
383
383
shrink_selection, "Shrink selection to previously expanded syntax node" ,
384
+ expand_selection_around, "Expand selection to parent syntax node, but exclude the selection you started with" ,
384
385
select_next_sibling, "Select next sibling in syntax tree" ,
385
386
select_prev_sibling, "Select previous sibling in syntax tree" ,
386
387
jump_forward, "Jump forward on jumplist" ,
@@ -4295,6 +4296,8 @@ fn rotate_selection_contents_backward(cx: &mut Context) {
4295
4296
// tree sitter node selection
4296
4297
4297
4298
const EXPAND_KEY : & str = "expand" ;
4299
+ const EXPAND_AROUND_BASE_KEY : & str = "expand_around_base" ;
4300
+ const PARENTS_KEY : & str = "parents" ;
4298
4301
4299
4302
fn expand_selection ( cx : & mut Context ) {
4300
4303
let motion = |editor : & mut Editor | {
@@ -4330,6 +4333,27 @@ fn shrink_selection(cx: &mut Context) {
4330
4333
if let Some ( prev_selection) = prev_expansions. pop ( ) {
4331
4334
// allow shrinking the selection only if current selection contains the previous object selection
4332
4335
doc. set_selection_clear ( view, prev_selection, false ) ;
4336
+
4337
+ // Do a corresponding pop of the parents from `expand_selection_around`
4338
+ view. object_selections
4339
+ . entry ( PARENTS_KEY )
4340
+ . and_modify ( |parents| {
4341
+ parents. pop ( ) ;
4342
+ } ) ;
4343
+
4344
+ // need to do this again because borrowing
4345
+ let prev_expansions = view. object_selections . entry ( EXPAND_KEY ) . or_default ( ) ;
4346
+
4347
+ // if we've emptied out the previous expansions, then clear out the
4348
+ // base history as well so it doesn't get used again erroneously
4349
+ if prev_expansions. is_empty ( ) {
4350
+ view. object_selections
4351
+ . entry ( EXPAND_AROUND_BASE_KEY )
4352
+ . and_modify ( |base| {
4353
+ base. clear ( ) ;
4354
+ } ) ;
4355
+ }
4356
+
4333
4357
return ;
4334
4358
}
4335
4359
@@ -4345,6 +4369,68 @@ fn shrink_selection(cx: &mut Context) {
4345
4369
cx. editor . last_motion = Some ( Motion ( Box :: new ( motion) ) ) ;
4346
4370
}
4347
4371
4372
+ fn expand_selection_around ( cx : & mut Context ) {
4373
+ let motion = |editor : & mut Editor | {
4374
+ let ( view, doc) = current ! ( editor) ;
4375
+
4376
+ if let Some ( syntax) = doc. syntax ( ) {
4377
+ let text = doc. text ( ) . slice ( ..) ;
4378
+ let current_selection = doc. selection ( view. id ) ;
4379
+
4380
+ // [NOTE] we do this pop and push dance because if we don't take
4381
+ // ownership of the objects, then we require multiple
4382
+ // mutable references to the view's object selections
4383
+ let mut parents_selection =
4384
+ view. object_selections . entry ( PARENTS_KEY ) . or_default ( ) . pop ( ) ;
4385
+ let mut base_selection = view
4386
+ . object_selections
4387
+ . entry ( EXPAND_AROUND_BASE_KEY )
4388
+ . or_default ( )
4389
+ . pop ( ) ;
4390
+
4391
+ if parents_selection. is_none ( ) || base_selection. is_none ( ) {
4392
+ parents_selection = Some ( current_selection. clone ( ) ) ;
4393
+ base_selection = Some ( current_selection. clone ( ) ) ;
4394
+ }
4395
+
4396
+ let outside_selection =
4397
+ object:: expand_selection ( syntax, text, parents_selection. clone ( ) . unwrap ( ) ) ;
4398
+
4399
+ let target_selection = match outside_selection
4400
+ . clone ( )
4401
+ . without ( & base_selection. clone ( ) . unwrap ( ) )
4402
+ {
4403
+ Some ( sel) => sel,
4404
+ None => outside_selection. clone ( ) ,
4405
+ } ;
4406
+
4407
+ // check if selection is different from the last one
4408
+ if target_selection != * current_selection {
4409
+ // save current selection so it can be restored using shrink_selection
4410
+ view. object_selections
4411
+ . entry ( EXPAND_KEY )
4412
+ . or_default ( )
4413
+ . push ( current_selection. clone ( ) ) ;
4414
+
4415
+ doc. set_selection_clear ( view, target_selection, false ) ;
4416
+ }
4417
+
4418
+ let parents = view. object_selections . entry ( PARENTS_KEY ) . or_default ( ) ;
4419
+
4420
+ parents. push ( parents_selection. unwrap ( ) ) ;
4421
+ parents. push ( outside_selection) ;
4422
+
4423
+ view. object_selections
4424
+ . entry ( EXPAND_AROUND_BASE_KEY )
4425
+ . or_default ( )
4426
+ . push ( base_selection. unwrap ( ) ) ;
4427
+ }
4428
+ } ;
4429
+
4430
+ motion ( cx. editor ) ;
4431
+ cx. editor . last_motion = Some ( Motion ( Box :: new ( motion) ) ) ;
4432
+ }
4433
+
4348
4434
fn select_sibling_impl < F > ( cx : & mut Context , sibling_fn : & ' static F )
4349
4435
where
4350
4436
F : Fn ( Node ) -> Option < Node > ,
0 commit comments