summaryrefslogtreecommitdiffstats
path: root/src/crsm.cpp
diff options
context:
space:
mode:
authorMarkus Mittendrein <git@maxmitti.tk>2017-06-01 01:33:54 +0200
committerMarkus Mittendrein <git@maxmitti.tk>2017-06-01 12:10:53 +0200
commitccd8b87ba062a99e91f58bbe2e7494bcf3301aee (patch)
tree7374048c5153878eb555a5209fe22259a1b9f460 /src/crsm.cpp
parent8bd7d77ba07d84b7829201befe30c07b12c5568a (diff)
downloadmanager-ccd8b87ba062a99e91f58bbe2e7494bcf3301aee.tar.gz
manager-ccd8b87ba062a99e91f58bbe2e7494bcf3301aee.zip
Correct/suggest command names with the help of damerau levenshtein distance
Diffstat (limited to 'src/crsm.cpp')
-rw-r--r--src/crsm.cpp108
1 files changed, 96 insertions, 12 deletions
diff --git a/src/crsm.cpp b/src/crsm.cpp
index aa1ef13..e187123 100644
--- a/src/crsm.cpp
+++ b/src/crsm.cpp
@@ -245,6 +245,21 @@ bool CRSM::watchdog(const QString& id)
return false;
}
+QString CRSM::cmdErrorText(const QString& command, const ClientInfo& client, bool& ret)
+{
+ QString retText;
+ QStringList corrections;
+ if(!(ret = cmd(command, client, corrections)))
+ {
+ retText = "Unbekannter Befehl: \"" + command + "\"!\n";
+ if(!corrections.isEmpty())
+ {
+ retText += "Meintest du: " + corrections.join(", ") + "?\n";
+ }
+ }
+ return retText;
+}
+
bool CRSM::clientMessage(ClientInfo& client, const QString& message, ClonkOutputInterface::MessageType type, const QTime& time)
{
bool isMeMessage = (type == Action);
@@ -281,11 +296,16 @@ bool CRSM::clientMessage(ClientInfo& client, const QString& message, ClonkOutput
QString command = getCommand(message);
if(!command.isEmpty())
{
- if(!cmd(command, client))
+ bool ret;
+ const QString& txt = cmdErrorText(command, client, ret);
+ if(ret)
+ {
+ return true;
+ }
+ else
{
- respond(client, "Unbekannter Befehl: \"" + command + "\"!\n");
+ respond(client, txt);
}
- return true;
}
}
}
@@ -699,7 +719,8 @@ void CRSM::newManagementData()
if(data.at(0) == '/')
{
QString command = data.mid(1).trimmed();
- if(cmd(command, ClientInfo::managementClient(conn)))
+ QStringList corrections;
+ if(cmd(command, ClientInfo::managementClient(conn), corrections))
{
continue;
}
@@ -1431,12 +1452,58 @@ bool CRSM::cmdExists(const QString &name, ClientInterface interface)
return cmds.contains(name) && cmds.value(name).interfaces & interface;
}
-CmdFunctionRef* CRSM::findCommand(const QString &cmd, ClientInterface interface, QString &args)
+QStringList CRSM::guessCmd(const QString& name, ClientInterface interface)
+{
+ int minDistance = -1;
+ QString minDistanceCmd;
+ QStringList minDistanceCmds;
+
+ auto applyDistance = [&name, &minDistance, &minDistanceCmd, &minDistanceCmds](const QString& cmdName)
+ {
+ int distance = Util::damerauLevenshteinDistance(name, cmdName);
+ if(minDistance == -1 || distance < minDistance)
+ {
+ minDistance = distance;
+ minDistanceCmd = cmdName;
+ minDistanceCmds.clear();
+ }
+ else if(minDistance == distance && !minDistanceCmds.contains(cmdName))
+ {
+ minDistanceCmds.append(cmdName);
+ }
+ };
+
+ for(const auto& cmd : cmds)
+ {
+ if(cmd.interfaces & interface)
+ {
+ applyDistance(cmd.name);
+ }
+ }
+
+ for(const auto& alias : Config.CRSM.CommandAlias.keys())
+ {
+ applyDistance(alias);
+ }
+
+ if(!minDistanceCmds.contains(minDistanceCmd))
+ {
+ minDistanceCmds.append(minDistanceCmd);
+ }
+
+ if(minDistanceCmds.length() == 1 && minDistance >= std::min(3, name.length() - 1))
+ {
+ minDistanceCmds.clear();
+ }
+ return minDistanceCmds;
+}
+
+CmdFunctionRef* CRSM::findCommand(const QString &cmd, ClientInterface interface, QString &args, QStringList& corrections)
{
- return findCommand(cmd.split(QRegularExpression(R"(\s)"), QString::KeepEmptyParts), interface, args);
+ return findCommand(cmd.split(QRegularExpression(R"(\s)"), QString::KeepEmptyParts), interface, args, corrections);
}
-CmdFunctionRef* CRSM::findCommand(QStringList&& cmd, ClientInterface interface, QString &realCmd)
+CmdFunctionRef* CRSM::findCommand(QStringList&& cmd, ClientInterface interface, QString &realCmd, QStringList& corrections)
{
if(cmd.length() > 0)
{
@@ -1457,8 +1524,23 @@ CmdFunctionRef* CRSM::findCommand(QStringList&& cmd, ClientInterface interface,
}
else
{
+ const QStringList& guesses = guessCmd(cmdPart, interface);
+ if(guesses.length() == 1)
+ {
+ QString guess = guesses.first();
+ substituteCommandAlias(guess);
+ if(cmdExists(guess, interface))
+ {
+ return &cmds[guess];
+ }
+ }
+ else if(guesses.length() > 1)
+ {
+ corrections.append(guesses);
+ }
+
cmd.removeLast();
- return findCommand(std::move(cmd), interface, realCmd);
+ return findCommand(std::move(cmd), interface, realCmd, corrections);
}
}
}
@@ -1468,12 +1550,12 @@ CmdFunctionRef* CRSM::findCommand(QStringList&& cmd, ClientInterface interface,
}
}
-bool CRSM::cmd(const QString& cmd, const ClientInfo &client)
+bool CRSM::cmd(const QString& cmd, const ClientInfo &client, QStringList& corrections)
{
Log.commandLog(cmd, client, false);
CmdFunctionRef* cmdPtr;
QString realCmd = cmd;
- if((cmdPtr = findCommand(cmd, client.interface, realCmd)) != nullptr)
+ if((cmdPtr = findCommand(cmd, client.interface, realCmd, corrections)) != nullptr)
{
CmdFunctionRef cmdRef = *cmdPtr;
QString args = cmd.mid(realCmd.length()).trimmed();
@@ -2327,9 +2409,11 @@ void CRSM::handleIrcMessage(const ClientInfo &client, QString message, const QSt
if(!command.isEmpty())
{
- if(!cmd(command, client))
+ bool ret;
+ const QString& txt = cmdErrorText(command, client, ret);
+ if(!ret)
{
- respond(client, "Unbekannter Befehl: \"" + command + "\"!", (privateMessage ? RespondType::PrivateNotice : RespondType::Normal), true);
+ respond(client, txt, (privateMessage ? RespondType::PrivateNotice : RespondType::Normal), true);
}
}