bindings: allow for binding multiple chains to one key

This commit is contained in:
Andrzej Rybczak
2014-08-27 01:15:28 +02:00
parent afd5c22acf
commit a7f3992c97
5 changed files with 36 additions and 53 deletions

View File

@@ -22,17 +22,12 @@
## action2 ## action2
## ... ## ...
## ##
## This creates chain of actions. When such chain is ## This creates a chain of actions. When such chain is
## executed, each action in chain is run until the end of ## executed, each action in chain is run until the end of
## chain is reached or one of actions failed to execute ## chain is reached or one of its actions fails to execute
## due to its requirements not being met. Note that ## due to its requirements not being met. If multiple actions
## execution of chain of actions ALWAYS succeeds, no ## and/or chains are bound to the same key, they will be
## matter if one of actions from the chain failed (even ## consecutively run until one of them gets fully executed.
## if it was the first one in order and thus nothing
## was really executed). Because of that, if you decide
## to bind both actions and chains to a single key, make
## sure that chain is defined in the end. Otherwise, all
## actions bound to the key after chain will never be run.
## ##
## 3) When ncmpcpp starts, bindings configuration file is ## 3) When ncmpcpp starts, bindings configuration file is
## parsed and then ncmpcpp provides "missing pieces" ## parsed and then ncmpcpp provides "missing pieces"

View File

@@ -826,7 +826,8 @@ void ExecuteCommand::run()
if (cmd) if (cmd)
{ {
Statusbar::msg(1, "Executing %s...", cmd_name.c_str()); Statusbar::msg(1, "Executing %s...", cmd_name.c_str());
cmd->binding().execute(); bool res = cmd->binding().execute();
Statusbar::msg("Execution %s.", res ? "successful" : "unsuccessful");
} }
else else
Statusbar::msg("No command named \"%s\"", cmd_name.c_str()); Statusbar::msg("No command named \"%s\"", cmd_name.c_str());

View File

@@ -233,7 +233,7 @@ bool BindingsConfiguration::read(const std::string &file)
{ {
if (!actions.empty()) if (!actions.empty())
{ {
m_commands.insert(std::make_pair(cmd_name, Command(actions, cmd_immediate))); m_commands.insert(std::make_pair(cmd_name, Command(std::move(actions), cmd_immediate)));
actions.clear(); actions.clear();
return true; return true;
} }

View File

@@ -21,6 +21,8 @@
#ifndef NCMPCPP_BINDINGS_H #ifndef NCMPCPP_BINDINGS_H
#define NCMPCPP_BINDINGS_H #define NCMPCPP_BINDINGS_H
#include <algorithm>
#include <boost/bind.hpp>
#include <cassert> #include <cassert>
#include <unordered_map> #include <unordered_map>
#include "actions.h" #include "actions.h"
@@ -74,57 +76,43 @@ struct Binding
{ {
typedef std::vector<Actions::BaseAction *> ActionChain; typedef std::vector<Actions::BaseAction *> ActionChain;
Binding(Actions::Type at) : m_is_single(true), m_action(&Actions::get(at)) { } template <typename ArgT>
Binding(const ActionChain &actions) { Binding(ArgT &&actions)
assert(actions.size() > 0); : m_actions(std::forward<ArgT>(actions)) {
if (actions.size() == 1) { assert(!m_actions.empty());
m_is_single = true;
m_action = actions[0];
} else {
m_is_single = false;
m_chain = new ActionChain(actions);
}
} }
Binding(Actions::Type at)
: Binding(ActionChain({&Actions::get(at)})) { }
bool execute() const { bool execute() const {
bool result = false; return std::all_of(m_actions.begin(), m_actions.end(),
if (m_is_single) { boost::bind(&Actions::BaseAction::execute, _1)
assert(m_action); );
result = m_action->execute();
} else {
for (auto it = m_chain->begin(); it != m_chain->end(); ++it)
if (!(*it)->execute())
break;
result = true;
}
return result;
} }
bool isSingle() const { bool isSingle() const {
return m_is_single; return m_actions.size() == 1;
}
ActionChain *chain() const {
assert(!m_is_single);
return m_chain;
} }
Actions::BaseAction *action() const { Actions::BaseAction *action() const {
assert(m_is_single); assert(isSingle());
return m_action; return m_actions[0];
} }
const ActionChain &actions() const {
return m_actions;
}
private: private:
bool m_is_single; ActionChain m_actions;
union {
Actions::BaseAction *m_action;
ActionChain *m_chain;
};
}; };
/// Represents executable command /// Represents executable command
struct Command struct Command
{ {
Command(const Binding &binding_, bool immediate_) template <typename ArgT>
: m_binding(binding_), m_immediate(immediate_) { } Command(ArgT &&binding_, bool immediate_)
: m_binding(std::forward<ArgT>(binding_)), m_immediate(immediate_) { }
const Binding &binding() const { return m_binding; } const Binding &binding() const { return m_binding; }
bool immediate() const { return m_immediate; } bool immediate() const { return m_immediate; }
@@ -182,8 +170,9 @@ private:
return k != Key::noOp && m_bindings.find(k) == m_bindings.end(); return k != Key::noOp && m_bindings.find(k) == m_bindings.end();
} }
template <typename T> void bind(Key k, const T &t) { template <typename ArgT>
m_bindings[k].push_back(Binding(t)); void bind(Key k, ArgT &&t) {
m_bindings[k].push_back(std::forward<ArgT>(t));
} }
BindingsMap m_bindings; BindingsMap m_bindings;

View File

@@ -256,9 +256,7 @@ int main(int argc, char **argv)
try try
{ {
auto k = Bindings.get(input); auto k = Bindings.get(input);
for (; k.first != k.second; ++k.first) std::any_of(k.first, k.second, boost::bind(&Binding::execute, _1));
if (k.first->execute())
break;
} }
catch (ConversionError &e) catch (ConversionError &e)
{ {