From 281f2d1136f4b7190515c5822cb529ef165b1bf8 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 21 Jul 2010 10:08:38 +0200 Subject: [PATCH] added script interpreter for console --- apps/openmw/CMakeLists.txt | 1 + apps/openmw/mwgui/console.cpp | 217 ++++++++++++++++++++++++++++++++++ apps/openmw/mwgui/console.hpp | 171 ++++----------------------- 3 files changed, 240 insertions(+), 149 deletions(-) create mode 100644 apps/openmw/mwgui/console.cpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index b05ca6eaa1..6833ce0690 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -37,6 +37,7 @@ set(GAMEGUI_HEADER ) set(GAMEGUI mwgui/window_manager.cpp + mwgui/console.cpp ) source_group(apps\\openmw\\mwgui FILES ${GAMEGUI_HEADER} ${GAMEGUI}) diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp new file mode 100644 index 0000000000..f624bfb036 --- /dev/null +++ b/apps/openmw/mwgui/console.cpp @@ -0,0 +1,217 @@ + +#include "console.hpp" + +#include + +#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& 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& 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 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(""); + } +} + diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index 54ba503306..25212d627f 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -10,10 +10,11 @@ #include #include #include -#include -#include +#include +#include #include "../mwscript/compilercontext.hpp" +#include "../mwscript/interpretercontext.hpp" namespace MWGui { @@ -22,51 +23,15 @@ namespace MWGui private: MWScript::CompilerContext mCompilerContext; + MWWorld::Environment& mEnvironment; - bool compile (const std::string& cmd) - { - try - { - std::istringstream input (cmd + '\n'); - - Compiler::Scanner scanner (*this, input, mCompilerContext.getExtensions()); - - Compiler::Locals locals; - Compiler::Literals literals; - std::vector 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; - } + bool compile (const std::string& cmd, Compiler::Output& output); /// Report error to the user. - 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); - } + virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type); /// Report a file related error - virtual void report (const std::string& message, Type type) - { - printError ((type==ErrorMessage ? "error: " : "warning: ") + message); - } + virtual void report (const std::string& message, Type type); public: MyGUI::EditPtr command; @@ -79,127 +44,35 @@ namespace MWGui StringList::iterator current; std::string editString; - 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"); - 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 enable() - { - 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(""); - } + Console(int w, int h, MWWorld::Environment& environment, const Compiler::Extensions& extensions); + + void enable(); + + void disable(); + + void setFont(const std::string &fntName); + + void clearHistory(); // Print a message to the console. Messages may contain color // code, eg. "#FFFFFF this is white". - void print(const std::string &msg) - { history->addText(msg); } + void print(const std::string &msg); // These are pre-colored versions that you should use. /// Output from successful console command - void printOK(const std::string &msg) - { print("#FF00FF" + msg + "\n"); } + void printOK(const std::string &msg); /// Error message - void printError(const std::string &msg) - { print("#FF2222" + msg + "\n"); } + void printError(const std::string &msg); private: void 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 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(""); - } + MyGUI::Char _char); + + void acceptCommand(MyGUI::EditPtr _sender); }; } #endif