2010-07-21 10:08:38 +02:00
|
|
|
#include "console.hpp"
|
|
|
|
|
2015-01-10 02:50:43 +01:00
|
|
|
#include <MyGUI_EditBox.h>
|
2019-07-03 22:38:07 +02:00
|
|
|
#include <MyGUI_InputManager.h>
|
2019-05-16 10:28:56 +04:00
|
|
|
#include <MyGUI_LayerManager.h>
|
2015-01-10 02:50:43 +01:00
|
|
|
|
2022-05-24 21:18:21 +00:00
|
|
|
#include <filesystem>
|
|
|
|
#include <fstream>
|
2014-01-19 11:34:54 +04:00
|
|
|
|
2010-07-21 10:08:38 +02:00
|
|
|
#include <components/compiler/exception.hpp>
|
2013-08-07 13:16:20 -04:00
|
|
|
#include <components/compiler/extensions0.hpp>
|
2021-05-15 22:15:46 +02:00
|
|
|
#include <components/compiler/lineparser.hpp>
|
|
|
|
#include <components/compiler/locals.hpp>
|
|
|
|
#include <components/compiler/scanner.hpp>
|
|
|
|
#include <components/interpreter/interpreter.hpp>
|
2023-02-10 11:54:45 +00:00
|
|
|
#include <components/settings/settings.hpp>
|
2010-07-21 10:08:38 +02:00
|
|
|
|
|
|
|
#include "../mwscript/extensions.hpp"
|
2022-08-17 18:44:04 +02:00
|
|
|
#include "../mwscript/interpretercontext.hpp"
|
2010-07-21 10:08:38 +02:00
|
|
|
|
2012-04-23 15:27:03 +02:00
|
|
|
#include "../mwbase/environment.hpp"
|
2021-04-12 03:15:17 +02:00
|
|
|
#include "../mwbase/luamanager.hpp"
|
2019-03-10 17:05:56 +03:00
|
|
|
#include "../mwbase/scriptmanager.hpp"
|
2013-06-16 18:06:55 +02:00
|
|
|
#include "../mwbase/windowmanager.hpp"
|
2014-12-19 11:26:54 +01:00
|
|
|
#include "../mwbase/world.hpp"
|
2012-04-23 15:27:03 +02:00
|
|
|
|
2019-03-10 17:05:56 +03:00
|
|
|
#include "../mwworld/class.hpp"
|
2014-02-23 20:11:05 +01:00
|
|
|
#include "../mwworld/esmstore.hpp"
|
|
|
|
|
2010-07-21 10:08:38 +02:00
|
|
|
namespace MWGui
|
|
|
|
{
|
|
|
|
class ConsoleInterpreterContext : public MWScript::InterpreterContext
|
|
|
|
{
|
|
|
|
Console& mConsole;
|
2010-08-22 11:14:14 +02:00
|
|
|
|
2010-07-21 10:08:38 +02:00
|
|
|
public:
|
2012-04-23 15:27:03 +02:00
|
|
|
ConsoleInterpreterContext(Console& console, MWWorld::Ptr reference);
|
2010-08-22 11:14:14 +02:00
|
|
|
|
2020-10-16 22:18:54 +04:00
|
|
|
void report(const std::string& message) override;
|
2010-07-21 10:08:38 +02:00
|
|
|
};
|
2010-08-22 11:14:14 +02:00
|
|
|
|
2010-07-21 10:08:38 +02:00
|
|
|
ConsoleInterpreterContext::ConsoleInterpreterContext(Console& console, MWWorld::Ptr reference)
|
2020-11-13 11:39:47 +04:00
|
|
|
: MWScript::InterpreterContext(reference.isEmpty() ? nullptr : &reference.getRefData().getLocals(), reference)
|
2010-07-21 10:08:38 +02:00
|
|
|
, mConsole(console)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2011-04-26 21:48:13 +02:00
|
|
|
void ConsoleInterpreterContext::report(const std::string& message)
|
|
|
|
{
|
|
|
|
mConsole.printOK(message);
|
|
|
|
}
|
|
|
|
|
2010-07-21 10:08:38 +02:00
|
|
|
bool Console::compile(const std::string& cmd, Compiler::Output& output)
|
|
|
|
{
|
|
|
|
try
|
2010-08-22 11:14:14 +02:00
|
|
|
{
|
2010-07-21 13:34:52 +02:00
|
|
|
ErrorHandler::reset();
|
2010-08-22 11:14:14 +02:00
|
|
|
|
2010-07-21 10:08:38 +02:00
|
|
|
std::istringstream input(cmd + '\n');
|
2010-08-22 11:14:14 +02:00
|
|
|
|
2010-07-21 10:08:38 +02:00
|
|
|
Compiler::Scanner scanner(*this, input, mCompilerContext.getExtensions());
|
2010-08-22 11:14:14 +02:00
|
|
|
|
2010-07-21 10:08:38 +02:00
|
|
|
Compiler::LineParser parser(
|
2010-07-21 13:34:52 +02:00
|
|
|
*this, mCompilerContext, output.getLocals(), output.getLiterals(), output.getCode(), true);
|
2010-08-22 11:14:14 +02:00
|
|
|
|
2010-07-21 10:08:38 +02:00
|
|
|
scanner.scan(parser);
|
2010-08-22 11:14:14 +02:00
|
|
|
|
2010-07-21 10:08:38 +02:00
|
|
|
return isGood();
|
|
|
|
}
|
2012-03-15 16:01:41 +01:00
|
|
|
catch (const Compiler::SourceException&)
|
2010-07-21 10:08:38 +02:00
|
|
|
{
|
|
|
|
// error has already been reported via error handler
|
|
|
|
}
|
|
|
|
catch (const std::exception& error)
|
|
|
|
{
|
2014-05-28 22:32:26 +02:00
|
|
|
printError(std::string("Error: ") + error.what());
|
2010-07-21 10:08:38 +02:00
|
|
|
}
|
2010-08-22 11:14:14 +02:00
|
|
|
|
2010-07-21 10:08:38 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Console::report(const std::string& message, const Compiler::TokenLoc& loc, Type type)
|
|
|
|
{
|
|
|
|
std::ostringstream error;
|
|
|
|
error << "column " << loc.mColumn << " (" << loc.mLiteral << "):";
|
2010-08-22 11:14:14 +02:00
|
|
|
|
2010-07-21 10:08:38 +02:00
|
|
|
printError(error.str());
|
|
|
|
printError((type == ErrorMessage ? "error: " : "warning: ") + message);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Console::report(const std::string& message, Type type)
|
|
|
|
{
|
|
|
|
printError((type == ErrorMessage ? "error: " : "warning: ") + message);
|
|
|
|
}
|
2010-08-22 11:14:14 +02:00
|
|
|
|
2011-01-12 18:24:00 +01:00
|
|
|
void Console::listNames()
|
|
|
|
{
|
|
|
|
if (mNames.empty())
|
|
|
|
{
|
2011-01-12 18:48:37 +01:00
|
|
|
// keywords
|
2011-01-12 18:24:00 +01:00
|
|
|
std::istringstream input("");
|
|
|
|
|
|
|
|
Compiler::Scanner scanner(*this, input, mCompilerContext.getExtensions());
|
|
|
|
|
|
|
|
scanner.listKeywords(mNames);
|
|
|
|
|
2011-01-12 18:48:37 +01:00
|
|
|
// identifier
|
2012-11-06 00:34:11 +04:00
|
|
|
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type
The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID
Slowly going through all the changes to make, still hundreds of errors
a lot of functions/structures use std::string or stringview to designate an ID. So it takes time
Continues slowly replacing ids. There are technically more and more compilation errors
I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type
Continue moving forward, changes to the stores
slowly moving along
Starting to see the fruit of those changes.
still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type.
More replacements. Things are starting to get easier
I can see more and more often the issue is that the function is awaiting a RefId, but is given a string
there is less need to go down functions and to fix a long list of them.
Still moving forward, and for the first time error count is going down!
Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably
Cells are back to using string for the name, haven't fixed everything yet. Many other changes
Under the bar of 400 compilation errors.
more good progress <100 compile errors!
More progress
Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string
some more progress on other fronts
Mostly game settings clean
one error opened a lot of other errors. Down to 18, but more will prbably appear
only link errors left??
Fixed link errors
OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
|
|
|
std::vector<ESM::RefId> ids;
|
2012-11-06 00:34:11 +04:00
|
|
|
for (MWWorld::ESMStore::iterator it = store.begin(); it != store.end(); ++it)
|
2011-01-12 18:48:37 +01:00
|
|
|
{
|
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type
The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID
Slowly going through all the changes to make, still hundreds of errors
a lot of functions/structures use std::string or stringview to designate an ID. So it takes time
Continues slowly replacing ids. There are technically more and more compilation errors
I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type
Continue moving forward, changes to the stores
slowly moving along
Starting to see the fruit of those changes.
still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type.
More replacements. Things are starting to get easier
I can see more and more often the issue is that the function is awaiting a RefId, but is given a string
there is less need to go down functions and to fix a long list of them.
Still moving forward, and for the first time error count is going down!
Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably
Cells are back to using string for the name, haven't fixed everything yet. Many other changes
Under the bar of 400 compilation errors.
more good progress <100 compile errors!
More progress
Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string
some more progress on other fronts
Mostly game settings clean
one error opened a lot of other errors. Down to 18, but more will prbably appear
only link errors left??
Fixed link errors
OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
|
|
|
(*it)->listIdentifier(ids);
|
|
|
|
for (auto id : ids)
|
|
|
|
{
|
|
|
|
mNames.push_back(id.getRefIdString());
|
|
|
|
}
|
|
|
|
ids.clear();
|
2011-01-12 18:48:37 +01:00
|
|
|
}
|
|
|
|
|
2015-01-06 01:10:09 +01:00
|
|
|
// exterior cell names aren't technically identifiers, but since the COC function accepts them,
|
|
|
|
// we should list them too
|
|
|
|
for (MWWorld::Store<ESM::Cell>::iterator it = store.get<ESM::Cell>().extBegin();
|
|
|
|
it != store.get<ESM::Cell>().extEnd(); ++it)
|
|
|
|
{
|
|
|
|
if (!it->mName.empty())
|
2023-01-19 17:31:45 +01:00
|
|
|
mNames.push_back(it->mName);
|
2015-01-06 01:10:09 +01:00
|
|
|
}
|
|
|
|
|
2011-01-12 18:48:37 +01:00
|
|
|
// sort
|
2011-01-12 18:24:00 +01:00
|
|
|
std::sort(mNames.begin(), mNames.end());
|
2015-01-06 01:10:09 +01:00
|
|
|
|
|
|
|
// remove duplicates
|
|
|
|
mNames.erase(std::unique(mNames.begin(), mNames.end()), mNames.end());
|
2011-01-12 18:24:00 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-10 11:54:45 +00:00
|
|
|
Console::Console(int w, int h, bool consoleOnlyScripts, Files::ConfigurationManager& cfgMgr)
|
2013-07-14 23:54:28 +02:00
|
|
|
: WindowBase("openmw_console.layout")
|
2012-07-30 11:43:28 +02:00
|
|
|
, mCompilerContext(MWScript::CompilerContext::Type_Console)
|
|
|
|
, mConsoleOnlyScripts(consoleOnlyScripts)
|
2023-02-10 11:54:45 +00:00
|
|
|
, mCfgMgr(cfgMgr)
|
2010-07-21 10:08:38 +02:00
|
|
|
{
|
|
|
|
setCoord(10, 10, w - 10, h / 2);
|
|
|
|
|
2013-07-14 23:54:28 +02:00
|
|
|
getWidget(mCommandLine, "edit_Command");
|
|
|
|
getWidget(mHistory, "list_History");
|
2010-07-21 10:08:38 +02:00
|
|
|
|
|
|
|
// Set up the command line box
|
|
|
|
mCommandLine->eventEditSelectAccept += newDelegate(this, &Console::acceptCommand);
|
|
|
|
mCommandLine->eventKeyButtonPressed += newDelegate(this, &Console::keyPress);
|
|
|
|
|
|
|
|
// Set up the log window
|
2013-07-14 23:54:28 +02:00
|
|
|
mHistory->setOverflowToTheLeft(true);
|
2010-08-22 11:14:14 +02:00
|
|
|
|
2010-07-21 10:08:38 +02:00
|
|
|
// compiler
|
2013-08-06 20:38:41 -04:00
|
|
|
Compiler::registerExtensions(mExtensions, mConsoleOnlyScripts);
|
2012-07-30 11:43:28 +02:00
|
|
|
mCompilerContext.setExtensions(&mExtensions);
|
2023-02-10 11:54:45 +00:00
|
|
|
|
|
|
|
// command history file
|
|
|
|
initConsoleHistory();
|
|
|
|
}
|
|
|
|
|
|
|
|
Console::~Console()
|
|
|
|
{
|
|
|
|
if (mCommandHistoryFile && mCommandHistoryFile.is_open())
|
|
|
|
mCommandHistoryFile.close();
|
2010-07-21 10:08:38 +02:00
|
|
|
}
|
|
|
|
|
2017-09-22 17:10:53 +02:00
|
|
|
void Console::onOpen()
|
2010-07-21 10:08:38 +02:00
|
|
|
{
|
|
|
|
// Give keyboard focus to the combo box whenever the console is
|
2019-05-16 10:28:56 +04:00
|
|
|
// turned on and place it over other widgets
|
2019-06-09 02:08:09 +03:00
|
|
|
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCommandLine);
|
2019-05-16 10:28:56 +04:00
|
|
|
MyGUI::LayerManager::getInstance().upLayerItem(mMainWidget);
|
2010-07-21 10:08:38 +02:00
|
|
|
}
|
|
|
|
|
2022-04-09 23:07:57 +02:00
|
|
|
void Console::print(const std::string& msg, std::string_view color)
|
2010-07-21 10:08:38 +02:00
|
|
|
{
|
2022-04-09 23:07:57 +02:00
|
|
|
mHistory->addText(std::string(color) + MyGUI::TextIterator::toTagsString(msg));
|
2010-07-21 10:08:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Console::printOK(const std::string& msg)
|
|
|
|
{
|
2022-04-09 23:07:57 +02:00
|
|
|
print(msg + "\n", MWBase::WindowManager::sConsoleColor_Success);
|
2010-07-21 10:08:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Console::printError(const std::string& msg)
|
|
|
|
{
|
2022-04-09 23:07:57 +02:00
|
|
|
print(msg + "\n", MWBase::WindowManager::sConsoleColor_Error);
|
2010-07-21 10:08:38 +02:00
|
|
|
}
|
|
|
|
|
2012-07-30 11:57:19 +02:00
|
|
|
void Console::execute(const std::string& command)
|
|
|
|
{
|
|
|
|
// Log the command
|
2022-04-09 23:07:57 +02:00
|
|
|
if (mConsoleMode.empty())
|
|
|
|
print("> " + command + "\n");
|
|
|
|
else
|
|
|
|
print(mConsoleMode + " " + command + "\n");
|
|
|
|
|
|
|
|
if (!mConsoleMode.empty() || (command.size() >= 3 && std::string_view(command).substr(0, 3) == "lua"))
|
|
|
|
{
|
|
|
|
MWBase::Environment::get().getLuaManager()->handleConsoleCommand(mConsoleMode, command, mPtr);
|
|
|
|
return;
|
|
|
|
}
|
2012-07-30 11:57:19 +02:00
|
|
|
|
|
|
|
Compiler::Locals locals;
|
2019-03-10 17:05:56 +03:00
|
|
|
if (!mPtr.isEmpty())
|
|
|
|
{
|
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type
The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID
Slowly going through all the changes to make, still hundreds of errors
a lot of functions/structures use std::string or stringview to designate an ID. So it takes time
Continues slowly replacing ids. There are technically more and more compilation errors
I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type
Continue moving forward, changes to the stores
slowly moving along
Starting to see the fruit of those changes.
still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type.
More replacements. Things are starting to get easier
I can see more and more often the issue is that the function is awaiting a RefId, but is given a string
there is less need to go down functions and to fix a long list of them.
Still moving forward, and for the first time error count is going down!
Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably
Cells are back to using string for the name, haven't fixed everything yet. Many other changes
Under the bar of 400 compilation errors.
more good progress <100 compile errors!
More progress
Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string
some more progress on other fronts
Mostly game settings clean
one error opened a lot of other errors. Down to 18, but more will prbably appear
only link errors left??
Fixed link errors
OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
|
|
|
const ESM::RefId& script = mPtr.getClass().getScript(mPtr);
|
2019-03-10 17:05:56 +03:00
|
|
|
if (!script.empty())
|
|
|
|
locals = MWBase::Environment::get().getScriptManager()->getLocals(script);
|
|
|
|
}
|
2012-07-30 11:57:19 +02:00
|
|
|
Compiler::Output output(locals);
|
|
|
|
|
|
|
|
if (compile(command + "\n", output))
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
ConsoleInterpreterContext interpreterContext(*this, mPtr);
|
|
|
|
Interpreter::Interpreter interpreter;
|
|
|
|
MWScript::installOpcodes(interpreter, mConsoleOnlyScripts);
|
2023-01-10 04:10:18 +01:00
|
|
|
const Interpreter::Program program = output.getProgram();
|
|
|
|
interpreter.run(program, interpreterContext);
|
2012-07-30 11:57:19 +02:00
|
|
|
}
|
|
|
|
catch (const std::exception& error)
|
|
|
|
{
|
2014-05-28 22:32:26 +02:00
|
|
|
printError(std::string("Error: ") + error.what());
|
2012-07-30 11:57:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-30 12:37:46 +02:00
|
|
|
void Console::executeFile(const std::string& path)
|
|
|
|
{
|
2022-05-24 21:18:21 +00:00
|
|
|
std::ifstream stream((std::filesystem::path(path)));
|
2012-07-30 12:37:46 +02:00
|
|
|
|
|
|
|
if (!stream.is_open())
|
|
|
|
printError("failed to open file: " + path);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::string line;
|
|
|
|
|
|
|
|
while (std::getline(stream, line))
|
|
|
|
execute(line);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-30 16:57:07 +02:00
|
|
|
void Console::clear()
|
|
|
|
{
|
|
|
|
resetReference();
|
|
|
|
}
|
|
|
|
|
2019-06-07 18:41:35 +02:00
|
|
|
bool isWhitespace(char c)
|
|
|
|
{
|
|
|
|
return c == ' ' || c == '\t';
|
|
|
|
}
|
|
|
|
|
2013-03-03 13:11:02 +01:00
|
|
|
void Console::keyPress(MyGUI::Widget* _sender, MyGUI::KeyCode key, MyGUI::Char _char)
|
2010-07-21 10:08:38 +02:00
|
|
|
{
|
2019-06-06 22:09:45 +02:00
|
|
|
if (MyGUI::InputManager::getInstance().isControlPressed())
|
|
|
|
{
|
|
|
|
if (key == MyGUI::KeyCode::W)
|
|
|
|
{
|
2019-06-07 18:41:35 +02:00
|
|
|
const auto& caption = mCommandLine->getCaption();
|
|
|
|
if (caption.empty())
|
2019-06-06 22:09:45 +02:00
|
|
|
return;
|
2019-06-07 18:41:35 +02:00
|
|
|
size_t max = mCommandLine->getTextCursor();
|
|
|
|
while (max > 0 && (isWhitespace(caption[max - 1]) || caption[max - 1] == '>'))
|
2019-06-06 22:09:45 +02:00
|
|
|
max--;
|
2019-06-07 18:41:35 +02:00
|
|
|
while (max > 0 && !isWhitespace(caption[max - 1]) && caption[max - 1] != '>')
|
2019-06-06 22:09:45 +02:00
|
|
|
max--;
|
2019-06-07 18:41:35 +02:00
|
|
|
size_t length = mCommandLine->getTextCursor() - max;
|
|
|
|
if (length > 0)
|
|
|
|
{
|
2021-02-25 19:33:11 +01:00
|
|
|
auto text = caption;
|
2019-06-07 18:41:35 +02:00
|
|
|
text.erase(max, length);
|
|
|
|
mCommandLine->setCaption(text);
|
|
|
|
mCommandLine->setTextCursor(max);
|
|
|
|
}
|
2019-06-06 22:09:45 +02:00
|
|
|
}
|
|
|
|
else if (key == MyGUI::KeyCode::U)
|
|
|
|
{
|
2019-06-07 18:41:35 +02:00
|
|
|
if (mCommandLine->getTextCursor() > 0)
|
|
|
|
{
|
2021-02-25 19:33:11 +01:00
|
|
|
auto text = mCommandLine->getCaption();
|
2019-06-07 18:41:35 +02:00
|
|
|
text.erase(0, mCommandLine->getTextCursor());
|
|
|
|
mCommandLine->setCaption(text);
|
|
|
|
mCommandLine->setTextCursor(0);
|
|
|
|
}
|
|
|
|
}
|
2019-06-06 22:09:45 +02:00
|
|
|
}
|
2022-04-09 23:07:57 +02:00
|
|
|
else if (key == MyGUI::KeyCode::Tab && mConsoleMode.empty())
|
2011-07-18 18:49:38 +02:00
|
|
|
{
|
|
|
|
std::vector<std::string> matches;
|
|
|
|
listNames();
|
2014-05-02 22:19:02 +02:00
|
|
|
std::string oldCaption = mCommandLine->getCaption();
|
|
|
|
std::string newCaption = complete(mCommandLine->getOnlyText(), matches);
|
|
|
|
mCommandLine->setCaption(newCaption);
|
|
|
|
|
|
|
|
// List candidates if repeatedly pressing tab
|
2016-02-22 19:06:12 +01:00
|
|
|
if (oldCaption == newCaption && !matches.empty())
|
2011-07-18 18:49:38 +02:00
|
|
|
{
|
2014-05-02 22:19:02 +02:00
|
|
|
int i = 0;
|
|
|
|
printOK("");
|
2019-03-02 13:27:59 +04:00
|
|
|
for (std::string& match : matches)
|
2014-05-02 22:19:02 +02:00
|
|
|
{
|
2019-03-02 13:27:59 +04:00
|
|
|
if (i == 50)
|
2014-05-02 22:19:02 +02:00
|
|
|
break;
|
2019-03-02 13:27:59 +04:00
|
|
|
|
|
|
|
printOK(match);
|
|
|
|
i++;
|
2014-05-02 22:19:02 +02:00
|
|
|
}
|
2011-07-18 18:49:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-14 23:54:28 +02:00
|
|
|
if (mCommandHistory.empty())
|
|
|
|
return;
|
2010-07-21 10:08:38 +02:00
|
|
|
|
|
|
|
// Traverse history with up and down arrows
|
|
|
|
if (key == MyGUI::KeyCode::ArrowUp)
|
|
|
|
{
|
|
|
|
// If the user was editing a string, store it for later
|
2013-07-14 23:54:28 +02:00
|
|
|
if (mCurrent == mCommandHistory.end())
|
2014-01-04 05:24:32 +01:00
|
|
|
mEditString = mCommandLine->getOnlyText();
|
2010-07-21 10:08:38 +02:00
|
|
|
|
2013-07-14 23:54:28 +02:00
|
|
|
if (mCurrent != mCommandHistory.begin())
|
2010-07-21 10:08:38 +02:00
|
|
|
{
|
2013-07-31 18:46:32 +02:00
|
|
|
--mCurrent;
|
2013-07-14 23:54:28 +02:00
|
|
|
mCommandLine->setCaption(*mCurrent);
|
2010-07-21 10:08:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (key == MyGUI::KeyCode::ArrowDown)
|
|
|
|
{
|
2013-07-14 23:54:28 +02:00
|
|
|
if (mCurrent != mCommandHistory.end())
|
2010-07-21 10:08:38 +02:00
|
|
|
{
|
2013-11-23 22:48:39 +01:00
|
|
|
++mCurrent;
|
2010-07-21 10:08:38 +02:00
|
|
|
|
2013-07-14 23:54:28 +02:00
|
|
|
if (mCurrent != mCommandHistory.end())
|
|
|
|
mCommandLine->setCaption(*mCurrent);
|
2010-07-21 10:08:38 +02:00
|
|
|
else
|
|
|
|
// Restore the edit string
|
2013-07-14 23:54:28 +02:00
|
|
|
mCommandLine->setCaption(mEditString);
|
2010-07-21 10:08:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-03 13:11:02 +01:00
|
|
|
void Console::acceptCommand(MyGUI::EditBox* _sender)
|
2010-07-21 10:08:38 +02:00
|
|
|
{
|
2014-01-04 05:24:32 +01:00
|
|
|
const std::string& cm = mCommandLine->getOnlyText();
|
2010-07-21 10:08:38 +02:00
|
|
|
if (cm.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Add the command to the history, and set the current pointer to
|
|
|
|
// the end of the list
|
2015-01-27 02:08:09 +01:00
|
|
|
if (mCommandHistory.empty() || mCommandHistory.back() != cm)
|
2023-02-10 11:54:45 +00:00
|
|
|
{
|
2015-01-27 02:08:09 +01:00
|
|
|
mCommandHistory.push_back(cm);
|
2023-02-10 11:54:45 +00:00
|
|
|
|
|
|
|
if (mCommandHistoryFile && mCommandHistoryFile.good())
|
|
|
|
mCommandHistoryFile << cm << std::endl;
|
|
|
|
}
|
2013-07-14 23:54:28 +02:00
|
|
|
mCurrent = mCommandHistory.end();
|
|
|
|
mEditString.clear();
|
2022-04-17 20:25:09 +00:00
|
|
|
mHistory->setTextCursor(mHistory->getTextLength());
|
2015-06-05 22:44:06 +03:00
|
|
|
|
|
|
|
// Reset the command line before the command execution.
|
2015-06-05 22:57:35 +03:00
|
|
|
// It prevents the re-triggering of the acceptCommand() event for the same command
|
|
|
|
// during the actual command execution
|
2015-06-05 22:00:02 +03:00
|
|
|
mCommandLine->setCaption("");
|
2010-07-21 10:08:38 +02:00
|
|
|
|
2012-07-30 11:57:19 +02:00
|
|
|
execute(cm);
|
2010-07-21 10:08:38 +02:00
|
|
|
}
|
2011-07-18 18:49:38 +02:00
|
|
|
|
|
|
|
std::string Console::complete(std::string input, std::vector<std::string>& matches)
|
|
|
|
{
|
2013-04-17 18:56:48 -04:00
|
|
|
std::string output = input;
|
|
|
|
std::string tmp = input;
|
2011-07-19 18:42:34 +02:00
|
|
|
bool has_front_quote = false;
|
2011-07-18 18:49:38 +02:00
|
|
|
|
|
|
|
/* Does the input string contain things that don't have to be completed? If yes erase them. */
|
2018-08-02 09:49:53 +03:00
|
|
|
|
|
|
|
/* Erase a possible call to an explicit reference. */
|
|
|
|
size_t explicitPos = tmp.find("->");
|
|
|
|
if (explicitPos != std::string::npos)
|
|
|
|
{
|
|
|
|
tmp.erase(0, explicitPos + 2);
|
|
|
|
}
|
|
|
|
|
2011-07-19 18:42:34 +02:00
|
|
|
/* Are there quotation marks? */
|
2013-04-17 18:56:48 -04:00
|
|
|
if (tmp.find('"') != std::string::npos)
|
|
|
|
{
|
2011-07-19 18:42:34 +02:00
|
|
|
int numquotes = 0;
|
2013-04-17 18:56:48 -04:00
|
|
|
for (std::string::iterator it = tmp.begin(); it < tmp.end(); ++it)
|
|
|
|
{
|
2011-07-19 18:42:34 +02:00
|
|
|
if (*it == '"')
|
|
|
|
numquotes++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Is it terminated?*/
|
|
|
|
if (numquotes % 2)
|
|
|
|
{
|
|
|
|
tmp.erase(0, tmp.rfind('"') + 1);
|
|
|
|
has_front_quote = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
size_t pos;
|
2013-04-17 18:56:48 -04:00
|
|
|
if ((((pos = tmp.rfind(' ')) != std::string::npos)) && (pos > tmp.rfind('"')))
|
|
|
|
{
|
2011-07-19 18:42:34 +02:00
|
|
|
tmp.erase(0, tmp.rfind(' ') + 1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tmp.clear();
|
|
|
|
}
|
|
|
|
has_front_quote = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* No quotation marks. Are there spaces?*/
|
|
|
|
else
|
|
|
|
{
|
|
|
|
size_t rpos;
|
2013-04-17 18:56:48 -04:00
|
|
|
if ((rpos = tmp.rfind(' ')) != std::string::npos)
|
|
|
|
{
|
2011-07-19 18:42:34 +02:00
|
|
|
if (rpos == 0)
|
|
|
|
{
|
2011-07-18 18:49:38 +02:00
|
|
|
tmp.clear();
|
|
|
|
}
|
2011-07-19 18:42:34 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
tmp.erase(0, rpos + 1);
|
|
|
|
}
|
2011-07-18 18:49:38 +02:00
|
|
|
}
|
|
|
|
}
|
2018-08-02 03:16:33 +03:00
|
|
|
|
2011-07-18 18:49:38 +02:00
|
|
|
/* Erase the input from the output string so we can easily append the completed form later. */
|
|
|
|
output.erase(output.end() - tmp.length(), output.end());
|
|
|
|
|
|
|
|
/* Is there still something in the input string? If not just display all commands and return the unchanged
|
|
|
|
* input. */
|
|
|
|
if (tmp.length() == 0)
|
|
|
|
{
|
|
|
|
matches = mNames;
|
|
|
|
return input;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Iterate through the vector. */
|
2019-03-02 13:27:59 +04:00
|
|
|
for (std::string& name : mNames)
|
|
|
|
{
|
2011-07-18 18:49:38 +02:00
|
|
|
bool string_different = false;
|
|
|
|
|
|
|
|
/* Is the string shorter than the input string? If yes skip it. */
|
2019-03-02 13:27:59 +04:00
|
|
|
if (name.length() < tmp.length())
|
2011-07-18 18:49:38 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Is the beginning of the string different from the input string? If yes skip it. */
|
2019-03-02 13:27:59 +04:00
|
|
|
for (std::string::iterator iter = tmp.begin(), iter2 = name.begin(); iter < tmp.end(); ++iter, ++iter2)
|
|
|
|
{
|
2015-12-07 21:58:30 +01:00
|
|
|
if (Misc::StringUtils::toLower(*iter) != Misc::StringUtils::toLower(*iter2))
|
|
|
|
{
|
2011-07-18 18:49:38 +02:00
|
|
|
string_different = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (string_different)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* The beginning of the string matches the input string, save it for the next test. */
|
2019-03-02 13:27:59 +04:00
|
|
|
matches.push_back(name);
|
2011-07-18 18:49:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* There are no matches. Return the unchanged input. */
|
|
|
|
if (matches.empty())
|
|
|
|
{
|
|
|
|
return input;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Only one match. We're done. */
|
|
|
|
if (matches.size() == 1)
|
|
|
|
{
|
2011-07-19 18:42:34 +02:00
|
|
|
/* Adding quotation marks when the input string started with a quotation mark or has spaces in it*/
|
2013-04-17 18:56:48 -04:00
|
|
|
if ((matches.front().find(' ') != std::string::npos))
|
|
|
|
{
|
2011-07-19 18:42:34 +02:00
|
|
|
if (!has_front_quote)
|
2013-04-17 18:56:48 -04:00
|
|
|
output.append(std::string("\""));
|
|
|
|
return output.append(matches.front() + std::string("\" "));
|
2011-07-19 18:42:34 +02:00
|
|
|
}
|
|
|
|
else if (has_front_quote)
|
|
|
|
{
|
2013-04-17 18:56:48 -04:00
|
|
|
return output.append(matches.front() + std::string("\" "));
|
2011-07-19 18:42:34 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-04-17 18:56:48 -04:00
|
|
|
return output.append(matches.front() + std::string(" "));
|
2011-07-19 18:42:34 +02:00
|
|
|
}
|
2011-07-18 18:49:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if all matching strings match further than input. If yes complete to this match. */
|
|
|
|
int i = tmp.length();
|
|
|
|
|
2019-03-02 13:27:59 +04:00
|
|
|
for (std::string::iterator iter = matches.front().begin() + tmp.length(); iter < matches.front().end();
|
|
|
|
++iter, ++i)
|
|
|
|
{
|
|
|
|
for (std::string& match : matches)
|
|
|
|
{
|
|
|
|
if (Misc::StringUtils::toLower(match[i]) != Misc::StringUtils::toLower(*iter))
|
|
|
|
{
|
2011-07-18 18:49:38 +02:00
|
|
|
/* Append the longest match to the end of the output string*/
|
2019-03-02 13:27:59 +04:00
|
|
|
output.append(matches.front().substr(0, i));
|
2011-07-19 18:42:34 +02:00
|
|
|
return output;
|
2012-03-15 16:01:41 +01:00
|
|
|
}
|
2011-07-18 18:49:38 +02:00
|
|
|
}
|
|
|
|
}
|
2011-07-19 18:42:34 +02:00
|
|
|
|
2011-07-18 18:49:38 +02:00
|
|
|
/* All keywords match with the shortest. Append it to the output string and return it. */
|
|
|
|
return output.append(matches.front());
|
|
|
|
}
|
2012-05-28 09:19:25 +02:00
|
|
|
|
|
|
|
void Console::onResChange(int width, int height)
|
|
|
|
{
|
2022-04-09 23:07:57 +02:00
|
|
|
setCoord(10, 10, width - 10, height / 2);
|
2012-05-28 09:19:25 +02:00
|
|
|
}
|
2012-06-02 12:25:24 +02:00
|
|
|
|
2020-07-11 17:24:20 +04:00
|
|
|
void Console::updateSelectedObjectPtr(const MWWorld::Ptr& currentPtr, const MWWorld::Ptr& newPtr)
|
|
|
|
{
|
|
|
|
if (mPtr == currentPtr)
|
|
|
|
mPtr = newPtr;
|
|
|
|
}
|
|
|
|
|
2017-09-25 21:03:52 +02:00
|
|
|
void Console::setSelectedObject(const MWWorld::Ptr& object)
|
2012-06-02 12:25:24 +02:00
|
|
|
{
|
2013-04-29 21:19:13 +02:00
|
|
|
if (!object.isEmpty())
|
|
|
|
{
|
|
|
|
if (object == mPtr)
|
2022-04-09 23:07:57 +02:00
|
|
|
mPtr = MWWorld::Ptr();
|
2013-04-29 21:19:13 +02:00
|
|
|
else
|
|
|
|
mPtr = object;
|
2013-12-24 00:29:16 +01:00
|
|
|
// User clicked on an object. Restore focus to the console command line.
|
2019-06-09 02:08:09 +03:00
|
|
|
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCommandLine);
|
2013-04-29 21:19:13 +02:00
|
|
|
}
|
2012-06-02 14:19:02 +02:00
|
|
|
else
|
2013-04-29 21:19:13 +02:00
|
|
|
mPtr = MWWorld::Ptr();
|
2022-04-09 23:07:57 +02:00
|
|
|
updateConsoleTitle();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Console::updateConsoleTitle()
|
|
|
|
{
|
|
|
|
std::string title = "#{sConsoleTitle}";
|
|
|
|
if (!mConsoleMode.empty())
|
|
|
|
title = mConsoleMode + " " + title;
|
|
|
|
if (!mPtr.isEmpty())
|
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type
The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID
Slowly going through all the changes to make, still hundreds of errors
a lot of functions/structures use std::string or stringview to designate an ID. So it takes time
Continues slowly replacing ids. There are technically more and more compilation errors
I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type
Continue moving forward, changes to the stores
slowly moving along
Starting to see the fruit of those changes.
still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type.
More replacements. Things are starting to get easier
I can see more and more often the issue is that the function is awaiting a RefId, but is given a string
there is less need to go down functions and to fix a long list of them.
Still moving forward, and for the first time error count is going down!
Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably
Cells are back to using string for the name, haven't fixed everything yet. Many other changes
Under the bar of 400 compilation errors.
more good progress <100 compile errors!
More progress
Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string
some more progress on other fronts
Mostly game settings clean
one error opened a lot of other errors. Down to 18, but more will prbably appear
only link errors left??
Fixed link errors
OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
|
|
|
title.append(" (" + mPtr.getCellRef().getRefId().getRefIdString() + ")");
|
2022-04-09 23:07:57 +02:00
|
|
|
setTitle(title);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Console::setConsoleMode(std::string_view mode)
|
|
|
|
{
|
|
|
|
mConsoleMode = std::string(mode);
|
|
|
|
updateConsoleTitle();
|
2012-06-02 12:25:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Console::onReferenceUnavailable()
|
|
|
|
{
|
2017-09-25 21:03:52 +02:00
|
|
|
setSelectedObject(MWWorld::Ptr());
|
2012-06-02 12:25:24 +02:00
|
|
|
}
|
2014-06-12 21:46:23 +02:00
|
|
|
|
|
|
|
void Console::resetReference()
|
|
|
|
{
|
|
|
|
ReferenceInterface::resetReference();
|
2017-09-25 21:03:52 +02:00
|
|
|
setSelectedObject(MWWorld::Ptr());
|
2014-06-12 21:46:23 +02:00
|
|
|
}
|
2023-02-10 11:54:45 +00:00
|
|
|
|
|
|
|
void Console::initConsoleHistory()
|
|
|
|
{
|
|
|
|
const auto filePath = mCfgMgr.getUserConfigPath() / "console_history.txt";
|
|
|
|
const size_t retrievalLimit = Settings::Manager::getSize("console history buffer size", "General");
|
|
|
|
|
|
|
|
std::ifstream historyFile(filePath);
|
|
|
|
std::string line;
|
|
|
|
|
|
|
|
// Read the previous session's commands from the file
|
|
|
|
while (std::getline(historyFile, line))
|
|
|
|
{
|
|
|
|
// Truncate the list if it exceeds the retrieval limit
|
|
|
|
if (mCommandHistory.size() >= retrievalLimit)
|
|
|
|
mCommandHistory.pop_front();
|
|
|
|
mCommandHistory.push_back(line);
|
|
|
|
}
|
|
|
|
|
|
|
|
historyFile.close();
|
|
|
|
|
|
|
|
mCurrent = mCommandHistory.end();
|
|
|
|
try
|
|
|
|
{
|
|
|
|
mCommandHistoryFile.exceptions(std::fstream::failbit | std::fstream::badbit);
|
|
|
|
mCommandHistoryFile.open(filePath, std::ios_base::trunc);
|
|
|
|
|
|
|
|
// Update the history file
|
|
|
|
for (const auto& histObj : mCommandHistory)
|
|
|
|
mCommandHistoryFile << histObj << std::endl;
|
|
|
|
mCommandHistoryFile.close();
|
|
|
|
|
|
|
|
mCommandHistoryFile.open(filePath, std::ios_base::app);
|
|
|
|
}
|
|
|
|
catch (const std::ios_base::failure& e)
|
|
|
|
{
|
|
|
|
Log(Debug::Error) << "Error: Failed to write to console history file " << filePath << " : " << e.what()
|
|
|
|
<< " : " << std::generic_category().message(errno);
|
|
|
|
}
|
|
|
|
}
|
2010-07-21 10:08:38 +02:00
|
|
|
}
|