mirror of https://github.com/helix-editor/helix
Implement indent-aware delete (#1120)
* delete character backward can make undent behavior * improve to handle mixed indentationpull/1129/head
parent
bd56dde6e2
commit
5959356a24
|
@ -10,10 +10,11 @@ use helix_core::{
|
||||||
object, pos_at_coords,
|
object, pos_at_coords,
|
||||||
regex::{self, Regex, RegexBuilder},
|
regex::{self, Regex, RegexBuilder},
|
||||||
register::Register,
|
register::Register,
|
||||||
search, selection, surround, textobject, LineEnding, Position, Range, Rope, RopeGraphemes,
|
search, selection, surround, textobject,
|
||||||
RopeSlice, Selection, SmallVec, Tendril, Transaction,
|
unicode::width::UnicodeWidthChar,
|
||||||
|
LineEnding, Position, Range, Rope, RopeGraphemes, RopeSlice, Selection, SmallVec, Tendril,
|
||||||
|
Transaction,
|
||||||
};
|
};
|
||||||
|
|
||||||
use helix_view::{
|
use helix_view::{
|
||||||
clipboard::ClipboardType,
|
clipboard::ClipboardType,
|
||||||
document::{Mode, SCRATCH_BUFFER_NAME},
|
document::{Mode, SCRATCH_BUFFER_NAME},
|
||||||
|
@ -4014,19 +4015,70 @@ pub mod insert {
|
||||||
doc.apply(&transaction, view.id);
|
doc.apply(&transaction, view.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: handle indent-aware delete
|
|
||||||
pub fn delete_char_backward(cx: &mut Context) {
|
pub fn delete_char_backward(cx: &mut Context) {
|
||||||
let count = cx.count();
|
let count = cx.count();
|
||||||
let (view, doc) = current!(cx.editor);
|
let (view, doc) = current!(cx.editor);
|
||||||
let text = doc.text().slice(..);
|
let text = doc.text().slice(..);
|
||||||
|
let indent_unit = doc.indent_unit();
|
||||||
|
let tab_size = doc.tab_width();
|
||||||
|
|
||||||
let transaction =
|
let transaction =
|
||||||
Transaction::change_by_selection(doc.text(), doc.selection(view.id), |range| {
|
Transaction::change_by_selection(doc.text(), doc.selection(view.id), |range| {
|
||||||
let pos = range.cursor(text);
|
let pos = range.cursor(text);
|
||||||
(
|
let line_start_pos = text.line_to_char(range.cursor_line(text));
|
||||||
graphemes::nth_prev_grapheme_boundary(text, pos, count),
|
// considier to delete by indent level if all characters before `pos` are indent units.
|
||||||
pos,
|
let fragment = Cow::from(text.slice(line_start_pos..pos));
|
||||||
None,
|
if !fragment.is_empty() && fragment.chars().all(|ch| ch.is_whitespace()) {
|
||||||
)
|
if text.get_char(pos.saturating_sub(1)) == Some('\t') {
|
||||||
|
// fast path, delete one char
|
||||||
|
(
|
||||||
|
graphemes::nth_prev_grapheme_boundary(text, pos, 1),
|
||||||
|
pos,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
let unit_len = indent_unit.chars().count();
|
||||||
|
// NOTE: indent_unit always contains 'only spaces' or 'only tab' according to `IndentStyle` definition.
|
||||||
|
let unit_size = if indent_unit.starts_with('\t') {
|
||||||
|
tab_size * unit_len
|
||||||
|
} else {
|
||||||
|
unit_len
|
||||||
|
};
|
||||||
|
let width: usize = fragment
|
||||||
|
.chars()
|
||||||
|
.map(|ch| {
|
||||||
|
if ch == '\t' {
|
||||||
|
tab_size
|
||||||
|
} else {
|
||||||
|
// it can be none if it still meet control characters other than '\t'
|
||||||
|
// here just set the width to 1 (or some value better?).
|
||||||
|
ch.width().unwrap_or(1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.sum();
|
||||||
|
let mut drop = width % unit_size; // round down to nearest unit
|
||||||
|
if drop == 0 {
|
||||||
|
drop = unit_size
|
||||||
|
}; // if it's already at a unit, consume a whole unit
|
||||||
|
let mut chars = fragment.chars().rev();
|
||||||
|
let mut start = pos;
|
||||||
|
for _ in 0..drop {
|
||||||
|
// delete up to `drop` spaces
|
||||||
|
match chars.next() {
|
||||||
|
Some(' ') => start -= 1,
|
||||||
|
_ => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(start, pos, None) // delete!
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// delete char
|
||||||
|
(
|
||||||
|
graphemes::nth_prev_grapheme_boundary(text, pos, count),
|
||||||
|
pos,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
}
|
||||||
});
|
});
|
||||||
doc.apply(&transaction, view.id);
|
doc.apply(&transaction, view.id);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue