@@ -8,7 +8,7 @@ use helix_core::{
8 chars::{char_is_linebreak, char_is_whitespace},
8 chars::{char_is_linebreak, char_is_whitespace},
9 history::History,
9 history::History,
10 syntax::{LanguageConfiguration, LOADER},
10 syntax::{LanguageConfiguration, LOADER},
11− ChangeSet, Diagnostic, Rope, Selection, State, Syntax, Transaction,
11+ ChangeSet, Diagnostic, History, Rope, RopeSlice, RopeGraphemes, Selection, State, Syntax, Transaction,
14use crate::{DocumentId, ViewId};
14use crate::{DocumentId, ViewId};
@@ -22,12 +22,28 @@ pub enum Mode {
25#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
26#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
26pub enum IndentStyle {
27pub enum IndentStyle {
28 Spaces(u8),
29 Spaces(u8),
32+/// Represents one of the valid Unicode line endings.
33+/// Also acts as an index into `LINE_ENDINGS`.
34+#[derive(PartialEq, Copy, Clone, Debug)]
36+ None = 0, // No line ending
37+ CRLF = 1, // CarriageReturn followed by LineFeed
38+ LF = 2, // U+000A -- LineFeed
39+ VT = 3, // U+000B -- VerticalTab
40+ FF = 4, // U+000C -- FormFeed
41+ CR = 5, // U+000D -- CarriageReturn
42+ NEL = 6, // U+0085 -- NextLine
43+ LS = 7, // U+2028 -- Line Separator
44+ PS = 8, // U+2029 -- ParagraphSeparator
31pub struct Document {
47pub struct Document {
32 // rope + selection
48 // rope + selection
33 pub(crate) id: DocumentId,
49 pub(crate) id: DocumentId,
@@ -61,6 +77,7 @@ pub struct Document {
62 diagnostics: Vec<Diagnostic>,
78 diagnostics: Vec<Diagnostic>,
63 language_server: Option<Arc<helix_lsp::Client>>,
79 language_server: Option<Arc<helix_lsp::Client>>,
80+ line_ending: LineEnding
66use std::fmt;
83use std::fmt;
@@ -146,11 +163,61 @@ pub fn canonicalize_path(path: &Path) -> std::io::Result<PathBuf> {
146 std::env::current_dir().map(|current_dir| normalize_path(¤t_dir.join(path)))
163 std::env::current_dir().map(|current_dir| normalize_path(¤t_dir.join(path)))
166+pub fn auto_detect_line_ending(doc: &Rope) -> LineEnding {
167+ // based on https://github.com/cessen/led/blob/27572c8838a1c664ee378a19358604063881cc1d/src/editor/mod.rs#L88-L162
169+ let mut ending = LineEnding::None;
170+ for line in doc.lines().take(1) { // check first line only - unsure how sound this is
171+ // Get the line ending
172+ ending = if line.len_chars() == 1 {
173+ let g = RopeGraphemes::new(line.slice((line.len_chars() - 1)..))
176+ rope_slice_to_line_ending(&g)
177+ } else if line.len_chars() > 1 {
178+ let g = RopeGraphemes::new(line.slice((line.len_chars() - 2)..))
181+ rope_slice_to_line_ending(&g)
189+pub fn rope_slice_to_line_ending(g: &RopeSlice) -> LineEnding {
190+ if let Some(text) = g.as_str() {
191+ str_to_line_ending(text)
192+ } else if g == "\u{000D}\u{000A}" {
195+ // Not a line ending
200+pub fn str_to_line_ending(g: &str) -> LineEnding {
202+ "\u{000D}\u{000A}" => LineEnding::CRLF,
203+ "\u{000A}" => LineEnding::LF,
204+ "\u{000B}" => LineEnding::VT,
205+ "\u{000C}" => LineEnding::FF,
206+ "\u{000D}" => LineEnding::CR,
207+ "\u{0085}" => LineEnding::NEL,
208+ "\u{2028}" => LineEnding::LS,
209+ "\u{2029}" => LineEnding::PS,
211+ // Not a line ending
212+ _ => LineEnding::None,
149use helix_lsp::lsp;
216use helix_lsp::lsp;
150use url::Url;
217use url::Url;
152impl Document {
219impl Document {
153− pub fn new(text: Rope) -> Self {
220+ pub fn new(text: Rope, line_ending: LineEnding) -> Self {
154 let changes = ChangeSet::new(&text);
221 let changes = ChangeSet::new(&text);
155 let old_state = None;
222 let old_state = None;
@@ -171,6 +238,7 @@ impl Document {
171 history: Cell::new(History::default()),
238 history: Cell::new(History::default()),
172 last_saved_revision: 0,
239 last_saved_revision: 0,
173 language_server: None,
240 language_server: None,
241+ line_ending: line_ending
@@ -190,7 +258,10 @@ impl Document {
261+ // search for line endings
262+ let line_ending = auto_detect_line_ending(&doc);
193− let mut doc = Self::new(doc);
264+ let mut doc = Self::new(doc, line_ending);
194 // set the path and try detecting the language
265 // set the path and try detecting the language
195 doc.set_path(&path)?;
266 doc.set_path(&path)?;
196 doc.detect_indent_style();
267 doc.detect_indent_style();