From 7cce09edb69272b0d145577f8dd8165f808ebedd Mon Sep 17 00:00:00 2001 From: Renato Alencar Date: Wed, 17 Jul 2019 20:08:41 +0000 Subject: [PATCH 1/6] REPL: Load and write history to file Use libreadline to load and write command history to file. By default the history is written to ~/.hermes_history and is created when does not exists. --- tools/repl/repl.cpp | 48 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/tools/repl/repl.cpp b/tools/repl/repl.cpp index 8d2e33f9d46..79a19ff694c 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,8 @@ #define C_STRING(x) #x +#define HISTORY_FILE ".hermes_history" + using namespace hermes; static llvm::cl::opt PromptString( @@ -222,6 +227,38 @@ static bool needsAnotherLine(llvm::StringRef input) { return !stack.empty(); } +#if HAVE_LIBREADLINE +// Load history file or create it +std::error_code loadOrCreateHistoryFile(llvm::SmallString<128>& historyFile) { + llvm::Twine baseHistoryFile = llvm::Twine(HISTORY_FILE); + + if (llvm::sys::path::home_directory(historyFile)) { + llvm::sys::path::append(historyFile, baseHistoryFile); + + if (!llvm::sys::fs::exists(historyFile)) { + int fd; + auto err = llvm::sys::fs::openFileForWrite(llvm::Twine(historyFile), fd); + if (err) { + return err; + } + + llvm::sys::fs::closeFile(fd); + } + + 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(); + } + + // Use ENOENT here since it could not found a home directory + return std::error_code(ENOENT, std::system_category()); +} +#endif + // This is the vm driver. int main(int argc, char **argv) { llvm::sys::PrintStackTraceOnErrorSignal("Hermes REPL"); @@ -288,6 +325,14 @@ int main(int argc, char **argv) { runtime->getHeap().runtimeWillExecute(); +#if HAVE_LIBREADLINE + llvm::SmallString<128> historyFile = llvm::SmallString<128>(); + auto historyErr = loadOrCreateHistoryFile(historyFile); + if (historyErr) { + 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 +345,9 @@ 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 + ::write_history(historyFile.c_str()); +#endif return 0; } From dc42914c04f103f7bdba03c3b0d903aeaf98ac4e Mon Sep 17 00:00:00 2001 From: Renato Alencar Date: Wed, 17 Jul 2019 22:10:38 +0000 Subject: [PATCH 2/6] REPL: Set a limit of entries for history --- tools/repl/repl.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/repl/repl.cpp b/tools/repl/repl.cpp index 79a19ff694c..27045139b26 100644 --- a/tools/repl/repl.cpp +++ b/tools/repl/repl.cpp @@ -46,6 +46,7 @@ #define C_STRING(x) #x #define HISTORY_FILE ".hermes_history" +#define HISTORY_MAX_ENTRIES 500 using namespace hermes; @@ -346,6 +347,7 @@ int main(int argc, char **argv) { // EOF or user exit on non-continuation line. llvm::outs() << '\n'; #if HAVE_LIBREADLINE + ::stifle_history(HISTORY_MAX_ENTRIES); ::write_history(historyFile.c_str()); #endif return 0; From a9c2c1d4119ce041104d4fb53a636042f74fcd68 Mon Sep 17 00:00:00 2001 From: Renato Alencar Date: Wed, 17 Jul 2019 22:49:25 +0000 Subject: [PATCH 3/6] REPL: Fails first if find no home dir --- tools/repl/repl.cpp | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/tools/repl/repl.cpp b/tools/repl/repl.cpp index 27045139b26..f4a2a72b4a4 100644 --- a/tools/repl/repl.cpp +++ b/tools/repl/repl.cpp @@ -233,30 +233,30 @@ static bool needsAnotherLine(llvm::StringRef input) { std::error_code loadOrCreateHistoryFile(llvm::SmallString<128>& historyFile) { llvm::Twine baseHistoryFile = llvm::Twine(HISTORY_FILE); - if (llvm::sys::path::home_directory(historyFile)) { - llvm::sys::path::append(historyFile, baseHistoryFile); - - if (!llvm::sys::fs::exists(historyFile)) { - int fd; - auto err = llvm::sys::fs::openFileForWrite(llvm::Twine(historyFile), fd); - if (err) { - return err; - } + 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::fs::closeFile(fd); - } + llvm::sys::path::append(historyFile, baseHistoryFile); - 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()); + if (!llvm::sys::fs::exists(historyFile)) { + int fd; + auto err = llvm::sys::fs::openFileForWrite(llvm::Twine(historyFile), fd); + if (err) { + return err; } - return std::error_code(); + llvm::sys::fs::closeFile(fd); + } + + 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()); } - // Use ENOENT here since it could not found a home directory - return std::error_code(ENOENT, std::system_category()); + return std::error_code(); } #endif From 6ede90ea1456e1c374752f6b29f302236d4189cb Mon Sep 17 00:00:00 2001 From: Renato Alencar Date: Wed, 17 Jul 2019 23:41:58 +0000 Subject: [PATCH 4/6] REPL: Move and remove history variables * Switch from macros to static const variables in order to have proper typings; * Remove explicit Twine instantiation to implicit. --- tools/repl/repl.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tools/repl/repl.cpp b/tools/repl/repl.cpp index f4a2a72b4a4..726b9c79541 100644 --- a/tools/repl/repl.cpp +++ b/tools/repl/repl.cpp @@ -45,8 +45,8 @@ #define C_STRING(x) #x -#define HISTORY_FILE ".hermes_history" -#define HISTORY_MAX_ENTRIES 500 +static const std::string historyFileBaseName = ".hermes_history"; +static const int historyMaxEntries = 500; using namespace hermes; @@ -231,14 +231,12 @@ static bool needsAnotherLine(llvm::StringRef input) { #if HAVE_LIBREADLINE // Load history file or create it std::error_code loadOrCreateHistoryFile(llvm::SmallString<128>& historyFile) { - llvm::Twine baseHistoryFile = llvm::Twine(HISTORY_FILE); - 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, baseHistoryFile); + llvm::sys::path::append(historyFile, historyFileBaseName); if (!llvm::sys::fs::exists(historyFile)) { int fd; @@ -347,7 +345,7 @@ int main(int argc, char **argv) { // EOF or user exit on non-continuation line. llvm::outs() << '\n'; #if HAVE_LIBREADLINE - ::stifle_history(HISTORY_MAX_ENTRIES); + ::stifle_history(historyMaxEntries); ::write_history(historyFile.c_str()); #endif return 0; From b0bfa8233b828c1c47afa412d7754e4ff30e5358 Mon Sep 17 00:00:00 2001 From: Renato Alencar Date: Thu, 18 Jul 2019 22:02:14 +0000 Subject: [PATCH 5/6] REPL: Change historyFile instantiation --- tools/repl/repl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/repl/repl.cpp b/tools/repl/repl.cpp index 726b9c79541..a141ecd7622 100644 --- a/tools/repl/repl.cpp +++ b/tools/repl/repl.cpp @@ -325,7 +325,7 @@ int main(int argc, char **argv) { runtime->getHeap().runtimeWillExecute(); #if HAVE_LIBREADLINE - llvm::SmallString<128> historyFile = llvm::SmallString<128>(); + llvm::SmallString<128> historyFile{}; auto historyErr = loadOrCreateHistoryFile(historyFile); if (historyErr) { llvm::errs() << "Could not load history file: " << historyErr.message() << '\n'; From 304d08d89df20320c41a52ab8ba59cd4524daecb Mon Sep 17 00:00:00 2001 From: Renato Alencar Date: Wed, 24 Jul 2019 14:08:25 +0000 Subject: [PATCH 6/6] REPL: Avoid creating empty file when history is empty Besides that, let the `write_history` function create the history file on its own. And when reading the history ignore ENOENT errors. --- tools/repl/repl.cpp | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/tools/repl/repl.cpp b/tools/repl/repl.cpp index a141ecd7622..2278e6c9d67 100644 --- a/tools/repl/repl.cpp +++ b/tools/repl/repl.cpp @@ -230,7 +230,7 @@ static bool needsAnotherLine(llvm::StringRef input) { #if HAVE_LIBREADLINE // Load history file or create it -std::error_code loadOrCreateHistoryFile(llvm::SmallString<128>& historyFile) { +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()); @@ -238,16 +238,6 @@ std::error_code loadOrCreateHistoryFile(llvm::SmallString<128>& historyFile) { llvm::sys::path::append(historyFile, historyFileBaseName); - if (!llvm::sys::fs::exists(historyFile)) { - int fd; - auto err = llvm::sys::fs::openFileForWrite(llvm::Twine(historyFile), fd); - if (err) { - return err; - } - - llvm::sys::fs::closeFile(fd); - } - auto err = ::read_history(historyFile.c_str()); if (err != 0) { // Return a error_code object from a errno enum @@ -326,8 +316,8 @@ int main(int argc, char **argv) { #if HAVE_LIBREADLINE llvm::SmallString<128> historyFile{}; - auto historyErr = loadOrCreateHistoryFile(historyFile); - if (historyErr) { + auto historyErr = loadHistoryFile(historyFile); + if (historyErr && historyErr.value() != ENOENT) { llvm::errs() << "Could not load history file: " << historyErr.message() << '\n'; } #endif @@ -345,8 +335,10 @@ int main(int argc, char **argv) { // EOF or user exit on non-continuation line. llvm::outs() << '\n'; #if HAVE_LIBREADLINE - ::stifle_history(historyMaxEntries); - ::write_history(historyFile.c_str()); + if (history_length > 0) { + ::stifle_history(historyMaxEntries); + ::write_history(historyFile.c_str()); + } #endif return 0; }