Issue 49: Editor Module - Use std::expected return type

Update run_editor() to return std::expected<std::string, std::string>
for all editor-related failures instead of throwing exceptions.

Changes:
- include/editor.hpp: Change return type to std::expected
- src/editor.cpp: Replace all throw std::runtime_error() with
  return std::unexpected() for error cases:
  * Temp file open failure
  * No nvim/ set
  * Editor exit error
  * Scissors separator not found
  * Empty prompt after separator
- src/main.cpp: Use expect_or_exit() instead of try/catch
This commit is contained in:
2026-05-27 17:14:36 -05:00
parent f85abd85b6
commit f13007602b
3 changed files with 9 additions and 13 deletions
+2 -1
View File
@@ -1,5 +1,6 @@
#pragma once
#include "json_types.hpp"
#include <string>
#include <expected>
std::string run_editor(HarnessState state, bool full_history);
std::expected<std::string, std::string> run_editor(HarnessState state, bool full_history);
+6 -6
View File
@@ -52,7 +52,7 @@ public:
};
std::string run_editor(HarnessState state, bool full_history) {
std::expected<std::string, std::string> run_editor(HarnessState state, bool full_history) {
auto file_path = random_file_name();
auto cleanup = Defer([&](){
std::filesystem::remove(file_path);
@@ -61,7 +61,7 @@ std::string run_editor(HarnessState state, bool full_history) {
{
std::ofstream file(file_path);
if (!file.is_open()) {
throw std::runtime_error("Failed to open temp file for editor.");
return std::unexpected("Failed to open temp file for editor.");
}
if (state.history.empty()) {
@@ -102,13 +102,13 @@ std::string run_editor(HarnessState state, bool full_history) {
const char* editor_env = getenv("VISUAL");
if (!editor_env) editor_env = getenv("EDITOR");
if (!editor_env) {
throw std::runtime_error("Neither $VISUAL nor $EDITOR is set.");
return std::unexpected("Neither $VISUAL nor $EDITOR is set.");
}
std::string cmd = std::string(editor_env) + " " + file_path;
int res = system(cmd.c_str());
if (res != 0) {
throw std::runtime_error("Editor exited with error.");
return std::unexpected("Editor exited with error.");
}
std::ifstream infile(file_path);
@@ -117,7 +117,7 @@ std::string run_editor(HarnessState state, bool full_history) {
const std::string seperator = "\n-- >8 --\n";
size_t pos = content.find(seperator);
if (pos == std::string::npos) {
throw std::runtime_error("Scissors not found.");
return std::unexpected("Scissors not found.");
}
size_t last_pos = std::string::npos;
@@ -130,7 +130,7 @@ std::string run_editor(HarnessState state, bool full_history) {
extracted = trim(extracted);
if (extracted.empty()) {
throw std::runtime_error("Prompt is empty after separator.");
return std::unexpected("Prompt is empty after separator.");
}
return extracted;
+1 -6
View File
@@ -557,12 +557,7 @@ int main(int argc, char** argv) {
if (prompt) {
final_prompt = prompt;
} else {
try {
final_prompt = run_editor(harness.serialize(), full_history);
} catch (const std::runtime_error& e) {
std::cerr << "Editor error: " << e.what() << "\n";
exit(1);
}
final_prompt = expect_or_exit(run_editor(harness.serialize(), full_history));
}
std::cerr << "Prompt input:" << std::endl;