editor: add delete_word_forward/backward
This also fixes a small ordering bug in selection_delete.
This commit is contained in:
parent
46c274d490
commit
feb57872e8
@ -83,8 +83,10 @@ struct buffer {
|
||||
inline static constexpr line<C> * incref(line<C> * l);
|
||||
inline static constexpr int32_t line_length(line<C> 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<C, R>::put(const uint8_t c)
|
||||
return true;
|
||||
}
|
||||
|
||||
template <int C, int R>
|
||||
inline constexpr bool buffer<C, R>::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<C>*)) * n_lines);
|
||||
this->length--;
|
||||
this->lines[this->length] = nullptr;
|
||||
// no scrolling needed--cursor is already in the correct position
|
||||
} else {
|
||||
// c
|
||||
// 01234
|
||||
line<C> * 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 <int C, int R>
|
||||
inline constexpr bool buffer<C, R>::delete_backward()
|
||||
{
|
||||
@ -288,41 +328,31 @@ inline constexpr bool buffer<C, R>::delete_backward()
|
||||
}
|
||||
|
||||
template <int C, int R>
|
||||
inline constexpr bool buffer<C, R>::delete_forward()
|
||||
inline constexpr void buffer<C, R>::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<C>*)) * n_lines);
|
||||
this->length--;
|
||||
this->lines[this->length] = nullptr;
|
||||
// no scrolling needed--cursor is already in the correct position
|
||||
} else {
|
||||
// c
|
||||
// 01234
|
||||
line<C> * 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 <int C, int R>
|
||||
inline constexpr void buffer<C, R>::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 <int C, int R>
|
||||
@ -625,9 +655,12 @@ inline constexpr void buffer<C, R>::selection_delete(const selection& sel)
|
||||
decref(this->lines[ix]);
|
||||
}
|
||||
|
||||
// remove sel.min->col from lmin
|
||||
line<C> * 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<C> * lmin = mutref(this->lines[sel.min->row]);
|
||||
const line<C> * lmax = this->lines[sel.max->row];
|
||||
|
||||
// v
|
||||
@ -637,7 +670,6 @@ inline constexpr void buffer<C, R>::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 <int C, int R>
|
||||
inline constexpr bool buffer<C, R>::mark_delete()
|
||||
{
|
||||
const selection sel = mark_get();
|
||||
this->selection_delete(sel);
|
||||
selection_delete(sel);
|
||||
|
||||
// move cur to sel.min
|
||||
scroll_new_cursor(*sel.min);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user