on master help sign in
added some tests and a line_ending helper function in document.rs
commita9a718c3cad3af7b9fa38cd1aaa6ceb6c7126130 authorJan Hrastnik <jan.hrastnik2@gmail.com> dateSun 13 Jun 2021, 21:38 (5 years ago) parente4849f4
3 files changed+76−6
helix-core/src/lib.rs+1−1 helix-core/src/line_ending.rs+60−4 helix-view/src/document.rs+15−1
helix-core/src/lib.rs+1−1
@@ -110,5 +110,5 @@ pub use syntax::Syntax;
110110pub use diagnostic::Diagnostic;
111111pub use state::State;
112112
113−pub use line_ending::{auto_detect_line_ending, DEFAULT_LINE_ENDING, LineEnding};
113+pub use line_ending::{auto_detect_line_ending, LineEnding, DEFAULT_LINE_ENDING};
114114pub use transaction::{Assoc, Change, ChangeSet, Operation, Transaction};
helix-core/src/line_ending.rs+60−4
@@ -1,7 +1,6 @@
11use crate::{Rope, RopeGraphemes, RopeSlice};
22
33/// Represents one of the valid Unicode line endings.
4−/// VT, FF and PS are excluded here, as we don't expect them to show up as a default line break
54#[derive(PartialEq, Copy, Clone, Debug)]
65pub enum LineEnding {
76 Crlf, // CarriageReturn followed by LineFeed
@@ -9,6 +8,9 @@ pub enum LineEnding {
98 CR, // U+000D -- CarriageReturn
109 Nel, // U+0085 -- NextLine
1110 LS, // U+2028 -- Line Separator
11+ VT, // U+000B -- VerticalTab
12+ FF, // U+000C -- FormFeed
13+ PS, // U+2029 -- ParagraphSeparator
1214}
1315
1416pub fn rope_slice_to_line_ending(g: &RopeSlice) -> Option<LineEnding> {
@@ -38,8 +40,8 @@ pub fn auto_detect_line_ending(doc: &Rope) -> Option<LineEnding> {
3840 // based on https://github.com/cessen/led/blob/27572c8838a1c664ee378a19358604063881cc1d/src/editor/mod.rs#L88-L162
3941
4042 let mut ending = None;
41− for line in doc.lines().take(1) {
42− // check first line only - unsure how sound this is
43+ // return first matched line ending. Not all possible line endings are being matched, as they might be special-use only
44+ for line in doc.lines().take(100) {
4345 ending = match line.len_chars() {
4446 1 => {
4547 let g = RopeGraphemes::new(line.slice((line.len_chars() - 1)..))
@@ -54,6 +56,9 @@ pub fn auto_detect_line_ending(doc: &Rope) -> Option<LineEnding> {
5456 rope_slice_to_line_ending(&g)
5557 }
5658 _ => None,
59+ };
60+ if ending.is_some() {
61+ return ending;
5762 }
5863 }
5964 ending
@@ -62,4 +67,55 @@ pub fn auto_detect_line_ending(doc: &Rope) -> Option<LineEnding> {
6267#[cfg(target_os = "windows")]
6368pub const DEFAULT_LINE_ENDING: LineEnding = LineEnding::Crlf;
6469#[cfg(not(target_os = "windows"))]
65−pub const DEFAULT_LINE_ENDING: LineEnding = LineEnding::LF;
70+pub const DEFAULT_LINE_ENDING: LineEnding = LineEnding::LF;
71+
72+#[cfg(test)]
73+mod line_ending_tests {
74+ use super::*;
75+
76+ #[test]
77+ fn test_autodetect() {
78+ assert_eq!(
79+ auto_detect_line_ending(&Rope::from_str("\n")),
80+ Some(LineEnding::LF)
81+ );
82+ assert_eq!(
83+ auto_detect_line_ending(&Rope::from_str("\r\n")),
84+ Some(LineEnding::Crlf)
85+ );
86+ assert_eq!(auto_detect_line_ending(&Rope::from_str("hello")), None);
87+ assert_eq!(auto_detect_line_ending(&Rope::from_str("")), None);
88+ assert_eq!(
89+ auto_detect_line_ending(&Rope::from_str("hello\nhelix\r\n")),
90+ Some(LineEnding::LF)
91+ );
92+ assert_eq!(
93+ auto_detect_line_ending(&Rope::from_str("a formfeed\u{000C}")),
94+ None
95+ );
96+ assert_eq!(
97+ auto_detect_line_ending(&Rope::from_str("\n\u{000A}\n \u{000A}")),
98+ Some(LineEnding::LF)
99+ );
100+ assert_eq!(
101+ auto_detect_line_ending(&Rope::from_str(
102+ "a formfeed\u{000C} with a\u{000C} linefeed\u{000A}"
103+ )),
104+ Some(LineEnding::LF)
105+ );
106+ 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));
107+ }
108+
109+ #[test]
110+ fn test_rope_slice_to_line_ending() {
111+ let r = Rope::from_str("\r\n");
112+ assert_eq!(
113+ rope_slice_to_line_ending(&r.slice(1..2)),
114+ Some(LineEnding::LF)
115+ );
116+ assert_eq!(
117+ rope_slice_to_line_ending(&r.slice(0..2)),
118+ Some(LineEnding::Crlf)
119+ );
120+ }
121+}
helix-view/src/document.rs+15−1
@@ -6,9 +6,9 @@ use std::sync::Arc;
66
77use helix_core::{
88 chars::{char_is_linebreak, char_is_whitespace},
9− auto_detect_line_ending, DEFAULT_LINE_ENDING, history::History,
109 syntax::{LanguageConfiguration, LOADER},
1110 ChangeSet, Diagnostic, LineEnding, Rope, Selection, State, Syntax, Transaction,
11+ DEFAULT_LINE_ENDING,
1212};
1313
1414use crate::{DocumentId, ViewId};
@@ -740,6 +740,20 @@ impl Document {
740740 pub fn set_diagnostics(&mut self, diagnostics: Vec<Diagnostic>) {
741741 self.diagnostics = diagnostics;
742742 }
743+
744+ pub fn line_ending(&self) -> &str {
745+ match self.line_ending {
746+ LineEnding::Crlf => "\u{000D}\u{000A}",
747+ LineEnding::LF => "\u{000A}",
748+ LineEnding::Nel => "\u{0085}",
749+ LineEnding::LS => "\u{2028}",
750+ LineEnding::CR => "\u{000D}",
751+ _ => panic!(
752+ "Unexpected line ending: {:?}, expected Crlf, LF, CR, Nel, or LS.",
753+ self.line_ending
754+ ),
755+ }
756+ }
743757}
744758
745759#[cfg(test)]