From 4dccde78309919c23361926f440b0883791f1b0d Mon Sep 17 00:00:00 2001 From: Robert Bendun Date: Sat, 4 Mar 2023 17:59:33 +0100 Subject: [PATCH] Save history between command invocations --- CHANGELOG.md | 8 ++++ musique/common.hh | 7 +++ musique/main.cc | 12 ++--- musique/platform.hh | 25 +++++++++++ musique/user_directory.cc | 92 +++++++++++++++++++++++++++++++++++++++ musique/user_directory.hh | 15 +++++++ 6 files changed, 154 insertions(+), 5 deletions(-) create mode 100644 musique/platform.hh create mode 100644 musique/user_directory.cc create mode 100644 musique/user_directory.hh diff --git a/CHANGELOG.md b/CHANGELOG.md index 313139f..2af25d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- `CTRL-C` handler that turns notes that are playing off + +### Changed + +- Moved from `bestline` to `replxx` Readline implementation due to lack of Windows support from bestline + ## [0.4.0] ### Added diff --git a/musique/common.hh b/musique/common.hh index 0182bf3..0fcfcd9 100644 --- a/musique/common.hh +++ b/musique/common.hh @@ -62,4 +62,11 @@ concept Three_Way_Comparable = requires (T const& lhs, T const& rhs) { { lhs <=> rhs }; }; +template +requires (std::equality_comparable_with && ...) +constexpr bool one_of(Needle const& needle, Heystack const& ...heystack) +{ + return ((needle == heystack) || ...); +} + #endif diff --git a/musique/main.cc b/musique/main.cc index b15e67a..048bf22 100644 --- a/musique/main.cc +++ b/musique/main.cc @@ -14,9 +14,11 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -251,8 +253,9 @@ void completion(char const* buf, bestlineCompletions *lc) } #endif -bool is_tty() +static bool is_tty() { +// Can't use if constexpr since _isatty is not defined on non-windows platforms #ifdef _WIN32 return _isatty(STDOUT_FILENO); #else @@ -485,13 +488,11 @@ static std::optional Main(std::span args) replxx::Replxx repl; - { - std::ifstream history(".musique_history"); - repl.history_load(history); - } + auto const history_path = (user_directory::data_home() / "history").string(); repl.set_max_history_size(2048); repl.set_max_hint_rows(3); + repl.history_load(history_path); for (;;) { char const* input = nullptr; @@ -513,6 +514,7 @@ static std::optional Main(std::span args) } repl.history_add(std::string(command)); + repl.history_save(history_path); if (command.starts_with(':')) { command.remove_prefix(1); diff --git a/musique/platform.hh b/musique/platform.hh new file mode 100644 index 0000000..72c7cba --- /dev/null +++ b/musique/platform.hh @@ -0,0 +1,25 @@ +#ifndef MUSIQUE_PLATFORM_HH +#define MUSIQUE_PLATFORM_HH + +namespace platform +{ + enum class Operating_System + { + MacOS, + Unix, + Windows, + }; + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) + static constexpr Operating_System os = Operating_System::Windows; +#elif defined(__APPLE__) + static constexpr Operating_System os = Operating_System::MacOS; + Operating_System::MacOS +#elif defined(__linux__) || defined(__unix__) + static constexpr Operating_System os = Operating_System::Unix; +#else +#error "Unknown platform" +#endif +} + +#endif // MUSIQUE_PLATFORM_HH diff --git a/musique/user_directory.cc b/musique/user_directory.cc new file mode 100644 index 0000000..2a34672 --- /dev/null +++ b/musique/user_directory.cc @@ -0,0 +1,92 @@ +#include +#include +#include + +static std::filesystem::path home() +{ + if constexpr (platform::os == platform::Operating_System::Windows) { + if (auto home = std::getenv("USERPROFILE")) return home; + + if (auto drive = std::getenv("HOMEDRIVE")) { + if (auto path = std::getenv("HOMEPATH")) { + return std::string(drive) + path; + } + } + } else { + if (auto home = std::getenv("HOME")) { + return home; + } + } + + unreachable(); +} + +std::filesystem::path user_directory::data_home() +{ + std::filesystem::path path; + + static_assert(one_of(platform::os, + platform::Operating_System::Unix, + platform::Operating_System::Windows, + platform::Operating_System::MacOS + )); + + if constexpr (platform::os == platform::Operating_System::Unix) { + if (auto data = std::getenv("XDG_DATA_HOME")) { + path = data; + } else { + path = home() / ".local" / "share"; + } + } + + if constexpr (platform::os == platform::Operating_System::Windows) { + if (auto data = std::getenv("LOCALAPPDATA")) { + path = data; + } else { + path = home() / "AppData" / "Local"; + } + } + + if constexpr (platform::os == platform::Operating_System::MacOS) { + path = home() / "Library"; + } + + path /= "musique"; + std::filesystem::create_directories(path); + return path; +} + +std::filesystem::path user_directory::config_home() +{ + std::filesystem::path path; + + static_assert(one_of(platform::os, + platform::Operating_System::Unix, + platform::Operating_System::Windows, + platform::Operating_System::MacOS + )); + + if constexpr (platform::os == platform::Operating_System::Unix) { + if (auto data = std::getenv("XDG_CONFIG_HOME")) { + path = data; + } else { + path = home() / ".config"; + } + } + + if constexpr (platform::os == platform::Operating_System::Windows) { + if (auto data = std::getenv("LOCALAPPDATA")) { + path = data; + } else { + path = home() / "AppData" / "Local"; + } + } + + if constexpr (platform::os == platform::Operating_System::MacOS) { + path = home() / "Library" / "Preferences"; + } + + path /= "musique"; + std::filesystem::create_directories(path); + return path; +} diff --git a/musique/user_directory.hh b/musique/user_directory.hh new file mode 100644 index 0000000..faea869 --- /dev/null +++ b/musique/user_directory.hh @@ -0,0 +1,15 @@ +#ifndef MUSIQUE_USER_DIRECTORY_HH +#define MUSIQUE_USER_DIRECTORY_HH + +#include + +namespace user_directory +{ + /// Returns system-specific user directory for data; same as XDG_DATA_HOME + std::filesystem::path data_home(); + + /// Returns system-specific user directory for config; same as XDG_CONFIG_HOME + std::filesystem::path config_home(); +} + +#endif // MUSIQUE_USER_DIRECTORY_HH