on master help sign in
Abstract Transaction::change_by_selection, working del/backspace.
d466882Blaž Hrastnik
helix-core/src/commands.rs+32−2
@@ -1,4 +1,4 @@
1−use crate::graphemes::next_grapheme_boundary;
1+use crate::graphemes;
2use crate::selection::Range;
2use crate::selection::Range;
3use crate::state::{Direction, Granularity, Mode, State};
3use crate::state::{Direction, Granularity, Mode, State};
4use crate::transaction::{ChangeSet, Transaction};
4use crate::transaction::{ChangeSet, Transaction};
@@ -53,7 +53,10 @@ pub fn append_mode(state: &mut State, _count: usize) {
53 let text = &state.doc.slice(..);
53 let text = &state.doc.slice(..);
54 state.selection = state.selection.transform(|range| {
54 state.selection = state.selection.transform(|range| {
55 // TODO: to() + next char
55 // TODO: to() + next char
56+ Range::new(
57+ range.from(),
56− Range::new(range.from(), next_grapheme_boundary(text, range.to()))
58+ graphemes::next_grapheme_boundary(text, range.to()),
59+ )
57 })
60 })
58}
61}
59
62
@@ -75,3 +78,30 @@ pub fn insert_char(state: &mut State, c: char) {
75 transaction.apply(state);
78 transaction.apply(state);
76 // TODO: need to store into history if successful
79 // TODO: need to store into history if successful
77}
80}
81+
82+// TODO: handle indent-aware delete
83+pub fn delete_char_backward(state: &mut State, count: usize) {
84+ let text = &state.doc.slice(..);
85+ let transaction = Transaction::change_by_selection(state, |range| {
86+ (
87+ graphemes::nth_prev_grapheme_boundary(text, range.head, count),
88+ range.head,
89+ None,
90+ )
91+ });
92+ transaction.apply(state);
93+ // TODO: need to store into history if successful
94+}
95+
96+pub fn delete_char_forward(state: &mut State, count: usize) {
97+ let text = &state.doc.slice(..);
98+ let transaction = Transaction::change_by_selection(state, |range| {
99+ (
100+ graphemes::nth_next_grapheme_boundary(text, range.head, count),
101+ range.head,
102+ None,
103+ )
104+ });
105+ transaction.apply(state);
106+ // TODO: need to store into history if successful
107+}
helix-core/src/transaction.rs+24−18
@@ -342,31 +342,37 @@ impl Transaction {
342 true
342 true
343 }
343 }
344
344
345− pub fn insert(state: &State, text: Tendril) -> Self {
345+ pub fn change_by_selection<F>(state: &State, f: F) -> Self
346+ where
347+ F: Fn(&SelectionRange) -> (usize, usize, Option<Tendril>),
348+ {
346 let len = state.doc.len_chars();
349 let len = state.doc.len_chars();
347 let ranges = state.selection.ranges();
350 let ranges = state.selection.ranges();
348− let mut changes = Vec::with_capacity(2 * ranges.len() + 1);
351+ let mut acc = Vec::with_capacity(2 * ranges.len() + 1);
349− let mut last = 0;
352+
353+ let changes = ranges.iter().map(f);
354+
355+ // TODO: verify ranges are ordered and not overlapping.
350
356
351− for range in state.selection.ranges() {
357+ let mut last = 0;
352− let cur = range.head;
358+ for (from, to, tendril) in changes {
359+ // TODO: need to fill the in-between ranges too
360+ // Retain from last "to" to current "from"
353− changes.push(Change::Retain(cur));
361+ acc.push(Change::Retain(from - last));
362+ match tendril {
354− changes.push(Change::Insert(text.clone()));
363+ Some(text) => acc.push(Change::Insert(text)),
364+ None => acc.push(Change::Delete(to - from)),
365+ }
355− last = cur;
366+ last = to;
356 }
367 }
357− changes.push(Change::Retain(len - last));
368+ acc.push(Change::Retain(len - last));
358
369
359− Self::from(ChangeSet { changes, len })
370+ Self::from(ChangeSet { changes: acc, len })
360 }
371 }
361
372
362− pub fn change_selection<F>(selection: Selection, f: F) -> Self
373+ /// Insert text at each selection head.
363− where
374+ pub fn insert(state: &State, text: Tendril) -> Self {
364− F: Fn(SelectionRange) -> ChangeSet,
375+ Self::change_by_selection(state, |range| (range.head, range.head, Some(text.clone())))
365− {
366− selection.ranges().iter().map(|range| true);
367− // TODO: most idiomatic would be to return a
368− // Change { from: x, to: y, insert: "str" }
369− unimplemented!()
370 }
376 }
371}
377}
372
378
helix-term/src/editor.rs+10−2
@@ -259,7 +259,7 @@ impl Editor {
259 }
259 }
260 }
260 }
261
261
262− pub async fn print_events(&mut self) {
262+ pub async fn event_loop(&mut self) {
263 let mut reader = EventStream::new();
263 let mut reader = EventStream::new();
264 let keymap = keymap::default();
264 let keymap = keymap::default();
265
265
@@ -284,6 +284,14 @@ impl Editor {
284 KeyEvent {
284 KeyEvent {
285 code: KeyCode::Esc, ..
285 code: KeyCode::Esc, ..
286 } => helix_core::commands::normal_mode(state, 1),
286 } => helix_core::commands::normal_mode(state, 1),
287+ KeyEvent {
288+ code: KeyCode::Backspace,
289+ ..
290+ } => helix_core::commands::delete_char_backward(state, 1),
291+ KeyEvent {
292+ code: KeyCode::Delete,
293+ ..
294+ } => helix_core::commands::delete_char_forward(state, 1),
287 KeyEvent {
295 KeyEvent {
288 code: KeyCode::Char(c),
296 code: KeyCode::Char(c),
289 ..
297 ..
@@ -320,7 +328,7 @@ impl Editor {
320
328
321 execute!(stdout, terminal::EnterAlternateScreen)?;
329 execute!(stdout, terminal::EnterAlternateScreen)?;
322
330
323− self.print_events().await;
331+ self.event_loop().await;
324
332
325 // reset cursor shape
333 // reset cursor shape
326 write!(stdout, "\x1B[2 q");
334 write!(stdout, "\x1B[2 q");