diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f1d93b..3757967 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,7 +68,7 @@ file(GLOB_RECURSE PROJECT_SOURCES "src/*.cpp") add_executable(${PROJECT} ${PROJECT_SOURCES}) target_include_directories(${PROJECT} PRIVATE "src") -target_link_libraries(${PROJECT} ruc) +target_link_libraries(${PROJECT} readline ruc) # ------------------------------------------ # Execute target diff --git a/src/readline.cpp b/src/readline.cpp new file mode 100644 index 0000000..a210b66 --- /dev/null +++ b/src/readline.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2023 Riyyi + * + * SPDX-License-Identifier: MIT + */ + +#include // std::free +#include // FILE +#include +#include +#include + +#include "ruc/format/color.h" + +#include "readline.h" + +namespace blaze { + +Readline::Readline(bool pretty_print, std::string_view history_path) + : m_pretty_print(pretty_print) + , m_history_path(history_path) +{ + if (!pretty_print) { + m_prompt = "user> "; + } + else { + m_prompt = format(fg(ruc::format::TerminalColor::Blue), "user>"); + m_prompt += format(" \033[1m"); + } + + read_history(tilde_expand(history_path.data())); +} + +bool Readline::get(std::string& output) +{ + char* line = readline(m_prompt.c_str()); + if (line == nullptr) { + return false; + } + + // Add input to in-memory history + add_history(line); + append_history(1, m_history_path.data()); + + output = line; + std::free(line); + + return true; +} + +} // namespace blaze diff --git a/src/readline.h b/src/readline.h new file mode 100644 index 0000000..da2d4d0 --- /dev/null +++ b/src/readline.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2023 Riyyi + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include + +#include "ruc/singleton.h" + +namespace blaze { + +class Readline { +public: + Readline(bool pretty_print, std::string_view history_path); + virtual ~Readline() {} + + bool get(std::string& output); + +private: + bool m_pretty_print { false }; + std::string m_prompt; + std::string_view m_history_path; +}; + +} // namespace blaze diff --git a/src/step2_eval.cpp b/src/step2_eval.cpp index e0a546c..2a28b79 100644 --- a/src/step2_eval.cpp +++ b/src/step2_eval.cpp @@ -1,19 +1,18 @@ -#include // std::signal -#include // std::exit -#include // std::cin -#include // std::getline +#include // std::signal +#include // std::exit +#include #include -#include "environment.h" -#include "eval.h" #include "ruc/argparser.h" #include "ruc/format/color.h" #include "ast.h" -#include "error.h" +#include "environment.h" +#include "eval.h" #include "lexer.h" #include "printer.h" #include "reader.h" +#include "readline.h" #include "settings.h" #if 1 @@ -58,7 +57,7 @@ auto rep(std::string_view input) -> void static auto cleanup(int signal) -> void { - print("\033[0m"); + print("\033[0m\n"); std::exit(signal); } @@ -67,12 +66,14 @@ auto main(int argc, char* argv[]) -> int bool dump_lexer = false; bool dump_reader = false; bool pretty_print = false; + std::string_view history_path = "~/.mal-history"; // CLI arguments ruc::ArgParser arg_parser; arg_parser.addOption(dump_lexer, 'l', "dump-lexer", nullptr, nullptr); arg_parser.addOption(dump_reader, 'r', "dump-reader", nullptr, nullptr); arg_parser.addOption(pretty_print, 'c', "color", nullptr, nullptr); + arg_parser.addOption(history_path, 'h', "history", nullptr, nullptr); arg_parser.parse(argc, argv); // Set settings @@ -84,26 +85,18 @@ auto main(int argc, char* argv[]) -> int std::signal(SIGINT, cleanup); std::signal(SIGTERM, cleanup); - while (true) { - if (!pretty_print) { - print("user> "); - } - else { - print(fg(ruc::format::TerminalColor::Blue), "user>"); - print(" \033[1m"); - } - std::string line; - std::getline(std::cin, line); + blaze::Readline readline(pretty_print, history_path); + + std::string input; + while (readline.get(input)) { if (pretty_print) { print("\033[0m"); } + rep(input); + } - // Exit with Ctrl-D - if (std::cin.eof() || std::cin.fail()) { - break; - } - - rep(line); + if (pretty_print) { + print("\033[0m"); } return 0;