From 3af49ed6a41969a3f81c66998b0612ba03094ddb Mon Sep 17 00:00:00 2001 From: Ttibsi Date: Thu, 4 Dec 2025 22:10:54 +0000 Subject: [PATCH 1/5] refactor cursor movement for consistency --- src/action.h | 46 +++++++++++----------------------------------- src/view.cpp | 45 +++++++++++++++++++-------------------------- src/view.h | 4 ++-- 3 files changed, 32 insertions(+), 63 deletions(-) diff --git a/src/action.h b/src/action.h index 915c3fd..2bed2d2 100644 --- a/src/action.h +++ b/src/action.h @@ -118,7 +118,7 @@ template ActionType::DelCurrentChar, v->get_active_model()->current_line, v->get_active_model()->current_char, v->get_active_model()->get_current_char())); - v->cursor_right(); + v->cursor_right(1); Redraw ret = v->get_active_model()->backspace(); v->cur.move_left(); @@ -197,11 +197,7 @@ template if (logger != nullptr) { logger->info("Action called: JumpNextWord"); } std::optional count = v->get_active_model()->next_word_pos(); - if (count.has_value()) { - for (int i = 0; i < count.value(); i++) { - v->cursor_right(); - } - } + if (count.has_value()) { v->cursor_right(uint_t(count.value())); } } break; @@ -210,11 +206,7 @@ template if (logger != nullptr) { logger->info("Action called: JumpPrevWord"); } std::optional count = v->get_active_model()->prev_word_pos(); - if (count.has_value()) { - for (int i = 0; i < count.value(); i++) { - v->cursor_left(); - } - } + if (count.has_value()) { v->cursor_left(uint_t(count.value())); } } break; @@ -223,11 +215,9 @@ template auto logger = spdlog::get("basic_logger"); if (logger != nullptr) { logger->info("Action called: MoveCursorLeft"); } - return v->cursor_left(); + return v->cursor_left(1); } - break; - return {}; } break; case ActionType::MoveCursorUp: { @@ -251,7 +241,7 @@ template auto logger = spdlog::get("basic_logger"); if (logger != nullptr) { logger->info("Action called: MoveCursorRight"); } - return v->cursor_right(); + return v->cursor_right(1); } } break; @@ -376,18 +366,11 @@ template v->cursor_down(); } + const uint_t curr_char = v->get_active_model()->current_char; if (ret.value().horizontal > int32_t(v->get_active_model()->current_char)) { - std::size_t diff = - uint32_t(ret.value().horizontal) - v->get_active_model()->current_char; - for (std::size_t i = 0; i < diff; i++) { - v->cursor_right(); - } + v->cursor_right(uint32_t(ret.value().horizontal) - curr_char); } else { - uint32_t diff = - v->get_active_model()->current_char - uint32_t(ret.value().horizontal); - for (unsigned int i = 0; i < diff; i++) { - v->cursor_left(); - } + v->cursor_left(curr_char - uint32_t(ret.value().horizontal)); } v->draw_status_bar(); @@ -403,18 +386,11 @@ template v->cursor_up(); } + const uint_t curr_char = v->get_active_model()->current_char; if (ret.value().horizontal > int32_t(v->get_active_model()->current_char)) { - uint32_t diff = - uint32_t(ret.value().horizontal) - v->get_active_model()->current_char; - for (uint32_t i = 0; i < diff; i++) { - v->cursor_right(); - } + v->cursor_right(uint32_t(ret.value().horizontal) - curr_char); } else { - uint32_t diff = - v->get_active_model()->current_char - uint32_t(ret.value().horizontal); - for (uint32_t i = 0; i < diff; i++) { - v->cursor_left(); - } + v->cursor_left(curr_char - uint32_t(ret.value().horizontal)); } } } diff --git a/src/view.cpp b/src/view.cpp index 6da09cb..5a5a1bb 100644 --- a/src/view.cpp +++ b/src/view.cpp @@ -366,16 +366,16 @@ void View::display_message(std::string msg, std::optional color) } // Returns: (bool) Redraw whole screen -[[maybe_unused]] bool View::cursor_left() { +[[maybe_unused]] bool View::cursor_left(std::size_t dist) { if (get_active_model()->vertical_offset && uint_t(cur.horizontal) == (LINE_NUMBERS ? line_number_offset + 3 : 0)) { - get_active_model()->current_char--; + get_active_model()->current_char -= dist; if (get_active_model()->vertical_offset == 2) { get_active_model()->vertical_offset--; } - get_active_model()->vertical_offset--; + get_active_model()->vertical_offset -= dist; return true; } else if (get_active_model()->current_char) { - get_active_model()->current_char--; - cur.move_left(); + get_active_model()->current_char -= dist; + cur.move_left(int32_t(dist)); return false; } @@ -402,10 +402,7 @@ void View::display_message(std::string msg, std::optional color) } } - while (horizontal_clamp) { - cursor_left(); - horizontal_clamp--; - } + cursor_left(horizontal_clamp); return redraw_sentinal; } @@ -433,29 +430,28 @@ void View::display_message(std::string msg, std::optional color) } } - while (horizontal_clamp) { - cursor_left(); - horizontal_clamp--; - } - + cursor_left(horizontal_clamp); return redraw_sentinal; } // Return if we need to redraw after the cursor is moved -[[maybe_unused]] bool View::cursor_right() { +[[maybe_unused]] bool View::cursor_right(std::size_t dist) { // Only scroll if we're still in the line std::string_view curr_line = get_active_model()->buf.at(get_active_model()->current_line); const std::size_t line_size = curr_line.size(); if (get_active_model()->current_char == line_size) { return false; } + // Clamp dist to line + dist = std::min(dist, line_size - get_active_model()->current_char); + if (dist == 0) { return false; } + get_active_model()->current_char += dist; + if (cur.horizontal < view_size.horizontal - 2) { - get_active_model()->current_char++; - cur.move_right(); + cur.move_right(int32_t(dist)); return false; } else { - get_active_model()->current_char++; if (!get_active_model()->vertical_offset) { get_active_model()->vertical_offset++; } - get_active_model()->vertical_offset++; + get_active_model()->vertical_offset += dist; return true; } } @@ -463,10 +459,7 @@ void View::display_message(std::string msg, std::optional color) void View::cursor_end_of_line() { std::size_t line_len = get_active_model()->buf.at(get_active_model()->current_line).size(); std::size_t curr_pos = get_active_model()->current_char; - - for (std::size_t i = curr_pos; i < line_len; i++) { - cursor_right(); - } + cursor_right(line_len - curr_pos); } void View::cursor_start_of_line() { @@ -477,9 +470,9 @@ void View::cursor_start_of_line() { cur_line.begin(), cur_line.end(), [](char c) { return !(std::isspace(c)); }); if (it != cur_line.end()) { - while (get_active_model()->current_char > std::distance(cur_line.begin(), it)) { - cursor_left(); - } + const auto dist = std::distance(cur_line.begin(), it); + const long cursor_distance = get_active_model()->current_char - dist; + cursor_left(uint_t(cursor_distance)); } } } diff --git a/src/view.h b/src/view.h index 5367b61..83da062 100644 --- a/src/view.h +++ b/src/view.h @@ -48,10 +48,10 @@ struct View { [[maybe_unused]] const rawterm::Pos draw_command_bar(const std::size_t); void display_message(std::string, std::optional); [[nodiscard]] std::size_t clamp_horizontal_movement(const int); - [[maybe_unused]] bool cursor_left(); + [[maybe_unused]] bool cursor_left(std::size_t dist = 1); [[maybe_unused]] bool cursor_up(unsigned int count = 1); [[maybe_unused]] bool cursor_down(unsigned int count = 1); - [[maybe_unused]] bool cursor_right(); + [[maybe_unused]] bool cursor_right(std::size_t dist = 1); void cursor_end_of_line(); void cursor_start_of_line(); void center_current_line(); From d44e2598bbfa438a6b82f80c602c22afebdfb992 Mon Sep 17 00:00:00 2001 From: Ttibsi Date: Thu, 4 Dec 2025 22:11:54 +0000 Subject: [PATCH 2/5] adjust tests for new cursor movement --- tests/controller_test.cpp | 2 +- tests/view_test.cpp | 31 ++++++++++--------------------- 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/tests/controller_test.cpp b/tests/controller_test.cpp index 1f4a6a3..c97b9de 100644 --- a/tests/controller_test.cpp +++ b/tests/controller_test.cpp @@ -167,7 +167,7 @@ TEST_CASE("write_all", "[controller]") { REQUIRE(!c.models.at(0).unsaved); // Undo changes to not break other tests - c.view.cursor_right(); + c.view.cursor_right(1); std::ignore = c.models.at(0).backspace(); std::ignore = c.write_all(); } diff --git a/tests/view_test.cpp b/tests/view_test.cpp index 6db222a..a21c02d 100644 --- a/tests/view_test.cpp +++ b/tests/view_test.cpp @@ -192,7 +192,7 @@ TEST_CASE("cursor_left", "[view]") { v.add_model(&m); REQUIRE(v.cur == rawterm::Pos(1, 1)); - v.cursor_left(); + v.cursor_left(1); REQUIRE(v.cur == rawterm::Pos(1, 1)); } @@ -203,10 +203,8 @@ TEST_CASE("cursor_left", "[view]") { open_file("tests/fixture/test_file_1.txt").value(), "tests/fixture/test_file_1.txt"); v.add_model(&m); - for (int i = 1; i < 5; i++) { - v.cursor_right(); - } - v.cursor_left(); + v.cursor_right(4); + v.cursor_left(1); REQUIRE(v.cur == rawterm::Pos(1, 4)); REQUIRE(m.current_line == 0); REQUIRE(m.current_char == 3); @@ -222,7 +220,7 @@ TEST_CASE("cursor_up", "[view]") { v.add_model(&m); REQUIRE(v.cur == rawterm::Pos(1, 1)); - v.cursor_up(); + v.cursor_up(1); REQUIRE(v.cur == rawterm::Pos(1, 1)); } @@ -262,9 +260,7 @@ TEST_CASE("cursor_up", "[view]") { REQUIRE(text.at(idx).find("massa.") != std::string::npos); // Move cursor to top row - for (int i = 1; i < 23; i++) { - v.cursor_up(); - } + v.cursor_up(22); REQUIRE(v.cur == rawterm::Pos(1, 1)); REQUIRE(m.current_line == 12); @@ -360,11 +356,9 @@ TEST_CASE("cursor_right", "[view]") { v.add_model(&m); v.cur.move({v.cur.vertical, int(v.line_number_offset + 1)}); - for (int i = 1; i <= 80; i++) { - v.cursor_right(); - } + v.cursor_right(80); REQUIRE(v.cur == rawterm::Pos(1, 20)); - v.cursor_right(); + v.cursor_right(1); REQUIRE(v.cur == rawterm::Pos(1, 20)); } @@ -376,10 +370,7 @@ TEST_CASE("cursor_right", "[view]") { v.add_model(&m); v.cur.move({v.cur.vertical, int(v.line_number_offset + 1)}); - for (int i = 1; i <= 100; i++) { - v.cursor_right(); - } - + v.cursor_right(99); REQUIRE(v.cur == rawterm::Pos(1, 20)); REQUIRE(m.current_char == 17); } @@ -391,7 +382,7 @@ TEST_CASE("cursor_right", "[view]") { open_file("tests/fixture/test_file_1.txt").value(), "tests/fixture/test_file_1.txt"); v.add_model(&m); - v.cursor_right(); + v.cursor_right(1); REQUIRE(v.cur == rawterm::Pos(1, 2)); } } @@ -577,9 +568,7 @@ TEST_CASE("change_model_cursor", "[view]") { Model(open_file("tests/fixture/lorem_ipsum.txt").value(), "tests/fixture/lorem_ipsum.txt"); v.add_model(&m); - for (int i = 0; i < 5; i++) { - v.cursor_right(); - } + v.cursor_right(5); REQUIRE(v.cur == rawterm::Pos(1, 6)); From a10c4676ab9dd0d219b48f9f984ad8cb3736e66f Mon Sep 17 00:00:00 2001 From: Ttibsi Date: Mon, 8 Dec 2025 10:04:18 +0000 Subject: [PATCH 3/5] Update integration tests --- tests/integration/command_mode_test.py | 1 + tests/integration/insert_mode_test.py | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/integration/command_mode_test.py b/tests/integration/command_mode_test.py index f879c54..00680cb 100644 --- a/tests/integration/command_mode_test.py +++ b/tests/integration/command_mode_test.py @@ -209,6 +209,7 @@ def test_write_all_command(r: TmuxRunner): assert first_line[0] == "h" r.press("u") + time.sleep(0.1) r.iris_cmd("wa") with open(r.filename, "r") as f: diff --git a/tests/integration/insert_mode_test.py b/tests/integration/insert_mode_test.py index 051d14f..974002a 100644 --- a/tests/integration/insert_mode_test.py +++ b/tests/integration/insert_mode_test.py @@ -73,7 +73,7 @@ def test_inserting_char_end_of_line(r: TmuxRunner): with open("tests/fixture/test_file_1.txt") as f: contents = f.readlines() - r.type_str("l" * len(contents[0])) + r.type_str("l" * (len(contents[0]) - 1)) r.press("i") r.press("v") @@ -94,7 +94,7 @@ def test_inserting_char_end_of_file(r: TmuxRunner): for _ in range(len(contents)): r.press("j") - for _ in range(len(contents[-1])): + for _ in range(len(contents[-1]) - 1): r.press("l") r.press("i") @@ -178,7 +178,7 @@ def test_insert_newline(r: TmuxRunner): with open("tests/fixture/test_file_1.txt") as f: contents = f.readlines() - for _ in range(len(contents[-1])): + for _ in range(len(contents[-1]) - 1): r.press("l") r.press("i") From f031274f0769dc6fa1e68f93f2189acfb5a8c5ae Mon Sep 17 00:00:00 2001 From: Ttibsi Date: Thu, 12 Feb 2026 15:25:01 +0000 Subject: [PATCH 4/5] gitignore tst_file_2 --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index e9eb603..efbe7c9 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ release/ tests/fixture/temp_file.txt tests/fixture/does_not_exist.txt tests/fixture/read_only.txt +tests/fixture/test_file_2.txt This_is_a_really_really_really_really_really_really_really_really_long_file_name.txt # other From d7092efbfbecf279507862f2a194b226edb326f6 Mon Sep 17 00:00:00 2001 From: Ttibsi Date: Thu, 12 Feb 2026 15:32:20 +0000 Subject: [PATCH 5/5] pre-commit --- src/controller.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/controller.cpp b/src/controller.cpp index 6e45e63..8b78bb0 100644 --- a/src/controller.cpp +++ b/src/controller.cpp @@ -743,9 +743,7 @@ void Controller::add_model(const std::string& filename) { })->filename.size(); // "filename" - if (max_name_len < 8) { - max_name_len = 8; - } + if (max_name_len < 8) { max_name_len = 8; } max_name_len += 2; std::string title = "\u2551 id \u2502 filename" + std::string(uint_t(max_name_len - 8), ' '); @@ -774,18 +772,14 @@ void Controller::add_model(const std::string& filename) { line += rawterm::bold(m.filename); int spacing = 0; - if (max_name_len > m.filename.size()) { - spacing = max_name_len - m.filename.size(); - } + if (max_name_len > m.filename.size()) { spacing = max_name_len - m.filename.size(); } if (m.unsaved) { line += rawterm::bold("*"); spacing--; } - if (spacing > 0) { - line += std::string(spacing, ' '); - } + if (spacing > 0) { line += std::string(spacing, ' '); } line += " \u2502 "; line += std::to_string(m.current_line + 1);