Skip to content

Commit

Permalink
added line ending detection and '\r\n' is now being matched same as '…
Browse files Browse the repository at this point in the history
…\n', as this fixes CRLF files not rendering properly
  • Loading branch information
janhrastnik committed Jun 11, 2021
1 parent 037f45f commit dd1b5ca
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 6 deletions.
1 change: 1 addition & 0 deletions helix-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ pub use position::{coords_at_pos, pos_at_coords, Position};
pub use selection::{Range, Selection};
pub use smallvec::SmallVec;
pub use syntax::Syntax;
pub use graphemes::RopeGraphemes;

pub use diagnostic::Diagnostic;
pub use history::History;
Expand Down
2 changes: 1 addition & 1 deletion helix-term/src/ui/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ impl EditorView {

// iterate over range char by char
for grapheme in RopeGraphemes::new(text) {
if grapheme == "\n" {
if grapheme == "\n" || grapheme == "\r\n" {
visual_x = 0;
line += 1;

Expand Down
76 changes: 73 additions & 3 deletions helix-view/src/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::sync::Arc;

use helix_core::{
syntax::{LanguageConfiguration, LOADER},
ChangeSet, Diagnostic, History, Rope, Selection, State, Syntax, Transaction,
ChangeSet, Diagnostic, History, Rope, RopeSlice, RopeGraphemes, Selection, State, Syntax, Transaction,
};

use crate::{DocumentId, ViewId};
Expand All @@ -20,6 +20,21 @@ pub enum Mode {
Insert,
}

/// Represents one of the valid Unicode line endings.
/// Also acts as an index into `LINE_ENDINGS`.
#[derive(PartialEq, Copy, Clone, Debug)]
pub enum LineEnding {
None = 0, // No line ending
CRLF = 1, // CarriageReturn followed by LineFeed
LF = 2, // U+000A -- LineFeed
VT = 3, // U+000B -- VerticalTab
FF = 4, // U+000C -- FormFeed
CR = 5, // U+000D -- CarriageReturn
NEL = 6, // U+0085 -- NextLine
LS = 7, // U+2028 -- Line Separator
PS = 8, // U+2029 -- ParagraphSeparator
}

pub struct Document {
// rope + selection
pub(crate) id: DocumentId,
Expand Down Expand Up @@ -50,6 +65,7 @@ pub struct Document {

diagnostics: Vec<Diagnostic>,
language_server: Option<Arc<helix_lsp::Client>>,
line_ending: LineEnding
}

/// Like std::mem::replace() except it allows the replacement value to be mapped from the
Expand Down Expand Up @@ -112,11 +128,61 @@ pub fn canonicalize_path(path: &Path) -> std::io::Result<PathBuf> {
std::env::current_dir().map(|current_dir| normalize_path(&current_dir.join(path)))
}

pub fn auto_detect_line_ending(doc: &Rope) -> LineEnding {
// based on https://github.com/cessen/led/blob/27572c8838a1c664ee378a19358604063881cc1d/src/editor/mod.rs#L88-L162

let mut ending = LineEnding::None;
for line in doc.lines().take(1) { // check first line only - unsure how sound this is
// Get the line ending
ending = if line.len_chars() == 1 {
let g = RopeGraphemes::new(line.slice((line.len_chars() - 1)..))
.last()
.unwrap();
rope_slice_to_line_ending(&g)
} else if line.len_chars() > 1 {
let g = RopeGraphemes::new(line.slice((line.len_chars() - 2)..))
.last()
.unwrap();
rope_slice_to_line_ending(&g)
} else {
LineEnding::None
};
}
ending
}

pub fn rope_slice_to_line_ending(g: &RopeSlice) -> LineEnding {
if let Some(text) = g.as_str() {
str_to_line_ending(text)
} else if g == "\u{000D}\u{000A}" {
LineEnding::CRLF
} else {
// Not a line ending
LineEnding::None
}
}

pub fn str_to_line_ending(g: &str) -> LineEnding {
match g {
"\u{000D}\u{000A}" => LineEnding::CRLF,
"\u{000A}" => LineEnding::LF,
"\u{000B}" => LineEnding::VT,
"\u{000C}" => LineEnding::FF,
"\u{000D}" => LineEnding::CR,
"\u{0085}" => LineEnding::NEL,
"\u{2028}" => LineEnding::LS,
"\u{2029}" => LineEnding::PS,

// Not a line ending
_ => LineEnding::None,
}
}

use helix_lsp::lsp;
use url::Url;

impl Document {
pub fn new(text: Rope) -> Self {
pub fn new(text: Rope, line_ending: LineEnding) -> Self {
let changes = ChangeSet::new(&text);
let old_state = None;

Expand All @@ -136,6 +202,7 @@ impl Document {
history: Cell::new(History::default()),
last_saved_revision: 0,
language_server: None,
line_ending: line_ending
}
}

Expand All @@ -150,7 +217,10 @@ impl Document {
Rope::from_reader(BufReader::new(file))?
};

let mut doc = Self::new(doc);
// search for line endings
let line_ending = auto_detect_line_ending(&doc);

let mut doc = Self::new(doc, line_ending);
// set the path and try detecting the language
doc.set_path(&path)?;

Expand Down
4 changes: 2 additions & 2 deletions helix-view/src/editor.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{theme::Theme, tree::Tree, Document, DocumentId, RegisterSelection, View, ViewId};
use crate::{theme::Theme, tree::Tree, Document, DocumentId, RegisterSelection, View, ViewId, LineEnding};
use tui::layout::Rect;

use std::path::PathBuf;
Expand Down Expand Up @@ -131,7 +131,7 @@ impl Editor {

pub fn new_file(&mut self, action: Action) -> DocumentId {
use helix_core::Rope;
let doc = Document::new(Rope::from("\n"));
let doc = Document::new(Rope::from("\n"), LineEnding::LF);
let id = self.documents.insert(doc);
self.documents[id].id = id;
self.switch(id, action);
Expand Down
1 change: 1 addition & 0 deletions helix-view/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ new_key_type! { pub struct DocumentId; }
new_key_type! { pub struct ViewId; }

pub use document::Document;
pub use document::LineEnding;
pub use editor::Editor;
pub use register_selection::RegisterSelection;
pub use theme::Theme;
Expand Down

0 comments on commit dd1b5ca

Please sign in to comment.