@ -1,7 +1,6 @@
use crate ::{ Rope , RopeGraphemes , RopeSlice } ;
use crate ::{ Rope , RopeGraphemes , RopeSlice } ;
/// Represents one of the valid Unicode line endings.
/// Represents one of the valid Unicode line endings.
/// VT, FF and PS are excluded here, as we don't expect them to show up as a default line break
#[ derive(PartialEq, Copy, Clone, Debug) ]
#[ derive(PartialEq, Copy, Clone, Debug) ]
pub enum LineEnding {
pub enum LineEnding {
Crlf , // CarriageReturn followed by LineFeed
Crlf , // CarriageReturn followed by LineFeed
@ -9,6 +8,9 @@ pub enum LineEnding {
CR , // U+000D -- CarriageReturn
CR , // U+000D -- CarriageReturn
Nel , // U+0085 -- NextLine
Nel , // U+0085 -- NextLine
LS , // U+2028 -- Line Separator
LS , // U+2028 -- Line Separator
VT , // U+000B -- VerticalTab
FF , // U+000C -- FormFeed
PS , // U+2029 -- ParagraphSeparator
}
}
pub fn rope_slice_to_line_ending ( g : & RopeSlice ) -> Option < LineEnding > {
pub fn rope_slice_to_line_ending ( g : & RopeSlice ) -> Option < LineEnding > {
@ -38,8 +40,8 @@ pub fn auto_detect_line_ending(doc: &Rope) -> Option<LineEnding> {
// based on https://github.com/cessen/led/blob/27572c8838a1c664ee378a19358604063881cc1d/src/editor/mod.rs#L88-L162
// based on https://github.com/cessen/led/blob/27572c8838a1c664ee378a19358604063881cc1d/src/editor/mod.rs#L88-L162
let mut ending = None ;
let mut ending = None ;
for line in doc . lines ( ) . take ( 1 ) {
// return first matched line ending. Not all possible line endings are being matched, as they might be special-use only
// check first line only - unsure how sound this is
for line in doc . lines ( ) . take ( 100 ) {
ending = match line . len_chars ( ) {
ending = match line . len_chars ( ) {
1 = > {
1 = > {
let g = RopeGraphemes ::new ( line . slice ( ( line . len_chars ( ) - 1 ) .. ) )
let g = RopeGraphemes ::new ( line . slice ( ( line . len_chars ( ) - 1 ) .. ) )
@ -54,6 +56,9 @@ pub fn auto_detect_line_ending(doc: &Rope) -> Option<LineEnding> {
rope_slice_to_line_ending ( & g )
rope_slice_to_line_ending ( & g )
}
}
_ = > None ,
_ = > None ,
} ;
if ending . is_some ( ) {
return ending ;
}
}
}
}
ending
ending
@ -63,3 +68,54 @@ pub fn auto_detect_line_ending(doc: &Rope) -> Option<LineEnding> {
pub const DEFAULT_LINE_ENDING : LineEnding = LineEnding ::Crlf ;
pub const DEFAULT_LINE_ENDING : LineEnding = LineEnding ::Crlf ;
#[ cfg(not(target_os = " windows " )) ]
#[ cfg(not(target_os = " windows " )) ]
pub const DEFAULT_LINE_ENDING : LineEnding = LineEnding ::LF ;
pub const DEFAULT_LINE_ENDING : LineEnding = LineEnding ::LF ;
#[ cfg(test) ]
mod line_ending_tests {
use super ::* ;
#[ test ]
fn test_autodetect ( ) {
assert_eq! (
auto_detect_line_ending ( & Rope ::from_str ( "\n" ) ) ,
Some ( LineEnding ::LF )
) ;
assert_eq! (
auto_detect_line_ending ( & Rope ::from_str ( "\r\n" ) ) ,
Some ( LineEnding ::Crlf )
) ;
assert_eq! ( auto_detect_line_ending ( & Rope ::from_str ( "hello" ) ) , None ) ;
assert_eq! ( auto_detect_line_ending ( & Rope ::from_str ( "" ) ) , None ) ;
assert_eq! (
auto_detect_line_ending ( & Rope ::from_str ( "hello\nhelix\r\n" ) ) ,
Some ( LineEnding ::LF )
) ;
assert_eq! (
auto_detect_line_ending ( & Rope ::from_str ( "a formfeed\u{000C}" ) ) ,
None
) ;
assert_eq! (
auto_detect_line_ending ( & Rope ::from_str ( "\n\u{000A}\n \u{000A}" ) ) ,
Some ( LineEnding ::LF )
) ;
assert_eq! (
auto_detect_line_ending ( & Rope ::from_str (
"a formfeed\u{000C} with a\u{000C} linefeed\u{000A}"
) ) ,
Some ( LineEnding ::LF )
) ;
assert_eq! ( auto_detect_line_ending ( & Rope ::from_str ( "a formfeed\u{000C} with a\u{000C} carriage return linefeed\u{000D}\u{000A} and a linefeed\u{000A}" ) ) , Some ( LineEnding ::Crlf ) ) ;
}
#[ test ]
fn test_rope_slice_to_line_ending ( ) {
let r = Rope ::from_str ( "\r\n" ) ;
assert_eq! (
rope_slice_to_line_ending ( & r . slice ( 1 .. 2 ) ) ,
Some ( LineEnding ::LF )
) ;
assert_eq! (
rope_slice_to_line_ending ( & r . slice ( 0 .. 2 ) ) ,
Some ( LineEnding ::Crlf )
) ;
}
}