From b659e4e51c4580ea1185a4559957fe4ba37089a2 Mon Sep 17 00:00:00 2001 From: Ttibsi Date: Wed, 19 Nov 2025 08:29:35 +0000 Subject: [PATCH 1/6] unit tests for handling passing a filename in the command bar --- tests/text_io_test.cpp | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/tests/text_io_test.cpp b/tests/text_io_test.cpp index e61ac39..a4e1505 100644 --- a/tests/text_io_test.cpp +++ b/tests/text_io_test.cpp @@ -32,11 +32,31 @@ TEST_CASE("get_file_size", "[textio]") { TEST_CASE("write_to_file", "[textio]") { lines_t expected_buf = {"foo", "bar", "baz"}; auto m = Model(expected_buf, "tests/fixture/temp_file.txt"); - const WriteData data = write_to_file(&m); - REQUIRE(data.valid == true); - REQUIRE(data.bytes == 12); - REQUIRE(data.lines == 3); - REQUIRE(m.unsaved == false); + + SECTION("Filename already set") { + const WriteData data = write_to_file(&m, std::nullopt); + REQUIRE(data.valid == true); + REQUIRE(data.bytes == 12); + REQUIRE(data.lines == 3); + REQUIRE(m.unsaved == false); + } + + SECTION("Filename set in command") { + m.filename = ""; + const WriteData data = write_to_file(&m, "tests/fixture/temp_file.txt"); + REQUIRE(data.valid == true); + REQUIRE(data.bytes == 12); + REQUIRE(data.lines == 3); + REQUIRE(m.unsaved == false); + } + + SECTION("No filename given") { + m.filename = ""; + const WriteData data = write_to_file(&m, std::nullopt); + REQUIRE(data.valid == false); + REQUIRE(data.bytes == 0); + REQUIRE(data.lines == 0); + } } TEST_CASE("rtrim", "[textio]") { From f0d290a783b6e5baef5f2dcaca2417f2844b486c Mon Sep 17 00:00:00 2001 From: Ttibsi Date: Wed, 19 Nov 2025 10:46:40 +0000 Subject: [PATCH 2/6] Add integration tests --- tests/integration/command_mode_test.py | 27 +++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/tests/integration/command_mode_test.py b/tests/integration/command_mode_test.py index 976b12d..f0abbc8 100644 --- a/tests/integration/command_mode_test.py +++ b/tests/integration/command_mode_test.py @@ -134,13 +134,34 @@ def test_write_command(r: TmuxRunner): # Check highlighting colour message_line: str = r.color_screenshot()[-1] - assert "Saved" in message_line - assert "bytes" in message_line + # NOTE: This should already contain "hello world" -- set setup() + assert "Saved 19 bytes" in message_line assert "\x1b[38;2;0;128;0m" in message_line with open("tests/fixture/temp_file.txt") as f: text = f.read() - assert text.split()[0] == "foo" + assert text == "foo barHello world\n" + + file_size: int = os.path.getsize("tests/fixture/temp_file.txt") + assert file_size == 19 + + +@setup() +def test_write_with_filename_command(r: TmuxRunner): + r.type_str("ifoo bar") + r.press('Escape') + r.iris_cmd("w tests/fixture/temp_file.txt") + + message_line: str = r.color_screenshot()[-1] + assert "Saved 8 bytes" in message_line + assert "\x1b[38;2;0;128;0m" in message_line + + with open("tests/fixture/temp_file.txt") as f: + text = f.read() + assert text == "foo bar\n" + + file_size: int = os.path.getsize("tests/fixture/temp_file.txt") + assert file_size == 8 @setup("tests/fixture/does_not_exist.txt") From 7410ee7fdaaa39ebbaa51343e5223213c756e82a Mon Sep 17 00:00:00 2001 From: Ttibsi Date: Wed, 19 Nov 2025 10:47:04 +0000 Subject: [PATCH 3/6] Handle saving to a new file from command mode --- src/controller.cpp | 16 ++++++++++++---- src/text_io.cpp | 9 +++++++-- src/text_io.h | 2 +- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/controller.cpp b/src/controller.cpp index b35c789..a6f865e 100644 --- a/src/controller.cpp +++ b/src/controller.cpp @@ -2,6 +2,8 @@ #include #include +#include +#include #include #include @@ -608,7 +610,7 @@ bool Controller::parse_command() { } else if (cmd == ";wq") { // This just does the same as ;w and ;q - std::ignore = write_to_file(view.get_active_model()); + std::ignore = write_to_file(view.get_active_model(), std::nullopt); return quit_app(false); } else if (cmd == ";wa") { @@ -620,8 +622,14 @@ bool Controller::parse_command() { view.display_message("Error with saving files", rawterm::Colors::red); } - } else if (cmd == ";w") { - WriteData file_write = write_to_file(view.get_active_model()); + } else if (cmd.substr(0, 2) == ";w") { + std::optional chosen_filename = std::nullopt; + if (cmd.size() > 2) { + chosen_filename = cmd.substr(3, cmd.size()); + rtrim(chosen_filename.value()); + } + + WriteData file_write = write_to_file(view.get_active_model(), chosen_filename); if (file_write.valid) { std::string msg = std::format("Saved {} bytes ({} lines)", file_write.bytes, file_write.lines); @@ -723,7 +731,7 @@ void Controller::add_model(const std::string& filename) { continue; } - if (write_to_file(&m).valid) { + if (write_to_file(&m, std::nullopt).valid) { write_all_data.files++; } else { write_all_data.valid = false; diff --git a/src/text_io.cpp b/src/text_io.cpp index a2cfdc3..efc488b 100644 --- a/src/text_io.cpp +++ b/src/text_io.cpp @@ -64,10 +64,15 @@ } } -[[nodiscard]] WriteData write_to_file(Model* model) { - if (model->filename == "") { +[[nodiscard]] WriteData write_to_file(Model* model, std::optional filename_input) { + if (!filename_input.has_value() && model->filename == "") { return WriteData(); } + + if (filename_input.has_value()) { + model->filename = filename_input.value(); + } + std::ofstream out(model->filename); for (auto&& line : model->buf) { rtrim(line); diff --git a/src/text_io.h b/src/text_io.h index 16ef522..686bacf 100644 --- a/src/text_io.h +++ b/src/text_io.h @@ -37,7 +37,7 @@ struct Response { [[nodiscard]] opt_lines_t open_file(const std::string&); [[nodiscard]] unsigned int get_file_size(const std::string&); -[[nodiscard]] WriteData write_to_file(Model*); +[[nodiscard]] WriteData write_to_file(Model*, std::optional); void rtrim(std::string& str); [[nodiscard]] lines_t lines(const std::string&); [[nodiscard]] bool is_letter(const char&); From 70075628d2da365b8ea618aa07f8bd2b959b01df Mon Sep 17 00:00:00 2001 From: Ttibsi Date: Wed, 19 Nov 2025 10:49:12 +0000 Subject: [PATCH 4/6] update docs --- CHANGELOG.md | 1 + README.md | 2 +- src/main.cpp | 6 ++---- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0dea8c4..3020216 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ moves back that amount of space * Refactored how `;s` works for find and replace * Added `;f` command to find a given string further on in the buffer * Iris now handles horizontal scrolling when a line is longer than the screen +* Allow for specifying file to save to from command bar * Resolved issue with iris crashing after opening an existing file with 0 bytes * Resolved issue where filename isn't centered in the status bar diff --git a/README.md b/README.md index f417355..7d1eed4 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ following commands in alphabetical order are available: | `;w` | Save file | | `;wa` | Save all files | | `;qa` | Quit all | -| `wqa` | Write and quit all files | +| `;wqa` | Write and quit all files | Search flags for `;s` include: * `m` Multiline search diff --git a/src/main.cpp b/src/main.cpp index ecd172d..dc524f2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -12,12 +12,10 @@ #include "version.h" // TODO: command to toggle line numbers -// TODO: Save file with given name `;w foo.txt` // TODO: detect if `;e` is opening an already-open file and switch to that buf instead -// NOTE: Maybe post a message in the command bar too +// NOTE: Maybe post a message in the command bar too +// TODO: A way of detecting if the file is already open in another iris instance -// TODO: A way of detecting if the file is already open in another iris -// instance int main(int argc, char* argv[]) { CLI::App app {"Iris text editor"}; From 40cf86356220667bad2e585e28d1c54dd3246be3 Mon Sep 17 00:00:00 2001 From: Ttibsi Date: Wed, 19 Nov 2025 15:22:36 +0000 Subject: [PATCH 5/6] empty From afdef5e154abf7277e0ff4d1e7370d0f426d15f3 Mon Sep 17 00:00:00 2001 From: Ttibsi Date: Mon, 5 Jan 2026 10:21:14 +0000 Subject: [PATCH 6/6] update tests --- src/controller.cpp | 6 +----- tests/integration/command_mode_test.py | 4 +++- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/controller.cpp b/src/controller.cpp index a6f865e..81f6c67 100644 --- a/src/controller.cpp +++ b/src/controller.cpp @@ -600,11 +600,7 @@ bool Controller::parse_command() { return true; } else if (cmd == ";wqa") { - // This just does the same as ;w and ;q, but for every file - for (auto&& m : models) { - std::ignore = write_to_file(&m); - } - + WriteAllData write_data = write_all(); std::ignore = quit_app(true); return true; diff --git a/tests/integration/command_mode_test.py b/tests/integration/command_mode_test.py index f0abbc8..455dbc7 100644 --- a/tests/integration/command_mode_test.py +++ b/tests/integration/command_mode_test.py @@ -33,9 +33,11 @@ def test_quit_all_with_modified_buffer(r: TmuxRunner): r.type_str("test") r.press("Escape") r.iris_cmd("wqa") + time.sleep(0.1) with open(r.filename) as f: - assert f.read()[0:4] == "test" + text = f.read() + assert text[0:4] == "test" @setup("tests/fixture/test_file_1.txt")