reapack

Package manager for REAPER
Log | Files | Refs | Submodules | README | LICENSE

commit c9730b4afaa95d6fdf7258a697e5608fac5d3456
parent eada515538eb5f0a63f31c15c04b6dfa56934f46
Author: cfillion <cfillion@users.noreply.github.com>
Date:   Thu,  6 Jan 2022 01:44:28 -0500

filter: match synonymous words [p=2512900]

Diffstat:
Msrc/filter.cpp | 46++++++++++++++++++++++++++++++++++++++++++++--
Msrc/filter.hpp | 1+
Mtest/filter.cpp | 42++++++++++++++++++++++++++++++++++++++++++
3 files changed, 87 insertions(+), 2 deletions(-)

diff --git a/src/filter.cpp b/src/filter.cpp @@ -17,7 +17,7 @@ #include "filter.hpp" -#include <boost/algorithm/string/case_conv.hpp> +#include <boost/algorithm/string.hpp> Filter::Filter(const std::string &input) : m_root(Group::MatchAll) @@ -102,7 +102,7 @@ Filter::Group *Filter::Group::push(const std::string &buf, int *flags) if(!(*flags & LiteralFlag)) { if(buf == "NOT") { - *flags ^= Token::NotFlag; + *flags ^= NotFlag; return this; } else if(buf == "OR") { @@ -133,6 +133,8 @@ Filter::Group *Filter::Group::push(const std::string &buf, int *flags) return this; } + else if(pushSynonyms(buf, flags)) + return this; } m_nodes.push_back(std::make_unique<Token>(buf, *flags)); @@ -153,6 +155,46 @@ Filter::Group *Filter::Group::addSubGroup(const Type type, const int flags) return ptr; } +bool Filter::Group::pushSynonyms(const std::string &buf, int *flags) +{ + static const std::vector<std::string> synonyms[] { + { "open", "display", "view", "show", "hide" }, + { "delete", "clear", "remove", "erase" }, + { "insert", "add" }, + { "deselect", "unselect" }, + }; + + auto *match = [&]() -> decltype(&*synonyms) { + for(const auto &synonym : synonyms) { + for(const auto &word : synonym) { + if(boost::iequals(buf, word)) + return &synonym; + } + } + return nullptr; + }(); + + if(!match) + return false; + + Group *notGroup; + if(*flags & NotFlag) { + notGroup = addSubGroup(MatchAll, NotFlag); + *flags ^= NotFlag; + } + else + notGroup = this; + + Group *orGroup = notGroup->addSubGroup(MatchAny, 0); + if(!(*flags & FullWordFlag)) + orGroup->m_nodes.push_back(std::make_unique<Token>(buf, *flags)); + for(const auto &word : *match) + orGroup->m_nodes.push_back(std::make_unique<Token>(word, *flags | FullWordFlag)); + + *flags = 0; + return true; +} + bool Filter::Group::match(const std::vector<std::string> &rows) const { for(const auto &node : m_nodes) { diff --git a/src/filter.hpp b/src/filter.hpp @@ -71,6 +71,7 @@ private: private: Group *addSubGroup(Type, int flags); + bool pushSynonyms(const std::string &, int *flags); Group *m_parent; Type m_type; diff --git a/test/filter.cpp b/test/filter.cpp @@ -363,3 +363,45 @@ TEST_CASE("AND grouping", M) { REQUIRE(f.match({"d"})); } } + +TEST_CASE("synonymous words", M) { + Filter f; + + SECTION("basic") { + f.set("open"); + REQUIRE(f.match({"open"})); + REQUIRE(f.match({"display"})); + REQUIRE_FALSE(f.match({"door"})); + } + + SECTION("case-insensitive") { + f.set("OPEN"); + REQUIRE(f.match({"display"})); + } + + SECTION("full-word synonyms") { + f.set("unselect"); + REQUIRE(f.match({"unselect"})); + REQUIRE(f.match({"unselected"})); + REQUIRE(f.match({"deselect"})); + REQUIRE_FALSE(f.match({"deselected"})); + } + + SECTION("preserve anchor flags") { + f.set("^insert"); + REQUIRE(f.match({"add"})); + REQUIRE_FALSE(f.match({"don't add"})); + REQUIRE_FALSE(f.match({"not inserting things"})); + } + + SECTION("NOT applies to all synonyms") { + f.set("NOT open"); + REQUIRE(f.match({"foo bar"})); + REQUIRE_FALSE(f.match({"open display"})); + } + + SECTION("clear flags for the next token") { + f.set("^open bar"); + REQUIRE(f.match({"open bar"})); + } +}