diff --git a/editor/editor.hpp b/editor/editor.hpp index 3d82ddb..385dc0b 100644 --- a/editor/editor.hpp +++ b/editor/editor.hpp @@ -83,8 +83,10 @@ struct buffer { inline static constexpr line * incref(line * l); inline static constexpr int32_t line_length(line const * const l); inline constexpr bool put(uint8_t c); - inline constexpr bool delete_backward(); inline constexpr bool delete_forward(); + inline constexpr bool delete_backward(); + inline constexpr void delete_word_forward(); + inline constexpr void delete_word_backward(); inline constexpr bool cursor_left(); inline constexpr bool cursor_right(); @@ -248,6 +250,44 @@ inline constexpr bool buffer::put(const uint8_t c) return true; } +template +inline constexpr bool buffer::delete_forward() +{ + if (this->mode == mode::mark) { + this->mode = mode::normal; + return mark_delete(); + } + + editor::cursor& cur = this->cursor; + + if (cur.col < 0 || cur.col > C) + return false; + + if (line_length(this->lines[cur.row]) == 0) { + if (this->length == 1) return false; + decref(this->lines[cur.row]); + // shift all lines up by 1 + int32_t n_lines = this->length - (cur.row + 1); + move(&this->lines[cur.row], + &this->lines[cur.row+1], + (sizeof (line*)) * n_lines); + this->length--; + this->lines[this->length] = nullptr; + // no scrolling needed--cursor is already in the correct position + } else { + // c + // 01234 + line * l = mutref(this->lines[cur.row]); + int32_t length = l->length - cur.col; + move(&l->buf[cur.col], &l->buf[cur.col+1], length); + l->length--; + + // no scrolling needed--cursor is already in the correct position + } + + return true; +} + template inline constexpr bool buffer::delete_backward() { @@ -288,41 +328,31 @@ inline constexpr bool buffer::delete_backward() } template -inline constexpr bool buffer::delete_forward() +inline constexpr void buffer::delete_word_forward() { - if (this->mode == mode::mark) { - this->mode = mode::normal; - return mark_delete(); - } + mark_set(); + cursor_scan_word_forward(); + const selection sel = mark_get(); + selection_delete(sel); - editor::cursor& cur = this->cursor; + // move cur to sel.min + scroll_new_cursor(*sel.min); - if (cur.col < 0 || cur.col > C) - return false; + this->mode = mode::normal; +} - if (line_length(this->lines[cur.row]) == 0) { - if (this->length == 1) return false; - decref(this->lines[cur.row]); - // shift all lines up by 1 - int32_t n_lines = this->length - (cur.row + 1); - move(&this->lines[cur.row], - &this->lines[cur.row+1], - (sizeof (line*)) * n_lines); - this->length--; - this->lines[this->length] = nullptr; - // no scrolling needed--cursor is already in the correct position - } else { - // c - // 01234 - line * l = mutref(this->lines[cur.row]); - int32_t length = l->length - cur.col; - move(&l->buf[cur.col], &l->buf[cur.col+1], length); - l->length--; +template +inline constexpr void buffer::delete_word_backward() +{ + mark_set(); + cursor_scan_word_backward(); + const selection sel = mark_get(); + selection_delete(sel); - // no scrolling needed--cursor is already in the correct position - } + // move cur to sel.min + scroll_new_cursor(*sel.min); - return true; + this->mode = mode::normal; } template @@ -625,9 +655,12 @@ inline constexpr void buffer::selection_delete(const selection& sel) decref(this->lines[ix]); } + // remove sel.min->col from lmin + line * lmin = mutref(this->lines[sel.min->row]); + lmin->length -= (lmin->length - sel.min->col); + if (this->lines[sel.max->row] != nullptr) { // combine min/max; truncating overflow - line * lmin = mutref(this->lines[sel.min->row]); const line * lmax = this->lines[sel.max->row]; // v @@ -637,7 +670,6 @@ inline constexpr void buffer::selection_delete(const selection& sel) // 0cd - lmin->length -= (lmin->length - sel.min->col); int32_t move_length = min(lmax->length - sel.max->col, C - lmin->length); move(&lmin->buf[sel.min->col], &lmax->buf[sel.max->col], @@ -669,7 +701,7 @@ template inline constexpr bool buffer::mark_delete() { const selection sel = mark_get(); - this->selection_delete(sel); + selection_delete(sel); // move cur to sel.min scroll_new_cursor(*sel.min); diff --git a/editor/main_saturn.cpp b/editor/main_saturn.cpp index 3dbc58d..12cf647 100644 --- a/editor/main_saturn.cpp +++ b/editor/main_saturn.cpp @@ -127,16 +127,18 @@ inline void keyboard_regular_key(const enum keysym k) case MODIFIER_RIGHT_CTRL: [[fallthrough]]; case MODIFIER_BOTH_CTRL: switch (k) { - case keysym::SPACE: buffer.mark_set(); break; - case keysym::G : buffer.quit(); break; - case keysym::B : buffer.cursor_left(); break; - case keysym::F : buffer.cursor_right(); break; - case keysym::P : buffer.cursor_up(); break; - case keysym::N : buffer.cursor_down(); break; - case keysym::A : buffer.cursor_home(); break; - case keysym::E : buffer.cursor_end(); break; - case keysym::Y : buffer.shadow_paste(); break; - case keysym::W : buffer.shadow_cut(); break; + case keysym::BACKSPACE: buffer.delete_word_backward(); break; + case keysym::DELETE : buffer.delete_word_forward(); break; + case keysym::SPACE : buffer.mark_set(); break; + case keysym::G : buffer.quit(); break; + case keysym::B : buffer.cursor_left(); break; + case keysym::F : buffer.cursor_right(); break; + case keysym::P : buffer.cursor_up(); break; + case keysym::N : buffer.cursor_down(); break; + case keysym::A : buffer.cursor_home(); break; + case keysym::E : buffer.cursor_end(); break; + case keysym::Y : buffer.shadow_paste(); break; + case keysym::W : buffer.shadow_cut(); break; default: break; } break; diff --git a/editor/test_editor.cpp b/editor/test_editor.cpp index 895c0be..28b2701 100644 --- a/editor/test_editor.cpp +++ b/editor/test_editor.cpp @@ -763,6 +763,37 @@ void test_delete_forward() assert(b.lines[1]->buf[1] == 'w'); } +void test_delete_word_backward() +{ + buffer<8, 8> b {4, 2}; + + b.put('q'); + b.put('w'); + b.put('e'); + b.enter(); + assert(b.length == 2); + b.delete_word_backward(); + assert(b.length == 1); + assert(decltype(b)::line_length(b.lines[0]) == 0); + + b.put('f'); + b.put('o'); + b.put('o'); + b.put(' '); + b.put('b'); + b.put('a'); + b.put('r'); + b.enter(); + b.put('j'); + b.put('k'); + b.put('l'); + assert(b.length == 2); + b.delete_word_backward(); + b.delete_word_backward(); + assert(b.length == 1); + assert(decltype(b)::line_length(b.lines[0]) == 4); +} + int main() { test_allocate(); @@ -782,6 +813,7 @@ int main() test_shadow_paste_oneline(); test_shadow_paste_multiline(); test_delete_forward(); + test_delete_word_backward(); return 0; }