From 61750d6e53847873ceeadb17bbe0b6d2c19aca86 Mon Sep 17 00:00:00 2001 From: Vladislav Nepogodin Date: Wed, 15 Dec 2021 03:19:58 +0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=91=B7=20update=20deps=20and=20ui.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also refactor code --- CMakeLists.txt | 2 +- src/tui.cpp | 157 ++++++++++++++++++--- src/widgets.cpp | 38 ++++- src/widgets.hpp | 1 + subprojects/ftxui.wrap | 2 +- subprojects/packagefiles/ftxui/meson.build | 1 + 6 files changed, 177 insertions(+), 24 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f071848..5414765 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,7 @@ pkg_check_modules( FetchContent_Declare(ftxui GIT_REPOSITORY "https://github.com/arthursonzogni/ftxui.git" - GIT_TAG "602392c43d8bc2272c6548ae75b8802ab7ad0b2a" + GIT_TAG "7e5cd23b4c47972b70b99c39617d6e38f05d1b3a" ) FetchContent_MakeAvailable(ftxui) diff --git a/src/tui.cpp b/src/tui.cpp index 2392273..fb37fa1 100644 --- a/src/tui.cpp +++ b/src/tui.cpp @@ -9,6 +9,7 @@ #include // for transform #include // for exists, is_directory #include // for __shared_ptr_access +#include // for regex_search, match_results<>::_Base_type #include // for basic_string #include // for ftxui #include // for Renderer, Button @@ -432,7 +433,101 @@ bool mount_current_partition() noexcept { return true; } -void make_swap() noexcept { } +void make_swap() noexcept { + static constexpr auto SelSwpNone = "None"; + static constexpr auto SelSwpFile = "Swapfile"; + + auto* config_instance = Config::instance(); + auto& config_data = config_instance->data(); + const auto& mountpoint_info = std::get(config_data["MOUNTPOINT"]); + + { + std::vector temp{"None -"}; + const auto& root_filesystem = utils::exec(fmt::format("findmnt -ln -o FSTYPE \"{}\"", mountpoint_info)); + if (!(root_filesystem == "zfs" || root_filesystem == "btrfs")) { + temp.push_back("Swapfile -"); + } + const auto& partitions = std::get>(config_data["PARTITIONS"]); + temp.reserve(partitions.size()); + std::ranges::copy(partitions, std::back_inserter(temp)); + + std::int32_t selected{}; + bool success{}; + auto ok_callback = [&] { + auto src = temp[static_cast(selected)]; + const auto& lines = utils::make_multiline(src, false, " "); + config_data["ANSWER"] = lines[0]; + success = true; + std::raise(SIGINT); + }; + /* clang-format off */ + detail::menu_widget(temp, ok_callback, &selected); + if (!success) { return; } + /* clang-format on */ + } + + const auto& answer = std::get(config_data["ANSWER"]); + auto& partition = std::get(config_data["PARTITION"]); + /* clang-format off */ + if (answer == SelSwpNone) { return; } + partition = answer; + /* clang-format on */ + + if (partition == SelSwpFile) { + const auto& total_memory = utils::exec("grep MemTotal /proc/meminfo | awk \'{print $2/1024}\' | sed \'s/\\..*//\'"); + std::string value{fmt::format("{}M", total_memory)}; + if (!detail::inputbox_widget(value, "\nM = MB, G = GB\n", size(ftxui::HEIGHT, ftxui::LESS_THAN, 9) | size(ftxui::WIDTH, ftxui::LESS_THAN, 30))) { + return; + } + + while (utils::exec(fmt::format("echo \"{}\" | grep \"M\\|G\"", value)) == "") { + detail::msgbox_widget(fmt::format("\n{} Error: M = MB, G = GB\n", SelSwpFile)); + value = fmt::format("{}M", total_memory); + if (!detail::inputbox_widget(value, "\nM = MB, G = GB\n", size(ftxui::HEIGHT, ftxui::LESS_THAN, 9) | size(ftxui::WIDTH, ftxui::LESS_THAN, 30))) { + return; + } + } + +#ifdef NDEVENV + const auto& swapfile_path = fmt::format("{}/swapfile", mountpoint_info); + utils::exec(fmt::format("fallocate -l {} {}", value, swapfile_path)); + utils::exec(fmt::format("chmod 600 {}", swapfile_path)); + utils::exec(fmt::format("mkswap {}", swapfile_path)); + utils::exec(fmt::format("swapon {}", swapfile_path)); +#endif + return; + } + + auto& partitions = std::get>(config_data["PARTITIONS"]); + auto& number_partitions = std::get(config_data["NUMBER_PARTITIONS"]); + + // Warn user if creating a new swap + const auto& swap_part = utils::exec(fmt::format("lsblk -o FSTYPE \"{}\" | grep -i \"swap\"", partition)); + if (swap_part != "swap") { + const auto& do_swap = detail::yesno_widget(fmt::format("\nmkswap {}\n", partition), size(HEIGHT, LESS_THAN, 15) | size(WIDTH, LESS_THAN, 75)); + /* clang-format off */ + if (!do_swap) { return; } + /* clang-format on */ + +#ifdef NDEVENV + utils::exec(fmt::format("mkswap {} >/dev/null", partition)); +#endif + spdlog::info("mkswap.{}", partition); + } + +#ifdef NDEVENV + // Whether existing to newly created, activate swap + utils::exec(fmt::format("swapon {} >/dev/null", partition)); +#endif + + // TODO: reimplement natively + // Since a partition was used, remove that partition from the list + const auto& str = utils::make_multiline(partitions); + const auto& cmd = fmt::format("echo \"{0}\" | sed \"s~{1} [0-9]*[G-M]~~\" | sed \"s~{1} [0-9]*\\.[0-9]*[G-M]~~\" | sed \"s~{1}$\' -\'~~\"", str, partition); + const auto& res_text = utils::exec(cmd); + partitions = utils::make_multiline(res_text); + number_partitions -= 1; +} void mount_partitions() noexcept { auto* config_instance = Config::instance(); @@ -554,17 +649,35 @@ void mount_partitions() noexcept { // All other partitions const auto& number_partitions = std::get(config_data["NUMBER_PARTITIONS"]); const auto& system_info = std::get(config_data["SYSTEM"]); + const auto& partition = std::get(config_data["PARTITION"]); while (number_partitions > 0) { - // DIALOG " $_PrepMntPart " --menu "\n$_ExtPartBody\n " 0 0 12 "$_Done" $"-" ${PARTITIONS} 2>${ANSWER} || return 0 - // PARTITION=$(cat ${ANSWER}) + { + std::int32_t selected{}; + bool success{}; + const auto& partitions = std::get>(config_data["PARTITIONS"]); + std::vector temp{"Done -"}; + temp.reserve(partitions.size()); + std::ranges::copy(partitions, std::back_inserter(temp)); - // if [[ $PARTITION == $_Done ]]; then - // make_esp - // get_cryptroot - // get_cryptboot - // echo "$LUKS_DEV" > /tmp/.luks_dev - // return 0; - // else + auto ok_callback = [&] { + auto src = temp[static_cast(selected)]; + const auto& lines = utils::make_multiline(src, false, " "); + config_data["PARTITION"] = lines[0]; + success = true; + std::raise(SIGINT); + }; + /* clang-format off */ + detail::menu_widget(temp, ok_callback, &selected); + if (!success) { return; } + /* clang-format on */ + } + + if (partition == "Done") { + // make_esp(); + // get_cryptroot(); + // get_cryptboot(); + return; + } config_data["MOUNT"] = ""; tui::select_filesystem(); @@ -572,23 +685,28 @@ void mount_partitions() noexcept { // Ask user for mountpoint. Don't give /boot as an example for UEFI systems! std::string_view mnt_examples = "/boot\n/home\n/var"; if (system_info == "UEFI") { mnt_examples = "/home\n/var"; } + + std::string value{"/"}; + static constexpr auto ExtPartBody1 = "Specify partition mountpoint. Ensure\nthe name begins with a forward slash (/).\nExamples include:"; + if (!detail::inputbox_widget(value, fmt::format("\n{}\n{}\n", ExtPartBody1, mnt_examples))) { return; } /* clang-format on */ - // DIALOG " $_PrepMntPart $PARTITION " --inputbox "\n$_ExtPartBody1$MNT_EXAMPLES\n " 0 0 "/" 2>${ANSWER} || return 0 - // MOUNT=$(cat ${ANSWER}) auto& mount_dev = std::get(config_data["MOUNT"]); + mount_dev = std::move(value); + spdlog::info("\nmount_dev: {}\nexpression: {}\n", mount_dev, ((mount_dev.size() <= 1) || (mount_dev[0] != '/') || std::regex_match(mount_dev, std::regex{"\\s+|\\'"}))); // loop while the mountpoint specified is incorrect (is only '/', is blank, or has spaces). - /*while [[ ${MOUNT:0:1} != "/" ]] || [[ ${#MOUNT} -le 1 ]] || [[ $MOUNT =~ \ |\' ]]; do + while ((mount_dev.size() <= 1) || (mount_dev[0] != '/') || std::regex_match(mount_dev, std::regex{"\\s+|\\'"})) { // Warn user about naming convention - DIALOG " $_ErrTitle " --msgbox "\n$_ExtErrBody\n " 0 0 + detail::msgbox_widget("\nPartition cannot be mounted due to a problem with the mountpoint name.\nA name must be given after a forward slash.\n"); // Ask user for mountpoint again - DIALOG " $_PrepMntPart $PARTITON " --inputbox "\n$_ExtPartBody1$MNT_EXAMPLES\n " 0 0 "/" 2>${ANSWER} || return 0 - MOUNT=$(cat ${ANSWER}) - done*/ - + value = "/"; + if (!detail::inputbox_widget(value, fmt::format("\n{}\n{}\n", ExtPartBody1, mnt_examples))) { + return; + } + mount_dev = std::move(value); + } // Create directory and mount. tui::mount_current_partition(); - // delete_partition_in_list "$PARTITION" // Determine if a seperate /boot is used. // 0 = no seperate boot, @@ -602,7 +720,6 @@ void mount_partitions() noexcept { config_data["LVM_SEP_BOOT"] = 2; } } - //} } } diff --git a/src/widgets.cpp b/src/widgets.cpp index 4c1a2dc..cdded3a 100644 --- a/src/widgets.cpp +++ b/src/widgets.cpp @@ -144,6 +144,42 @@ void msgbox_widget(const std::string_view& content, Decorator boxsize) noexcept screen.Loop(renderer); } +bool inputbox_widget(std::string& value, const std::string_view& content, Decorator boxsize) noexcept { + auto screen = ScreenInteractive::Fullscreen(); + bool success{}; + auto ok_callback = [&] { + success = true; + std::raise(SIGINT); + }; + InputOption input_option{.on_enter = ok_callback}; + auto input_value = Input(&value, "", input_option); + auto content_container = Renderer([&] { + return multiline_text(utils::make_multiline(content)) | hcenter | boxsize; + }); + + ButtonOption button_option{.border = false}; + auto controls_container = controls_widget({"OK", "Cancel"}, {ok_callback, screen.ExitLoopClosure()}, &button_option); + + auto controls = Renderer(controls_container, [&] { + return controls_container->Render() | hcenter | size(HEIGHT, LESS_THAN, 3) | size(WIDTH, GREATER_THAN, 25); + }); + + auto global = Container::Vertical({ + content_container, + Renderer([] { return separator(); }), + input_value, + Renderer([] { return separator(); }), + controls, + }); + + auto renderer = Renderer(global, [&] { + return centered_interative_multi("New CLI Installer", global); + }); + + screen.Loop(renderer); + return success; +} + void infobox_widget(const std::string_view& content, Decorator boxsize) noexcept { auto screen = Screen::Create( Dimension::Full(), // Width @@ -180,7 +216,6 @@ bool yesno_widget(const std::string_view& content, Decorator boxsize) noexcept { }); screen.Loop(renderer); - return success; } @@ -214,7 +249,6 @@ bool yesno_widget(ftxui::Component& container, Decorator boxsize) noexcept { }); screen.Loop(renderer); - return success; } diff --git a/src/widgets.hpp b/src/widgets.hpp index 1beeae1..3189c48 100644 --- a/src/widgets.hpp +++ b/src/widgets.hpp @@ -18,6 +18,7 @@ namespace detail { auto from_checklist_string(const std::vector& opts, bool* opts_state) noexcept -> std::string; auto from_checklist_vector(const std::vector& opts, bool* opts_state) noexcept -> std::vector; void msgbox_widget(const std::string_view& content, ftxui::Decorator boxsize = size(ftxui::HEIGHT, ftxui::GREATER_THAN, 5)) noexcept; + bool inputbox_widget(std::string& value, const std::string_view& content, ftxui::Decorator boxsize = size(ftxui::HEIGHT, ftxui::GREATER_THAN, 5)) noexcept; void infobox_widget(const std::string_view& content, ftxui::Decorator boxsize = size(ftxui::HEIGHT, ftxui::GREATER_THAN, 5)) noexcept; bool yesno_widget(const std::string_view& content, ftxui::Decorator boxsize = size(ftxui::HEIGHT, ftxui::GREATER_THAN, 5)) noexcept; bool yesno_widget(ftxui::Component& container, ftxui::Decorator boxsize = size(ftxui::HEIGHT, ftxui::GREATER_THAN, 5)) noexcept; diff --git a/subprojects/ftxui.wrap b/subprojects/ftxui.wrap index faa0924..00207e2 100644 --- a/subprojects/ftxui.wrap +++ b/subprojects/ftxui.wrap @@ -1,6 +1,6 @@ [wrap-git] url = https://github.com/arthursonzogni/ftxui.git -revision = 602392c43d8bc2272c6548ae75b8802ab7ad0b2a +revision = 7e5cd23b4c47972b70b99c39617d6e38f05d1b3a patch_directory = ftxui diff --git a/subprojects/packagefiles/ftxui/meson.build b/subprojects/packagefiles/ftxui/meson.build index 1044849..61c5f34 100644 --- a/subprojects/packagefiles/ftxui/meson.build +++ b/subprojects/packagefiles/ftxui/meson.build @@ -48,6 +48,7 @@ ftxui_dom_lib = static_library('ftxui_dom', 'src/ftxui/dom/flexbox_config.cpp', 'src/ftxui/dom/flexbox_helper.cpp', 'src/ftxui/dom/flexbox_helper.hpp', + 'src/ftxui/dom/focus.cpp', 'src/ftxui/dom/frame.cpp', 'src/ftxui/dom/gauge.cpp', 'src/ftxui/dom/graph.cpp',