@ -489,6 +489,7 @@ impl MappableCommand {
select_prev_sibling , "Select previous sibling the in syntax tree" ,
select_prev_sibling , "Select previous sibling the in syntax tree" ,
select_all_siblings , "Select all siblings of the current node" ,
select_all_siblings , "Select all siblings of the current node" ,
select_all_children , "Select all children of the current node" ,
select_all_children , "Select all children of the current node" ,
expand_selection_around , "Expand selection to parent syntax node, but exclude the selection you started with" ,
jump_forward , "Jump forward on jumplist" ,
jump_forward , "Jump forward on jumplist" ,
jump_backward , "Jump backward on jumplist" ,
jump_backward , "Jump backward on jumplist" ,
save_selection , "Save current selection to jumplist" ,
save_selection , "Save current selection to jumplist" ,
@ -5033,6 +5034,8 @@ fn reverse_selection_contents(cx: &mut Context) {
// tree sitter node selection
// tree sitter node selection
const EXPAND_KEY : & str = "expand" ;
const EXPAND_KEY : & str = "expand" ;
const EXPAND_AROUND_BASE_KEY : & str = "expand_around_base" ;
const PARENTS_KEY : & str = "parents" ;
fn expand_selection ( cx : & mut Context ) {
fn expand_selection ( cx : & mut Context ) {
let motion = | editor : & mut Editor | {
let motion = | editor : & mut Editor | {
@ -5076,6 +5079,33 @@ fn shrink_selection(cx: &mut Context) {
if let Some ( prev_selection ) = prev_expansions . pop ( ) {
if let Some ( prev_selection ) = prev_expansions . pop ( ) {
// allow shrinking the selection only if current selection contains the previous object selection
// allow shrinking the selection only if current selection contains the previous object selection
doc . set_selection_clear ( view . id , prev_selection , false ) ;
doc . set_selection_clear ( view . id , prev_selection , false ) ;
// Do a corresponding pop of the parents from `expand_selection_around`
doc . view_data_mut ( view . id )
. object_selections
. entry ( PARENTS_KEY )
. and_modify ( | parents | {
parents . pop ( ) ;
} ) ;
// need to do this again because borrowing
let prev_expansions = doc
. view_data_mut ( view . id )
. object_selections
. entry ( EXPAND_KEY )
. or_default ( ) ;
// if we've emptied out the previous expansions, then clear out the
// base history as well so it doesn't get used again erroneously
if prev_expansions . is_empty ( ) {
doc . view_data_mut ( view . id )
. object_selections
. entry ( EXPAND_AROUND_BASE_KEY )
. and_modify ( | base | {
base . clear ( ) ;
} ) ;
}
return ;
return ;
}
}
@ -5090,6 +5120,81 @@ fn shrink_selection(cx: &mut Context) {
cx . editor . apply_motion ( motion ) ;
cx . editor . apply_motion ( motion ) ;
}
}
fn expand_selection_around ( cx : & mut Context ) {
let motion = | editor : & mut Editor | {
let ( view , doc ) = current ! ( editor ) ;
if doc . syntax ( ) . is_some ( ) {
// [NOTE] we do this pop and push dance because if we don't take
// ownership of the objects, then we require multiple
// mutable references to the view's object selections
let mut parents_selection = doc
. view_data_mut ( view . id )
. object_selections
. entry ( PARENTS_KEY )
. or_default ( )
. pop ( ) ;
let mut base_selection = doc
. view_data_mut ( view . id )
. object_selections
. entry ( EXPAND_AROUND_BASE_KEY )
. or_default ( )
. pop ( ) ;
let current_selection = doc . selection ( view . id ) . clone ( ) ;
if parents_selection . is_none ( ) | | base_selection . is_none ( ) {
parents_selection = Some ( current_selection . clone ( ) ) ;
base_selection = Some ( current_selection . clone ( ) ) ;
}
let text = doc . text ( ) . slice ( .. ) ;
let syntax = doc . syntax ( ) . unwrap ( ) ;
let outside_selection =
object ::expand_selection ( syntax , text , parents_selection . clone ( ) . unwrap ( ) ) ;
let target_selection = match outside_selection
. clone ( )
. without ( & base_selection . clone ( ) . unwrap ( ) )
{
Some ( sel ) = > sel ,
None = > outside_selection . clone ( ) ,
} ;
// check if selection is different from the last one
if target_selection ! = current_selection {
// save current selection so it can be restored using shrink_selection
doc . view_data_mut ( view . id )
. object_selections
. entry ( EXPAND_KEY )
. or_default ( )
. push ( current_selection ) ;
doc . set_selection_clear ( view . id , target_selection , false ) ;
}
let parents = doc
. view_data_mut ( view . id )
. object_selections
. entry ( PARENTS_KEY )
. or_default ( ) ;
parents . push ( parents_selection . unwrap ( ) ) ;
parents . push ( outside_selection ) ;
doc . view_data_mut ( view . id )
. object_selections
. entry ( EXPAND_AROUND_BASE_KEY )
. or_default ( )
. push ( base_selection . unwrap ( ) ) ;
}
} ;
cx . editor . apply_motion ( motion ) ;
}
fn select_sibling_impl < F > ( cx : & mut Context , sibling_fn : F )
fn select_sibling_impl < F > ( cx : & mut Context , sibling_fn : F )
where
where
F : Fn ( & helix_core ::Syntax , RopeSlice , Selection ) -> Selection + ' static ,
F : Fn ( & helix_core ::Syntax , RopeSlice , Selection ) -> Selection + ' static ,
@ -5104,6 +5209,7 @@ where
doc . set_selection ( view . id , selection ) ;
doc . set_selection ( view . id , selection ) ;
}
}
} ;
} ;
cx . editor . apply_motion ( motion ) ;
cx . editor . apply_motion ( motion ) ;
}
}