@ -5,16 +5,15 @@ use tree_sitter::{Node, QueryCursor};
use crate ::{
use crate ::{
chars ::{ categorize_char , char_is_line_ending , CharCategory } ,
chars ::{ categorize_char , char_is_line_ending , CharCategory } ,
coords_at_pos ,
graphemes ::{
graphemes ::{
next_grapheme_boundary , nth_next_grapheme_boundary , nth_prev_grapheme_boundary ,
next_grapheme_boundary , nth_next_grapheme_boundary , nth_prev_grapheme_boundary ,
prev_grapheme_boundary ,
prev_grapheme_boundary ,
} ,
} ,
line_ending ::rope_is_line_ending ,
line_ending ::rope_is_line_ending ,
pos_at_ coords,
pos_at_ visual_ coords,
syntax ::LanguageConfiguration ,
syntax ::LanguageConfiguration ,
textobject ::TextObject ,
textobject ::TextObject ,
Position, Range , RopeSlice ,
visual_coords_at_pos, Position, Range , RopeSlice ,
} ;
} ;
#[ derive(Debug, Copy, Clone, PartialEq, Eq) ]
#[ derive(Debug, Copy, Clone, PartialEq, Eq) ]
@ -35,6 +34,7 @@ pub fn move_horizontally(
dir : Direction ,
dir : Direction ,
count : usize ,
count : usize ,
behaviour : Movement ,
behaviour : Movement ,
_ : usize ,
) -> Range {
) -> Range {
let pos = range . cursor ( slice ) ;
let pos = range . cursor ( slice ) ;
@ -54,15 +54,12 @@ pub fn move_vertically(
dir : Direction ,
dir : Direction ,
count : usize ,
count : usize ,
behaviour : Movement ,
behaviour : Movement ,
tab_width : usize ,
) -> Range {
) -> Range {
let pos = range . cursor ( slice ) ;
let pos = range . cursor ( slice ) ;
// Compute the current position's 2d coordinates.
// Compute the current position's 2d coordinates.
// TODO: switch this to use `visual_coords_at_pos` rather than
let Position { row , col } = visual_coords_at_pos ( slice , pos , tab_width ) ;
// `coords_at_pos` as this will cause a jerky movement when the visual
// position does not match, like moving from a line with tabs/CJK to
// a line without
let Position { row , col } = coords_at_pos ( slice , pos ) ;
let horiz = range . horiz . unwrap_or ( col as u32 ) ;
let horiz = range . horiz . unwrap_or ( col as u32 ) ;
// Compute the new position.
// Compute the new position.
@ -71,7 +68,7 @@ pub fn move_vertically(
Direction ::Backward = > row . saturating_sub ( count ) ,
Direction ::Backward = > row . saturating_sub ( count ) ,
} ;
} ;
let new_col = col . max ( horiz as usize ) ;
let new_col = col . max ( horiz as usize ) ;
let new_pos = pos_at_ coords( slice , Position ::new ( new_row , new_col ) , true ) ;
let new_pos = pos_at_ visual_ coords( slice , Position ::new ( new_row , new_col ) , tab_width ) ;
// Special-case to avoid moving to the end of the last non-empty line.
// Special-case to avoid moving to the end of the last non-empty line.
if behaviour = = Movement ::Extend & & slice . line ( new_row ) . len_chars ( ) = = 0 {
if behaviour = = Movement ::Extend & & slice . line ( new_row ) . len_chars ( ) = = 0 {
@ -446,6 +443,8 @@ pub fn goto_treesitter_object(
mod test {
mod test {
use ropey ::Rope ;
use ropey ::Rope ;
use crate ::{ coords_at_pos , pos_at_coords } ;
use super ::* ;
use super ::* ;
const SINGLE_LINE_SAMPLE : & str = "This is a simple alphabetic line" ;
const SINGLE_LINE_SAMPLE : & str = "This is a simple alphabetic line" ;
@ -472,7 +471,7 @@ mod test {
assert_eq! (
assert_eq! (
coords_at_pos (
coords_at_pos (
slice ,
slice ,
move_vertically ( slice , range , Direction ::Forward , 1 , Movement ::Move ). head
move_vertically ( slice , range , Direction ::Forward , 1 , Movement ::Move , 4 ). head
) ,
) ,
( 1 , 3 ) . into ( )
( 1 , 3 ) . into ( )
) ;
) ;
@ -496,7 +495,7 @@ mod test {
] ;
] ;
for ( ( direction , amount ) , coordinates ) in moves_and_expected_coordinates {
for ( ( direction , amount ) , coordinates ) in moves_and_expected_coordinates {
range = move_horizontally ( slice , range , direction , amount , Movement ::Move );
range = move_horizontally ( slice , range , direction , amount , Movement ::Move , 0 );
assert_eq! ( coords_at_pos ( slice , range . head ) , coordinates . into ( ) )
assert_eq! ( coords_at_pos ( slice , range . head ) , coordinates . into ( ) )
}
}
}
}
@ -522,7 +521,7 @@ mod test {
] ;
] ;
for ( ( direction , amount ) , coordinates ) in moves_and_expected_coordinates {
for ( ( direction , amount ) , coordinates ) in moves_and_expected_coordinates {
range = move_horizontally ( slice , range , direction , amount , Movement ::Move );
range = move_horizontally ( slice , range , direction , amount , Movement ::Move , 0 );
assert_eq! ( coords_at_pos ( slice , range . head ) , coordinates . into ( ) ) ;
assert_eq! ( coords_at_pos ( slice , range . head ) , coordinates . into ( ) ) ;
assert_eq! ( range . head , range . anchor ) ;
assert_eq! ( range . head , range . anchor ) ;
}
}
@ -544,7 +543,7 @@ mod test {
] ;
] ;
for ( direction , amount ) in moves {
for ( direction , amount ) in moves {
range = move_horizontally ( slice , range , direction , amount , Movement ::Extend );
range = move_horizontally ( slice , range , direction , amount , Movement ::Extend , 0 );
assert_eq! ( range . anchor , original_anchor ) ;
assert_eq! ( range . anchor , original_anchor ) ;
}
}
}
}
@ -568,7 +567,7 @@ mod test {
] ;
] ;
for ( ( direction , amount ) , coordinates ) in moves_and_expected_coordinates {
for ( ( direction , amount ) , coordinates ) in moves_and_expected_coordinates {
range = move_vertically ( slice , range , direction , amount , Movement ::Move );
range = move_vertically ( slice , range , direction , amount , Movement ::Move , 4 );
assert_eq! ( coords_at_pos ( slice , range . head ) , coordinates . into ( ) ) ;
assert_eq! ( coords_at_pos ( slice , range . head ) , coordinates . into ( ) ) ;
assert_eq! ( range . head , range . anchor ) ;
assert_eq! ( range . head , range . anchor ) ;
}
}
@ -602,8 +601,8 @@ mod test {
for ( ( axis , direction , amount ) , coordinates ) in moves_and_expected_coordinates {
for ( ( axis , direction , amount ) , coordinates ) in moves_and_expected_coordinates {
range = match axis {
range = match axis {
Axis ::H = > move_horizontally ( slice , range , direction , amount , Movement ::Move ),
Axis ::H = > move_horizontally ( slice , range , direction , amount , Movement ::Move , 0 ),
Axis ::V = > move_vertically ( slice , range , direction , amount , Movement ::Move ),
Axis ::V = > move_vertically ( slice , range , direction , amount , Movement ::Move , 4 ),
} ;
} ;
assert_eq! ( coords_at_pos ( slice , range . head ) , coordinates . into ( ) ) ;
assert_eq! ( coords_at_pos ( slice , range . head ) , coordinates . into ( ) ) ;
assert_eq! ( range . head , range . anchor ) ;
assert_eq! ( range . head , range . anchor ) ;
@ -627,18 +626,18 @@ mod test {
let moves_and_expected_coordinates = [
let moves_and_expected_coordinates = [
// Places cursor at the fourth kana.
// Places cursor at the fourth kana.
( ( Axis ::H , Direction ::Forward , 4 ) , ( 0 , 4 ) ) ,
( ( Axis ::H , Direction ::Forward , 4 ) , ( 0 , 4 ) ) ,
// Descent places cursor at the 4 th character.
// Descent places cursor at the 8 th character.
( ( Axis ::V , Direction ::Forward , 1 usize ) , ( 1 , 4 ) ) ,
( ( Axis ::V , Direction ::Forward , 1 usize ) , ( 1 , 8 ) ) ,
// Moving back 1 character .
// Moving back 2 characters .
( ( Axis ::H , Direction ::Backward , 1usize ) , ( 1 , 3 ) ) ,
( ( Axis ::H , Direction ::Backward , 2usize ) , ( 1 , 6 ) ) ,
// Jumping back up 1 line.
// Jumping back up 1 line.
( ( Axis ::V , Direction ::Backward , 1 usize ) , ( 0 , 3 ) ) ,
( ( Axis ::V , Direction ::Backward , 1 usize ) , ( 0 , 3 ) ) ,
] ;
] ;
for ( ( axis , direction , amount ) , coordinates ) in moves_and_expected_coordinates {
for ( ( axis , direction , amount ) , coordinates ) in moves_and_expected_coordinates {
range = match axis {
range = match axis {
Axis ::H = > move_horizontally ( slice , range , direction , amount , Movement ::Move ),
Axis ::H = > move_horizontally ( slice , range , direction , amount , Movement ::Move , 0 ),
Axis ::V = > move_vertically ( slice , range , direction , amount , Movement ::Move ),
Axis ::V = > move_vertically ( slice , range , direction , amount , Movement ::Move , 4 ),
} ;
} ;
assert_eq! ( coords_at_pos ( slice , range . head ) , coordinates . into ( ) ) ;
assert_eq! ( coords_at_pos ( slice , range . head ) , coordinates . into ( ) ) ;
assert_eq! ( range . head , range . anchor ) ;
assert_eq! ( range . head , range . anchor ) ;