From 74145410f24d6c60b6cdca81aa14e40564691cda Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 10 Apr 2013 22:49:22 +0200 Subject: [PATCH] basic syntax highlighting in script subview --- apps/opencs/CMakeLists.txt | 4 +- apps/opencs/model/world/scriptcontext.cpp | 22 ++++ apps/opencs/model/world/scriptcontext.hpp | 26 +++++ apps/opencs/view/world/scripthighlighter.cpp | 105 +++++++++++++++++++ apps/opencs/view/world/scripthighlighter.hpp | 77 ++++++++++++++ apps/opencs/view/world/scriptsubview.cpp | 4 + components/CMakeLists.txt | 2 +- components/compiler/nullerrorhandler.cpp | 6 ++ components/compiler/nullerrorhandler.hpp | 21 ++++ 9 files changed, 264 insertions(+), 3 deletions(-) create mode 100644 apps/opencs/model/world/scriptcontext.cpp create mode 100644 apps/opencs/model/world/scriptcontext.hpp create mode 100644 apps/opencs/view/world/scripthighlighter.cpp create mode 100644 apps/opencs/view/world/scripthighlighter.hpp create mode 100644 components/compiler/nullerrorhandler.cpp create mode 100644 components/compiler/nullerrorhandler.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index bd882892f..5c15938bd 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -22,7 +22,7 @@ opencs_units (model/world opencs_units_noqt (model/world - universalid data record idcollection commands columnbase + universalid data record idcollection commands columnbase scriptcontext ) opencs_hdrs_noqt (model/world @@ -59,7 +59,7 @@ opencs_units (view/world ) opencs_units_noqt (view/world - dialoguesubview util subviews enumdelegate vartypedelegate + dialoguesubview util subviews enumdelegate vartypedelegate scripthighlighter ) diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp new file mode 100644 index 000000000..69b72abf2 --- /dev/null +++ b/apps/opencs/model/world/scriptcontext.cpp @@ -0,0 +1,22 @@ + +#include "scriptcontext.hpp" + +bool CSMWorld::ScriptContext::canDeclareLocals() const +{ + return false; +} + +char CSMWorld::ScriptContext::getGlobalType (const std::string& name) const +{ + return ' '; +} + +char CSMWorld::ScriptContext::getMemberType (const std::string& name, const std::string& id) const +{ + return ' '; +} + +bool CSMWorld::ScriptContext::isId (const std::string& name) const +{ + return false; +} \ No newline at end of file diff --git a/apps/opencs/model/world/scriptcontext.hpp b/apps/opencs/model/world/scriptcontext.hpp new file mode 100644 index 000000000..1231aea64 --- /dev/null +++ b/apps/opencs/model/world/scriptcontext.hpp @@ -0,0 +1,26 @@ +#ifndef CSM_WORLD_SCRIPTCONTEXT_H +#define CSM_WORLD_SCRIPTCONTEXT_H + +#include + +namespace CSMWorld +{ + class ScriptContext : public Compiler::Context + { + public: + + virtual bool canDeclareLocals() const; + ///< Is the compiler allowed to declare local variables? + + virtual char getGlobalType (const std::string& name) const; + ///< 'l: long, 's': short, 'f': float, ' ': does not exist. + + virtual char getMemberType (const std::string& name, const std::string& id) const; + ///< 'l: long, 's': short, 'f': float, ' ': does not exist. + + virtual bool isId (const std::string& name) const; + ///< Does \a name match an ID, that can be referenced? + }; +} + +#endif diff --git a/apps/opencs/view/world/scripthighlighter.cpp b/apps/opencs/view/world/scripthighlighter.cpp new file mode 100644 index 000000000..1e93ac26b --- /dev/null +++ b/apps/opencs/view/world/scripthighlighter.cpp @@ -0,0 +1,105 @@ + +#include "scripthighlighter.hpp" + +#include + +#include + +bool CSVWorld::ScriptHighlighter::parseInt (int value, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner) +{ + highlight (loc, Type_Int); + return true; +} + +bool CSVWorld::ScriptHighlighter::parseFloat (float value, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner) +{ + highlight (loc, Type_Float); + return true; +} + +bool CSVWorld::ScriptHighlighter::parseName (const std::string& name, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner) +{ + highlight (loc, Type_Name); + return true; +} + +bool CSVWorld::ScriptHighlighter::parseKeyword (int keyword, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner) +{ + highlight (loc, Type_Keyword); + return true; +} + +bool CSVWorld::ScriptHighlighter::parseSpecial (int code, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner) +{ + highlight (loc, Type_Special); + return true; +} + +void CSVWorld::ScriptHighlighter::parseEOF (Compiler::Scanner& scanner) +{} + +void CSVWorld::ScriptHighlighter::highlight (const Compiler::TokenLoc& loc, Type type) +{ + int length = static_cast (loc.mLiteral.size()); + + int index = loc.mColumn; + + // compensate for bug in Compiler::Scanner (position of token is the character after the token) + index -= length; + + setFormat (index, length, mScheme[type]); +} + +CSVWorld::ScriptHighlighter::ScriptHighlighter (QTextDocument *parent) +: QSyntaxHighlighter (parent), Compiler::Parser (mErrorHandler, mContext) +{ + /// \ŧodo replace this with user settings + { + QTextCharFormat format; + format.setForeground (Qt::darkMagenta); + mScheme.insert (std::make_pair (Type_Int, format)); + } + + { + QTextCharFormat format; + format.setForeground (Qt::green); + mScheme.insert (std::make_pair (Type_Float, format)); + } + + { + QTextCharFormat format; + format.setForeground (Qt::gray); + mScheme.insert (std::make_pair (Type_Name, format)); + } + + { + QTextCharFormat format; + format.setForeground (Qt::red); + mScheme.insert (std::make_pair (Type_Keyword, format)); + } + + { + QTextCharFormat format; + format.setForeground (Qt::darkYellow); + mScheme.insert (std::make_pair (Type_Special, format)); + } +} + +void CSVWorld::ScriptHighlighter::highlightBlock (const QString& text) +{ + std::istringstream stream (text.toUtf8().constData()); + + Compiler::Scanner scanner (mErrorHandler, stream, mContext.getExtensions()); + + try + { + scanner.scan (*this); + } + catch (...) {} // ignore syntax errors + +} \ No newline at end of file diff --git a/apps/opencs/view/world/scripthighlighter.hpp b/apps/opencs/view/world/scripthighlighter.hpp new file mode 100644 index 000000000..e9918f99b --- /dev/null +++ b/apps/opencs/view/world/scripthighlighter.hpp @@ -0,0 +1,77 @@ +#ifndef CSV_WORLD_SCRIPTHIGHLIGHTER_H +#define CSV_WORLD_SCRIPTHIGHLIGHTER_H + +#include + +#include + +#include +#include + +#include "../../model/world/scriptcontext.hpp" + +namespace CSVWorld +{ + class ScriptHighlighter : public QSyntaxHighlighter, private Compiler::Parser + { + public: + + enum Type + { + Type_Int, + Type_Float, + Type_Name, + Type_Keyword, + Type_Special + }; + + private: + + Compiler::NullErrorHandler mErrorHandler; + CSMWorld::ScriptContext mContext; + std::map mScheme; + + private: + + virtual bool parseInt (int value, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner); + ///< Handle an int token. + /// \return fetch another token? + + virtual bool parseFloat (float value, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner); + ///< Handle a float token. + /// \return fetch another token? + + virtual bool parseName (const std::string& name, + const Compiler::TokenLoc& loc, Compiler::Scanner& scanner); + ///< Handle a name token. + /// \return fetch another token? + + virtual bool parseKeyword (int keyword, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner); + ///< Handle a keyword token. + /// \return fetch another token? + + virtual bool parseSpecial (int code, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner); + ///< Handle a special character token. + /// \return fetch another token? + + ///< Handle a special character token. + /// \return fetch another token? + + virtual void parseEOF (Compiler::Scanner& scanner); + ///< Handle EOF token. + + void highlight (const Compiler::TokenLoc& loc, Type type); + + public: + + ScriptHighlighter (QTextDocument *parent); + + virtual void highlightBlock (const QString& text); + }; +} + +#endif diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 0319033b0..ab1c2d57c 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -12,6 +12,8 @@ #include "../../model/world/commands.hpp" #include "../../model/world/idtable.hpp" +#include "scripthighlighter.hpp" + CSVWorld::ScriptSubView::ChangeLock::ChangeLock (ScriptSubView& view) : mView (view) { ++mView.mChangeLocked; @@ -55,6 +57,8 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: connect (mModel, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), this, SLOT (rowsAboutToBeRemoved (const QModelIndex&, int, int))); + + new ScriptHighlighter (mEditor->document()); } void CSVWorld::ScriptSubView::setEditLock (bool locked) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a2f416fcc..ed12ff2f0 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -54,7 +54,7 @@ add_component_dir (files add_component_dir (compiler context controlparser errorhandler exception exprparser extensions fileparser generator lineparser literals locals output parser scanner scriptparser skipparser streamerrorhandler - stringparser tokenloc + stringparser tokenloc nullerrorhandler ) add_component_dir (interpreter diff --git a/components/compiler/nullerrorhandler.cpp b/components/compiler/nullerrorhandler.cpp new file mode 100644 index 000000000..3071701e8 --- /dev/null +++ b/components/compiler/nullerrorhandler.cpp @@ -0,0 +1,6 @@ + +#include "nullerrorhandler.hpp" + +void Compiler::NullErrorHandler::report (const std::string& message, const TokenLoc& loc, Type type) {} + +void Compiler::NullErrorHandler::report (const std::string& message, Type type) {} \ No newline at end of file diff --git a/components/compiler/nullerrorhandler.hpp b/components/compiler/nullerrorhandler.hpp new file mode 100644 index 000000000..bb4db99a2 --- /dev/null +++ b/components/compiler/nullerrorhandler.hpp @@ -0,0 +1,21 @@ + +#ifndef COMPILER_NULLERRORHANDLER_H_INCLUDED +#define COMPILER_NULLERRORHANDLER_H_INCLUDED + +#include "errorhandler.hpp" + +namespace Compiler +{ + /// \brief Error handler implementation: Ignore all error messages + + class NullErrorHandler : public ErrorHandler + { + virtual void report (const std::string& message, const TokenLoc& loc, Type type); + ///< Report error to the user. + + virtual void report (const std::string& message, Type type); + ///< Report a file related error + }; +} + +#endif