Move most Command variables into the CommandController shared variables (#3824)
This commit is contained in:
@@ -41,6 +41,7 @@
|
|||||||
- Dev: Overhaul highlight system by moving all checks into a Controller allowing for easier tests. (#3399, #3801)
|
- Dev: Overhaul highlight system by moving all checks into a Controller allowing for easier tests. (#3399, #3801)
|
||||||
- Dev: Use Game Name returned by Get Streams instead of querying it from the Get Games API. (#3662)
|
- Dev: Use Game Name returned by Get Streams instead of querying it from the Get Games API. (#3662)
|
||||||
- Dev: Batch checking live status for all channels after startup. (#3757, #3762, #3767)
|
- Dev: Batch checking live status for all channels after startup. (#3757, #3762, #3767)
|
||||||
|
- Dev: Move most command context into the command controller. (#3824)
|
||||||
|
|
||||||
## 2.3.5
|
## 2.3.5
|
||||||
|
|
||||||
|
|||||||
@@ -177,80 +177,213 @@ bool appendWhisperMessageStringLocally(const QString &textNoEmoji)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::function<QString(const QString &, const ChannelPtr &)>
|
using VariableReplacer = std::function<QString(
|
||||||
noOpPlaceholder = [](const auto &altText, const auto &channel) {
|
const QString &, const ChannelPtr &, const Message *)>;
|
||||||
|
|
||||||
|
const VariableReplacer NO_OP_PLACEHOLDER =
|
||||||
|
[](const auto &altText, const auto &channel, const auto *message) {
|
||||||
return altText;
|
return altText;
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::map<QString,
|
const std::unordered_map<QString, VariableReplacer> COMMAND_VARS{
|
||||||
std::function<QString(const QString &, const ChannelPtr &)>>
|
{
|
||||||
COMMAND_VARS{
|
"channel.name",
|
||||||
{
|
[](const auto &altText, const auto &channel, const auto *message) {
|
||||||
"channel.name",
|
(void)(altText); //unused
|
||||||
[](const auto &altText, const auto &channel) {
|
(void)(message); //unused
|
||||||
(void)(altText); //unused
|
return channel->getName();
|
||||||
return channel->getName();
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
},
|
||||||
"channel.id",
|
{
|
||||||
[](const auto &altText, const auto &channel) {
|
"channel.id",
|
||||||
auto *tc = dynamic_cast<TwitchChannel *>(channel.get());
|
[](const auto &altText, const auto &channel, const auto *message) {
|
||||||
if (tc == nullptr)
|
(void)(message); //unused
|
||||||
{
|
auto *tc = dynamic_cast<TwitchChannel *>(channel.get());
|
||||||
return altText;
|
if (tc == nullptr)
|
||||||
}
|
{
|
||||||
|
return altText;
|
||||||
|
}
|
||||||
|
|
||||||
return tc->roomId();
|
return tc->roomId();
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
},
|
||||||
"stream.game",
|
{
|
||||||
[](const auto &altText, const auto &channel) {
|
// NOTE: The use of {channel} is deprecated and support for it will drop at some point
|
||||||
auto *tc = dynamic_cast<TwitchChannel *>(channel.get());
|
// Users should be encouraged to use {channel.name} instead.
|
||||||
if (tc == nullptr)
|
"channel",
|
||||||
{
|
[](const auto &altText, const auto &channel, const auto *message) {
|
||||||
return altText;
|
(void)(altText); //unused
|
||||||
}
|
(void)(message); //unused
|
||||||
const auto &status = tc->accessStreamStatus();
|
return channel->getName();
|
||||||
return status->live ? status->game : altText;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
},
|
||||||
"stream.title",
|
{
|
||||||
[](const auto &altText, const auto &channel) {
|
"stream.game",
|
||||||
auto *tc = dynamic_cast<TwitchChannel *>(channel.get());
|
[](const auto &altText, const auto &channel, const auto *message) {
|
||||||
if (tc == nullptr)
|
(void)(message); //unused
|
||||||
{
|
auto *tc = dynamic_cast<TwitchChannel *>(channel.get());
|
||||||
return altText;
|
if (tc == nullptr)
|
||||||
}
|
{
|
||||||
const auto &status = tc->accessStreamStatus();
|
return altText;
|
||||||
return status->live ? status->title : altText;
|
}
|
||||||
},
|
const auto &status = tc->accessStreamStatus();
|
||||||
|
return status->live ? status->game : altText;
|
||||||
},
|
},
|
||||||
{
|
},
|
||||||
"my.id",
|
{
|
||||||
[](const auto &altText, const auto &channel) {
|
"stream.title",
|
||||||
(void)(channel); //unused
|
[](const auto &altText, const auto &channel, const auto *message) {
|
||||||
auto uid = getApp()->accounts->twitch.getCurrent()->getUserId();
|
(void)(message); //unused
|
||||||
return uid.isEmpty() ? altText : uid;
|
auto *tc = dynamic_cast<TwitchChannel *>(channel.get());
|
||||||
},
|
if (tc == nullptr)
|
||||||
|
{
|
||||||
|
return altText;
|
||||||
|
}
|
||||||
|
const auto &status = tc->accessStreamStatus();
|
||||||
|
return status->live ? status->title : altText;
|
||||||
},
|
},
|
||||||
{
|
},
|
||||||
"my.name",
|
{
|
||||||
[](const auto &altText, const auto &channel) {
|
"my.id",
|
||||||
(void)(channel); //unused
|
[](const auto &altText, const auto &channel, const auto *message) {
|
||||||
auto name =
|
(void)(channel); //unused
|
||||||
getApp()->accounts->twitch.getCurrent()->getUserName();
|
(void)(message); //unused
|
||||||
return name.isEmpty() ? altText : name;
|
auto uid = getApp()->accounts->twitch.getCurrent()->getUserId();
|
||||||
},
|
return uid.isEmpty() ? altText : uid;
|
||||||
},
|
},
|
||||||
// variables used in mod buttons and the like, these make no sense in normal commands, so they are left empty
|
},
|
||||||
{"input.text", noOpPlaceholder},
|
{
|
||||||
{"msg.id", noOpPlaceholder},
|
"my.name",
|
||||||
{"user.name", noOpPlaceholder},
|
[](const auto &altText, const auto &channel, const auto *message) {
|
||||||
{"msg.text", noOpPlaceholder},
|
(void)(channel); //unused
|
||||||
};
|
(void)(message); //unused
|
||||||
|
auto name = getApp()->accounts->twitch.getCurrent()->getUserName();
|
||||||
|
return name.isEmpty() ? altText : name;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"user.name",
|
||||||
|
[](const auto &altText, const auto &channel, const auto *message) {
|
||||||
|
(void)(channel); //unused
|
||||||
|
if (message == nullptr)
|
||||||
|
{
|
||||||
|
return altText;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &v = message->loginName;
|
||||||
|
|
||||||
|
if (v.isEmpty())
|
||||||
|
{
|
||||||
|
return altText;
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// NOTE: The use of {user} is deprecated and support for it will drop at some point
|
||||||
|
// Users should be encouraged to use {user.name} instead.
|
||||||
|
"user",
|
||||||
|
[](const auto &altText, const auto &channel, const auto *message) {
|
||||||
|
(void)(channel); //unused
|
||||||
|
if (message == nullptr)
|
||||||
|
{
|
||||||
|
return altText;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &v = message->loginName;
|
||||||
|
|
||||||
|
if (v.isEmpty())
|
||||||
|
{
|
||||||
|
return altText;
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"msg.id",
|
||||||
|
[](const auto &altText, const auto &channel, const auto *message) {
|
||||||
|
(void)(channel); //unused
|
||||||
|
if (message == nullptr)
|
||||||
|
{
|
||||||
|
return altText;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &v = message->id;
|
||||||
|
|
||||||
|
if (v.isEmpty())
|
||||||
|
{
|
||||||
|
return altText;
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// NOTE: The use of {msg-id} is deprecated and support for it will drop at some point
|
||||||
|
// Users should be encouraged to use {msg.id} instead.
|
||||||
|
"msg-id",
|
||||||
|
[](const auto &altText, const auto &channel, const auto *message) {
|
||||||
|
(void)(channel); //unused
|
||||||
|
if (message == nullptr)
|
||||||
|
{
|
||||||
|
return altText;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &v = message->id;
|
||||||
|
|
||||||
|
if (v.isEmpty())
|
||||||
|
{
|
||||||
|
return altText;
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"msg.text",
|
||||||
|
[](const auto &altText, const auto &channel, const auto *message) {
|
||||||
|
(void)(channel); //unused
|
||||||
|
if (message == nullptr)
|
||||||
|
{
|
||||||
|
return altText;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &v = message->messageText;
|
||||||
|
|
||||||
|
if (v.isEmpty())
|
||||||
|
{
|
||||||
|
return altText;
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// NOTE: The use of {message} is deprecated and support for it will drop at some point
|
||||||
|
// Users should be encouraged to use {msg.text} instead.
|
||||||
|
"message",
|
||||||
|
[](const auto &altText, const auto &channel, const auto *message) {
|
||||||
|
(void)(channel); //unused
|
||||||
|
if (message == nullptr)
|
||||||
|
{
|
||||||
|
return altText;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &v = message->messageText;
|
||||||
|
|
||||||
|
if (v.isEmpty())
|
||||||
|
{
|
||||||
|
return altText;
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// variables used in mod buttons and the like, these make no sense in normal commands, so they are left empty
|
||||||
|
{"input.text", NO_OP_PLACEHOLDER},
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@@ -1120,10 +1253,10 @@ void CommandController::registerCommand(QString commandName,
|
|||||||
this->defaultChatterinoCommandAutoCompletions_.append(commandName);
|
this->defaultChatterinoCommandAutoCompletions_.append(commandName);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString CommandController::execCustomCommand(const QStringList &words,
|
QString CommandController::execCustomCommand(
|
||||||
const Command &command,
|
const QStringList &words, const Command &command, bool dryRun,
|
||||||
bool dryRun, ChannelPtr channel,
|
ChannelPtr channel, const Message *message,
|
||||||
std::map<QString, QString> context)
|
std::unordered_map<QString, QString> context)
|
||||||
{
|
{
|
||||||
QString result;
|
QString result;
|
||||||
|
|
||||||
@@ -1167,20 +1300,21 @@ QString CommandController::execCustomCommand(const QStringList &words,
|
|||||||
|
|
||||||
if (var != context.end())
|
if (var != context.end())
|
||||||
{
|
{
|
||||||
|
// Found variable in `context`
|
||||||
result += var->second.isEmpty() ? altText : var->second;
|
result += var->second.isEmpty() ? altText : var->second;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
auto it = COMMAND_VARS.find(varName);
|
||||||
|
if (it != COMMAND_VARS.end())
|
||||||
{
|
{
|
||||||
auto it = COMMAND_VARS.find(varName);
|
// Found variable in `COMMAND_VARS`
|
||||||
if (it != COMMAND_VARS.end())
|
result += it->second(altText, channel, message);
|
||||||
{
|
continue;
|
||||||
result += it->second(altText, channel);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result += "{" + match.captured(3) + "}";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fall back to replacing it with the actual matched string
|
||||||
|
result += "{" + match.captured(3) + "}";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
@@ -34,9 +35,10 @@ public:
|
|||||||
|
|
||||||
CommandModel *createModel(QObject *parent);
|
CommandModel *createModel(QObject *parent);
|
||||||
|
|
||||||
QString execCustomCommand(const QStringList &words, const Command &command,
|
QString execCustomCommand(
|
||||||
bool dryRun, ChannelPtr channel,
|
const QStringList &words, const Command &command, bool dryRun,
|
||||||
std::map<QString, QString> context = {});
|
ChannelPtr channel, const Message *message = nullptr,
|
||||||
|
std::unordered_map<QString, QString> context = {});
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void load(Paths &paths);
|
void load(Paths &paths);
|
||||||
|
|||||||
@@ -2125,20 +2125,12 @@ void ChannelView::addCommandExecutionContextMenuItems(
|
|||||||
{
|
{
|
||||||
userText = split->getInput().getInputText();
|
userText = split->getInput().getInputText();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Execute command through right-clicking a message -> Execute command
|
||||||
QString value = getApp()->commands->execCustomCommand(
|
QString value = getApp()->commands->execCustomCommand(
|
||||||
inputText.split(' '), cmd, true, channel,
|
inputText.split(' '), cmd, true, channel, layout->getMessage(),
|
||||||
{
|
{
|
||||||
{"user.name", layout->getMessage()->loginName},
|
|
||||||
{"msg.id", layout->getMessage()->id},
|
|
||||||
{"msg.text", layout->getMessage()->messageText},
|
|
||||||
{"input.text", userText},
|
{"input.text", userText},
|
||||||
|
|
||||||
// old placeholders
|
|
||||||
{"user", layout->getMessage()->loginName},
|
|
||||||
{"msg-id", layout->getMessage()->id},
|
|
||||||
{"message", layout->getMessage()->messageText},
|
|
||||||
|
|
||||||
{"channel", this->channel()->getName()},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
value = getApp()->commands->execCommand(value, channel, false);
|
value = getApp()->commands->execCommand(value, channel, false);
|
||||||
@@ -2283,21 +2275,10 @@ void ChannelView::handleLinkClick(QMouseEvent *event, const Link &link,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Execute command clicking a moderator button
|
||||||
value = getApp()->commands->execCustomCommand(
|
value = getApp()->commands->execCustomCommand(
|
||||||
QStringList(), Command{"(modaction)", value}, true, channel,
|
QStringList(), Command{"(modaction)", value}, true, channel,
|
||||||
{
|
layout->getMessage());
|
||||||
{"user.name", layout->getMessage()->loginName},
|
|
||||||
{"msg.id", layout->getMessage()->id},
|
|
||||||
{"msg.text", layout->getMessage()->messageText},
|
|
||||||
|
|
||||||
// old placeholders
|
|
||||||
{"user", layout->getMessage()->loginName},
|
|
||||||
{"msg-id", layout->getMessage()->id},
|
|
||||||
{"message", layout->getMessage()->messageText},
|
|
||||||
|
|
||||||
// new version of this is inside execCustomCommand
|
|
||||||
{"channel", this->channel()->getName()},
|
|
||||||
});
|
|
||||||
|
|
||||||
value = getApp()->commands->execCommand(value, channel, false);
|
value = getApp()->commands->execCommand(value, channel, false);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user