Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
22 changes: 13 additions & 9 deletions src/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#include <algorithm>
#include <format>
#include <optional>
#include <ranges>

#include <rawterm/core.h>
#include <rawterm/cursor.h>
Expand Down Expand Up @@ -598,17 +600,13 @@ 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;

} 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") {
Expand All @@ -620,8 +618,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<std::string> 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);
Expand Down Expand Up @@ -723,7 +727,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;
Expand Down
6 changes: 2 additions & 4 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"};

Expand Down
9 changes: 7 additions & 2 deletions src/text_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,15 @@
}
}

[[nodiscard]] WriteData write_to_file(Model* model) {
if (model->filename == "") {
[[nodiscard]] WriteData write_to_file(Model* model, std::optional<std::string> 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);
Expand Down
2 changes: 1 addition & 1 deletion src/text_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::string>);
void rtrim(std::string& str);
[[nodiscard]] lines_t lines(const std::string&);
[[nodiscard]] bool is_letter(const char&);
Expand Down
31 changes: 27 additions & 4 deletions tests/integration/command_mode_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -134,13 +136,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 == "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.split()[0] == "foo"
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")
Expand Down
30 changes: 25 additions & 5 deletions tests/text_io_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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]") {
Expand Down
Loading