replace more Core cpp code with calls to helpdb

also document devel/dump-rpc builtin
develop
myk002 2022-07-14 13:19:30 -07:00
parent 185f49976c
commit e926e1116e
No known key found for this signature in database
GPG Key ID: 8A39CA0FA0C16E78
5 changed files with 547 additions and 608 deletions

@ -255,6 +255,17 @@ type
----
``type command`` shows where ``command`` is implemented.
.. _devel/dump-rpc:
devel/dump-rpc
--------------
Writes RPC endpoint information to the specified file.
Usage::
devel/dump-rpc FILENAME
Other Commands
--------------
The following commands are *not* built-in, but offer similarly useful functions.

@ -277,65 +277,6 @@ static string dfhack_version_desc()
return s.str();
}
static std::string getScriptHelp(std::string path, std::string helpprefix)
{
ifstream script(path.c_str());
if (script.good())
{
std::string help;
if (getline(script, help) &&
help.substr(0,helpprefix.length()) == helpprefix)
{
help = help.substr(helpprefix.length());
while (help.size() && help[0] == ' ')
help = help.substr(1);
return help;
}
}
return "No help available.";
}
static void listScripts(PluginManager *plug_mgr, std::map<string,string> &pset, std::string path, bool all, std::string prefix = "")
{
std::vector<string> files;
Filesystem::listdir(path, files);
path += '/';
for (size_t i = 0; i < files.size(); i++)
{
if (hasEnding(files[i], ".lua"))
{
string help = getScriptHelp(path + files[i], "--");
string key = prefix + files[i].substr(0, files[i].size()-4);
if (pset.find(key) == pset.end()) {
pset[key] = help;
}
}
else if (plug_mgr->ruby && plug_mgr->ruby->is_enabled() && hasEnding(files[i], ".rb"))
{
string help = getScriptHelp(path + files[i], "#");
string key = prefix + files[i].substr(0, files[i].size()-3);
if (pset.find(key) == pset.end()) {
pset[key] = help;
}
}
else if (all && !files[i].empty() && files[i][0] != '.' && files[i] != "internal" && files[i] != "test")
{
listScripts(plug_mgr, pset, path+files[i]+"/", all, prefix+files[i]+"/");
}
}
}
static void listAllScripts(map<string, string> &pset, bool all)
{
vector<string> paths;
Core::getInstance().getScriptPaths(&paths);
for (string path : paths)
listScripts(Core::getInstance().getPluginManager(), pset, path, all);
}
namespace {
struct ScriptArgs {
const string *pcmd;
@ -442,60 +383,52 @@ command_result Core::runCommand(color_ostream &out, const std::string &command)
return CR_NOT_IMPLEMENTED;
}
// List of built in commands
static const std::set<std::string> built_in_commands = {
"ls" ,
"help" ,
"tags" ,
"type" ,
"load" ,
"unload" ,
"reload" ,
"enable" ,
"disable" ,
"plug" ,
"keybinding" ,
"alias" ,
"fpause" ,
"cls" ,
"die" ,
"kill-lua" ,
"script" ,
"hide" ,
"show" ,
"sc-script"
};
bool is_builtin(color_ostream &con, const string &command) {
CoreSuspender suspend;
auto L = Lua::Core::State;
Lua::StackUnwinder top(L);
static bool try_autocomplete(color_ostream &con, const std::string &first, std::string &completed)
{
std::vector<std::string> possible;
if (!lua_checkstack(L, 1) ||
!Lua::PushModulePublic(con, L, "helpdb", "is_builtin")) {
con.printerr("Failed to load helpdb Lua code\n");
return false;
}
// Check for possible built in commands to autocomplete first
for (auto const &command : built_in_commands)
if (command.substr(0, first.size()) == first)
possible.push_back(command);
Lua::Push(L, command);
auto plug_mgr = Core::getInstance().getPluginManager();
for (auto it = plug_mgr->begin(); it != plug_mgr->end(); ++it)
{
const Plugin * plug = it->second;
for (size_t j = 0; j < plug->size(); j++)
{
const PluginCommand &pcmd = (*plug)[j];
if (pcmd.isHotkeyCommand())
continue;
if (pcmd.name.substr(0, first.size()) == first)
possible.push_back(pcmd.name);
if (!Lua::SafeCall(con, L, 1, 1)) {
con.printerr("Failed Lua call to helpdb.is_builtin.\n");
return false;
}
return lua_toboolean(L, -1);
}
void get_commands(color_ostream &con, vector<string> &commands) {
CoreSuspender suspend;
auto L = Lua::Core::State;
Lua::StackUnwinder top(L);
if (!lua_checkstack(L, 1) ||
!Lua::PushModulePublic(con, L, "helpdb", "get_commands")) {
con.printerr("Failed to load helpdb Lua code\n");
return;
}
if (!Lua::SafeCall(con, L, 0, 1)) {
con.printerr("Failed Lua call to helpdb.get_commands.\n");
}
bool all = (first.find('/') != std::string::npos);
Lua::GetVector(L, commands);
}
std::map<string, string> scripts;
listAllScripts(scripts, all);
for (auto iter = scripts.begin(); iter != scripts.end(); ++iter)
if (iter->first.substr(0, first.size()) == first)
possible.push_back(iter->first);
static bool try_autocomplete(color_ostream &con, const std::string &first, std::string &completed)
{
std::vector<std::string> commands, possible;
for (auto &command : commands)
if (command.substr(0, first.size()) == first)
possible.push_back(command);
if (possible.size() == 1)
{
@ -651,30 +584,6 @@ static std::string sc_event_name (state_change_event id) {
return "SC_UNKNOWN";
}
string getBuiltinCommand(std::string cmd)
{
std::string builtin = "";
// Check our list of builtin commands from the header
if (built_in_commands.count(cmd))
builtin = cmd;
// Check for some common aliases for built in commands
else if (cmd == "?" || cmd == "man")
builtin = "help";
else if (cmd == "dir")
builtin = "ls";
else if (cmd == "clear")
builtin = "cls";
else if (cmd == "devel/dump-rpc")
builtin = "devel/dump-rpc";
return builtin;
}
void help_helper(color_ostream &con, const string &entry_name) {
CoreSuspender suspend;
auto L = Lua::Core::State;
@ -753,10 +662,10 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
return CR_FAILURE;
}
command_result res;
if (!first.empty())
{
if(first.find('\\') != std::string::npos)
if (first.empty())
return CR_NOT_IMPLEMENTED;
if (first.find('\\') != std::string::npos)
{
con.printerr("Replacing backslashes with forward slashes in \"%s\"\n", first.c_str());
for (size_t i = 0; i < first.size(); i++)
@ -767,8 +676,8 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
}
// let's see what we actually got
string builtin = getBuiltinCommand(first);
if (builtin == "help")
command_result res;
if (first == "help" || first == "man" || first == "?")
{
if(!parts.size())
{
@ -803,15 +712,15 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
help_helper(con, parts[0]);
}
}
else if (builtin == "tags")
else if (first == "tags")
{
tags_helper(con);
}
else if (builtin == "load" || builtin == "unload" || builtin == "reload")
else if (first == "load" || first == "unload" || first == "reload")
{
bool all = false;
bool load = (builtin == "load");
bool unload = (builtin == "unload");
bool load = (first == "load");
bool unload = (first == "unload");
if (parts.size())
{
for (auto p = parts.begin(); p != parts.end(); p++)
@ -845,12 +754,12 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
}
}
else
con.printerr("%s: no arguments\n", builtin.c_str());
con.printerr("%s: no arguments\n", first.c_str());
}
else if( builtin == "enable" || builtin == "disable" )
else if( first == "enable" || first == "disable" )
{
CoreSuspender suspend;
bool enable = (builtin == "enable");
bool enable = (first == "enable");
if(parts.size())
{
@ -885,14 +794,14 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
else if (!plug->can_set_enabled())
{
res = CR_NOT_IMPLEMENTED;
con.printerr("Cannot %s plugin: %s\n", builtin.c_str(), part.c_str());
con.printerr("Cannot %s plugin: %s\n", first.c_str(), part.c_str());
}
else
{
res = plug->set_enabled(con, enable);
if (res != CR_OK || plug->is_enabled() != enable)
con.printerr("Could not %s plugin: %s\n", builtin.c_str(), part.c_str());
con.printerr("Could not %s plugin: %s\n", first.c_str(), part.c_str());
}
}
@ -914,11 +823,11 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
}
}
}
else if (builtin == "ls" || builtin == "dir")
else if (first == "ls" || first == "dir")
{
ls_helper(con, parts);
}
else if (builtin == "plug")
else if (first == "plug")
{
const char *header_format = "%30s %10s %4s %8s\n";
const char *row_format = "%30s %10s %4i %8s\n";
@ -964,7 +873,7 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
con.color(COLOR_RESET);
}
}
else if (builtin == "type")
else if (first == "type")
{
if (!parts.size())
{
@ -972,15 +881,13 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
return CR_WRONG_USAGE;
}
con << parts[0];
string builtin_cmd = getBuiltinCommand(parts[0]);
bool builtin = is_builtin(con, parts[0]);
string lua_path = findScript(parts[0] + ".lua");
string ruby_path = findScript(parts[0] + ".rb");
Plugin *plug = plug_mgr->getPluginByCommand(parts[0]);
if (builtin_cmd.size())
if (builtin)
{
con << " is a built-in command";
if (builtin_cmd != parts[0])
con << " (aliased to " << builtin_cmd << ")";
con << std::endl;
}
else if (IsAlias(parts[0]))
@ -1008,7 +915,7 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
return CR_FAILURE;
}
}
else if (builtin == "keybinding")
else if (first == "keybinding")
{
if (parts.size() >= 3 && (parts[0] == "set" || parts[0] == "add"))
{
@ -1056,7 +963,7 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
<< Gui::getFocusString(Core::getTopViewscreen()) << endl;
}
}
else if (builtin == "alias")
else if (first == "alias")
{
if (parts.size() >= 3 && (parts[0] == "add" || parts[0] == "replace"))
{
@ -1092,7 +999,7 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
<< " alias list" << endl;
}
}
else if (builtin == "fpause")
else if (first == "fpause")
{
World::SetPauseState(true);
if (auto scr = Gui::getViewscreenByType<df::viewscreen_new_regionst>())
@ -1101,7 +1008,7 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
}
con.print("The game was forced to pause!\n");
}
else if (builtin == "cls")
else if (first == "cls" || first == "clear")
{
if (con.is_console())
((Console&)con).clear();
@ -1111,11 +1018,11 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
return CR_NEEDS_CONSOLE;
}
}
else if (builtin == "die")
else if (first == "die")
{
std::_Exit(666);
}
else if (builtin == "kill-lua")
else if (first == "kill-lua")
{
bool force = false;
for (auto it = parts.begin(); it != parts.end(); ++it)
@ -1132,7 +1039,7 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
" profiling and coverage monitoring.\n");
}
}
else if (builtin == "script")
else if (first == "script")
{
if(parts.size() == 1)
{
@ -1145,7 +1052,7 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
return CR_WRONG_USAGE;
}
}
else if (builtin=="hide")
else if (first == "hide")
{
if (!getConsole().hide())
{
@ -1154,7 +1061,7 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
}
return CR_OK;
}
else if (builtin=="show")
else if (first == "show")
{
if (!getConsole().show())
{
@ -1163,7 +1070,7 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
}
return CR_OK;
}
else if (builtin == "sc-script")
else if (first == "sc-script")
{
if (parts.empty() || parts[0] == "help" || parts[0] == "?")
{
@ -1257,7 +1164,7 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
return CR_WRONG_USAGE;
}
}
else if (builtin == "devel/dump-rpc")
else if (first == "devel/dump-rpc")
{
if (parts.size() == 1)
{
@ -1331,9 +1238,6 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
}
return CR_OK;
}
return CR_NOT_IMPLEMENTED;
}
bool Core::loadScriptFile(color_ostream &out, string fname, bool silent)

@ -148,6 +148,16 @@ void Lua::Push(lua_State *state, df::coord2d pos)
lua_setfield(state, -2, "y");
}
void GetVector(lua_State *state, std::vector<std::string> &pvec)
{
lua_pushnil(state); // first key
while (lua_next(state, 1) != 0)
{
pvec.push_back(lua_tostring(state, -1));
lua_pop(state, 1); // remove value, leave key
}
}
int Lua::PushPosXYZ(lua_State *state, df::coord pos)
{
if (!pos.isValid())

@ -339,6 +339,8 @@ namespace DFHack {namespace Lua {
}
}
DFHACK_EXPORT void GetVector(lua_State *state, std::vector<std::string> &pvec);
DFHACK_EXPORT int PushPosXYZ(lua_State *state, df::coord pos);
DFHACK_EXPORT int PushPosXY(lua_State *state, df::coord2d pos);

@ -250,6 +250,7 @@ local BUILTINS = {
alias='Configure helper aliases for other DFHack commands.',
cls='Clear the console screen.',
clear='Clear the console screen.',
['devel/dump-rpc']='Write RPC endpoint information to a file.',
die='Force DF to close immediately, without saving.',
enable='Enable a plugin or persistent script.',
disable='Disable a plugin or persistent script.',
@ -575,15 +576,26 @@ function search_entries(include, exclude)
ensure_db()
include = normalize_filter(include)
exclude = normalize_filter(exclude)
local commands = {}
for command in pairs(db) do
if (not include or matches(command, include)) and
(not exclude or not matches(command, exclude)) then
table.insert(commands, command)
local entries = {}
for entry in pairs(db) do
if (not include or matches(entry, include)) and
(not exclude or not matches(entry, exclude)) then
table.insert(entries, entry)
end
end
table.sort(commands, sort_by_basename)
return commands
table.sort(entries, sort_by_basename)
return entries
end
-- returns a list of all commands. used by Core's autocomplete functionality.
function get_commands()
local include = {types={ENTRY_TYPES.COMMAND}}
return search_entries(include)
end
function is_builtin(command)
ensure_db()
return db[command] and db[command].entry_types[ENTRY_TYPES.BUILTIN]
end
---------------------------------------------------------------------------
@ -633,7 +645,7 @@ function list_entries(skip_tags, include, exclude)
end
end
if #entries == 0 then
print('no entries found.')
print('No matches.')
end
end