2022-02-23 23:08:28 -05:00
|
|
|
#include "wrap-string.hpp"
|
|
|
|
|
#include "wrap-vector.hpp"
|
2022-04-16 02:26:32 -04:00
|
|
|
#include "eng-malloc.hpp"
|
|
|
|
|
#include "luastack.hpp"
|
2021-01-23 16:10:29 -05:00
|
|
|
#include "luaconsole.hpp"
|
2021-02-10 16:22:24 -05:00
|
|
|
#include "util.hpp"
|
2022-02-23 23:08:28 -05:00
|
|
|
|
|
|
|
|
#include <cstring>
|
2021-10-07 14:58:20 -04:00
|
|
|
#include <iostream>
|
2021-02-10 16:22:24 -05:00
|
|
|
|
2021-01-23 16:10:29 -05:00
|
|
|
LuaConsole::LuaConsole() {
|
2023-04-07 14:20:45 -04:00
|
|
|
lua_state_ = LuaCoreStack::newstate(eng::l_alloc);
|
2021-11-04 14:49:25 -04:00
|
|
|
clear_raw_input();
|
2021-01-23 16:10:29 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LuaConsole::~LuaConsole() {
|
|
|
|
|
lua_close(lua_state_);
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-24 02:17:41 -05:00
|
|
|
static LuaConsole::StringVec split_words(const eng::string &raw) {
|
2021-11-04 14:49:25 -04:00
|
|
|
LuaConsole::StringVec result;
|
2022-02-24 02:17:41 -05:00
|
|
|
eng::string acc;
|
2021-11-04 14:49:25 -04:00
|
|
|
for (char c : raw) {
|
2021-10-07 14:58:20 -04:00
|
|
|
if ((c == ' ')||(c == '\n')||(c == '\r')) {
|
2021-02-02 16:29:07 -05:00
|
|
|
if (!acc.empty()) {
|
2021-11-04 14:49:25 -04:00
|
|
|
result.push_back(acc);
|
2021-02-02 16:29:07 -05:00
|
|
|
acc = "";
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
acc += c;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!acc.empty()) {
|
2021-11-04 14:49:25 -04:00
|
|
|
result.push_back(acc);
|
2021-02-02 16:29:07 -05:00
|
|
|
}
|
2021-11-04 14:49:25 -04:00
|
|
|
return result;
|
2021-02-02 16:29:07 -05:00
|
|
|
}
|
|
|
|
|
|
2021-11-04 14:49:25 -04:00
|
|
|
LuaConsole::StringVec LuaConsole::get_command() {
|
|
|
|
|
StringVec result = words_;
|
|
|
|
|
words_.clear();
|
2021-10-07 14:58:20 -04:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-04 14:49:25 -04:00
|
|
|
void LuaConsole::clear_raw_input() {
|
|
|
|
|
raw_input_ = "";
|
|
|
|
|
lines_ = 0;
|
|
|
|
|
prompt_ = "> ";
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-24 02:17:41 -05:00
|
|
|
void LuaConsole::add(eng::string line) {
|
2021-01-23 16:10:29 -05:00
|
|
|
for (int i = 0; i < int(line.size()); i++) {
|
|
|
|
|
if (line[i] == '\n') line[i] = ' ';
|
|
|
|
|
}
|
2021-02-02 16:29:07 -05:00
|
|
|
raw_input_ += line;
|
|
|
|
|
raw_input_ += '\n';
|
2021-01-23 16:10:29 -05:00
|
|
|
lines_ += 1;
|
2021-11-04 14:49:25 -04:00
|
|
|
prompt_ = ">> ";
|
2021-11-16 12:20:11 -05:00
|
|
|
words_.clear();
|
2021-01-23 16:10:29 -05:00
|
|
|
|
2021-11-04 14:58:38 -04:00
|
|
|
// Try to interpret it as a slash-command.
|
|
|
|
|
if ((lines_ == 1)&&(raw_input_[0] == '/')) {
|
2024-02-28 18:24:36 -05:00
|
|
|
words_ = split_words(raw_input_.substr(1));
|
|
|
|
|
if ((words_.size() == 1) && (sv::valid_int64(words_[0]))) {
|
|
|
|
|
eng::string num = words_[0];
|
|
|
|
|
words_.clear();
|
|
|
|
|
words_.push_back("choose");
|
|
|
|
|
words_.push_back(num);
|
|
|
|
|
}
|
2021-11-04 14:58:38 -04:00
|
|
|
clear_raw_input();
|
|
|
|
|
return;
|
2021-01-23 16:10:29 -05:00
|
|
|
}
|
2021-02-07 15:35:31 -05:00
|
|
|
|
2021-11-26 13:56:24 -05:00
|
|
|
// Translate lua expression, deal with initial prefix.
|
2022-02-24 02:17:41 -05:00
|
|
|
eng::string partial;
|
|
|
|
|
eng::string lua_mode;
|
2022-04-16 02:26:32 -04:00
|
|
|
if (sv::has_prefix(raw_input_, "?=")) {
|
2021-11-26 13:56:24 -05:00
|
|
|
lua_mode = "luaprobe";
|
2022-02-24 02:17:41 -05:00
|
|
|
partial = eng::string("return ") + raw_input_.substr(2);
|
2022-04-16 02:26:32 -04:00
|
|
|
} else if (sv::has_prefix(raw_input_, "?")) {
|
2021-11-26 13:56:24 -05:00
|
|
|
lua_mode = "luaprobe";
|
|
|
|
|
partial = raw_input_.substr(1);
|
2022-04-16 02:26:32 -04:00
|
|
|
} else if (sv::has_prefix(raw_input_, "=")) {
|
2021-11-26 13:56:24 -05:00
|
|
|
lua_mode = "luainvoke";
|
2022-02-24 02:17:41 -05:00
|
|
|
partial = eng::string("return ") + raw_input_.substr(1);
|
2021-02-02 16:29:07 -05:00
|
|
|
} else {
|
2021-11-26 13:56:24 -05:00
|
|
|
lua_mode = "luainvoke";
|
2021-02-07 15:35:31 -05:00
|
|
|
partial = raw_input_;
|
2021-02-02 16:29:07 -05:00
|
|
|
}
|
2021-01-23 16:10:29 -05:00
|
|
|
|
2021-02-10 16:22:24 -05:00
|
|
|
// Try to parse the lua expression
|
2021-01-23 16:10:29 -05:00
|
|
|
{
|
2025-12-03 19:55:53 -05:00
|
|
|
LuaVar result;
|
2025-12-15 22:22:03 -05:00
|
|
|
LuaExtStack LS(lua_state_, result);
|
2025-12-03 19:55:53 -05:00
|
|
|
eng::string errmsg = LS.load(result, partial, "stdin");
|
|
|
|
|
if (errmsg.empty()) {
|
|
|
|
|
words_.push_back(lua_mode);
|
|
|
|
|
words_.emplace_back(sv::rtrim(partial));
|
|
|
|
|
clear_raw_input();
|
|
|
|
|
} else if (errmsg.find("<eof>") != std::string::npos) {
|
|
|
|
|
// We have an incomplete expression.
|
|
|
|
|
// Do nothing, just let the user type more stuff.
|
|
|
|
|
} else {
|
2021-11-04 11:20:29 -04:00
|
|
|
words_.push_back("syntax");
|
2025-12-03 19:55:53 -05:00
|
|
|
words_.push_back(errmsg);
|
2021-11-04 14:49:25 -04:00
|
|
|
clear_raw_input();
|
2021-01-23 16:10:29 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-10-07 14:58:20 -04:00
|
|
|
|
2024-02-28 18:24:36 -05:00
|
|
|
void CommonCommands::do_command(const StringVec &words) {
|
|
|
|
|
if (words.size() == 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (words[0] == "view") {
|
|
|
|
|
if (words.size() == 1) {
|
|
|
|
|
return do_view_command();
|
|
|
|
|
} else {
|
|
|
|
|
return do_syntax_error("/view takes no arguments");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (words[0] == "moveto") {
|
|
|
|
|
if ((words.size() == 3) && sv::valid_int64(words[1]) && sv::valid_int64(words[2])) {
|
|
|
|
|
return do_moveto_command(sv::to_int64(words[1]), sv::to_int64(words[2]));
|
|
|
|
|
} else {
|
|
|
|
|
return do_syntax_error("/moveto [x] [y]");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (words[0] == "quit") {
|
|
|
|
|
if (words.size() == 1) {
|
|
|
|
|
return do_quit_command();
|
|
|
|
|
} else {
|
|
|
|
|
return do_syntax_error("/quit takes no arguments");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (words[0] == "cpl") {
|
|
|
|
|
if (words.size() == 1) {
|
|
|
|
|
return do_cpl_command();
|
|
|
|
|
} else {
|
|
|
|
|
return do_syntax_error("/cpl takes no arguments");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (words[0] == "work") {
|
|
|
|
|
if (words.size() == 1) {
|
|
|
|
|
return do_work_command();
|
|
|
|
|
} else {
|
|
|
|
|
return do_syntax_error("/work takes no arguments");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (words[0] == "display") {
|
|
|
|
|
if (words.size() == 1) {
|
|
|
|
|
return do_display_command();
|
|
|
|
|
} else {
|
|
|
|
|
return do_syntax_error("/display takes no arguments");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (words[0] == "aborthttp") {
|
|
|
|
|
if (words.size() == 1) {
|
|
|
|
|
return do_aborthttp_command();
|
|
|
|
|
} else {
|
|
|
|
|
return do_syntax_error("/aborthttp takes no arguments");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (words[0] == "connect") {
|
|
|
|
|
if ((words.size() == 2)&&(sv::valid_hostname(words[1]))) {
|
|
|
|
|
return do_connect_command(words[1]);
|
|
|
|
|
} else {
|
|
|
|
|
return do_syntax_error("/connect [hostname]");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (words[0] == "luainvoke") {
|
|
|
|
|
if (words.size() == 2) {
|
|
|
|
|
return do_luainvoke_command(words[1]);
|
|
|
|
|
} else {
|
|
|
|
|
return do_syntax_error("/luainvoke [command]");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (words[0] == "luaprobe") {
|
|
|
|
|
if (words.size() == 2) {
|
|
|
|
|
return do_luaprobe_command(words[1]);
|
|
|
|
|
} else {
|
|
|
|
|
return do_syntax_error("/luainvoke [command]");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return do_unknown_command(words[0]);
|
|
|
|
|
}
|