aboutsummaryrefslogtreecommitdiff
path: root/helix-term/src
diff options
context:
space:
mode:
Diffstat (limited to 'helix-term/src')
-rw-r--r--helix-term/src/commands.rs43
-rw-r--r--helix-term/src/ui/editor.rs4
-rw-r--r--helix-term/src/ui/markdown.rs2
3 files changed, 29 insertions, 20 deletions
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index bcf946b7..28c4fe3a 100644
--- a/helix-term/src/commands.rs
+++ b/helix-term/src/commands.rs
@@ -1,12 +1,12 @@
use helix_core::{
- comment, coords_at_pos, find_first_non_whitespace_char, find_root, graphemes, indent,
- match_brackets,
+ comment, coords_at_pos, find_first_non_whitespace_char, find_root, get_line_ending, graphemes,
+ indent, line_end_char_index, match_brackets,
movement::{self, Direction},
object, pos_at_coords,
regex::{self, Regex},
register::{self, Register, Registers},
- search, selection, Change, ChangeSet, Position, Range, Rope, RopeSlice, Selection, SmallVec,
- Tendril, Transaction,
+ search, selection, Change, ChangeSet, LineEnding, Position, Range, Rope, RopeSlice, Selection,
+ SmallVec, Tendril, Transaction, DEFAULT_LINE_ENDING,
};
use helix_view::{
@@ -303,9 +303,8 @@ 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(2);
+ let pos = line_end_char_index(&text.slice(..), line);
+
Range::new(pos, pos)
});
@@ -452,6 +451,8 @@ where
let count = cx.count();
// need to wait for next key
+ // TODO: should this be done by grapheme rather than char? For example,
+ // we can't properly handle the line-ending case here in terms of char.
cx.on_next_key(move |cx, event| {
let ch = match event {
KeyEvent {
@@ -585,7 +586,7 @@ fn replace(cx: &mut Context) {
KeyEvent {
code: KeyCode::Enter,
..
- } => Some('\n'),
+ } => Some('\n'), // TODO: use the document's default line ending.
_ => None,
};
@@ -725,9 +726,8 @@ 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(2);
+ let pos = line_end_char_index(&text.slice(..), line);
+
Range::new(range.anchor, pos)
});
@@ -922,7 +922,13 @@ fn delete_selection_impl(reg: &mut Register, doc: &mut Document, view_id: ViewId
// then delete
let transaction =
Transaction::change_by_selection(doc.text(), doc.selection(view_id), |range| {
- let max_to = doc.text().len_chars().saturating_sub(1);
+ let alltext = doc.text();
+ let line = alltext.char_to_line(range.head);
+ let max_to = doc.text().len_chars().saturating_sub(
+ get_line_ending(&alltext.line(line))
+ .map(|le| le.len_chars())
+ .unwrap_or(0),
+ );
let to = std::cmp::min(max_to, range.to() + 1);
(range.from(), to, None)
});
@@ -1003,7 +1009,7 @@ 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(doc.line_ending().as_str().into()))]),
);
doc.apply(&transaction, view.id);
}
@@ -1683,8 +1689,7 @@ fn append_to_line(cx: &mut Context) {
let selection = doc.selection(view.id).transform(|range| {
let text = doc.text();
let line = text.char_to_line(range.head);
- // we can't use line_to_char(line + 1) - 2 because the last line might not contain \n
- let pos = (text.line_to_char(line) + text.line(line).len_chars()).saturating_sub(1);
+ let pos = line_end_char_index(&text.slice(..), line);
Range::new(pos, pos)
});
doc.set_selection(view.id, selection);
@@ -2344,7 +2349,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().as_str());
text.push_str(&indent);
let head = pos + offs + text.chars().count();
@@ -2365,7 +2370,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().as_str());
text.push_str(&indent);
}
@@ -2530,7 +2535,9 @@ fn paste_impl(
);
// if any of values ends \n it's linewise paste
- let linewise = values.iter().any(|value| value.ends_with('\n'));
+ let linewise = values
+ .iter()
+ .any(|value| value.ends_with(doc.line_ending().as_str()));
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 7f0d06e9..faede58c 100644
--- a/helix-term/src/ui/editor.rs
+++ b/helix-term/src/ui/editor.rs
@@ -9,7 +9,7 @@ use crate::{
use helix_core::{
coords_at_pos,
syntax::{self, HighlightEvent},
- Position, Range,
+ LineEnding, Position, Range,
};
use helix_view::{document::Mode, Document, Editor, Theme, View};
use std::borrow::Cow;
@@ -176,7 +176,7 @@ impl EditorView {
// iterate over range char by char
for grapheme in RopeGraphemes::new(text) {
- if grapheme == "\n" {
+ if LineEnding::from_rope_slice(&grapheme).is_some() {
visual_x = 0;
line += 1;
diff --git a/helix-term/src/ui/markdown.rs b/helix-term/src/ui/markdown.rs
index 75e2f4b4..72a3e4ff 100644
--- a/helix-term/src/ui/markdown.rs
+++ b/helix-term/src/ui/markdown.rs
@@ -115,6 +115,8 @@ fn parse<'a>(
// TODO: replace tabs with indentation
let mut slice = &text[start..end];
+ // TODO: do we need to handle all unicode line endings
+ // here, or is just '\n' okay?
while let Some(end) = slice.find('\n') {
// emit span up to newline
let text = &slice[..end];