Skip to content

Commit

Permalink
Immediately applying system context
Browse files Browse the repository at this point in the history
  • Loading branch information
houmain committed Jan 25, 2021
1 parent 0b74a01 commit ea5fe75
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 20 deletions.
1 change: 1 addition & 0 deletions src/config/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <string>

struct Context {
bool system_filter_matched;
std::string window_class_filter;
std::string window_title_filter;
};
Expand Down
55 changes: 44 additions & 11 deletions src/config/ParseConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,16 +65,18 @@ namespace {
}
} // namespace

Config ParseConfig::operator()(std::istream& is) {
Config ParseConfig::operator()(std::istream& is, bool add_default_mappings) {
m_line_no = 0;
m_config.commands.clear();
m_config.contexts.clear();
m_commands_mapped.clear();
m_macros.clear();

// automatically add mappings for common modifiers
for (auto key : { Key::Shift, Key::Control, Key::AltLeft, Key::AltRight })
add_mapping( { { *key, KeyState::Down } }, { { *key, KeyState::Down } });
if (add_default_mappings) {
// add mappings for immediately passing on common modifiers
for (auto key : { Key::Shift, Key::Control, Key::AltLeft, Key::AltRight })
add_mapping( { { *key, KeyState::Down } }, { { *key, KeyState::Down } });
}

auto line = std::string();
while (is.good()) {
Expand All @@ -88,6 +90,33 @@ Config ParseConfig::operator()(std::istream& is) {
if (!kv.second)
throw ParseError("command '" + kv.first + "' was not mapped");

// remove contexts of other systems
// and apply contexts without class and title filter immediately
auto context_index = 0;
for (auto it = begin(m_config.contexts); it != end(m_config.contexts); ++context_index) {
auto& context = *it;
if (!context.system_filter_matched ||
(context.window_class_filter.empty() &&
context.window_title_filter.empty())) {
for (auto& command : m_config.commands) {
auto& mappings = command.context_mappings;
const auto mapping = std::find_if(cbegin(mappings), cend(mappings),
[&](const ContextMapping& mapping) {
return (mapping.context_index == context_index);
});
if (mapping != cend(mappings)) {
if (context.system_filter_matched)
command.default_mapping = mapping->output;
mappings.erase(mapping);
}
}
it = m_config.contexts.erase(it);
}
else {
++it;
}
}

replace_logical_modifiers(*Key::Shift, *Key::ShiftLeft, *Key::ShiftRight);
replace_logical_modifiers(*Key::Control, *Key::ControlLeft, *Key::ControlRight);
replace_logical_modifiers(*Key::Meta, *Key::MetaLeft, *Key::MetaRight);
Expand Down Expand Up @@ -154,12 +183,16 @@ void ParseConfig::parse_context(It it, const It end) {
auto title_filter = std::string();
auto system_filter_matched = true;

while (it != end) {
do {
const auto attrib = read_ident(&it, end);
if (attrib.empty())
error("identifier expected");

skip_space(&it, end);
if (!skip(&it, end, "="))
error("missing '='");

skip_space(&it, end);
auto value = read_value(&it, end);
if (attrib == "class") {
class_filter = std::move(value);
Expand All @@ -175,13 +208,13 @@ void ParseConfig::parse_context(It it, const It end) {
}
skip_space(&it, end);
}
while (it != end);

// simply set invalid class when system filter did not match
if (!system_filter_matched)
class_filter = "$";

m_config.contexts.push_back(
{ std::move(class_filter), std::move(title_filter) });
m_config.contexts.push_back({
system_filter_matched,
std::move(class_filter),
std::move(title_filter)
});
}

void ParseConfig::parse_mapping(std::string name, It begin, It end) {
Expand Down
2 changes: 1 addition & 1 deletion src/config/ParseConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

class ParseConfig {
public:
Config operator()(std::istream& is);
Config operator()(std::istream& is, bool add_default_mappings = true);

private:
using It = std::string::const_iterator;
Expand Down
58 changes: 50 additions & 8 deletions src/test/test1_ParseConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace {
Config parse_config(const char* config) {
static auto parse = ParseConfig();
auto stream = std::stringstream(config);
return parse(stream);
return parse(stream, false);
}
} // namespace

Expand All @@ -23,11 +23,11 @@ TEST_CASE("Valid config", "[ParseConfig]") {
E >> CommandB
# comment
[window class='test' title=test] # comment
[ system = "Windows" class='test'title=test ] # comment
CommandA >> Y # comment
CommandB >> MyMacro # comment
[window system='Linux'] # comment
[system='Linux'] # comment
CommandA >> Shift{Y} # comment
CommandB >> Shift{MyMacro} # comment
)";
Expand Down Expand Up @@ -75,9 +75,18 @@ TEST_CASE("Problems", "[ParseConfig]") {
)";
REQUIRE_THROWS(parse_config(string));

// empty declarative
string = R"(
C >> CommandA
[]
CommandA >> D
)";
REQUIRE_THROWS(parse_config(string));

// mapping not defined command
string = R"(
[window class='']
[class='']
CommandB >> D
)";
REQUIRE_THROWS(parse_config(string));
Expand All @@ -86,22 +95,22 @@ TEST_CASE("Problems", "[ParseConfig]") {
string = R"(
C >> CommandA
[window class='']
[class='']
CommandA >> D
CommandA >> E
)";
REQUIRE_THROWS(parse_config(string));

// mapping sequence in context
string = R"(
[window class='abc']
[class='abc']
C >> D
)";
REQUIRE_THROWS(parse_config(string));

// defining command in context
string = R"(
[window class='abc']
[class='abc']
C >> CommandA
)";
REQUIRE_THROWS(parse_config(string));
Expand All @@ -110,14 +119,47 @@ TEST_CASE("Problems", "[ParseConfig]") {
string = R"(
C >> CommandA
[window class='']
[class='']
CommandA >> D
)";
REQUIRE_NOTHROW(parse_config(string));
}

//--------------------------------------------------------------------

TEST_CASE("System contexts", "[ParseConfig]") {
auto string = R"(
A >> B
B >> command
[system="Linux"]
command >> L
[system="Linux" title="app"]
command >> X
[system="Windows"]
command >> W
[system="Windows" title="app"]
command >> Y
)";
auto config = parse_config(string);
REQUIRE(config.contexts.size() == 1);
auto commands = config.commands;
REQUIRE(commands.size() == 2);
REQUIRE(commands[0].context_mappings.empty());
REQUIRE(commands[1].context_mappings.size() == 1);
REQUIRE(format_sequence(commands[0].default_mapping) == "+B");
#if defined(__linux__)
REQUIRE(format_sequence(commands[1].default_mapping) == "+L");
#else
REQUIRE(format_sequence(commands[1].default_mapping) == "+W");
#endif
}

//--------------------------------------------------------------------

TEST_CASE("Macros", "[ParseConfig]") {
// correct
auto string = R"(
Expand Down

0 comments on commit ea5fe75

Please sign in to comment.