diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 94f89ea6af..a3f845cbd0 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -8,6 +8,7 @@ add_library(common goos/PrettyPrinter.cpp goos/Reader.cpp goos/TextDB.cpp + goos/ReplHistory.cpp log/log.cpp type_system/deftype.cpp type_system/Type.cpp diff --git a/common/goos/Reader.cpp b/common/goos/Reader.cpp index fd42da1323..2a6312460c 100644 --- a/common/goos/Reader.cpp +++ b/common/goos/Reader.cpp @@ -10,9 +10,10 @@ */ #include "Reader.h" -#include "third-party/linenoise.h" #include "common/util/FileUtil.h" #include "third-party/fmt/core.h" +#include +#include "ReplHistory.h" namespace goos { @@ -103,7 +104,7 @@ void TextStream::seek_past_whitespace_and_comments() { Reader::Reader() { // third-party library used for a fancy line in - linenoise::SetHistoryMaxLen(400); + ReplHistory::repl_set_history_max_size(5000); // add default macros add_reader_macro("'", "quote"); @@ -142,8 +143,8 @@ Object Reader::read_from_stdin(const std::string& prompt_name) { std::string line; // escape code will make sure that we remove any color std::string prompt_full = "\033[0m" + prompt_name + "> "; - linenoise::Readline(prompt_full.c_str(), line); - linenoise::AddHistory(line.c_str()); + ReplHistory::repl_readline(prompt_full.c_str(), line); + ReplHistory::repl_add_to_history(line.c_str()); // todo, decide if we should keep reading or not. // create text fragment and add to the DB diff --git a/common/goos/ReplHistory.cpp b/common/goos/ReplHistory.cpp new file mode 100644 index 0000000000..3dd325b3a3 --- /dev/null +++ b/common/goos/ReplHistory.cpp @@ -0,0 +1,38 @@ +#include "ReplHistory.h" + +#include "common/util/FileUtil.h" +#include "third-party/linenoise.h" + +bool ReplHistory::repl_set_history_max_size(size_t len) { + return linenoise::SetHistoryMaxLen(len); +} + +bool ReplHistory::repl_readline(const char* prompt, std::string& line) { + return linenoise::Readline(prompt, line); +} + +bool ReplHistory::repl_add_to_history(const char* line) { + return linenoise::AddHistory(line); +} + +bool ReplHistory::repl_save_history() { + // NOTE - library doesn't seem unicode safe on windows + std::filesystem::path path = file_util::get_user_home_dir(); + if (std::filesystem::exists(path)) { + return linenoise::SaveHistory((path / ".opengoal.repl.history").string().c_str()); + } + return false; +} + +bool ReplHistory::repl_load_history() { + // NOTE - library doesn't seem unicode safe on windows + std::filesystem::path path = file_util::get_user_home_dir(); + if (std::filesystem::exists(path)) { + return linenoise::LoadHistory((path / ".opengoal.repl.history").string().c_str()); + } + return false; +} + +const std::vector& ReplHistory::repl_get_history() { + return linenoise::GetHistory(); +} diff --git a/common/goos/ReplHistory.h b/common/goos/ReplHistory.h new file mode 100644 index 0000000000..f38c503ed4 --- /dev/null +++ b/common/goos/ReplHistory.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +// Linenoise declares history as a static array, so when trying to use the +// library across files, the history array is different +// Solve this by wrapping the API +namespace ReplHistory { +bool repl_set_history_max_size(size_t len); +bool repl_readline(const char* prompt, std::string& line); +bool repl_add_to_history(const char* line); +bool repl_save_history(); +bool repl_load_history(); +const std::vector& repl_get_history(); +}; // namespace ReplHistory diff --git a/common/util/FileUtil.cpp b/common/util/FileUtil.cpp index 34bd460338..9e9e394780 100644 --- a/common/util/FileUtil.cpp +++ b/common/util/FileUtil.cpp @@ -13,6 +13,7 @@ #include "BinaryWriter.h" #include "common/common_types.h" #include "third-party/svpng.h" +#include #ifdef _WIN32 #include @@ -22,6 +23,17 @@ #endif namespace file_util { +std::filesystem::path get_user_home_dir() { +#ifdef _WIN32 + // NOTE - on older systems, this may case issues if it cannot be found! + std::string home_dir = std::getenv("USERPROFILE"); + return std::filesystem::path(home_dir); +#else + std::string home_dir = std::getenv("HOME"); + return std::filesystem::path(home_dir); +#endif +} + std::string get_project_path() { #ifdef _WIN32 char buffer[FILENAME_MAX]; diff --git a/common/util/FileUtil.h b/common/util/FileUtil.h index 946f753126..3127207afa 100644 --- a/common/util/FileUtil.h +++ b/common/util/FileUtil.h @@ -7,8 +7,10 @@ #include #include +#include namespace file_util { +std::filesystem::path get_user_home_dir(); std::string get_project_path(); std::string get_file_path(const std::vector& input); bool create_dir_if_needed(const std::string& path); diff --git a/goalc/CMakeLists.txt b/goalc/CMakeLists.txt index ce8439939e..232d7c3b99 100644 --- a/goalc/CMakeLists.txt +++ b/goalc/CMakeLists.txt @@ -36,7 +36,8 @@ add_library(compiler regalloc/allocate.cpp regalloc/allocate_common.cpp compiler/Compiler.cpp - compiler/compilation/Asm.cpp) + compiler/compilation/Asm.cpp + ) target_link_libraries(compiler common Zydis) diff --git a/goalc/compiler/compilation/CompilerControl.cpp b/goalc/compiler/compilation/CompilerControl.cpp index 23f47c521c..b6c77bc5ea 100644 --- a/goalc/compiler/compilation/CompilerControl.cpp +++ b/goalc/compiler/compilation/CompilerControl.cpp @@ -11,6 +11,7 @@ #include "common/util/FileUtil.h" #include "goalc/data_compiler/game_text.h" #include "goalc/data_compiler/game_count.h" +#include "common/goos/ReplHistory.h" /*! * Exit the compiler. Disconnects the listener and tells the target to reset itself. @@ -30,6 +31,7 @@ Val* Compiler::compile_exit(const goos::Object& form, const goos::Object& rest, } // flag for the REPL. m_want_exit = true; + ReplHistory::repl_save_history(); return get_none(); } diff --git a/goalc/main.cpp b/goalc/main.cpp index 93487b5adc..f03f928e85 100644 --- a/goalc/main.cpp +++ b/goalc/main.cpp @@ -7,6 +7,8 @@ #include "third-party/fmt/core.h"; #include "third-party/fmt/color.h"; +#include "common/goos/ReplHistory.h" + void setup_logging(bool verbose) { lg::set_file(file_util::get_file_path({"log/compiler.txt"})); if (verbose) { @@ -61,6 +63,7 @@ int main(int argc, char** argv) { fmt::print(fmt::emphasis::bold | fg(fmt::color::cyan), "(lt)"); fmt::print(" to connect to the local listener.\n"); + ReplHistory::repl_load_history(); if (argument.empty()) { compiler.execute_repl(); } else {