commit
7a619eac9e
Binary file not shown.
Before Width: | Height: | Size: 4.1 KiB |
@ -1,22 +0,0 @@
|
||||
command-prompt
|
||||
==============
|
||||
|
||||
.. dfhack-tool::
|
||||
:summary: An in-game DFHack terminal where you can run other commands.
|
||||
:tags: dfhack
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
::
|
||||
|
||||
command-prompt [entry]
|
||||
|
||||
If called with parameters, it starts with that text in the command edit area.
|
||||
This is most useful for developers, who can set a keybinding to open a language
|
||||
interpreter for lua or Ruby by starting with the `:lua <lua>` or `:rb <rb>`
|
||||
portions of the command already filled in.
|
||||
|
||||
Also see `gui/quickcmd` for a different take on running commands from the UI.
|
||||
|
||||
.. image:: ../images/command-prompt.png
|
@ -1,359 +0,0 @@
|
||||
// command-prompt: A one-line command entry at the top of the screen for quick commands
|
||||
|
||||
#include "Core.h"
|
||||
#include <ColorText.h>
|
||||
#include <Console.h>
|
||||
#include <Export.h>
|
||||
#include <MiscUtils.h>
|
||||
#include <PluginManager.h>
|
||||
|
||||
#include <modules/Gui.h>
|
||||
#include <modules/Screen.h>
|
||||
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "df/enabler.h"
|
||||
#include "df/graphic.h"
|
||||
#include "df/interface_key.h"
|
||||
#include "df/ui.h"
|
||||
|
||||
using namespace DFHack;
|
||||
using namespace df::enums;
|
||||
|
||||
DFHACK_PLUGIN("command-prompt");
|
||||
REQUIRE_GLOBAL(ui);
|
||||
REQUIRE_GLOBAL(gps);
|
||||
REQUIRE_GLOBAL(enabler);
|
||||
|
||||
std::vector<std::string> command_history;
|
||||
|
||||
class viewscreen_commandpromptst;
|
||||
class prompt_ostream:public buffered_color_ostream
|
||||
{
|
||||
viewscreen_commandpromptst *parent_;
|
||||
protected:
|
||||
void flush_proxy();
|
||||
public:
|
||||
prompt_ostream(viewscreen_commandpromptst* parent)
|
||||
: parent_(parent)
|
||||
{}
|
||||
bool empty() { return buffer.empty(); }
|
||||
};
|
||||
class viewscreen_commandpromptst : public dfhack_viewscreen {
|
||||
public:
|
||||
void feed(std::set<df::interface_key> *events);
|
||||
|
||||
void logic() {
|
||||
dfhack_viewscreen::logic();
|
||||
}
|
||||
|
||||
void render();
|
||||
void help() {}
|
||||
int8_t movies_okay() { return 0; }
|
||||
|
||||
df::unit* getSelectedUnit() { return Gui::getAnyUnit(parent); }
|
||||
df::item* getSelectedItem() { return Gui::getAnyItem(parent); }
|
||||
df::building* getSelectedBuilding() { return Gui::getAnyBuilding(parent); }
|
||||
df::plant* getSelectedPlant() { return Gui::getAnyPlant(parent); }
|
||||
|
||||
std::string getFocusString() { return "commandprompt"; }
|
||||
viewscreen_commandpromptst(std::string entry)
|
||||
: submitted(false), is_response(false)
|
||||
{
|
||||
show_fps = gps->display_frames;
|
||||
gps->display_frames = 0;
|
||||
cursor_pos = entry.size();
|
||||
frame = 0;
|
||||
history_idx = command_history.size();
|
||||
if (history_idx > 0)
|
||||
{
|
||||
if (command_history[history_idx - 1] == "")
|
||||
{
|
||||
command_history.pop_back();
|
||||
history_idx--;
|
||||
}
|
||||
}
|
||||
command_history.push_back(entry);
|
||||
}
|
||||
~viewscreen_commandpromptst()
|
||||
{
|
||||
gps->display_frames = show_fps;
|
||||
}
|
||||
|
||||
void add_response(color_value v, std::string s)
|
||||
{
|
||||
std::stringstream ss(s);
|
||||
std::string part;
|
||||
while (std::getline(ss, part))
|
||||
{
|
||||
responses.push_back(std::make_pair(v, part + '\n'));
|
||||
}
|
||||
}
|
||||
std::string get_entry()
|
||||
{
|
||||
return command_history[history_idx];
|
||||
}
|
||||
void set_entry(std::string entry)
|
||||
{
|
||||
command_history[history_idx] = entry;
|
||||
}
|
||||
void back_word()
|
||||
{
|
||||
std::string entry = get_entry();
|
||||
if (cursor_pos == 0)
|
||||
return;
|
||||
cursor_pos--;
|
||||
while (cursor_pos > 0 && !isalnum(entry[cursor_pos]))
|
||||
cursor_pos--;
|
||||
while (cursor_pos > 0 && isalnum(entry[cursor_pos]))
|
||||
cursor_pos--;
|
||||
if (!isalnum(entry[cursor_pos]) && cursor_pos != 0)
|
||||
cursor_pos++;
|
||||
}
|
||||
void forward_word()
|
||||
{
|
||||
std::string entry = get_entry();
|
||||
int len = entry.size();
|
||||
if (cursor_pos == len)
|
||||
return;
|
||||
cursor_pos++;
|
||||
while (cursor_pos <= len && !isalnum(entry[cursor_pos]))
|
||||
cursor_pos++;
|
||||
while (cursor_pos <= len && isalnum(entry[cursor_pos]))
|
||||
cursor_pos++;
|
||||
if (cursor_pos > len)
|
||||
cursor_pos = len;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::list<std::pair<color_value, std::string> > responses;
|
||||
int cursor_pos;
|
||||
int history_idx;
|
||||
bool submitted;
|
||||
bool is_response;
|
||||
bool show_fps;
|
||||
int frame;
|
||||
void submit();
|
||||
};
|
||||
void prompt_ostream::flush_proxy()
|
||||
{
|
||||
if (buffer.empty())
|
||||
return;
|
||||
for(auto it = buffer.begin(); it != buffer.end(); it++)
|
||||
parent_->add_response(it->first, it->second);
|
||||
buffer.clear();
|
||||
}
|
||||
void viewscreen_commandpromptst::render()
|
||||
{
|
||||
++frame;
|
||||
if (frame >= enabler->gfps)
|
||||
frame = 0;
|
||||
if (Screen::isDismissed(this))
|
||||
return;
|
||||
|
||||
dfhack_viewscreen::render();
|
||||
|
||||
auto dim = Screen::getWindowSize();
|
||||
parent->render();
|
||||
if (is_response)
|
||||
{
|
||||
int y = 0;
|
||||
for (auto &response : responses)
|
||||
{
|
||||
std::vector<std::string> lines;
|
||||
word_wrap(&lines, response.second, dim.x);
|
||||
for (auto &line : lines)
|
||||
{
|
||||
Screen::fillRect(Screen::Pen(' ', 7, 0), 0, y, dim.x, y);
|
||||
Screen::paintString(Screen::Pen(' ', response.first, 0), 0, y, line);
|
||||
if (++y >= dim.y)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string entry = get_entry();
|
||||
Screen::fillRect(Screen::Pen(' ', 7, 0), 0, 0, dim.x, 0);
|
||||
Screen::paintString(Screen::Pen(' ', 7, 0), 0, 0, "[DFHack]#");
|
||||
std::string cursor = (frame < enabler->gfps / 2) ? "_" : " ";
|
||||
if (cursor_pos < dim.x - 10)
|
||||
{
|
||||
Screen::paintString(Screen::Pen(' ', 7, 0), 10, 0, entry);
|
||||
if (int16_t(entry.size()) > dim.x - 10)
|
||||
Screen::paintTile(Screen::Pen('\032', 7, 0), dim.x - 1, 0);
|
||||
if (cursor != " ")
|
||||
Screen::paintString(Screen::Pen(' ', 10, 0), 10 + cursor_pos, 0, cursor);
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t start = cursor_pos - dim.x + 10 + 1;
|
||||
Screen::paintTile(Screen::Pen('\033', 7, 0), 9, 0);
|
||||
Screen::paintString(Screen::Pen(' ', 7, 0), 10, 0, entry.substr(start));
|
||||
if (cursor != " ")
|
||||
Screen::paintString(Screen::Pen(' ', 10, 0), dim.x - 1, 0, cursor);
|
||||
}
|
||||
}
|
||||
}
|
||||
void viewscreen_commandpromptst::submit()
|
||||
{
|
||||
CoreSuspendClaimer suspend;
|
||||
if (is_response)
|
||||
{
|
||||
Screen::dismiss(this);
|
||||
return;
|
||||
}
|
||||
if (submitted)
|
||||
return;
|
||||
submitted = true;
|
||||
prompt_ostream out(this);
|
||||
{
|
||||
Screen::Hide hide_guard(this, Screen::Hide::RESTORE_AT_TOP);
|
||||
Core::getInstance().runCommand(out, get_entry());
|
||||
}
|
||||
if (out.empty() && responses.empty())
|
||||
Screen::dismiss(this);
|
||||
else
|
||||
{
|
||||
is_response = true;
|
||||
}
|
||||
}
|
||||
void viewscreen_commandpromptst::feed(std::set<df::interface_key> *events)
|
||||
{
|
||||
int old_pos = cursor_pos;
|
||||
std::string entry = get_entry();
|
||||
bool leave_all = events->count(interface_key::LEAVESCREEN_ALL);
|
||||
if (leave_all || events->count(interface_key::LEAVESCREEN))
|
||||
{
|
||||
events->clear();
|
||||
Screen::dismiss(this);
|
||||
if (leave_all)
|
||||
{
|
||||
events->insert(interface_key::LEAVESCREEN);
|
||||
parent->feed(events);
|
||||
events->clear();
|
||||
}
|
||||
//if (command_history.size() && !entry.size())
|
||||
// command_history.pop_back();
|
||||
return;
|
||||
}
|
||||
if (events->count(interface_key::SELECT))
|
||||
{
|
||||
submit();
|
||||
return;
|
||||
}
|
||||
if (is_response)
|
||||
return;
|
||||
for (auto it = events->begin(); it != events->end(); ++it)
|
||||
{
|
||||
auto key = *it;
|
||||
if (key == interface_key::STRING_A000) //delete?
|
||||
{
|
||||
if (entry.size() && cursor_pos > 0)
|
||||
{
|
||||
entry.erase(cursor_pos - 1, 1);
|
||||
cursor_pos--;
|
||||
}
|
||||
if (size_t(cursor_pos) > entry.size())
|
||||
cursor_pos = entry.size();
|
||||
continue;
|
||||
}
|
||||
int charcode = Screen::keyToChar(key);
|
||||
if (charcode > 0)
|
||||
{
|
||||
entry.insert(cursor_pos, 1, char(charcode));
|
||||
cursor_pos++;
|
||||
set_entry(entry);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Prevent number keys from moving cursor
|
||||
if (events->count(interface_key::CURSOR_RIGHT))
|
||||
{
|
||||
cursor_pos++;
|
||||
if (size_t(cursor_pos) > entry.size())
|
||||
cursor_pos = entry.size();
|
||||
}
|
||||
else if (events->count(interface_key::CURSOR_LEFT))
|
||||
{
|
||||
cursor_pos--;
|
||||
if (cursor_pos < 0) cursor_pos = 0;
|
||||
}
|
||||
else if (events->count(interface_key::CURSOR_RIGHT_FAST))
|
||||
{
|
||||
forward_word();
|
||||
}
|
||||
else if (events->count(interface_key::CURSOR_LEFT_FAST))
|
||||
{
|
||||
back_word();
|
||||
}
|
||||
else if (events->count(interface_key::CUSTOM_CTRL_A))
|
||||
{
|
||||
cursor_pos = 0;
|
||||
}
|
||||
else if (events->count(interface_key::CUSTOM_CTRL_E))
|
||||
{
|
||||
cursor_pos = entry.size();
|
||||
}
|
||||
else if (events->count(interface_key::CURSOR_UP))
|
||||
{
|
||||
history_idx--;
|
||||
if (history_idx < 0)
|
||||
history_idx = 0;
|
||||
entry = get_entry();
|
||||
cursor_pos = entry.size();
|
||||
}
|
||||
else if (events->count(interface_key::CURSOR_DOWN))
|
||||
{
|
||||
if (size_t(history_idx) < command_history.size() - 1)
|
||||
{
|
||||
history_idx++;
|
||||
if (size_t(history_idx) >= command_history.size())
|
||||
history_idx = command_history.size() - 1;
|
||||
entry = get_entry();
|
||||
cursor_pos = entry.size();
|
||||
}
|
||||
}
|
||||
set_entry(entry);
|
||||
if (old_pos != cursor_pos)
|
||||
frame = 0;
|
||||
|
||||
}
|
||||
|
||||
command_result show_prompt(color_ostream &out, std::vector <std::string> & parameters)
|
||||
{
|
||||
if (Gui::getCurFocus(true) == "dfhack/commandprompt")
|
||||
{
|
||||
Screen::dismiss(Gui::getCurViewscreen(true));
|
||||
return CR_OK;
|
||||
}
|
||||
std::string params;
|
||||
for(size_t i = 0; i < parameters.size(); i++)
|
||||
params += parameters[i] + " ";
|
||||
Screen::show(dts::make_unique<viewscreen_commandpromptst>(params), plugin_self);
|
||||
return CR_OK;
|
||||
}
|
||||
|
||||
DFhackCExport command_result plugin_init(color_ostream &out, std::vector <PluginCommand> &commands)
|
||||
{
|
||||
commands.push_back(PluginCommand(
|
||||
"command-prompt",
|
||||
"Allows you to run a DFHack command from in-game.",
|
||||
show_prompt,
|
||||
Gui::anywhere_hotkey));
|
||||
return CR_OK;
|
||||
}
|
||||
|
||||
DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event e)
|
||||
{
|
||||
return CR_OK;
|
||||
}
|
||||
|
||||
DFhackCExport command_result plugin_shutdown(color_ostream &out)
|
||||
{
|
||||
return CR_OK;
|
||||
}
|
Loading…
Reference in New Issue