From 22172309e16850fc5bf187ede5b565551d03d1ea Mon Sep 17 00:00:00 2001 From: oleg Date: Mon, 13 Apr 2026 07:08:38 +0300 Subject: [PATCH] add regex search --- CMakeLists.txt | 3 ++- Makefile | 1 + src/canid_unit.hpp | 25 ++++++++++++++----- src/main.cpp | 1 + src/mainform.cpp | 62 ++++++++++++++++++++++++++++++++++++++-------- 5 files changed, 75 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e1953f2..46af207 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,7 @@ option(BUILD_SHARED_LIBS "Build using shared libraries" OFF) include(cmake/dependencies.cmake) project(canscope) +find_package(Boost REQUIRED COMPONENTS regex) file(GLOB_RECURSE SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/*.hpp ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp) add_executable(${CMAKE_PROJECT_NAME} ${SOURCES}) @@ -30,5 +31,5 @@ target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE ${clipp_SOURCE_DIR}/include ) -target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE ftxui::component ftxui::screen ftxui::dom tiny-process-library xlnt sqlite3_lib z ${Boost_LIBRARIES}) +target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE ftxui::component ftxui::screen ftxui::dom tiny-process-library xlnt sqlite3_lib z Boost::regex ${Boost_LIBRARIES}) diff --git a/Makefile b/Makefile index 58a7fa6..383c446 100644 --- a/Makefile +++ b/Makefile @@ -72,6 +72,7 @@ install_static: ## Install static binary to PREFIX/bin docker-run: ## Build and run in Docker (works on Linux/Mac/Windows) docker build -t $(DEV_IMAGE) -f docker/Dockerfile.dev . docker run --rm -it \ + -e TERM=xterm-256color \ -v $(CURDIR):/app \ -v $(SSH_DIR):/host_ssh:ro \ -v /etc/hosts:/etc/hosts:ro \ diff --git a/src/canid_unit.hpp b/src/canid_unit.hpp index 7df4473..8423e60 100644 --- a/src/canid_unit.hpp +++ b/src/canid_unit.hpp @@ -19,14 +19,25 @@ class CanIDUnit : public ftxui::ComponentBase { public: - CanIDUnit(const std::string &iface, const std::string &canid, const std::string &protocol, size_t &spn_count, const std::vector &data, ftxui::ScreenInteractive *screen, - signals_map_t &smap, ftxui::Component content, ftxui::Component container, ftxui::Component spn_settings_dialog, ftxui::Component cansettings_dialog, bool is_deployed, - bool is_verbose, bool is_brief, bool is_manual, std::string &, bool &, bool &canbus_parameters_export_shown, bool &filedialog_shown, + CanIDUnit(const std::string &iface, const std::string &canid, const std::string &protocol, size_t &spn_count, + const std::vector &data, ftxui::ScreenInteractive *screen, signals_map_t &smap, + ftxui::Component content, ftxui::Component container, ftxui::Component spn_settings_dialog, + ftxui::Component cansettings_dialog, bool is_deployed, bool is_verbose, bool is_brief, bool is_manual, + std::string &, bool &, bool &canbus_parameters_export_shown, bool &filedialog_shown, std::map> &spnSettingsFormMap, spn_settings_map_t &spnSettingsMap); inline const std::string &getIfaceName() const { return m_iface_; } inline const std::string &getCanID() const { return m_canid_; } + + inline std::string getLabel() const { + if (m_data_verbose_ && !m_data_verbose_->is_null() && m_data_verbose_->contains("Label")) { + return (*m_data_verbose_)["Label"].get(); + } + + return {}; + } + inline size_t getDataSize() const { return m_data_.size(); } inline const std::vector &getData() const { return m_data_; } @@ -37,8 +48,8 @@ public: inline ftxui::Component getSpnSettingsForm() { return m_spnSettingsForm_; } inline const auto &getParametersExportMap() const { return s_canbus_parameters_export_map_; } - void update(const can_frame_data_s &data, const can_frame_diff_s &diff, - std::shared_ptr verbose, std::shared_ptr brief); + void update(const can_frame_data_s &data, const can_frame_diff_s &diff, std::shared_ptr verbose, + std::shared_ptr brief); bool OnEvent(ftxui::Event event) override; @@ -64,6 +75,8 @@ private: static inline std::map< /* canid */ std::string, std::tuple>>> + /* Selected spns to export */ + std::map>>> s_canbus_parameters_export_map_ = {}; }; diff --git a/src/main.cpp b/src/main.cpp index b02667f..10a55d3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -392,6 +392,7 @@ int32_t main(int32_t argc, char *argv[]) { source->request_stop(); } } + if (candump_fd >= 0) { ::close(candump_fd); candump_fd = -1; diff --git a/src/mainform.cpp b/src/mainform.cpp index d015824..4d0cd1f 100644 --- a/src/mainform.cpp +++ b/src/mainform.cpp @@ -3,6 +3,7 @@ #include "tagsettingrow.hpp" #include "tagsettings.hpp" #include +#include #include #include #include @@ -24,10 +25,11 @@ ftxui::Component makeMainForm(ftxui::ScreenInteractive *screen, signals_map_t &s explicit Impl(ftxui::ScreenInteractive *screen, signals_map_t &smap) { static bool canbus_params_export_dialog_shown = false, file_dialog_shown = false, canbus_player_dialog_shown = false, canplayer_is_ready = false; - ; + static float focus_relative = 0.15f; static float canbus_params_focus_relative = 0; static std::string canid_active; + static std::string filter_text; static size_t tags_count = 0u; static std::unordered_map> canid_lookup; static std::atomic database_atomic{nullptr}; @@ -129,10 +131,24 @@ ftxui::Component makeMainForm(ftxui::ScreenInteractive *screen, signals_map_t &s canidsCont, ftxui::Container::Vertical({}), canbus_params_export_dialog, false, false, true, false, canid_active, file_dialog_shown, canbus_params_export_dialog_shown, file_dialog_shown, spnSettingsFormMap, tagSettingsMap); + auto unit = std::static_pointer_cast(new_cmp); unit->update(entry.data, entry.diff, entry.verbose, entry.brief); canid_lookup[entry.canid] = unit; - canidsCont->Add(new_cmp); + + canidsCont->Add(ftxui::Maybe(new_cmp, [unit]() -> bool { + if (filter_text.empty()) { + return true; + } + + try { + boost::regex re(filter_text, boost::regex_constants::icase); + std::string subject = unit->getCanID() + " " + unit->getLabel(); + return boost::regex_search(subject, re); + } catch (...) { + return true; + } + })); } } }); @@ -170,14 +186,40 @@ ftxui::Component makeMainForm(ftxui::ScreenInteractive *screen, signals_map_t &s fmt::format(" Uptime: {} ", fmt::format("{:02}:{:02}:{:02}", hours, minutes, seconds)))}); }), - ftxui::Renderer([]() { - return ftxui::hbox({ - ftxui::separator(), - ftxui::filler(), - ftxui::separator(), - }) | - ftxui::xflex; - }), + ftxui::Renderer([]() { return ftxui::separator(); }), + ftxui::Container::Horizontal({ + ftxui::Input({ + .content = &filter_text, + .placeholder = "regex filter ...", + .transform = [](ftxui::InputState state) -> ftxui::Element { + bool valid = true; + + if (!filter_text.empty()) { + try { + boost::regex(filter_text, boost::regex_constants::icase); + } catch (...) { + valid = false; + } + } + + state.element |= (!valid ? ftxui::color(ftxui::Color::Red) : ftxui::nothing) | + (state.focused ? ftxui::color(ftxui::Color::Cyan) : ftxui::nothing) | + (state.hovered ? ftxui::bold : ftxui::nothing); + + return ftxui::hbox({ + ftxui::text(" Search: [ "), + state.element | + (state.hovered || state.focused ? ftxui::bgcolor(ftxui::Color::Grey11) + : ftxui::nothing) | + ftxui::flex, + ftxui::text(" ]"), + }) | + ftxui::flex; + }, + }), + }) | ftxui::flex, + + ftxui::Renderer([]() { return ftxui::separator(); }), ftxui::Checkbox({ .transform = [this](const ftxui::EntryState &state) -> ftxui::Element {