mirror of https://github.com/helix-editor/helix
parent
5a344a3ae5
commit
c17dcb8633
|
@ -45,7 +45,10 @@ pub fn move_vertically(
|
||||||
|
|
||||||
let new_line = match dir {
|
let new_line = match dir {
|
||||||
Direction::Backward => row.saturating_sub(count),
|
Direction::Backward => row.saturating_sub(count),
|
||||||
Direction::Forward => std::cmp::min(row.saturating_add(count), text.len_lines() - 2),
|
Direction::Forward => std::cmp::min(
|
||||||
|
row.saturating_add(count),
|
||||||
|
text.len_lines().saturating_sub(2),
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
// convert to 0-indexed, subtract another 1 because len_chars() counts \n
|
// convert to 0-indexed, subtract another 1 because len_chars() counts \n
|
||||||
|
|
|
@ -383,7 +383,7 @@ pub fn split_on_matches(
|
||||||
// TODO: retain range direction
|
// TODO: retain range direction
|
||||||
|
|
||||||
let end = text.byte_to_char(start_byte + mat.start());
|
let end = text.byte_to_char(start_byte + mat.start());
|
||||||
result.push(Range::new(start, end - 1));
|
result.push(Range::new(start, end.saturating_sub(1)));
|
||||||
start = text.byte_to_char(start_byte + mat.end());
|
start = text.byte_to_char(start_byte + mat.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,7 +90,8 @@ impl ChangeSet {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.len_after += fragment.len();
|
// Avoiding std::str::len() to account for UTF-8 characters.
|
||||||
|
self.len_after += fragment.chars().count();
|
||||||
|
|
||||||
let new_last = match self.changes.as_mut_slice() {
|
let new_last = match self.changes.as_mut_slice() {
|
||||||
[.., Insert(prev)] | [.., Insert(prev), Delete(_)] => {
|
[.., Insert(prev)] | [.., Insert(prev), Delete(_)] => {
|
||||||
|
@ -754,4 +755,21 @@ mod test {
|
||||||
use Operation::*;
|
use Operation::*;
|
||||||
assert_eq!(changes.changes, &[Insert("a".into())]);
|
assert_eq!(changes.changes, &[Insert("a".into())]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn combine_with_utf8() {
|
||||||
|
const TEST_CASE: &'static str = "Hello, これはヒレクスエディターです!";
|
||||||
|
|
||||||
|
let empty = Rope::from("");
|
||||||
|
let mut a = ChangeSet::new(&empty);
|
||||||
|
|
||||||
|
let mut b = ChangeSet::new(&empty);
|
||||||
|
b.insert(TEST_CASE.into());
|
||||||
|
|
||||||
|
let changes = a.compose(b);
|
||||||
|
|
||||||
|
use Operation::*;
|
||||||
|
assert_eq!(changes.changes, &[Insert(TEST_CASE.into())]);
|
||||||
|
assert_eq!(changes.len_after, TEST_CASE.chars().count());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -669,7 +669,7 @@ fn _search(doc: &mut Document, view: &mut View, contents: &str, regex: &Regex, e
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let head = end - 1;
|
let head = end;
|
||||||
|
|
||||||
let selection = if extend {
|
let selection = if extend {
|
||||||
selection.clone().push(Range::new(start, head))
|
selection.clone().push(Range::new(start, head))
|
||||||
|
@ -749,7 +749,9 @@ pub fn select_line(cx: &mut Context) {
|
||||||
|
|
||||||
let line = text.char_to_line(pos.head);
|
let line = text.char_to_line(pos.head);
|
||||||
let start = text.line_to_char(line);
|
let start = text.line_to_char(line);
|
||||||
let end = text.line_to_char(line + count).saturating_sub(1);
|
let end = text
|
||||||
|
.line_to_char(std::cmp::min(doc.text().len_lines(), line + count))
|
||||||
|
.saturating_sub(1);
|
||||||
|
|
||||||
doc.set_selection(view.id, Selection::single(start, end));
|
doc.set_selection(view.id, Selection::single(start, end));
|
||||||
}
|
}
|
||||||
|
|
|
@ -341,7 +341,7 @@ impl EditorView {
|
||||||
let info: Style = theme.get("info");
|
let info: Style = theme.get("info");
|
||||||
let hint: Style = theme.get("hint");
|
let hint: Style = theme.get("hint");
|
||||||
|
|
||||||
for (i, line) in (view.first_line..last_line).enumerate() {
|
for (i, line) in (view.first_line..=last_line).enumerate() {
|
||||||
use helix_core::diagnostic::Severity;
|
use helix_core::diagnostic::Severity;
|
||||||
if let Some(diagnostic) = doc.diagnostics.iter().find(|d| d.line == line) {
|
if let Some(diagnostic) = doc.diagnostics.iter().find(|d| d.line == line) {
|
||||||
surface.set_stringn(
|
surface.set_stringn(
|
||||||
|
|
|
@ -114,7 +114,7 @@ impl Prompt {
|
||||||
let selected_color = theme.get("ui.menu.selected");
|
let selected_color = theme.get("ui.menu.selected");
|
||||||
// completion
|
// completion
|
||||||
|
|
||||||
let max_col = area.width / BASE_WIDTH;
|
let max_col = std::cmp::max(1, area.width / BASE_WIDTH);
|
||||||
let height = ((self.completion.len() as u16 + max_col - 1) / max_col);
|
let height = ((self.completion.len() as u16 + max_col - 1) / max_col);
|
||||||
let completion_area = Rect::new(
|
let completion_area = Rect::new(
|
||||||
area.x,
|
area.x,
|
||||||
|
|
|
@ -106,7 +106,7 @@ impl View {
|
||||||
/// Calculates the last visible line on screen
|
/// Calculates the last visible line on screen
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn last_line(&self, doc: &Document) -> usize {
|
pub fn last_line(&self, doc: &Document) -> usize {
|
||||||
let height = self.area.height.saturating_sub(1); // - 1 for statusline
|
let height = self.area.height.saturating_sub(2); // - 2 for statusline
|
||||||
std::cmp::min(
|
std::cmp::min(
|
||||||
self.first_line + height as usize,
|
self.first_line + height as usize,
|
||||||
doc.text().len_lines() - 1,
|
doc.text().len_lines() - 1,
|
||||||
|
|
Loading…
Reference in New Issue