diff --git a/helix-core/src/lib.rs b/helix-core/src/lib.rs index 35124069..55365500 100644 --- a/helix-core/src/lib.rs +++ b/helix-core/src/lib.rs @@ -110,5 +110,7 @@ pub use syntax::Syntax; pub use diagnostic::Diagnostic; pub use state::State; -pub use line_ending::{auto_detect_line_ending, LineEnding, DEFAULT_LINE_ENDING}; +pub use line_ending::{ + auto_detect_line_ending, rope_slice_to_line_ending, LineEnding, DEFAULT_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 47420f9e..4f5708ec 100644 --- a/helix-core/src/line_ending.rs +++ b/helix-core/src/line_ending.rs @@ -31,6 +31,9 @@ pub fn str_to_line_ending(g: &str) -> Option { "\u{000D}" => Some(LineEnding::CR), "\u{0085}" => Some(LineEnding::Nel), "\u{2028}" => Some(LineEnding::LS), + "\u{000B}" => Some(LineEnding::VT), + "\u{000C}" => Some(LineEnding::FF), + "\u{2029}" => Some(LineEnding::PS), // Not a line ending _ => None, } @@ -58,7 +61,10 @@ pub fn auto_detect_line_ending(doc: &Rope) -> Option { _ => None, }; if ending.is_some() { - return ending; + match ending { + Some(LineEnding::VT) | Some(LineEnding::FF) | Some(LineEnding::PS) => {} + _ => return ending, + } } } ending diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index c80716d4..144e1f3c 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -4,9 +4,14 @@ use helix_core::{ movement::{self, Direction}, object, pos_at_coords, regex::{self, Regex}, +<<<<<<< HEAD register::{self, Register, Registers}, search, selection, Change, ChangeSet, Position, Range, Rope, RopeSlice, Selection, SmallVec, Tendril, Transaction, +======= + register, search, selection, Change, ChangeSet, LineEnding, Position, Range, Rope, RopeSlice, + Selection, SmallVec, Tendril, Transaction, +>>>>>>> 856fd95 (trying out line ending helper functions in commands.rs) }; use helix_view::{ @@ -184,8 +189,14 @@ pub fn move_line_end(cx: &mut Context) { 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(2); + // subtract 3 if the line ending is \r\n, otherwise subtract 2 as I assume all others are just 1 char length + let pos = + text.line_to_char(line + 1) + .saturating_sub(if doc.line_ending == LineEnding::Crlf { + 3 + } else { + 2 + }); Range::new(pos, pos) }); @@ -337,7 +348,7 @@ where KeyEvent { code: KeyCode::Enter, .. - } => '\n', + } => '\n', // TODO: we should be calling doc.line_ending() here KeyEvent { code: KeyCode::Char(ch), .. @@ -465,7 +476,7 @@ pub fn replace(cx: &mut Context) { KeyEvent { code: KeyCode::Enter, .. - } => Some('\n'), + } => Some('\n'), // TODO: we should be calling doc.line_ending() here _ => None, }; @@ -606,8 +617,14 @@ pub fn extend_line_end(cx: &mut Context) { 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(2); + // subtract 3 if the line ending is \r\n, otherwise subtract 2 as I assume all others are just 1 char length + let pos = + text.line_to_char(line + 1) + .saturating_sub(if doc.line_ending == LineEnding::Crlf { + 3 + } else { + 2 + }); Range::new(range.anchor, pos) }); @@ -896,7 +913,7 @@ pub fn append_mode(cx: &mut Context) { if selection.iter().any(|range| range.head == end) { let transaction = Transaction::change( doc.text(), - std::array::IntoIter::new([(end, end, Some(Tendril::from_char('\n')))]), + std::array::IntoIter::new([(end, end, Some(Tendril::from_char('\n')))]), // TODO: change \n to doc.line_ending() ); doc.apply(&transaction, view.id); } @@ -1523,7 +1540,7 @@ fn open(cx: &mut Context, open: Open) { ); let indent = doc.indent_unit().repeat(indent_level); let mut text = String::with_capacity(1 + indent.len()); - text.push('\n'); + text.push_str(doc.line_ending()); text.push_str(&indent); let text = text.repeat(count); @@ -2131,7 +2148,7 @@ pub mod insert { ); let indent = doc.indent_unit().repeat(indent_level); let mut text = String::with_capacity(1 + indent.len()); - text.push('\n'); + text.push_str(doc.line_ending()); text.push_str(&indent); let head = pos + offs + text.chars().count(); @@ -2152,7 +2169,7 @@ pub mod insert { if helix_core::auto_pairs::PAIRS.contains(&(prev, curr)) { // another newline, indent the end bracket one level less let indent = doc.indent_unit().repeat(indent_level.saturating_sub(1)); - text.push('\n'); + text.push_str(doc.line_ending()); text.push_str(&indent); } @@ -2268,8 +2285,15 @@ fn paste_impl( .unwrap(), ); +<<<<<<< HEAD // if any of values ends \n it's linewise paste let linewise = values.iter().any(|value| value.ends_with('\n')); +======= + // if any of values ends \n it's linewise paste + let linewise = values + .iter() + .any(|value| value.ends_with(doc.line_ending())); +>>>>>>> 856fd95 (trying out line ending helper functions in commands.rs) let mut values = values.iter().cloned().map(Tendril::from).chain(repeat); diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 0a646e93..d6010e6c 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -7,7 +7,7 @@ use crate::{ }; use helix_core::{ - coords_at_pos, + coords_at_pos, rope_slice_to_line_ending, syntax::{self, HighlightEvent}, Position, Range, }; @@ -179,7 +179,7 @@ impl EditorView { // iterate over range char by char for grapheme in RopeGraphemes::new(text) { - if grapheme == "\n" || grapheme == "\r\n" { + if rope_slice_to_line_ending(&grapheme).is_some() { visual_x = 0; line += 1; diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index bd5f8012..5f61f05a 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -76,7 +76,7 @@ pub struct Document { diagnostics: Vec, language_server: Option>, - line_ending: LineEnding, + pub line_ending: LineEnding, } use std::fmt;