Add new built-in "alias" command

Closes #701
develop
lethosor 2017-06-18 17:39:54 -04:00
parent f1241e6084
commit 0796fafb2a
3 changed files with 142 additions and 4 deletions

@ -106,6 +106,29 @@ of DFhack, rather than plugins or scripts.
.. _cls: .. _cls:
alias
-----
The ``alias`` command allows configuring aliases to other DFHack commands.
Aliases are resolved immediately after built-in commands, which means that an
alias cannot override a built-in command, but can override a command implemented
by a plugin or script.
Usage:
:``alias list``: lists all configured aliases
:``alias add <name> <command> [arguments...]``: adds an alias
:``alias replace <name> <command> [arguments...]``: replaces an existing
alias with a new command, or adds the alias if it does not already exist
:``alias delete <name>``: removes the specified alias
Aliases can be given additional arguments when created and invoked, which will
be passed to the underlying command in order. An example with `devel/print-args`::
[DFHack]# alias add pargs devel/print-args example
[DFHack]# pargs text
example
text
cls cls
--- ---
Clear the terminal. Does not delete command history. Clear the terminal. Does not delete command history.

@ -603,6 +603,7 @@ string getBuiltinCommand(std::string cmd)
cmd == "disable" || cmd == "disable" ||
cmd == "plug" || cmd == "plug" ||
cmd == "keybinding" || cmd == "keybinding" ||
cmd == "alias" ||
cmd == "fpause" || cmd == "fpause" ||
cmd == "cls" || cmd == "cls" ||
cmd == "die" || cmd == "die" ||
@ -650,6 +651,7 @@ void ls_helper(color_ostream &con, const PluginCommand &pcmd)
command_result Core::runCommand(color_ostream &con, const std::string &first_, vector<string> &parts) command_result Core::runCommand(color_ostream &con, const std::string &first_, vector<string> &parts)
{ {
std::string first = first_; std::string first = first_;
command_result res;
if (!first.empty()) if (!first.empty())
{ {
if(first.find('\\') != std::string::npos) if(first.find('\\') != std::string::npos)
@ -787,8 +789,6 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
if(parts.size()) if(parts.size())
{ {
command_result res = CR_OK;
for (size_t i = 0; i < parts.size(); i++) for (size_t i = 0; i < parts.size(); i++)
{ {
std::string part = parts[i]; std::string part = parts[i];
@ -994,6 +994,10 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
con << " (aliased to " << builtin_cmd << ")"; con << " (aliased to " << builtin_cmd << ")";
con << std::endl; con << std::endl;
} }
else if (IsAlias(parts[0]))
{
con << " is an alias: " << GetAliasCommand(parts[0]) << std::endl;
}
else if (plug) else if (plug)
{ {
con << " is a command implemented by the plugin " << plug->getName() << std::endl; con << " is a command implemented by the plugin " << plug->getName() << std::endl;
@ -1063,6 +1067,42 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
<< Gui::getFocusString(Core::getTopViewscreen()) << endl; << Gui::getFocusString(Core::getTopViewscreen()) << endl;
} }
} }
else if (builtin == "alias")
{
if (parts.size() >= 3 && (parts[0] == "add" || parts[0] == "replace"))
{
const string &name = parts[1];
vector<string> cmd(parts.begin() + 2, parts.end());
if (!AddAlias(name, cmd, parts[0] == "replace"))
{
con.printerr("Could not add alias %s - already exists\n", name.c_str());
return CR_FAILURE;
}
}
else if (parts.size() >= 2 && (parts[0] == "delete" || parts[0] == "clear"))
{
if (!RemoveAlias(parts[1]))
{
con.printerr("Could not remove alias %s\n", parts[1].c_str());
return CR_FAILURE;
}
}
else if (parts.size() >= 1 && (parts[0] == "list"))
{
auto aliases = ListAliases();
for (auto p : aliases)
{
con << p.first << ": " << join_strings(" ", p.second) << endl;
}
}
else
{
con << "Usage: " << endl
<< " alias add|replace <name> <command...>" << endl
<< " alias delete|clear <name> <command...>" << endl
<< " alias list" << endl;
}
}
else if (builtin == "fpause") else if (builtin == "fpause")
{ {
World::SetPauseState(true); World::SetPauseState(true);
@ -1218,9 +1258,13 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
return CR_WRONG_USAGE; return CR_WRONG_USAGE;
} }
} }
else if (RunAlias(con, first, parts, res))
{
return res;
}
else else
{ {
command_result res = plug_mgr->InvokeCommand(con, first, parts); res = plug_mgr->InvokeCommand(con, first, parts);
if(res == CR_NOT_IMPLEMENTED) if(res == CR_NOT_IMPLEMENTED)
{ {
string completed; string completed;
@ -1405,7 +1449,8 @@ Core::Core()
hotkey_set = false; hotkey_set = false;
HotkeyMutex = 0; HotkeyMutex = 0;
HotkeyCond = 0; HotkeyCond = 0;
misc_data_mutex=0; alias_mutex = 0;
misc_data_mutex = 0;
last_world_data_ptr = NULL; last_world_data_ptr = NULL;
last_local_map_ptr = NULL; last_local_map_ptr = NULL;
last_pause_state = false; last_pause_state = false;
@ -1526,6 +1571,7 @@ bool Core::Init()
// Init global object pointers // Init global object pointers
df::global::InitGlobals(); df::global::InitGlobals();
alias_mutex = new recursive_mutex();
cerr << "Initializing Console.\n"; cerr << "Initializing Console.\n";
// init the console. // init the console.
@ -2576,6 +2622,64 @@ std::vector<std::string> Core::ListKeyBindings(std::string keyspec)
return rv; return rv;
} }
bool Core::AddAlias(const std::string &name, const std::vector<std::string> &command, bool replace)
{
tthread::lock_guard<tthread::recursive_mutex> lock(*alias_mutex);
if (!IsAlias(name) || replace)
{
aliases[name] = command;
return true;
}
return false;
}
bool Core::RemoveAlias(const std::string &name)
{
tthread::lock_guard<tthread::recursive_mutex> lock(*alias_mutex);
if (IsAlias(name))
{
aliases.erase(name);
return true;
}
return false;
}
bool Core::IsAlias(const std::string &name)
{
tthread::lock_guard<tthread::recursive_mutex> lock(*alias_mutex);
return aliases.find(name) != aliases.end();
}
bool Core::RunAlias(color_ostream &out, const std::string &name,
const std::vector<std::string> &parameters, command_result &result)
{
tthread::lock_guard<tthread::recursive_mutex> lock(*alias_mutex);
if (!IsAlias(name))
{
return false;
}
const string &first = aliases[name][0];
vector<string> parts(aliases[name].begin() + 1, aliases[name].end());
parts.insert(parts.end(), parameters.begin(), parameters.end());
result = runCommand(out, first, parts);
return true;
}
std::map<std::string, std::vector<std::string>> Core::ListAliases()
{
tthread::lock_guard<tthread::recursive_mutex> lock(*alias_mutex);
return aliases;
}
std::string Core::GetAliasCommand(const std::string &name, const std::string &default_)
{
tthread::lock_guard<tthread::recursive_mutex> lock(*alias_mutex);
if (IsAlias(name))
return join_strings(" ", aliases[name]);
else
return default_;
}
///////////////// /////////////////
// ClassNameCheck // ClassNameCheck

@ -170,6 +170,14 @@ namespace DFHack
std::vector<std::string> ListKeyBindings(std::string keyspec); std::vector<std::string> ListKeyBindings(std::string keyspec);
int8_t getModstate() { return modstate; } int8_t getModstate() { return modstate; }
bool AddAlias(const std::string &name, const std::vector<std::string> &command, bool replace = false);
bool RemoveAlias(const std::string &name);
bool IsAlias(const std::string &name);
bool RunAlias(color_ostream &out, const std::string &name,
const std::vector<std::string> &parameters, command_result &result);
std::map<std::string, std::vector<std::string>> ListAliases();
std::string GetAliasCommand(const std::string &name, const std::string &default_ = "");
std::string getHackPath(); std::string getHackPath();
bool isWorldLoaded() { return (last_world_data_ptr != NULL); } bool isWorldLoaded() { return (last_world_data_ptr != NULL); }
@ -256,6 +264,9 @@ namespace DFHack
tthread::mutex * HotkeyMutex; tthread::mutex * HotkeyMutex;
tthread::condition_variable * HotkeyCond; tthread::condition_variable * HotkeyCond;
std::map<std::string, std::vector<std::string>> aliases;
tthread::recursive_mutex * alias_mutex;
bool SelectHotkey(int key, int modifiers); bool SelectHotkey(int key, int modifiers);
// for state change tracking // for state change tracking