saturn-examples/editor/test_editor.cpp
Zack Buhman 6a5ebab01f editor: add shadow-lines and region-deletes
This implements the "copy" portion of copy-and-paste and the "delete"
portion of cut-and-paste.

'backspace' was also partially refactored to share code with the new
'selection_delete'.

I am excited in how expressiveness/readability improved in 'backspace'
after selection_delete was implemented.
2023-06-10 02:57:54 +00:00

591 lines
11 KiB
C++

#include <assert.h>
#include <iostream>
#include "editor.hpp"
using namespace editor;
static void test_allocate()
{
buffer<8, 4> b {4, 2};
decltype(b)::line_type * l;
assert(b.row[0].length == -1);
assert(b.row[1].length == -1);
assert(b.row[2].length == -1);
assert(b.row[3].length == -1);
l = b.allocate();
assert(b.row[0].length == 0);
assert(b.row[1].length == -1);
assert(b.row[2].length == -1);
assert(b.row[3].length == -1);
assert(l == &b.row[0]);
l = b.allocate();
assert(b.row[0].length == 0);
assert(b.row[1].length == 0);
assert(b.row[2].length == -1);
assert(b.row[3].length == -1);
assert(l == &b.row[1]);
l = b.allocate();
assert(b.row[0].length == 0);
assert(b.row[1].length == 0);
assert(b.row[2].length == 0);
assert(b.row[3].length == -1);
assert(l == &b.row[2]);
l = b.allocate();
assert(b.row[0].length == 0);
assert(b.row[1].length == 0);
assert(b.row[2].length == 0);
assert(b.row[3].length == 0);
assert(l == &b.row[3]);
l = &b.row[1];
b.deallocate(l);
assert(b.row[0].length == 0);
assert(b.row[1].length == -1);
assert(b.row[2].length == 0);
assert(b.row[3].length == 0);
l = b.allocate();
assert(b.row[0].length == 0);
assert(b.row[1].length == 0);
assert(b.row[2].length == 0);
assert(b.row[3].length == 0);
assert(l == &b.row[1]);
}
static void test_put()
{
// v
// "as" -> "abs"
buffer<8, 4> b {4, 2};
decltype(b)::line_type * l;
assert(b.cursor.col == 0);
assert(b.cursor.row == 0);
assert(b.length == 1);
b.put('a');
l = b.lines[0];
assert(l = &b.row[0]);
assert(l->length == 1);
assert(l->buf[0] == 'a');
assert(b.cursor.col == 1);
assert(b.cursor.row == 0);
assert(b.length == 1);
b.put('b');
l = b.lines[0];
assert(l->length == 2);
assert(l->buf[0] == 'a');
assert(l->buf[1] == 'b');
assert(b.cursor.col == 2);
assert(b.cursor.row == 0);
assert(b.length == 1);
b.cursor.col = 1;
b.put('c');
l = b.lines[0];
assert(l->length == 3);
assert(l->buf[0] == 'a');
assert(l->buf[1] == 'c');
assert(l->buf[2] == 'b');
assert(b.cursor.col == 2);
assert(b.cursor.row == 0);
assert(b.length == 1);
}
void test_backspace()
{
buffer<8, 4> b {4, 2};
decltype(b)::line_type * l;
b.put('a');
l = b.lines[0];
assert(l->length == 1);
assert(l->buf[0] == 'a');
assert(b.backspace() == true);
assert(l->length == 0);
assert(b.backspace() == false);
b.put('b');
b.put('c');
b.put('d');
b.put('e');
b.cursor.col = 2;
assert(l->length == 4);
//"bcde"
assert(b.backspace() == true);
assert(l->buf[0] == 'b');
assert(l->buf[1] == 'd');
assert(l->buf[2] == 'e');
assert(l->length == 3);
}
void test_enter()
{
// [0] asDf
// [1] qwer
// [0] as
// [1] Df
// [2] qwer
buffer<8, 4> b {4, 2};
b.cursor.row = 0;
b.cursor.col = 0;
b.put('a');
b.put('s');
b.put('d');
b.put('f');
b.cursor.row = 1;
b.cursor.col = 0;
b.put('q');
b.put('w');
b.put('e');
b.put('r');
assert(b.length == 2);
assert(b.lines[0]->buf[0] == 'a');
assert(b.lines[0]->buf[3] == 'f');
assert(b.lines[1]->buf[0] == 'q');
assert(b.lines[1]->buf[3] == 'r');
b.cursor.row = 0;
b.cursor.col = 2;
b.enter();
assert(b.length == 3);
assert(b.lines[0]->length == 2);
assert(b.lines[1]->length == 2);
assert(b.lines[2]->length == 4);
assert(b.lines[0]->buf[0] == 'a');
assert(b.lines[0]->buf[1] == 's');
assert(b.lines[1]->buf[0] == 'd');
assert(b.lines[1]->buf[1] == 'f');
assert(b.lines[2]->buf[0] == 'q');
assert(b.lines[2]->buf[1] == 'w');
assert(b.lines[2]->buf[2] == 'e');
assert(b.lines[2]->buf[3] == 'r');
}
void test_enter_backspace1()
{
// abcd
// ab
//
// cd
// abcd
// ab
// cd
buffer<8, 4> b {4, 2};
b.put('a');
b.put('b');
b.put('c');
b.put('d');
b.cursor_left();
b.cursor_left();
b.enter();
b.enter();
assert(b.length == 3);
b.backspace();
b.backspace();
assert(b.length == 1);
b.enter();
assert(b.length == 2);
assert(b.lines[0]->buf[0] == 'a');
assert(b.lines[0]->buf[1] == 'b');
assert(b.lines[1]->buf[0] == 'c');
assert(b.lines[1]->buf[1] == 'd');
}
void test_enter_backspace2()
{
buffer<8, 4> b {4, 2};
b.put('a');
b.enter();
assert(b.cursor.row == 1);
assert(b.cursor.col == 0);
assert(b.length == 2);
b.backspace();
assert(b.cursor.row == 0);
assert(b.cursor.col == 1);
assert(b.length == 1);
}
void test_enter_scroll()
{
buffer<8, 4> b {4, 2};
assert(b.window.top == 0);
b.put('a');
assert(b.window.top == 0);
b.enter();
assert(b.window.top == 0);
b.put('b');
assert(b.window.top == 0);
b.enter();
assert(b.cursor.row == 2);
assert(b.window.top == 1);
b.put('c');
assert(b.window.top == 1);
b.enter();
assert(b.window.top == 2);
b.put('d');
assert(b.window.top == 2);
}
void test_first_enter()
{
buffer<8, 4> b {4, 2};
b.enter();
assert(b.length == 2);
}
void test_enter_backspace3()
{
// a
//
//
// b
buffer<8, 8> b {4, 2};
b.put('a');
b.enter();
b.enter();
b.enter();
b.put('b');
b.cursor_up();
assert(b.lines[0]->buf[0] == 'a');
assert(b.lines[1]->length == 0);
assert(b.lines[2]->length == 0);
assert(b.lines[3]->buf[0] == 'b');
assert(b.lines[4] == nullptr);
assert(b.length == 4);
b.backspace();
assert(b.length == 3);
assert(b.lines[0]->buf[0] == 'a');
assert(b.lines[1]->length == 0);
assert(b.lines[2]->buf[0] == 'b');
assert(b.lines[3] == nullptr);
}
void test_copy()
{
// 0123
// asDf
// qwer
// jKlo
// asklo
//
// df
// qwer
// j
buffer<8, 8> b {4, 2};
b.put('a');
b.put('s');
b.put('d');
b.put('f');
b.enter();
b.put('q');
b.put('w');
b.put('e');
b.put('r');
b.enter();
b.put('j');
b.put('k');
b.put('l');
b.put('o');
b.cursor_up();
b.cursor_up();
b.cursor_left();
b.cursor_left();
b.mark_set();
b.cursor_down();
b.cursor_down();
b.cursor_left();
assert(b.mark.row == 0);
assert(b.mark.col == 2);
assert(b.cursor.row == 2);
assert(b.cursor.col == 1);
b.shadow_copy();
assert(b.shadow.length == 3);
assert(b.shadow.lines[0] != nullptr);
assert(b.shadow.lines[1] != nullptr);
assert(b.shadow.lines[2] != nullptr);
assert(b.shadow.lines[3] == nullptr);
assert(b.shadow.lines[0]->length == 2);
assert(b.shadow.lines[1]->length == 4);
assert(b.shadow.lines[2]->length == 1);
assert(b.shadow.lines[0]->buf[0] == 'd');
assert(b.shadow.lines[0]->buf[1] == 'f');
assert(b.shadow.lines[1]->buf[0] == 'q');
assert(b.shadow.lines[1]->buf[1] == 'w');
assert(b.shadow.lines[1]->buf[2] == 'e');
assert(b.shadow.lines[1]->buf[3] == 'r');
assert(b.shadow.lines[2]->buf[0] == 'j');
assert(b.shadow.lines[0] != b.lines[0]);
assert(b.shadow.lines[1] == b.lines[1]);
assert(b.shadow.lines[2] != b.lines[2]);
}
void test_copy_same_line()
{
buffer<8, 8> b {4, 2};
// v
// asdF
//
// sd
b.put('a');
b.put('s');
b.put('d');
b.put('f');
b.cursor_left();
b.mark_set();
b.cursor_left();
b.cursor_left();
// non-cow same line
b.shadow_copy();
assert(b.shadow.length == 1);
assert(b.shadow.lines[0] != nullptr);
assert(b.shadow.lines[1] == nullptr);
assert(b.shadow.lines[0] != b.lines[0]);
assert(b.shadow.lines[0]->length == 2);
assert(b.shadow.lines[0]->buf[0] == 's');
assert(b.shadow.lines[0]->buf[1] == 'd');
// cow same line
b.cursor_home();
b.mark_set();
b.cursor_end();
b.shadow_copy();
assert(b.shadow.length == 1);
assert(b.shadow.lines[0] == b.lines[0]);
}
void test_copy_multi_line_cow()
{
buffer<8, 8> b {4, 2};
// v
// asdF
//
// sd
b.put('a');
b.put('s');
b.put('d');
b.put('f');
b.enter();
b.put('q');
b.put('w');
b.put('e');
b.put('r');
b.mark_set();
b.cursor_up();
b.cursor_home();
b.shadow_copy();
assert(b.shadow.length == 2);
assert(b.shadow.lines[0] == b.lines[0]);
assert(b.shadow.lines[1] == b.lines[1]);
}
void test_copy_multi_line_offset()
{
buffer<8, 8> b {4, 2};
b.put('a');
b.put('s');
b.put('d');
b.put('f');
b.enter();
b.put('q');
b.put('w');
b.put('e');
b.put('r');
b.enter();
b.put('s');
b.put('h');
b.put('a');
b.put('d');
b.enter();
b.put('o');
b.put('w');
// qwEr
// sHad
// er
// s
b.cursor_up();
b.cursor_home();
b.cursor_right();
b.mark_set();
b.cursor_up();
b.cursor_right();
b.shadow_copy();
assert(b.shadow.length == 2);
assert(b.shadow.lines[0]->length == 2);
assert(b.shadow.lines[1]->length == 1);
assert(b.shadow.lines[0]->buf[0] == 'e');
assert(b.shadow.lines[0]->buf[1] == 'r');
assert(b.shadow.lines[1]->buf[0] == 's');
b.cursor_home();
b.mark_set();
b.cursor_down();
b.cursor_down();
b.cursor_end();
b.shadow_copy();
assert(b.shadow.length == 3);
assert(b.shadow.lines[0] == b.lines[1]);
assert(b.shadow.lines[1] == b.lines[2]);
assert(b.shadow.lines[2] == b.lines[3]);
}
void test_delete_from_line()
{
buffer<8, 8> b {4, 2};
b.put('a');
b.put('s');
b.put('d');
b.put('f');
// S E
// asdf
// af
b.delete_from_line(b.lines[0], 1, 3);
assert(b.lines[0]->length == 2);
assert(b.lines[0]->buf[0] == 'a');
assert(b.lines[0]->buf[1] == 'f');
b.delete_from_line(b.lines[0], 0, 2);
assert(b.lines[0] == nullptr);
}
void test_selection_delete()
{
buffer<8, 8> b {4, 2};
b.put('s');
b.put('p');
b.put('a');
b.put('m');
b.enter();
b.put('a');
b.put('s');
b.put('d');
b.put('f');
b.enter();
b.put('0');
b.put('1');
b.put('2');
b.put('3');
b.enter();
b.put('j');
b.put('k');
b.put('l');
b.put('p');
b.enter();
b.put('q');
b.put('w');
b.put('e');
b.put('r');
// spam (0)
// asDf < (1)
// 0123 -- (2) (del)
// jKlp < (3) (del)
// qwer (4)
// (5)
// spam (0)
// asklp (1)
// qwer (2)
cursor min { 2, 1 };
cursor max { 1, 3 };
selection sel { &min, &max };
b.selection_delete(sel);
assert(b.length == 3);
assert(b.lines[0]->length == 4);
assert(b.lines[0]->buf[0] == 's');
assert(b.lines[0]->buf[1] == 'p');
assert(b.lines[0]->buf[2] == 'a');
assert(b.lines[0]->buf[3] == 'm');
assert(b.lines[1]->length == 5);
assert(b.lines[1]->buf[0] == 'a');
assert(b.lines[1]->buf[1] == 's');
assert(b.lines[1]->buf[2] == 'k');
assert(b.lines[1]->buf[3] == 'l');
assert(b.lines[1]->buf[4] == 'p');
assert(b.lines[2]->length == 4);
assert(b.lines[2]->buf[0] == 'q');
assert(b.lines[2]->buf[1] == 'w');
assert(b.lines[2]->buf[2] == 'e');
assert(b.lines[2]->buf[3] == 'r');
}
int main()
{
test_allocate();
test_put();
test_backspace();
test_enter_backspace1();
test_enter_backspace2();
test_enter_backspace3();
test_enter_scroll();
test_first_enter();
test_copy();
test_copy_same_line();
test_copy_multi_line_cow();
test_copy_multi_line_offset();
test_delete_from_line();
test_selection_delete();
editor::buffer<64, 12 * 1024> b {0, 0};
std::cerr << "size: " << (sizeof (b)) << '\n';
std::cerr << " row: " << (sizeof (b.row)) << '\n';
std::cerr << " lines: " << (sizeof (b.lines)) << '\n';
std::cerr << " offsetof lines[1]: " << (reinterpret_cast<uint8_t*>(&b.lines[1]) -
reinterpret_cast<uint8_t*>(&b.lines[0])) << '\n';
std::cerr << " shadow.lines: " << (sizeof (b.shadow.lines)) << '\n';
return 0;
}