Merge branch 'script'
commit
5bfa691f14
@ -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;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
#ifndef CSM_WORLD_SCRIPTCONTEXT_H
|
||||
#define CSM_WORLD_SCRIPTCONTEXT_H
|
||||
|
||||
#include <components/compiler/context.hpp>
|
||||
|
||||
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
|
@ -0,0 +1,118 @@
|
||||
|
||||
#include "scripthighlighter.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <components/compiler/scanner.hpp>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool CSVWorld::ScriptHighlighter::parseComment (const std::string& comment,
|
||||
const Compiler::TokenLoc& loc, Compiler::Scanner& scanner)
|
||||
{
|
||||
highlight (loc, Type_Comment);
|
||||
return true;
|
||||
}
|
||||
|
||||
void CSVWorld::ScriptHighlighter::parseEOF (Compiler::Scanner& scanner)
|
||||
{}
|
||||
|
||||
void CSVWorld::ScriptHighlighter::highlight (const Compiler::TokenLoc& loc, Type type)
|
||||
{
|
||||
int length = static_cast<int> (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::magenta);
|
||||
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));
|
||||
}
|
||||
|
||||
{
|
||||
QTextCharFormat format;
|
||||
format.setForeground (Qt::green);
|
||||
mScheme.insert (std::make_pair (Type_Comment, 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
|
||||
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
#ifndef CSV_WORLD_SCRIPTHIGHLIGHTER_H
|
||||
#define CSV_WORLD_SCRIPTHIGHLIGHTER_H
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <QSyntaxHighlighter>
|
||||
|
||||
#include <components/compiler/nullerrorhandler.hpp>
|
||||
#include <components/compiler/parser.hpp>
|
||||
|
||||
#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,
|
||||
Type_Comment
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
Compiler::NullErrorHandler mErrorHandler;
|
||||
CSMWorld::ScriptContext mContext;
|
||||
std::map<Type, QTextCharFormat> 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?
|
||||
|
||||
virtual bool parseComment (const std::string& comment, const Compiler::TokenLoc& loc,
|
||||
Compiler::Scanner& scanner);
|
||||
///< Handle comment 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
|
@ -0,0 +1,99 @@
|
||||
|
||||
#include "scriptsubview.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <QTextEdit>
|
||||
|
||||
#include "../../model/doc/document.hpp"
|
||||
#include "../../model/world/universalid.hpp"
|
||||
#include "../../model/world/data.hpp"
|
||||
#include "../../model/world/columnbase.hpp"
|
||||
#include "../../model/world/commands.hpp"
|
||||
#include "../../model/world/idtable.hpp"
|
||||
|
||||
#include "scripthighlighter.hpp"
|
||||
|
||||
CSVWorld::ScriptSubView::ChangeLock::ChangeLock (ScriptSubView& view) : mView (view)
|
||||
{
|
||||
++mView.mChangeLocked;
|
||||
}
|
||||
|
||||
CSVWorld::ScriptSubView::ChangeLock::~ChangeLock()
|
||||
{
|
||||
--mView.mChangeLocked;
|
||||
}
|
||||
|
||||
CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document)
|
||||
: SubView (id), mDocument (document), mColumn (-1), mChangeLocked (0)
|
||||
{
|
||||
setWidget (mEditor = new QTextEdit (this));
|
||||
|
||||
mEditor->setAcceptRichText (false);
|
||||
mEditor->setLineWrapMode (QTextEdit::NoWrap);
|
||||
mEditor->setTabStopWidth (4);
|
||||
mEditor->setUndoRedoEnabled (false); // we use OpenCS-wide undo/redo instead
|
||||
|
||||
mModel = &dynamic_cast<CSMWorld::IdTable&> (
|
||||
*document.getData().getTableModel (CSMWorld::UniversalId::Type_Scripts));
|
||||
|
||||
for (int i=0; i<mModel->columnCount(); ++i)
|
||||
if (mModel->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display)==
|
||||
CSMWorld::ColumnBase::Display_Script)
|
||||
{
|
||||
mColumn = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (mColumn==-1)
|
||||
throw std::logic_error ("Can't find script column");
|
||||
|
||||
mEditor->setPlainText (mModel->data (mModel->getModelIndex (id.getId(), mColumn)).toString());
|
||||
|
||||
connect (mEditor, SIGNAL (textChanged()), this, SLOT (textChanged()));
|
||||
|
||||
connect (mModel, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
|
||||
this, SLOT (dataChanged (const QModelIndex&, const QModelIndex&)));
|
||||
|
||||
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)
|
||||
{
|
||||
mEditor->setReadOnly (locked);
|
||||
}
|
||||
|
||||
void CSVWorld::ScriptSubView::textChanged()
|
||||
{
|
||||
ChangeLock lock (*this);
|
||||
|
||||
mDocument.getUndoStack().push (new CSMWorld::ModifyCommand (*mModel,
|
||||
mModel->getModelIndex (getUniversalId().getId(), mColumn), mEditor->toPlainText()));
|
||||
}
|
||||
|
||||
void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight)
|
||||
{
|
||||
if (mChangeLocked)
|
||||
return;
|
||||
|
||||
QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn);
|
||||
|
||||
if (index.row()>=topLeft.row() && index.row()<=bottomRight.row() &&
|
||||
index.column()>=topLeft.column() && index.column()<=bottomRight.column())
|
||||
{
|
||||
QTextCursor cursor = mEditor->textCursor();
|
||||
mEditor->setPlainText (mModel->data (index).toString());
|
||||
mEditor->setTextCursor (cursor);
|
||||
}
|
||||
}
|
||||
|
||||
void CSVWorld::ScriptSubView::rowsAboutToBeRemoved (const QModelIndex& parent, int start, int end)
|
||||
{
|
||||
QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn);
|
||||
|
||||
if (!parent.isValid() && index.row()>=start && index.row()<=end)
|
||||
deleteLater();
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
#ifndef CSV_WORLD_SCRIPTSUBVIEW_H
|
||||
#define CSV_WORLD_SCRIPTSUBVIEW_H
|
||||
|
||||
#include "../doc/subview.hpp"
|
||||
|
||||
class QTextEdit;
|
||||
class QModelIndex;
|
||||
|
||||
namespace CSMDoc
|
||||
{
|
||||
class Document;
|
||||
}
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class IdTable;
|
||||
}
|
||||
|
||||
namespace CSVWorld
|
||||
{
|
||||
class ScriptSubView : public CSVDoc::SubView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
QTextEdit *mEditor;
|
||||
CSMDoc::Document& mDocument;
|
||||
CSMWorld::IdTable *mModel;
|
||||
int mColumn;
|
||||
int mChangeLocked;
|
||||
|
||||
class ChangeLock
|
||||
{
|
||||
ScriptSubView& mView;
|
||||
|
||||
ChangeLock (const ChangeLock&);
|
||||
ChangeLock& operator= (const ChangeLock&);
|
||||
|
||||
public:
|
||||
|
||||
ChangeLock (ScriptSubView& view);
|
||||
~ChangeLock();
|
||||
};
|
||||
|
||||
friend class ChangeLock;
|
||||
|
||||
public:
|
||||
|
||||
ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document);
|
||||
|
||||
virtual void setEditLock (bool locked);
|
||||
|
||||
private slots:
|
||||
|
||||
void textChanged();
|
||||
|
||||
void dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
|
||||
|
||||
void rowsAboutToBeRemoved (const QModelIndex& parent, int start, int end);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -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) {}
|
@ -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
|
Loading…
Reference in New Issue