From ecb884db98fbe6ed70743d1080ce7f78e121ba50 Mon Sep 17 00:00:00 2001
From: Jan Hrastnik
Date: Sat, 19 Jun 2021 14:03:14 +0200
Subject: added get_line_ending from pr comment

---
 helix-core/src/lib.rs         |  2 +-
 helix-core/src/line_ending.rs | 23 ++++++++++++++++++-----
 helix-term/src/commands.rs    | 12 +++++-------
 3 files changed, 24 insertions(+), 13 deletions(-)

diff --git a/helix-core/src/lib.rs b/helix-core/src/lib.rs
index 55365500..3f6bea5a 100644
--- a/helix-core/src/lib.rs
+++ b/helix-core/src/lib.rs
@@ -111,6 +111,6 @@ pub use diagnostic::Diagnostic;
 pub use state::State;
 
 pub use line_ending::{
-    auto_detect_line_ending, rope_slice_to_line_ending, LineEnding, DEFAULT_LINE_ENDING,
+    auto_detect_line_ending, rope_slice_to_line_ending, LineEnding, DEFAULT_LINE_ENDING, get_line_ending
 };
 pub use transaction::{Assoc, Change, ChangeSet, Operation, Transaction};
diff --git a/helix-core/src/line_ending.rs b/helix-core/src/line_ending.rs
index f9d67b57..423f4b92 100644
--- a/helix-core/src/line_ending.rs
+++ b/helix-core/src/line_ending.rs
@@ -14,7 +14,7 @@ pub enum LineEnding {
 }
 
 impl LineEnding {
-    pub fn len(&self) -> usize {
+    pub fn len_chars(&self) -> usize {
         match self {
             Self::Crlf => 2,
             _ => 1,
@@ -28,10 +28,9 @@ impl LineEnding {
             Self::Nel => "\u{0085}",
             Self::LS => "\u{2028}",
             Self::CR => "\u{000D}",
-            _ => panic!(
-                "Unexpected line ending: {:?}, expected Crlf, LF, CR, Nel, or LS.",
-                self
-            ),
+            Self::VT => "\u{000B}",
+            Self::FF => "\u{000C}",
+            Self::PS => "\u{2029}",
         }
     }
 }
@@ -93,6 +92,20 @@ pub fn auto_detect_line_ending(doc: &Rope) -> Option<LineEnding> {
     ending
 }
 
+/// Returns the passed line's line ending, if any.
+pub fn get_line_ending(line: &RopeSlice) -> Option<LineEnding> {
+    // Last character as str.
+    let g1 = line.slice(line.len_chars().saturating_sub(1)..).as_str().unwrap();
+
+    // Last two characters as str, or empty str if they're not contiguous.
+    // It's fine to punt on the non-contiguous case, because Ropey guarantees
+    // that CRLF is always contiguous.
+    let g2 = line.slice(line.len_chars().saturating_sub(2)..).as_str().unwrap_or("");
+
+    // First check the two-character case for CRLF, then check the single-character case.
+    str_to_line_ending(g2).or_else(|| str_to_line_ending(g1))
+}
+
 #[cfg(target_os = "windows")]
 pub const DEFAULT_LINE_ENDING: LineEnding = LineEnding::Crlf;
 #[cfg(not(target_os = "windows"))]
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index 62faadf9..d894a646 100644
--- a/helix-term/src/commands.rs
+++ b/helix-term/src/commands.rs
@@ -5,7 +5,7 @@ use helix_core::{
     object, pos_at_coords,
     regex::{self, Regex},
     register::{self, Register, Registers},
-    search, selection, Change, ChangeSet, LineEnding, Position, Range, Rope, RopeSlice, Selection,
+    search, selection, Change, ChangeSet, LineEnding, Position, Range, Rope, RopeSlice, Selection, get_line_ending,
     SmallVec, Tendril, Transaction,
 };
 
@@ -183,11 +183,10 @@ pub fn move_line_end(cx: &mut Context) {
         let text = doc.text();
         let line = text.char_to_line(range.head);
 
-        // Line end is pos at the start of next line - 1
-        // subtract another 1 because the line ends with \n
         let pos = text
             .line_to_char(line + 1)
-            .saturating_sub(doc.line_ending().len() + 1);
+            .saturating_sub(get_line_ending(&text.line(line)).map(|le| le.len_chars()).unwrap_or(0));
+
         Range::new(pos, pos)
     });
 
@@ -607,11 +606,10 @@ pub fn extend_line_end(cx: &mut Context) {
         let text = doc.text();
         let line = text.char_to_line(range.head);
 
-        // Line end is pos at the start of next line - 1
-        // subtract another 1 because the line ends with \n
         let pos = text
             .line_to_char(line + 1)
-            .saturating_sub(doc.line_ending().len() + 1);
+            .saturating_sub(get_line_ending(&text.line(line)).map(|le| le.len_chars()).unwrap_or(0));
+
         Range::new(range.anchor, pos)
     });
 
-- 
cgit v1.2.3-70-g09d2