keys: implement support for a few macro utilities
This commit is contained in:
@@ -59,6 +59,8 @@ struct Action
|
||||
const char *Name() const { return itsName; }
|
||||
ActionType Type() const { return itsType; }
|
||||
|
||||
virtual bool canBeRun() const { return true; }
|
||||
|
||||
bool Execute()
|
||||
{
|
||||
if (canBeRun())
|
||||
@@ -78,7 +80,7 @@ struct Action
|
||||
static bool AskYesNoQuestion(const std::string &question, void (*callback)());
|
||||
static bool isMPDMusicDirSet();
|
||||
|
||||
static Action *Get(ActionType);
|
||||
static Action *Get(ActionType at);
|
||||
static Action *Get(const std::string &name);
|
||||
|
||||
static bool OriginalStatusbarVisibility;
|
||||
@@ -91,7 +93,6 @@ struct Action
|
||||
static size_t FooterStartY;
|
||||
|
||||
protected:
|
||||
virtual bool canBeRun() const { return true; }
|
||||
virtual void Run() = 0;
|
||||
|
||||
static void Seek();
|
||||
|
||||
72
src/keys.cpp
72
src/keys.cpp
@@ -20,8 +20,8 @@
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include "global.h"
|
||||
#include "keys.h"
|
||||
#include "utility/comparators.h"
|
||||
#include "utility/string.h"
|
||||
|
||||
KeyConfiguration Keys;
|
||||
@@ -30,7 +30,7 @@ Key Key::noOp = Key(ERR, NCurses);
|
||||
|
||||
namespace {//
|
||||
|
||||
Key stringToKey(const std::string &s)
|
||||
Key stringToSpecialKey(const std::string &s)
|
||||
{
|
||||
Key result = Key::noOp;
|
||||
if (!s.compare("mouse"))
|
||||
@@ -73,7 +73,13 @@ Key stringToKey(const std::string &s)
|
||||
result = Key(KEY_BACKSPACE, Key::NCurses);
|
||||
else if (!s.compare("backspace_2"))
|
||||
result = Key(KEY_BACKSPACE_2, Key::Standard);
|
||||
else
|
||||
return result;
|
||||
}
|
||||
|
||||
Key stringToKey(const std::string &s)
|
||||
{
|
||||
Key result = stringToSpecialKey(s);
|
||||
if (result == Key::noOp)
|
||||
{
|
||||
std::wstring ws = ToWString(s);
|
||||
if (ws.length() == 1)
|
||||
@@ -82,6 +88,56 @@ Key stringToKey(const std::string &s)
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
Action *parseActionLine(const std::string &line, F error)
|
||||
{
|
||||
Action *result = 0;
|
||||
size_t i = 0;
|
||||
for (; i < line.size() && !isspace(line[i]); ++i) { }
|
||||
if (i == line.size()) // only action name
|
||||
result = Action::Get(line);
|
||||
else // there is something else
|
||||
{
|
||||
std::string action_name = line.substr(0, i);
|
||||
if (action_name == "push_character")
|
||||
{
|
||||
// push single character into input queue
|
||||
std::string arg = getEnclosedString(line, '"', '"', 0);
|
||||
Key k = stringToSpecialKey(arg);
|
||||
if (k != Key::noOp)
|
||||
result = new PushCharacters(&Global::wFooter, { k.getChar() });
|
||||
else
|
||||
error() << "invalid argument to function push_character: '" << arg << "'\n";
|
||||
}
|
||||
else if (action_name == "push_characters")
|
||||
{
|
||||
// push sequence of characters into input queue
|
||||
std::string arg = getEnclosedString(line, '"', '"', 0);
|
||||
if (!arg.empty())
|
||||
{
|
||||
std::vector<int> queue(arg.begin(), arg.end());
|
||||
// if char is signed, cancel 1s from char -> int conversion
|
||||
for (auto it = arg.begin(); it != arg.end(); ++it)
|
||||
*it &= 0xff;
|
||||
result = new PushCharacters(&Global::wFooter, std::move(queue));
|
||||
}
|
||||
else
|
||||
error() << "push_characters requires its argument to be non-empty";
|
||||
}
|
||||
else if (action_name == "require_runnable")
|
||||
{
|
||||
// require that given action is runnable
|
||||
std::string arg = getEnclosedString(line, '"', '"', 0);
|
||||
Action *action = Action::Get(arg);
|
||||
if (action)
|
||||
result = new RequireRunnable(action);
|
||||
else
|
||||
error() << "invalid action passed as argument to require_runnable: '" << arg << "'\n";
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Key Key::read(NC::Window &w)
|
||||
@@ -138,6 +194,7 @@ bool KeyConfiguration::read(const std::string &file)
|
||||
result = false;
|
||||
return std::cerr;
|
||||
};
|
||||
|
||||
auto bind_key_def = [&]() -> bool {
|
||||
if (!actions.empty())
|
||||
{
|
||||
@@ -147,7 +204,7 @@ bool KeyConfiguration::read(const std::string &file)
|
||||
}
|
||||
else
|
||||
{
|
||||
error() << "definition of key \"" << strkey << "\" cannot be empty.\n";
|
||||
error() << "definition of key '" << strkey << "' cannot be empty.\n";
|
||||
return false;
|
||||
}
|
||||
};
|
||||
@@ -170,19 +227,19 @@ bool KeyConfiguration::read(const std::string &file)
|
||||
key = stringToKey(strkey);
|
||||
if (key == Key::noOp)
|
||||
{
|
||||
error() << "invalid key: \"" << strkey << "\"\n";
|
||||
error() << "invalid key: '" << strkey << "'\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (isspace(line[0])) // name of action to be bound
|
||||
{
|
||||
trim(line);
|
||||
Action *action = Action::Get(line);
|
||||
Action *action = parseActionLine(line, error);
|
||||
if (action)
|
||||
actions.push_back(action);
|
||||
else
|
||||
{
|
||||
error() << "unknown action: \"" << line << "\"\n";
|
||||
error() << "unknown action: '" << line << "'\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -191,7 +248,6 @@ bool KeyConfiguration::read(const std::string &file)
|
||||
bind_key_def();
|
||||
f.close();
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
void KeyConfiguration::generateBindings()
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include <cassert>
|
||||
#include "actions.h"
|
||||
#include "macro_utilities.h"
|
||||
|
||||
/// Key for binding actions to it. Supports non-ascii characters.
|
||||
struct Key
|
||||
|
||||
@@ -18,34 +18,37 @@
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef _MACRO_UTILITIES
|
||||
#define _MACRO_UTILITIES
|
||||
|
||||
#include <cassert>
|
||||
#include "actions.h"
|
||||
|
||||
struct PushCharacters : public Action
|
||||
{
|
||||
template <typename Iterator> PushCharacters(Window **w, Iterator first, Iterator last) : Action(aMacroUtility, "")
|
||||
{
|
||||
construct(w, first, last);
|
||||
PushCharacters(NC::Window **w, std::vector<int> &&queue)
|
||||
: Action(aMacroUtility, ""), m_window(w), m_queue(queue) { }
|
||||
|
||||
virtual void Run() {
|
||||
for (auto it = m_queue.begin(); it != m_queue.end(); ++it)
|
||||
(*m_window)->pushChar(*it);
|
||||
}
|
||||
|
||||
PushCharacters(Window **w, const std::initializer_list<int> &v) : Action(aMacroUtility, "")
|
||||
{
|
||||
construct(w, v.begin(), v.end());
|
||||
}
|
||||
|
||||
virtual void Run()
|
||||
{
|
||||
for (auto it = itsQueue.begin(); it != itsQueue.end(); ++it)
|
||||
(*itsWindow)->PushChar(*it);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename Iterator> void construct(Window **w, Iterator first, Iterator last)
|
||||
{
|
||||
itsWindow = w;
|
||||
for (; first != last; ++first)
|
||||
itsQueue.push_back(*first);
|
||||
}
|
||||
|
||||
Window **itsWindow;
|
||||
std::vector<int> itsQueue;
|
||||
private:
|
||||
NC::Window **m_window;
|
||||
std::vector<int> m_queue;
|
||||
};
|
||||
|
||||
struct RequireRunnable : public Action
|
||||
{
|
||||
RequireRunnable(Action *action)
|
||||
: Action(aMacroUtility, ""), m_action(action) { assert(action); }
|
||||
|
||||
virtual bool canBeRun() const { return m_action->canBeRun(); }
|
||||
virtual void Run() { }
|
||||
|
||||
private:
|
||||
Action *m_action;
|
||||
};
|
||||
|
||||
#endif // _MACRO_UTILITIES
|
||||
|
||||
Reference in New Issue
Block a user