@ -1,4 +1,4 @@
use crate ::{ editor::GutterType , graphics ::Rect , Document , DocumentId , ViewId } ;
use crate ::{ align_view, editor::GutterType , graphics ::Rect , Align , Document , DocumentId , ViewId } ;
use helix_core ::{
use helix_core ::{
pos_at_visual_coords , visual_coords_at_pos , Position , RopeSlice , Selection , Transaction ,
pos_at_visual_coords , visual_coords_at_pos , Position , RopeSlice , Selection , Transaction ,
} ;
} ;
@ -169,6 +169,15 @@ impl View {
& self ,
& self ,
doc : & Document ,
doc : & Document ,
scrolloff : usize ,
scrolloff : usize ,
) -> Option < ( usize , usize ) > {
self . offset_coords_to_in_view_center ( doc , scrolloff , false )
}
pub fn offset_coords_to_in_view_center (
& self ,
doc : & Document ,
scrolloff : usize ,
centering : bool ,
) -> Option < ( usize , usize ) > {
) -> Option < ( usize , usize ) > {
let cursor = doc
let cursor = doc
. selection ( self . id )
. selection ( self . id )
@ -180,47 +189,69 @@ impl View {
let inner_area = self . inner_area ( doc ) ;
let inner_area = self . inner_area ( doc ) ;
let last_line = ( self . offset . row + inner_area . height as usize ) . saturating_sub ( 1 ) ;
let last_line = ( self . offset . row + inner_area . height as usize ) . saturating_sub ( 1 ) ;
// - 1 so we have at least one gap in the middle.
// a height of 6 with padding of 3 on each side will keep shifting the view back and forth
// as we type
let scrolloff = scrolloff . min ( inner_area . height . saturating_sub ( 1 ) as usize / 2 ) ;
let last_col = self . offset . col + inner_area . width . saturating_sub ( 1 ) as usize ;
let last_col = self . offset . col + inner_area . width . saturating_sub ( 1 ) as usize ;
let row = if line > last_line . saturating_sub ( scrolloff ) {
let new_offset = | scrolloff : usize | {
// scroll down
// - 1 so we have at least one gap in the middle.
self . offset . row + line - ( last_line . saturating_sub ( scrolloff ) )
// a height of 6 with padding of 3 on each side will keep shifting the view back and forth
} else if line < self . offset . row + scrolloff {
// as we type
// scroll up
let scrolloff = scrolloff . min ( inner_area . height . saturating_sub ( 1 ) as usize / 2 ) ;
line . saturating_sub ( scrolloff )
} else {
let row = if line > last_line . saturating_sub ( scrolloff ) {
self . offset . row
// scroll down
self . offset . row + line - ( last_line . saturating_sub ( scrolloff ) )
} else if line < self . offset . row + scrolloff {
// scroll up
line . saturating_sub ( scrolloff )
} else {
self . offset . row
} ;
let col = if col > last_col . saturating_sub ( scrolloff ) {
// scroll right
self . offset . col + col - ( last_col . saturating_sub ( scrolloff ) )
} else if col < self . offset . col + scrolloff {
// scroll left
col . saturating_sub ( scrolloff )
} else {
self . offset . col
} ;
( row , col )
} ;
} ;
let current_offset = ( self . offset . row , self . offset . col ) ;
let col = if col > last_col . saturating_sub ( scrolloff ) {
if centering {
// scroll right
// return None if cursor is out of view
self . offset . col + col - ( last_col . saturating_sub ( scrolloff ) )
let offset = new_offset ( 0 ) ;
} else if col < self . offset . col + scrolloff {
( offset = = current_offset ) . then ( | | {
// scroll left
if scrolloff = = 0 {
col . saturating_sub ( scrolloff )
offset
} else {
new_offset ( scrolloff )
}
} )
} else {
} else {
self . offset . col
// return None if cursor is in (view - scrolloff)
} ;
let offset = new_offset ( scrolloff ) ;
if row = = self . offset . row & & col = = self . offset . col {
( offset ! = current_offset ) . then ( | | offset ) // TODO: use 'then_some' when 1.62 <= MSRV
None
} else {
Some ( ( row , col ) )
}
}
}
}
pub fn ensure_cursor_in_view ( & mut self , doc : & Document , scrolloff : usize ) {
pub fn ensure_cursor_in_view ( & mut self , doc : & Document , scrolloff : usize ) {
if let Some ( ( row , col ) ) = self . offset_coords_to_in_view ( doc , scrolloff ) {
if let Some ( ( row , col ) ) = self . offset_coords_to_in_view _center ( doc , scrolloff , false ) {
self . offset . row = row ;
self . offset . row = row ;
self . offset . col = col ;
self . offset . col = col ;
}
}
}
}
pub fn ensure_cursor_in_view_center ( & mut self , doc : & Document , scrolloff : usize ) {
if let Some ( ( row , col ) ) = self . offset_coords_to_in_view_center ( doc , scrolloff , true ) {
self . offset . row = row ;
self . offset . col = col ;
} else {
align_view ( doc , self , Align ::Center ) ;
}
}
pub fn is_cursor_in_view ( & mut self , doc : & Document , scrolloff : usize ) -> bool {
pub fn is_cursor_in_view ( & mut self , doc : & Document , scrolloff : usize ) -> bool {
self . offset_coords_to_in_view ( doc , scrolloff ) . is_none ( )
self . offset_coords_to_in_view ( doc , scrolloff ) . is_none ( )
}
}