mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-03-29 22:06:45 +00:00
added script interpreter for console
This commit is contained in:
parent
d72ed19460
commit
281f2d1136
3 changed files with 235 additions and 144 deletions
|
@ -37,6 +37,7 @@ set(GAMEGUI_HEADER
|
||||||
)
|
)
|
||||||
set(GAMEGUI
|
set(GAMEGUI
|
||||||
mwgui/window_manager.cpp
|
mwgui/window_manager.cpp
|
||||||
|
mwgui/console.cpp
|
||||||
)
|
)
|
||||||
source_group(apps\\openmw\\mwgui FILES ${GAMEGUI_HEADER} ${GAMEGUI})
|
source_group(apps\\openmw\\mwgui FILES ${GAMEGUI_HEADER} ${GAMEGUI})
|
||||||
|
|
||||||
|
|
217
apps/openmw/mwgui/console.cpp
Normal file
217
apps/openmw/mwgui/console.cpp
Normal file
|
@ -0,0 +1,217 @@
|
||||||
|
|
||||||
|
#include "console.hpp"
|
||||||
|
|
||||||
|
#include <components/compiler/exception.hpp>
|
||||||
|
|
||||||
|
#include "../mwscript/extensions.hpp"
|
||||||
|
|
||||||
|
namespace MWGui
|
||||||
|
{
|
||||||
|
class ConsoleInterpreterContext : public MWScript::InterpreterContext
|
||||||
|
{
|
||||||
|
Console& mConsole;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
ConsoleInterpreterContext (Console& console, MWWorld::Environment& environment,
|
||||||
|
MWWorld::Ptr reference);
|
||||||
|
|
||||||
|
virtual void messageBox (const std::string& message,
|
||||||
|
const std::vector<std::string>& buttons);
|
||||||
|
};
|
||||||
|
|
||||||
|
ConsoleInterpreterContext::ConsoleInterpreterContext (Console& console,
|
||||||
|
MWWorld::Environment& environment, MWWorld::Ptr reference)
|
||||||
|
: MWScript::InterpreterContext (environment,
|
||||||
|
reference.isEmpty() ? 0 : &reference.getRefData().getLocals(), reference),
|
||||||
|
mConsole (console)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void ConsoleInterpreterContext::messageBox (const std::string& message,
|
||||||
|
const std::vector<std::string>& buttons)
|
||||||
|
{
|
||||||
|
if (!buttons.empty())
|
||||||
|
mConsole.printError ("MessageBox doesn't support buttons while in console mode");
|
||||||
|
else
|
||||||
|
mConsole.printOK (message);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Console::compile (const std::string& cmd, Compiler::Output& output)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::istringstream input (cmd + '\n');
|
||||||
|
|
||||||
|
Compiler::Scanner scanner (*this, input, mCompilerContext.getExtensions());
|
||||||
|
|
||||||
|
Compiler::LineParser parser (*this, mCompilerContext, output.getLocals(),
|
||||||
|
output.getLiterals(), output.getCode());
|
||||||
|
|
||||||
|
scanner.scan (parser);
|
||||||
|
|
||||||
|
return isGood();
|
||||||
|
}
|
||||||
|
catch (const Compiler::SourceException&)
|
||||||
|
{
|
||||||
|
// error has already been reported via error handler
|
||||||
|
}
|
||||||
|
catch (const std::exception& error)
|
||||||
|
{
|
||||||
|
printError (std::string ("An exception has been thrown: ") + error.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Console::report (const std::string& message, const Compiler::TokenLoc& loc, Type type)
|
||||||
|
{
|
||||||
|
std::ostringstream error;
|
||||||
|
error << "column " << loc.mColumn << " (" << loc.mLiteral << "):";
|
||||||
|
|
||||||
|
printError (error.str());
|
||||||
|
printError ((type==ErrorMessage ? "error: " : "warning: ") + message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Console::report (const std::string& message, Type type)
|
||||||
|
{
|
||||||
|
printError ((type==ErrorMessage ? "error: " : "warning: ") + message);
|
||||||
|
}
|
||||||
|
|
||||||
|
Console::Console(int w, int h, MWWorld::Environment& environment,
|
||||||
|
const Compiler::Extensions& extensions)
|
||||||
|
: Layout("openmw_console_layout.xml"),
|
||||||
|
mCompilerContext (MWScript::CompilerContext::Type_Console, environment),
|
||||||
|
mEnvironment (environment)
|
||||||
|
{
|
||||||
|
setCoord(10,10, w-10, h/2);
|
||||||
|
|
||||||
|
getWidget(command, "edit_Command");
|
||||||
|
getWidget(history, "list_History");
|
||||||
|
|
||||||
|
// Set up the command line box
|
||||||
|
command->eventEditSelectAccept =
|
||||||
|
newDelegate(this, &Console::acceptCommand);
|
||||||
|
command->eventKeyButtonPressed =
|
||||||
|
newDelegate(this, &Console::keyPress);
|
||||||
|
|
||||||
|
// Set up the log window
|
||||||
|
history->setOverflowToTheLeft(true);
|
||||||
|
history->setEditStatic(true);
|
||||||
|
history->setVisibleVScroll(true);
|
||||||
|
|
||||||
|
// compiler
|
||||||
|
mCompilerContext.setExtensions (&extensions);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Console::enable()
|
||||||
|
{
|
||||||
|
setVisible(true);
|
||||||
|
|
||||||
|
// Give keyboard focus to the combo box whenever the console is
|
||||||
|
// turned on
|
||||||
|
MyGUI::InputManager::getInstance().setKeyFocusWidget(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Console::disable()
|
||||||
|
{
|
||||||
|
setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Console::setFont(const std::string &fntName)
|
||||||
|
{
|
||||||
|
history->setFontName(fntName);
|
||||||
|
command->setFontName(fntName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Console::clearHistory()
|
||||||
|
{
|
||||||
|
history->setCaption("");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Console::print(const std::string &msg)
|
||||||
|
{
|
||||||
|
history->addText(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Console::printOK(const std::string &msg)
|
||||||
|
{
|
||||||
|
print("#FF00FF" + msg + "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Console::printError(const std::string &msg)
|
||||||
|
{
|
||||||
|
print("#FF2222" + msg + "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Console::keyPress(MyGUI::WidgetPtr _sender,
|
||||||
|
MyGUI::KeyCode key,
|
||||||
|
MyGUI::Char _char)
|
||||||
|
{
|
||||||
|
if(command_history.empty()) return;
|
||||||
|
|
||||||
|
// Traverse history with up and down arrows
|
||||||
|
if(key == MyGUI::KeyCode::ArrowUp)
|
||||||
|
{
|
||||||
|
// If the user was editing a string, store it for later
|
||||||
|
if(current == command_history.end())
|
||||||
|
editString = command->getCaption();
|
||||||
|
|
||||||
|
if(current != command_history.begin())
|
||||||
|
{
|
||||||
|
current--;
|
||||||
|
command->setCaption(*current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(key == MyGUI::KeyCode::ArrowDown)
|
||||||
|
{
|
||||||
|
if(current != command_history.end())
|
||||||
|
{
|
||||||
|
current++;
|
||||||
|
|
||||||
|
if(current != command_history.end())
|
||||||
|
command->setCaption(*current);
|
||||||
|
else
|
||||||
|
// Restore the edit string
|
||||||
|
command->setCaption(editString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Console::acceptCommand(MyGUI::EditPtr _sender)
|
||||||
|
{
|
||||||
|
const std::string &cm = command->getCaption();
|
||||||
|
if(cm.empty()) return;
|
||||||
|
|
||||||
|
// Add the command to the history, and set the current pointer to
|
||||||
|
// the end of the list
|
||||||
|
command_history.push_back(cm);
|
||||||
|
current = command_history.end();
|
||||||
|
editString.clear();
|
||||||
|
|
||||||
|
// Log the command
|
||||||
|
print("#FFFFFF> " + cm + "\n");
|
||||||
|
|
||||||
|
Compiler::Locals locals;
|
||||||
|
Compiler::Output output (locals);
|
||||||
|
|
||||||
|
if (compile (cm, output))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ConsoleInterpreterContext interpreterContext (*this, mEnvironment, MWWorld::Ptr());
|
||||||
|
Interpreter::Interpreter interpreter (interpreterContext);
|
||||||
|
MWScript::installOpcodes (interpreter);
|
||||||
|
std::vector<Interpreter::Type_Code> code;
|
||||||
|
output.getCode (code);
|
||||||
|
interpreter.run (&code[0], code.size());
|
||||||
|
}
|
||||||
|
catch (const std::exception& error)
|
||||||
|
{
|
||||||
|
printError (std::string ("An exception has been thrown: ") + error.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
command->setCaption("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -10,10 +10,11 @@
|
||||||
#include <components/compiler/lineparser.hpp>
|
#include <components/compiler/lineparser.hpp>
|
||||||
#include <components/compiler/scanner.hpp>
|
#include <components/compiler/scanner.hpp>
|
||||||
#include <components/compiler/locals.hpp>
|
#include <components/compiler/locals.hpp>
|
||||||
#include <components/compiler/literals.hpp>
|
#include <components/compiler/output.hpp>
|
||||||
#include <components/compiler/exception.hpp>
|
#include <components/interpreter/interpreter.hpp>
|
||||||
|
|
||||||
#include "../mwscript/compilercontext.hpp"
|
#include "../mwscript/compilercontext.hpp"
|
||||||
|
#include "../mwscript/interpretercontext.hpp"
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
|
@ -22,51 +23,15 @@ namespace MWGui
|
||||||
private:
|
private:
|
||||||
|
|
||||||
MWScript::CompilerContext mCompilerContext;
|
MWScript::CompilerContext mCompilerContext;
|
||||||
|
MWWorld::Environment& mEnvironment;
|
||||||
|
|
||||||
bool compile (const std::string& cmd)
|
bool compile (const std::string& cmd, Compiler::Output& output);
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
std::istringstream input (cmd + '\n');
|
|
||||||
|
|
||||||
Compiler::Scanner scanner (*this, input, mCompilerContext.getExtensions());
|
|
||||||
|
|
||||||
Compiler::Locals locals;
|
|
||||||
Compiler::Literals literals;
|
|
||||||
std::vector<Interpreter::Type_Code> code;
|
|
||||||
Compiler::LineParser parser (*this, mCompilerContext, locals, literals, code);
|
|
||||||
|
|
||||||
scanner.scan (parser);
|
|
||||||
|
|
||||||
return isGood();
|
|
||||||
}
|
|
||||||
catch (const Compiler::SourceException&)
|
|
||||||
{
|
|
||||||
// error has already been reported via error handler
|
|
||||||
}
|
|
||||||
catch (const std::exception& error)
|
|
||||||
{
|
|
||||||
printError (std::string ("An exception has been thrown: ") + error.what());
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Report error to the user.
|
/// Report error to the user.
|
||||||
virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type)
|
virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type);
|
||||||
{
|
|
||||||
std::ostringstream error;
|
|
||||||
error << "column " << loc.mColumn << " (" << loc.mLiteral << "):";
|
|
||||||
|
|
||||||
printError (error.str());
|
|
||||||
printError ((type==ErrorMessage ? "error: " : "warning: ") + message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Report a file related error
|
/// Report a file related error
|
||||||
virtual void report (const std::string& message, Type type)
|
virtual void report (const std::string& message, Type type);
|
||||||
{
|
|
||||||
printError ((type==ErrorMessage ? "error: " : "warning: ") + message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MyGUI::EditPtr command;
|
MyGUI::EditPtr command;
|
||||||
|
@ -79,127 +44,35 @@ namespace MWGui
|
||||||
StringList::iterator current;
|
StringList::iterator current;
|
||||||
std::string editString;
|
std::string editString;
|
||||||
|
|
||||||
Console(int w, int h, MWWorld::Environment& environment, const Compiler::Extensions& extensions)
|
Console(int w, int h, MWWorld::Environment& environment, const Compiler::Extensions& extensions);
|
||||||
: Layout("openmw_console_layout.xml"),
|
|
||||||
mCompilerContext (MWScript::CompilerContext::Type_Console, environment)
|
|
||||||
{
|
|
||||||
setCoord(10,10, w-10, h/2);
|
|
||||||
|
|
||||||
getWidget(command, "edit_Command");
|
void enable();
|
||||||
getWidget(history, "list_History");
|
|
||||||
|
|
||||||
// Set up the command line box
|
void disable();
|
||||||
command->eventEditSelectAccept =
|
|
||||||
newDelegate(this, &Console::acceptCommand);
|
|
||||||
command->eventKeyButtonPressed =
|
|
||||||
newDelegate(this, &Console::keyPress);
|
|
||||||
|
|
||||||
// Set up the log window
|
void setFont(const std::string &fntName);
|
||||||
history->setOverflowToTheLeft(true);
|
|
||||||
history->setEditStatic(true);
|
|
||||||
history->setVisibleVScroll(true);
|
|
||||||
|
|
||||||
// compiler
|
|
||||||
mCompilerContext.setExtensions (&extensions);
|
|
||||||
}
|
|
||||||
|
|
||||||
void enable()
|
void clearHistory();
|
||||||
{
|
|
||||||
setVisible(true);
|
|
||||||
|
|
||||||
// Give keyboard focus to the combo box whenever the console is
|
|
||||||
// turned on
|
|
||||||
MyGUI::InputManager::getInstance().setKeyFocusWidget(command);
|
|
||||||
}
|
|
||||||
|
|
||||||
void disable()
|
|
||||||
{
|
|
||||||
setVisible(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setFont(const std::string &fntName)
|
|
||||||
{
|
|
||||||
history->setFontName(fntName);
|
|
||||||
command->setFontName(fntName);
|
|
||||||
}
|
|
||||||
|
|
||||||
void clearHistory()
|
|
||||||
{
|
|
||||||
history->setCaption("");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print a message to the console. Messages may contain color
|
// Print a message to the console. Messages may contain color
|
||||||
// code, eg. "#FFFFFF this is white".
|
// code, eg. "#FFFFFF this is white".
|
||||||
void print(const std::string &msg)
|
void print(const std::string &msg);
|
||||||
{ history->addText(msg); }
|
|
||||||
|
|
||||||
// These are pre-colored versions that you should use.
|
// These are pre-colored versions that you should use.
|
||||||
|
|
||||||
/// Output from successful console command
|
/// Output from successful console command
|
||||||
void printOK(const std::string &msg)
|
void printOK(const std::string &msg);
|
||||||
{ print("#FF00FF" + msg + "\n"); }
|
|
||||||
|
|
||||||
/// Error message
|
/// Error message
|
||||||
void printError(const std::string &msg)
|
void printError(const std::string &msg);
|
||||||
{ print("#FF2222" + msg + "\n"); }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void keyPress(MyGUI::WidgetPtr _sender,
|
void keyPress(MyGUI::WidgetPtr _sender,
|
||||||
MyGUI::KeyCode key,
|
MyGUI::KeyCode key,
|
||||||
MyGUI::Char _char)
|
MyGUI::Char _char);
|
||||||
{
|
|
||||||
if(command_history.empty()) return;
|
|
||||||
|
|
||||||
// Traverse history with up and down arrows
|
void acceptCommand(MyGUI::EditPtr _sender);
|
||||||
if(key == MyGUI::KeyCode::ArrowUp)
|
|
||||||
{
|
|
||||||
// If the user was editing a string, store it for later
|
|
||||||
if(current == command_history.end())
|
|
||||||
editString = command->getCaption();
|
|
||||||
|
|
||||||
if(current != command_history.begin())
|
|
||||||
{
|
|
||||||
current--;
|
|
||||||
command->setCaption(*current);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(key == MyGUI::KeyCode::ArrowDown)
|
|
||||||
{
|
|
||||||
if(current != command_history.end())
|
|
||||||
{
|
|
||||||
current++;
|
|
||||||
|
|
||||||
if(current != command_history.end())
|
|
||||||
command->setCaption(*current);
|
|
||||||
else
|
|
||||||
// Restore the edit string
|
|
||||||
command->setCaption(editString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void acceptCommand(MyGUI::EditPtr _sender)
|
|
||||||
{
|
|
||||||
const std::string &cm = command->getCaption();
|
|
||||||
if(cm.empty()) return;
|
|
||||||
|
|
||||||
// Add the command to the history, and set the current pointer to
|
|
||||||
// the end of the list
|
|
||||||
command_history.push_back(cm);
|
|
||||||
current = command_history.end();
|
|
||||||
editString.clear();
|
|
||||||
|
|
||||||
// Log the command
|
|
||||||
print("#FFFFFF> " + cm + "\n");
|
|
||||||
|
|
||||||
if (compile (cm))
|
|
||||||
{
|
|
||||||
// TODO execute command
|
|
||||||
}
|
|
||||||
|
|
||||||
command->setCaption("");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue