Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement indent-aware delete #1120

Merged
merged 2 commits into from
Nov 18, 2021
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 36 additions & 3 deletions helix-term/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ use helix_core::{
search, selection, surround, textobject, LineEnding, Position, Range, Rope, RopeGraphemes,
RopeSlice, Selection, SmallVec, Tendril, Transaction,
};

use helix_view::{
clipboard::ClipboardType,
document::{Mode, SCRATCH_BUFFER_NAME},
Expand Down Expand Up @@ -4014,16 +4013,50 @@ pub mod insert {
doc.apply(&transaction, view.id);
}

// TODO: handle indent-aware delete
pub fn delete_char_backward(cx: &mut Context) {
let count = cx.count();
let (view, doc) = current!(cx.editor);
let text = doc.text().slice(..);
let transaction =
Transaction::change_by_selection(doc.text(), doc.selection(view.id), |range| {
let pos = range.cursor(text);
let line_start_pos = text.line_to_char(range.cursor_line(text));

// considier to delete by indent level if all characters before `pos` are indent units.
let indent_unit = doc.indent_unit();
let line_to_start = text.slice(line_start_pos..pos).as_str().unwrap();
WindSoilder marked this conversation as resolved.
Show resolved Hide resolved
WindSoilder marked this conversation as resolved.
Show resolved Hide resolved
// using unwrap here is ok because indent_unit always contains `spaces` or `tab`.
let indent_unit_base = indent_unit.chars().nth(0).unwrap();

// it's ok to dedent when there are only `indent_unit_base` character(e.g: ' ') in `line_to_start`.
let mut ok_to_dedent = true;
for c in line_to_start.chars() {
if c != indent_unit_base {
ok_to_dedent = false;
break;
}
}
WindSoilder marked this conversation as resolved.
Show resolved Hide resolved

let delete_count = if ok_to_dedent {
// current position just at start of line.
if line_to_start.is_empty() {
count
} else {
let steps_to_aligned = line_to_start.len() % indent_unit.len();
// current position is just aligned with indent_unit length, when hit delete, should
// delete a whole `indent_unit`.
if steps_to_aligned == 0 {
indent_unit.len()
} else {
steps_to_aligned
}
}
} else {
count
};
WindSoilder marked this conversation as resolved.
Show resolved Hide resolved

(
graphemes::nth_prev_grapheme_boundary(text, pos, count),
graphemes::nth_prev_grapheme_boundary(text, pos, delete_count),
pos,
None,
)
Expand Down