diff --git a/editor/editor.hpp b/editor/editor.hpp index d4d2c2b..3d82ddb 100644 --- a/editor/editor.hpp +++ b/editor/editor.hpp @@ -85,12 +85,19 @@ struct buffer { inline constexpr bool put(uint8_t c); inline constexpr bool delete_backward(); inline constexpr bool delete_forward(); + inline constexpr bool cursor_left(); inline constexpr bool cursor_right(); inline constexpr bool cursor_up(); inline constexpr bool cursor_down(); inline constexpr bool cursor_home(); inline constexpr bool cursor_end(); + inline constexpr uint8_t cursor_get(const editor::cursor& cur); + inline constexpr bool cursor_increment(editor::cursor& cur); + inline constexpr void cursor_scan_word_forward(); + inline constexpr bool cursor_decrement(editor::cursor& cur); + inline constexpr void cursor_scan_word_backward(); + inline constexpr bool enter(); inline constexpr void mark_set(); inline constexpr selection mark_get(); @@ -116,6 +123,8 @@ struct buffer { inline constexpr void scroll_right(); inline constexpr void scroll_up(); inline constexpr void scroll_down(); + inline constexpr void scroll_new_cursor(const editor::cursor& cur); + inline constexpr void scroll_new_col(const int32_t col); }; template @@ -262,13 +271,7 @@ inline constexpr bool buffer::delete_backward() cur.row--; scroll_up(); - if (min.col < cur.col) { - cur.col = min.col; - scroll_right(); - } else { - cur.col = min.col; - scroll_left(); - } + scroll_new_col(min.col); } else { // c // 01234 @@ -422,6 +425,94 @@ inline constexpr bool buffer::cursor_end() return true; } +static inline constexpr bool word_boundary(int8_t c) +{ + return ((c >= 'a' && c <= 'z') + || (c >= 'A' && c <= 'Z') + || (c >= '0' && c <= '9')); +} + +template +inline constexpr uint8_t buffer::cursor_get(const editor::cursor& cur) +{ + return this->lines[cur.row] == nullptr ? 0 : + (cur.col == this->lines[cur.row]->length ? '\n' : + this->lines[cur.row]->buf[cur.col]); +} + +template +inline constexpr bool buffer::cursor_increment(editor::cursor& cur) +{ + if (cur.col >= line_length(this->lines[cur.row])) { + if (cur.row + 1 >= this->length) { + return false; + } else { + cur.row++; + cur.col = 0; + } + } else { + cur.col++; + } + return true; +} + +template +inline constexpr void buffer::cursor_scan_word_forward() +{ + // copy of this->cursor + editor::cursor cur = this->cursor; + + // if we are not inside a word boundary, scan in `dir` direction until we are + // inside a word boundary + while (!word_boundary(cursor_get(cur))) { + if (!cursor_increment(cur)) { scroll_new_cursor(cur); return; } + } + + // scan in `dir` direction until we are not inside a word boundary + while (word_boundary(cursor_get(cur))) { + if (!cursor_increment(cur)) { scroll_new_cursor(cur); return; } + } + + scroll_new_cursor(cur); +} + +template +inline constexpr bool buffer::cursor_decrement(editor::cursor& cur) +{ + if (cur.col == 0) { + if (cur.row - 1 < 0) { + return false; + } else { + cur.row--; + cur.col = this->lines[cur.row]->length; + } + } else { + cur.col--; + } + return true; +} + +template +inline constexpr void buffer::cursor_scan_word_backward() +{ + // copy of this->cursor + editor::cursor cur = this->cursor; + cursor_decrement(cur); + // if we are not inside a word boundary, scan in `dir` direction until we are + // inside a word boundary + while (!word_boundary(cursor_get(cur))) { + if (!cursor_decrement(cur)) { scroll_new_cursor(cur); return; } + } + + // scan in `dir` direction until we are not inside a word boundary + while (word_boundary(cursor_get(cur))) { + if (!cursor_decrement(cur)) { scroll_new_cursor(cur); return; } + } + + cursor_increment(cur); + scroll_new_cursor(cur); +} + template inline constexpr bool buffer::enter() { @@ -581,13 +672,7 @@ inline constexpr bool buffer::mark_delete() this->selection_delete(sel); // move cur to sel.min - editor::cursor& cur = this->cursor; - const editor::cursor& min = *sel.min; - if (min.row < cur.row) { cur.row = min.row; scroll_up(); } - else { cur.row = min.row; scroll_down(); } - - if (min.col < cur.col) { cur.col = min.col; scroll_right(); } - else { cur.col = min.col; scroll_left(); } + scroll_new_cursor(*sel.min); return true; } @@ -790,14 +875,8 @@ inline constexpr bool buffer::shadow_paste() cur.row += last_line_offset; scroll_down(); - int32_t new_col = line_length(last_line_src); - if (new_col < cur.col) { - cur.col = new_col; - scroll_right(); - } else { - cur.col = new_col; - scroll_left(); - } + int32_t col = line_length(last_line_src); + scroll_new_col(col); } return true; @@ -844,4 +923,25 @@ inline constexpr void buffer::scroll_right() if (this->cursor.col >= this->window.left + this->window.cell_width) this->window.left = (this->cursor.col - (this->window.cell_width - 1)); } + +template +inline constexpr void buffer::scroll_new_cursor(const editor::cursor& oth) +{ + editor::cursor& cur = this->cursor; + + if (oth.row < cur.row) { cur.row = oth.row; scroll_up(); } + else { cur.row = oth.row; scroll_down(); } + + if (oth.col < cur.col) { cur.col = oth.col; scroll_right(); } + else { cur.col = oth.col; scroll_left(); } +} + +template +inline constexpr void buffer::scroll_new_col(const int32_t col) +{ + editor::cursor& cur = this->cursor; + + if (col < cur.col) { cur.col = col; scroll_right(); } + else { cur.col = col; scroll_left(); } +} } diff --git a/editor/main_saturn.cpp b/editor/main_saturn.cpp index 814fe8e..3dbc58d 100644 --- a/editor/main_saturn.cpp +++ b/editor/main_saturn.cpp @@ -127,16 +127,16 @@ 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::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; @@ -145,7 +145,11 @@ inline void keyboard_regular_key(const enum keysym k) case MODIFIER_RIGHT_ALT: [[fallthrough]]; case MODIFIER_BOTH_ALT: switch (k) { - case keysym::W : buffer.shadow_copy(); break; + case keysym::ARROW_LEFT : buffer.cursor_scan_word_backward(); break; + case keysym::B : buffer.cursor_scan_word_backward(); break; + case keysym::ARROW_RIGHT: buffer.cursor_scan_word_forward(); break; + case keysym::F : buffer.cursor_scan_word_forward(); break; + case keysym::W : buffer.shadow_copy(); break; default: break; } break;