on master help sign in
added get_line_ending from pr comment
ecb884dJan Hrastnik
helix-core/src/lib.rs+1−1
@@ -111,6 +111,6 @@ pub use diagnostic::Diagnostic;
111pub use state::State;
111pub use state::State;
112
112
113pub use line_ending::{
113pub use line_ending::{
114− auto_detect_line_ending, rope_slice_to_line_ending, LineEnding, DEFAULT_LINE_ENDING,
114+ auto_detect_line_ending, rope_slice_to_line_ending, LineEnding, DEFAULT_LINE_ENDING, get_line_ending
115};
115};
116pub use transaction::{Assoc, Change, ChangeSet, Operation, Transaction};
116pub use transaction::{Assoc, Change, ChangeSet, Operation, Transaction};
helix-core/src/line_ending.rs+18−5
@@ -14,7 +14,7 @@ pub enum LineEnding {
14}
14}
15
15
16impl LineEnding {
16impl LineEnding {
17− pub fn len(&self) -> usize {
17+ pub fn len_chars(&self) -> usize {
18 match self {
18 match self {
19 Self::Crlf => 2,
19 Self::Crlf => 2,
20 _ => 1,
20 _ => 1,
@@ -28,10 +28,9 @@ impl LineEnding {
28 Self::Nel => "\u{0085}",
28 Self::Nel => "\u{0085}",
29 Self::LS => "\u{2028}",
29 Self::LS => "\u{2028}",
30 Self::CR => "\u{000D}",
30 Self::CR => "\u{000D}",
31− _ => panic!(
31+ Self::VT => "\u{000B}",
32− "Unexpected line ending: {:?}, expected Crlf, LF, CR, Nel, or LS.",
32+ Self::FF => "\u{000C}",
33− self
33+ Self::PS => "\u{2029}",
34− ),
35 }
34 }
36 }
35 }
37}
36}
@@ -93,6 +92,20 @@ pub fn auto_detect_line_ending(doc: &Rope) -> Option<LineEnding> {
93 ending
92 ending
94}
93}
95
94
95+/// Returns the passed line's line ending, if any.
96+pub fn get_line_ending(line: &RopeSlice) -> Option<LineEnding> {
97+ // Last character as str.
98+ let g1 = line.slice(line.len_chars().saturating_sub(1)..).as_str().unwrap();
99+
100+ // Last two characters as str, or empty str if they're not contiguous.
101+ // It's fine to punt on the non-contiguous case, because Ropey guarantees
102+ // that CRLF is always contiguous.
103+ let g2 = line.slice(line.len_chars().saturating_sub(2)..).as_str().unwrap_or("");
104+
105+ // First check the two-character case for CRLF, then check the single-character case.
106+ str_to_line_ending(g2).or_else(|| str_to_line_ending(g1))
107+}
108+
96#[cfg(target_os = "windows")]
109#[cfg(target_os = "windows")]
97pub const DEFAULT_LINE_ENDING: LineEnding = LineEnding::Crlf;
110pub const DEFAULT_LINE_ENDING: LineEnding = LineEnding::Crlf;
98#[cfg(not(target_os = "windows"))]
111#[cfg(not(target_os = "windows"))]
helix-term/src/commands.rs+5−7
@@ -5,7 +5,7 @@ use helix_core::{
5 object, pos_at_coords,
5 object, pos_at_coords,
6 regex::{self, Regex},
6 regex::{self, Regex},
7 register::{self, Register, Registers},
7 register::{self, Register, Registers},
8− search, selection, Change, ChangeSet, LineEnding, Position, Range, Rope, RopeSlice, Selection,
8+ search, selection, Change, ChangeSet, LineEnding, Position, Range, Rope, RopeSlice, Selection, get_line_ending,
9 SmallVec, Tendril, Transaction,
9 SmallVec, Tendril, Transaction,
10};
10};
11
11
@@ -183,11 +183,10 @@ pub fn move_line_end(cx: &mut Context) {
183 let text = doc.text();
183 let text = doc.text();
184 let line = text.char_to_line(range.head);
184 let line = text.char_to_line(range.head);
185
185
186− // Line end is pos at the start of next line - 1
187− // subtract another 1 because the line ends with \n
188 let pos = text
186 let pos = text
189 .line_to_char(line + 1)
187 .line_to_char(line + 1)
190− .saturating_sub(doc.line_ending().len() + 1);
188+ .saturating_sub(get_line_ending(&text.line(line)).map(|le| le.len_chars()).unwrap_or(0));
189+
191 Range::new(pos, pos)
190 Range::new(pos, pos)
192 });
191 });
193
192
@@ -607,11 +606,10 @@ pub fn extend_line_end(cx: &mut Context) {
607 let text = doc.text();
606 let text = doc.text();
608 let line = text.char_to_line(range.head);
607 let line = text.char_to_line(range.head);
609
608
610− // Line end is pos at the start of next line - 1
611− // subtract another 1 because the line ends with \n
612 let pos = text
609 let pos = text
613 .line_to_char(line + 1)
610 .line_to_char(line + 1)
614− .saturating_sub(doc.line_ending().len() + 1);
611+ .saturating_sub(get_line_ending(&text.line(line)).map(|le| le.len_chars()).unwrap_or(0));
612+
615 Range::new(range.anchor, pos)
613 Range::new(range.anchor, pos)
616 });
614 });
617
615