diff --git a/run.py b/run.py index d9e6768..b577d6d 100755 --- a/run.py +++ b/run.py @@ -54,7 +54,11 @@ def test(testname: str | None, asan: bool) -> None: run_shell_cmd("cmake --build build/") run_shell_cmd( f"./build/tests/test_exe {testname if testname else ''}", - env={"RAWTERM_DEBUG": "true"}, + env={ + "RAWTERM_DEBUG": "true", + "ASAN_OPTIONS": "symbolize=1", + "ASAN_SYMBOLIZER_PATH": "/usr/bin/llvm-symbolizer", + }, ) diff --git a/src/view.cpp b/src/view.cpp index 84b8cbd..ad0188d 100644 --- a/src/view.cpp +++ b/src/view.cpp @@ -1,6 +1,8 @@ #include "view.h" +#include #include +#include #include #include @@ -8,6 +10,7 @@ #include "constants.h" #include "controller.h" +#include "gapvector.h" #include "logger.h" View::View(Controller* controller, const rawterm::Pos dims) @@ -47,6 +50,7 @@ void View::render_screen() { rawterm::Pos starting_cur_pos = cur; std::string screen = ""; int line_count = viewable_models.at(active_model - 1)->vertical_file_offset + 1; + const int max_line_width = view_size.horizontal - line_number_offset - 4; rawterm::clear_screen(); cur.move({1, 1}); @@ -87,11 +91,12 @@ void View::render_screen() { // Truncate line horizontal_counter++; - if (horizontal_counter + line_number_offset + 2 == view_size.horizontal) { + if (horizontal_counter >= max_line_width) { screen += "\u00BB\r\n"; - while (get_active_model()->buf.at(gv_counter) != '\n') { - gv_counter++; - } + Gapvector<>* buf_ptr = &get_active_model()->buf; + gv_counter += std::distance( + buf_ptr->begin() + gv_counter, + std::find(buf_ptr->begin() + gv_counter, buf_ptr->end(), '\n')); remaining_rows--; line_count++; @@ -101,6 +106,11 @@ void View::render_screen() { screen += rawterm::set_foreground( std::format("{:>{}}\u2502", line_count, line_number_offset), COLOR_UI_BG); } + + if (gv_counter < get_active_model()->buf.size()) { + gv_counter++; // Skip the newline + } + continue; } if (c == '\n') { @@ -163,6 +173,7 @@ void View::draw_status_bar() { cur.move(starting_cur_pos); } +// TODO: The center text isn't aligned right - it ends at the center point const std::string View::render_status_bar() const { std::string filename = open_files.at(active_model - 1).filename; @@ -219,6 +230,7 @@ void View::render_line() { } std::cout << line.substr(0, horizontal_draw_space); + // Truncate if (line.size() > horizontal_draw_space) { std::cout << "\u00BB"; } diff --git a/tests/view_test.cpp b/tests/view_test.cpp index 9db73b5..d040fc2 100644 --- a/tests/view_test.cpp +++ b/tests/view_test.cpp @@ -1,5 +1,6 @@ #include "view.h" +#include #include #include #include @@ -12,6 +13,9 @@ #include "file_io.h" #include "model.h" +// TODO: Create a test util function that takes in a lambda to wrap the stdout +// redirection + TEST_CASE("Constructor", "[VIEW]") { Controller c; auto v = View(&c, rawterm::Pos(24, 80)); @@ -80,24 +84,49 @@ TEST_CASE("render_screen", "[VIEW]") { Controller c; auto v = View(&c, rawterm::Pos(24, 80)); - auto m = - Model(open_file("tests/fixture/test_file_1.txt").value(), "tests/fixture/test_file_1.txt"); - v.add_model(&m); + SECTION("Render single text file") { + auto m = Model( + open_file("tests/fixture/test_file_1.txt").value(), "tests/fixture/test_file_1.txt"); + v.add_model(&m); - // https://truong.io/posts/capturing_stdout_for_c++_unit_testing.html - // capture stdout - std::stringstream buffer; - std::streambuf* prevcoutbuf = std::cout.rdbuf(buffer.rdbuf()); + // https://truong.io/posts/capturing_stdout_for_c++_unit_testing.html + // capture stdout + std::stringstream buffer; + std::streambuf* prevcoutbuf = std::cout.rdbuf(buffer.rdbuf()); - v.render_screen(); - std::vector text = splitStringOnNewlines(buffer.str()); + v.render_screen(); + std::vector text = splitStringOnNewlines(buffer.str()); - // restore stdout - std::cout.rdbuf(prevcoutbuf); + // restore stdout + std::cout.rdbuf(prevcoutbuf); + + REQUIRE(text.size() == 4); + REQUIRE(rawterm::raw_at(text.at(0), 5) == 'T'); + REQUIRE(rawterm::raw_at(text.at(1), 1) == '2'); + } + + SECTION("Truncated line") { + auto m = Model(); + v.add_model(&m); + + for (int i = 0; i < 80; i++) { + m.insert_char('_'); + } + + // capture stdout + std::stringstream buffer; + std::streambuf* prevcoutbuf = std::cout.rdbuf(buffer.rdbuf()); + + v.render_screen(); + std::vector text = splitStringOnNewlines(buffer.str()); + + // restore stdout + std::cout.rdbuf(prevcoutbuf); - REQUIRE(text.size() == 4); - REQUIRE(rawterm::raw_at(text.at(0), 5) == 'T'); - REQUIRE(rawterm::raw_at(text.at(1), 1) == '2'); + REQUIRE(text.size() == 3); + // REQUIRE(rawterm::raw_str(text.at(0)).size() == 83); // TODO: rawterm 55 + REQUIRE(text.at(0).substr(text.at(0).size() - 3, 2) == "\u00bb"); + } } TEST_CASE("generate_tab_bar", "[VIEW]") { @@ -154,28 +183,53 @@ TEST_CASE("render_line", "[VIEW]") { Controller c; auto v = View(&c, rawterm::Pos(24, 80)); - auto m = - Model(open_file("tests/fixture/test_file_1.txt").value(), "tests/fixture/test_file_1.txt"); - v.add_model(&m); + SECTION("Standard line rendering") { + auto m = Model( + open_file("tests/fixture/test_file_1.txt").value(), "tests/fixture/test_file_1.txt"); + v.add_model(&m); - // capture stdout - std::stringstream buffer; - std::streambuf* prevcoutbuf = std::cout.rdbuf(buffer.rdbuf()); + // capture stdout + std::stringstream buffer; + std::streambuf* prevcoutbuf = std::cout.rdbuf(buffer.rdbuf()); - v.render_line(); - std::string text = buffer.str(); + v.render_line(); + std::string text = buffer.str(); - // restore stdout - std::cout.rdbuf(prevcoutbuf); + // restore stdout + std::cout.rdbuf(prevcoutbuf); - int expected_size = 17; - if (LINE_NUMBERS) { - expected_size = 23; + int expected_size = 17; + if (LINE_NUMBERS) { + expected_size = 23; + } + + // TODO: expected size is 22 if we only run the one test, but 23 when running all tests? + REQUIRE(rawterm::raw_size(text) == expected_size); + // REQUIRE(text == " 1\u2502This is some text"); // TODO: raw string - rawterm #55 } - // TODO: expected size is 22 if we only run the one test, but 23 when running all tests? - REQUIRE(rawterm::raw_size(text) == expected_size); - // REQUIRE(text == "This is some text"); // TODO: raw string - rawterm #55 + SECTION("Truncated line") { + auto m = Model(); + v.add_model(&m); + + for (int i = 0; i < 80; i++) { + m.insert_char('_'); + } + + // capture stdout + std::stringstream buffer; + std::streambuf* prevcoutbuf = std::cout.rdbuf(buffer.rdbuf()); + + v.render_line(); + std::string text = rawterm::raw_str(buffer.str()); + + // restore stdout + std::cout.rdbuf(prevcoutbuf); + + REQUIRE(text.substr(text.size() - 2, 2) == "\u00BB"); + // size is +3 because "\u2502".size() == 3 is "\u00bb".size() == 2 + REQUIRE(text.size() == 84); + } } TEST_CASE("set_status", "[VIEW]") {