feat(ipc): hook, prev, next, reset module actions (#2528)
* WIP ipc actions * feat(ipc): Add hook, prev, next and reset actions Closes: #2464 * ipc: format code * ipc: fix comparison * Apply suggestions from code review Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * ipc: make index 0-based * ipc: add 0-based indexing breaking change to Changelog * ipc: restore 1-based index for and message * ipc: fix initial=0 throwing an error Co-authored-by: Martin Terneborg <martinterneborg@protonmail.com> Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com>
This commit is contained in:
parent
22014c70c4
commit
231af35354
@ -132,6 +132,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
([`#1441`](https://github.com/polybar/polybar/issues/1441))
|
||||
- `internal/xkeyboard`: Allow configuring icons using variant
|
||||
([`#2414`](https://github.com/polybar/polybar/issues/2414))
|
||||
- `custom/ipc`: Add `hook`, `next`, `prev`, `reset` actions to the ipc module
|
||||
([`#2464`](https://github.com/polybar/polybar/issues/2464))
|
||||
|
||||
### Changed
|
||||
- Polybar now also reads `config.ini` when searching for config files.
|
||||
|
@ -261,10 +261,17 @@ custom/menu
|
||||
custom/ipc
|
||||
^^^^^^^^^^
|
||||
|
||||
:``send``: *(Has Data)* Replace the contents of the module with the data passed in this action.
|
||||
|
||||
.. versionadded:: 3.6.0
|
||||
|
||||
:``send``: *(Has Data)* Replace the contents of the module with the data passed in this action.
|
||||
:``hook``: *(Has Data)* Trigger the given hook.
|
||||
|
||||
The data is the 0-based index of the hook to trigger.
|
||||
:``next``: Switches to the next hook and wrap around when the last hook was displayed.
|
||||
:``prev``: Switches to the previous hook and wrap around when the first hook was displayed.
|
||||
:``reset``: Reset the module to its startup state: either empty or according to the ``initial`` setting.
|
||||
|
||||
|
||||
Deprecated Action Names
|
||||
-----------------------
|
||||
|
||||
|
@ -35,9 +35,17 @@ namespace modules {
|
||||
static constexpr auto TYPE = "custom/ipc";
|
||||
|
||||
static constexpr auto EVENT_SEND = "send";
|
||||
static constexpr auto EVENT_HOOK = "hook";
|
||||
static constexpr auto EVENT_NEXT = "next";
|
||||
static constexpr auto EVENT_PREV = "prev";
|
||||
static constexpr auto EVENT_RESET = "reset";
|
||||
|
||||
protected:
|
||||
void action_send(const string& data);
|
||||
void action_hook(const string& data);
|
||||
void action_next();
|
||||
void action_prev();
|
||||
void action_reset();
|
||||
|
||||
private:
|
||||
static constexpr const char* TAG_OUTPUT{"<output>"};
|
||||
@ -45,6 +53,8 @@ namespace modules {
|
||||
map<mousebtn, string> m_actions;
|
||||
string m_output;
|
||||
size_t m_initial;
|
||||
size_t m_current_hook;
|
||||
void exec_hook();
|
||||
};
|
||||
} // namespace modules
|
||||
|
||||
|
@ -14,8 +14,12 @@ namespace modules {
|
||||
* Load user-defined ipc hooks and
|
||||
* create formatting tags
|
||||
*/
|
||||
ipc_module::ipc_module(const bar_settings& bar, string name_) : module<ipc_module>(bar, move(name_)) {
|
||||
ipc_module::ipc_module(const bar_settings& bar, string name_) : module<ipc_module>(bar, move(name_)), m_initial(0) {
|
||||
m_router->register_action_with_data(EVENT_SEND, [this](const std::string& data) { action_send(data); });
|
||||
m_router->register_action_with_data(EVENT_HOOK, [this](const std::string& data) { action_hook(data); });
|
||||
m_router->register_action(EVENT_NEXT, [this]() { action_next(); });
|
||||
m_router->register_action(EVENT_PREV, [this]() { action_prev(); });
|
||||
m_router->register_action(EVENT_RESET, [this]() { action_reset(); });
|
||||
|
||||
size_t index = 0;
|
||||
|
||||
@ -25,8 +29,16 @@ namespace modules {
|
||||
|
||||
m_log.info("%s: Loaded %d hooks", name(), m_hooks.size());
|
||||
|
||||
if ((m_initial = m_conf.get(name(), "initial", 0_z)) && m_initial > m_hooks.size()) {
|
||||
throw module_error("Initial hook out of bounds (defined: " + to_string(m_hooks.size()) + ")");
|
||||
m_initial = m_conf.get(name(), "initial", 0_z);
|
||||
if (m_conf.has(name(), "initial") && m_initial != 0) {
|
||||
if (m_initial <= m_hooks.size()) {
|
||||
m_current_hook = m_initial - 1;
|
||||
} else {
|
||||
throw module_error("Initial hook out of bounds '" + to_string(m_initial) + "'. Defined hooks goes from 1 to " +
|
||||
to_string(m_hooks.size()) + ")");
|
||||
}
|
||||
} else {
|
||||
m_current_hook = m_hooks.size();
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
@ -62,11 +74,9 @@ namespace modules {
|
||||
broadcast();
|
||||
});
|
||||
|
||||
if (m_initial) {
|
||||
if (m_initial != 0) {
|
||||
// TODO do this in a thread.
|
||||
auto command = command_util::make_command<output_policy::REDIRECTED>(m_hooks.at(m_initial - 1)->command);
|
||||
command->exec(false);
|
||||
command->tail([this](string line) { m_output = line; });
|
||||
exec_hook();
|
||||
}
|
||||
}
|
||||
|
||||
@ -107,25 +117,14 @@ namespace modules {
|
||||
* execute its command
|
||||
*/
|
||||
void ipc_module::on_message(const string& message) {
|
||||
for (auto&& hook : m_hooks) {
|
||||
if (hook->payload != message) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < m_hooks.size(); i++) {
|
||||
const auto& hook = m_hooks[i];
|
||||
if (hook->payload == message) {
|
||||
m_log.info("%s: Found matching hook (%s)", name(), hook->payload);
|
||||
|
||||
try {
|
||||
// Clear the output in case the command produces no output
|
||||
m_output.clear();
|
||||
auto command = command_util::make_command<output_policy::REDIRECTED>(hook->command);
|
||||
command->exec(false);
|
||||
command->tail([this](string line) { m_output = line; });
|
||||
} catch (const exception& err) {
|
||||
m_log.err("%s: Failed to execute hook command (err: %s)", err.what());
|
||||
m_output.clear();
|
||||
m_current_hook = i;
|
||||
this->exec_hook();
|
||||
break;
|
||||
}
|
||||
|
||||
broadcast();
|
||||
}
|
||||
}
|
||||
|
||||
@ -133,6 +132,69 @@ namespace modules {
|
||||
m_output = data;
|
||||
broadcast();
|
||||
}
|
||||
|
||||
void ipc_module::action_hook(const string& data) {
|
||||
try {
|
||||
int hook = std::stoi(data);
|
||||
|
||||
if (hook < 0 || (size_t)hook >= m_hooks.size()) {
|
||||
m_log.err("%s: Hook action received with an out of bounds hook '%s'. Defined hooks goes from 0 to %zu.", name(),
|
||||
data, m_hooks.size() - 1);
|
||||
} else {
|
||||
m_current_hook = hook;
|
||||
this->exec_hook();
|
||||
}
|
||||
} catch (const std::invalid_argument& err) {
|
||||
m_log.err(
|
||||
"%s: Hook action received '%s' cannot be converted to a valid hook index. Defined hooks goes from 0 to %zu.",
|
||||
name(), data, m_hooks.size() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void ipc_module::action_next() {
|
||||
// this is the case where initial is not defined on first 'next'
|
||||
if (m_current_hook == m_hooks.size()) {
|
||||
m_current_hook = 0;
|
||||
} else {
|
||||
m_current_hook = (m_current_hook + 1) % m_hooks.size();
|
||||
}
|
||||
this->exec_hook();
|
||||
}
|
||||
|
||||
void ipc_module::action_prev() {
|
||||
if (m_current_hook == 0) {
|
||||
m_current_hook = m_hooks.size();
|
||||
}
|
||||
m_current_hook--;
|
||||
this->exec_hook();
|
||||
}
|
||||
|
||||
void ipc_module::action_reset() {
|
||||
if (m_initial != 0) {
|
||||
m_current_hook = m_initial - 1;
|
||||
this->exec_hook();
|
||||
} else {
|
||||
m_current_hook = m_hooks.size();
|
||||
m_output.clear();
|
||||
broadcast();
|
||||
}
|
||||
}
|
||||
|
||||
void ipc_module::exec_hook() {
|
||||
// Clear the output in case the command produces no output
|
||||
m_output.clear();
|
||||
|
||||
try {
|
||||
auto command = command_util::make_command<output_policy::REDIRECTED>(m_hooks[m_current_hook]->command);
|
||||
command->exec(false);
|
||||
command->tail([this](string line) { m_output = line; });
|
||||
} catch (const exception& err) {
|
||||
m_log.err("%s: Failed to execute hook command (err: %s)", name(), err.what());
|
||||
m_output.clear();
|
||||
}
|
||||
|
||||
broadcast();
|
||||
}
|
||||
} // namespace modules
|
||||
|
||||
POLYBAR_NS_END
|
||||
|
Loading…
Reference in New Issue
Block a user