diff --git a/tools/repl/repl.cpp b/tools/repl/repl.cpp index 8d2e33f9d46..2278e6c9d67 100644 --- a/tools/repl/repl.cpp +++ b/tools/repl/repl.cpp @@ -7,7 +7,10 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/ADT/SmallString.h" #include "hermes/CompilerDriver/CompilerDriver.h" #include "hermes/ConsoleHost/ConsoleHost.h" @@ -42,6 +45,9 @@ #define C_STRING(x) #x +static const std::string historyFileBaseName = ".hermes_history"; +static const int historyMaxEntries = 500; + using namespace hermes; static llvm::cl::opt PromptString( @@ -222,6 +228,26 @@ static bool needsAnotherLine(llvm::StringRef input) { return !stack.empty(); } +#if HAVE_LIBREADLINE +// Load history file or create it +std::error_code loadHistoryFile(llvm::SmallString<128>& historyFile) { + if (!llvm::sys::path::home_directory(historyFile)) { + // Use ENOENT here since it could not found a home directory + return std::error_code(ENOENT, std::system_category()); + } + + llvm::sys::path::append(historyFile, historyFileBaseName); + + auto err = ::read_history(historyFile.c_str()); + if (err != 0) { + // Return a error_code object from a errno enum + return std::error_code(err, std::system_category()); + } + + return std::error_code(); +} +#endif + // This is the vm driver. int main(int argc, char **argv) { llvm::sys::PrintStackTraceOnErrorSignal("Hermes REPL"); @@ -288,6 +314,14 @@ int main(int argc, char **argv) { runtime->getHeap().runtimeWillExecute(); +#if HAVE_LIBREADLINE + llvm::SmallString<128> historyFile{}; + auto historyErr = loadHistoryFile(historyFile); + if (historyErr && historyErr.value() != ENOENT) { + llvm::errs() << "Could not load history file: " << historyErr.message() << '\n'; + } +#endif + // SetUnbuffered because there is no explicit flush after prompt (>>). // There is also no explicitly flush at end of line. (An automatic flush // mechanism is not guaranteed to be present, from my experiment on Windows) @@ -300,6 +334,12 @@ int main(int argc, char **argv) { (readResult == ReadResult::INTERRUPT && code.empty())) { // EOF or user exit on non-continuation line. llvm::outs() << '\n'; +#if HAVE_LIBREADLINE + if (history_length > 0) { + ::stifle_history(historyMaxEntries); + ::write_history(historyFile.c_str()); + } +#endif return 0; }