diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | ce4a32fe52ef09d8f5ff1dd22c001110902b60a2 (patch) | |
tree | 5ac38a06f3dde268dc7927dc155896926aaf7012 /kate/part/katehighlight.cpp | |
download | tdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.tar.gz tdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdelibs@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kate/part/katehighlight.cpp')
-rw-r--r-- | kate/part/katehighlight.cpp | 3473 |
1 files changed, 3473 insertions, 0 deletions
diff --git a/kate/part/katehighlight.cpp b/kate/part/katehighlight.cpp new file mode 100644 index 000000000..84bfc67fd --- /dev/null +++ b/kate/part/katehighlight.cpp @@ -0,0 +1,3473 @@ +/* This file is part of the KDE libraries + Copyright (C) 2003, 2004 Anders Lund <anders@alweb.dk> + Copyright (C) 2003 Hamish Rodda <rodda@kde.org> + Copyright (C) 2001,2002 Joseph Wenninger <jowenn@kde.org> + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + Copyright (C) 1999 Jochen Wilhelmy <digisnap@cs.tu-berlin.de> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +//BEGIN INCLUDES +#include "katehighlight.h" +#include "katehighlight.moc" + +#include "katetextline.h" +#include "katedocument.h" +#include "katesyntaxdocument.h" +#include "katerenderer.h" +#include "katefactory.h" +#include "kateschema.h" +#include "kateconfig.h" + +#include <kconfig.h> +#include <kglobal.h> +#include <kinstance.h> +#include <kmimetype.h> +#include <klocale.h> +#include <kregexp.h> +#include <kpopupmenu.h> +#include <kglobalsettings.h> +#include <kdebug.h> +#include <kstandarddirs.h> +#include <kmessagebox.h> +#include <kstaticdeleter.h> +#include <kapplication.h> + +#include <qstringlist.h> +#include <qtextstream.h> +//END + +//BEGIN defines +// same as in kmimemagic, no need to feed more data +#define KATE_HL_HOWMANY 1024 + +// min. x seconds between two dynamic contexts reset +static const int KATE_DYNAMIC_CONTEXTS_RESET_DELAY = 30 * 1000; + +// x is a QString. if x is "true" or "1" this expression returns "true" +#define IS_TRUE(x) x.lower() == QString("true") || x.toInt() == 1 +//END defines + +//BEGIN Prviate HL classes + +inline bool kateInsideString (const QString &str, QChar ch) +{ + const QChar *unicode = str.unicode(); + const uint len = str.length(); + for (uint i=0; i < len; i++) + if (unicode[i] == ch) + return true; + + return false; +} + +class KateHlItem +{ + public: + KateHlItem(int attribute, int context,signed char regionId, signed char regionId2); + virtual ~KateHlItem(); + + public: + // caller must keep in mind: LEN > 0 is a must !!!!!!!!!!!!!!!!!!!!!1 + // Now, the function returns the offset detected, or 0 if no match is found. + // bool linestart isn't needed, this is equivalent to offset == 0. + virtual int checkHgl(const QString& text, int offset, int len) = 0; + + virtual bool lineContinue(){return false;} + + virtual QStringList *capturedTexts() {return 0;} + virtual KateHlItem *clone(const QStringList *) {return this;} + + static void dynamicSubstitute(QString& str, const QStringList *args); + + QMemArray<KateHlItem*> subItems; + int attr; + int ctx; + signed char region; + signed char region2; + + bool lookAhead; + + bool dynamic; + bool dynamicChild; + bool firstNonSpace; + bool onlyConsume; + int column; + + // start enable flags, nicer than the virtual methodes + // saves function calls + bool alwaysStartEnable; + bool customStartEnable; +}; + +class KateHlContext +{ + public: + KateHlContext(const QString &_hlId, int attribute, int lineEndContext,int _lineBeginContext, + bool _fallthrough, int _fallthroughContext, bool _dynamic,bool _noIndentationBasedFolding); + virtual ~KateHlContext(); + KateHlContext *clone(const QStringList *args); + + QValueVector<KateHlItem*> items; + QString hlId; ///< A unique highlight identifier. Used to look up correct properties. + int attr; + int ctx; + int lineBeginContext; + /** @internal anders: possible escape if no rules matches. + false unless 'fallthrough="1|true"' (insensitive) + if true, go to ftcxt w/o eating of string. + ftctx is "fallthroughContext" in xml files, valid values are int or #pop[..] + see in KateHighlighting::doHighlight */ + bool fallthrough; + int ftctx; // where to go after no rules matched + + bool dynamic; + bool dynamicChild; + bool noIndentationBasedFolding; +}; + +class KateEmbeddedHlInfo +{ + public: + KateEmbeddedHlInfo() {loaded=false;context0=-1;} + KateEmbeddedHlInfo(bool l, int ctx0) {loaded=l;context0=ctx0;} + + public: + bool loaded; + int context0; +}; + +class KateHlIncludeRule +{ + public: + KateHlIncludeRule(int ctx_=0, uint pos_=0, const QString &incCtxN_="", bool incAttrib=false) + : ctx(ctx_) + , pos( pos_) + , incCtxN( incCtxN_ ) + , includeAttrib( incAttrib ) + { + incCtx=-1; + } + //KateHlIncludeRule(int ctx_, uint pos_, bool incAttrib) {ctx=ctx_;pos=pos_;incCtx=-1;incCtxN="";includeAttrib=incAttrib} + + public: + int ctx; + uint pos; + int incCtx; + QString incCtxN; + bool includeAttrib; +}; + +class KateHlCharDetect : public KateHlItem +{ + public: + KateHlCharDetect(int attribute, int context,signed char regionId,signed char regionId2, QChar); + + virtual int checkHgl(const QString& text, int offset, int len); + virtual KateHlItem *clone(const QStringList *args); + + private: + QChar sChar; +}; + +class KateHl2CharDetect : public KateHlItem +{ + public: + KateHl2CharDetect(int attribute, int context, signed char regionId,signed char regionId2, QChar ch1, QChar ch2); + KateHl2CharDetect(int attribute, int context,signed char regionId,signed char regionId2, const QChar *ch); + + virtual int checkHgl(const QString& text, int offset, int len); + virtual KateHlItem *clone(const QStringList *args); + + private: + QChar sChar1; + QChar sChar2; +}; + +class KateHlStringDetect : public KateHlItem +{ + public: + KateHlStringDetect(int attribute, int context, signed char regionId,signed char regionId2, const QString &, bool inSensitive=false); + + virtual int checkHgl(const QString& text, int offset, int len); + virtual KateHlItem *clone(const QStringList *args); + + private: + const QString str; + const int strLen; + const bool _inSensitive; +}; + +class KateHlRangeDetect : public KateHlItem +{ + public: + KateHlRangeDetect(int attribute, int context, signed char regionId,signed char regionId2, QChar ch1, QChar ch2); + + virtual int checkHgl(const QString& text, int offset, int len); + + private: + QChar sChar1; + QChar sChar2; +}; + +class KateHlKeyword : public KateHlItem +{ + public: + KateHlKeyword(int attribute, int context,signed char regionId,signed char regionId2, bool insensitive, const QString& delims); + virtual ~KateHlKeyword (); + + void addList(const QStringList &); + virtual int checkHgl(const QString& text, int offset, int len); + + private: + QMemArray< QDict<bool>* > dict; + bool _insensitive; + const QString& deliminators; + int minLen; + int maxLen; +}; + +class KateHlInt : public KateHlItem +{ + public: + KateHlInt(int attribute, int context, signed char regionId,signed char regionId2); + + virtual int checkHgl(const QString& text, int offset, int len); +}; + +class KateHlFloat : public KateHlItem +{ + public: + KateHlFloat(int attribute, int context, signed char regionId,signed char regionId2); + virtual ~KateHlFloat () {} + + virtual int checkHgl(const QString& text, int offset, int len); +}; + +class KateHlCFloat : public KateHlFloat +{ + public: + KateHlCFloat(int attribute, int context, signed char regionId,signed char regionId2); + + virtual int checkHgl(const QString& text, int offset, int len); + int checkIntHgl(const QString& text, int offset, int len); +}; + +class KateHlCOct : public KateHlItem +{ + public: + KateHlCOct(int attribute, int context, signed char regionId,signed char regionId2); + + virtual int checkHgl(const QString& text, int offset, int len); +}; + +class KateHlCHex : public KateHlItem +{ + public: + KateHlCHex(int attribute, int context, signed char regionId,signed char regionId2); + + virtual int checkHgl(const QString& text, int offset, int len); +}; + +class KateHlLineContinue : public KateHlItem +{ + public: + KateHlLineContinue(int attribute, int context, signed char regionId,signed char regionId2); + + virtual bool endEnable(QChar c) {return c == '\0';} + virtual int checkHgl(const QString& text, int offset, int len); + virtual bool lineContinue(){return true;} +}; + +class KateHlCStringChar : public KateHlItem +{ + public: + KateHlCStringChar(int attribute, int context, signed char regionId,signed char regionId2); + + virtual int checkHgl(const QString& text, int offset, int len); +}; + +class KateHlCChar : public KateHlItem +{ + public: + KateHlCChar(int attribute, int context,signed char regionId,signed char regionId2); + + virtual int checkHgl(const QString& text, int offset, int len); +}; + +class KateHlAnyChar : public KateHlItem +{ + public: + KateHlAnyChar(int attribute, int context, signed char regionId,signed char regionId2, const QString& charList); + + virtual int checkHgl(const QString& text, int offset, int len); + + private: + const QString _charList; +}; + +class KateHlRegExpr : public KateHlItem +{ + public: + KateHlRegExpr(int attribute, int context,signed char regionId,signed char regionId2 ,QString expr, bool insensitive, bool minimal); + ~KateHlRegExpr() { delete Expr; }; + + virtual int checkHgl(const QString& text, int offset, int len); + virtual QStringList *capturedTexts(); + virtual KateHlItem *clone(const QStringList *args); + + private: + QRegExp *Expr; + bool handlesLinestart; + QString _regexp; + bool _insensitive; + bool _minimal; +}; + +class KateHlDetectSpaces : public KateHlItem +{ + public: + KateHlDetectSpaces (int attribute, int context,signed char regionId,signed char regionId2) + : KateHlItem(attribute,context,regionId,regionId2) {} + + virtual int checkHgl(const QString& text, int offset, int len) + { + int len2 = offset + len; + while ((offset < len2) && text[offset].isSpace()) offset++; + return offset; + } +}; + +class KateHlDetectIdentifier : public KateHlItem +{ + public: + KateHlDetectIdentifier (int attribute, int context,signed char regionId,signed char regionId2) + : KateHlItem(attribute,context,regionId,regionId2) { alwaysStartEnable = false; } + + virtual int checkHgl(const QString& text, int offset, int len) + { + // first char should be a letter or underscore + if ( text[offset].isLetter() || text[offset] == QChar ('_') ) + { + // memorize length + int len2 = offset+len; + + // one char seen + offset++; + + // now loop for all other thingies + while ( + (offset < len2) + && (text[offset].isLetterOrNumber() || (text[offset] == QChar ('_'))) + ) + offset++; + + return offset; + } + + return 0; + } +}; + +//END + +//BEGIN STATICS +KateHlManager *KateHlManager::s_self = 0; + +static const bool trueBool = true; +static const QString stdDeliminator = QString (" \t.():!+,-<=>%&*/;?[]^{|}~\\"); +//END + +//BEGIN NON MEMBER FUNCTIONS +static KateHlItemData::ItemStyles getDefStyleNum(QString name) +{ + if (name=="dsNormal") return KateHlItemData::dsNormal; + else if (name=="dsKeyword") return KateHlItemData::dsKeyword; + else if (name=="dsDataType") return KateHlItemData::dsDataType; + else if (name=="dsDecVal") return KateHlItemData::dsDecVal; + else if (name=="dsBaseN") return KateHlItemData::dsBaseN; + else if (name=="dsFloat") return KateHlItemData::dsFloat; + else if (name=="dsChar") return KateHlItemData::dsChar; + else if (name=="dsString") return KateHlItemData::dsString; + else if (name=="dsComment") return KateHlItemData::dsComment; + else if (name=="dsOthers") return KateHlItemData::dsOthers; + else if (name=="dsAlert") return KateHlItemData::dsAlert; + else if (name=="dsFunction") return KateHlItemData::dsFunction; + else if (name=="dsRegionMarker") return KateHlItemData::dsRegionMarker; + else if (name=="dsError") return KateHlItemData::dsError; + + return KateHlItemData::dsNormal; +} +//END + +//BEGIN KateHlItem +KateHlItem::KateHlItem(int attribute, int context,signed char regionId,signed char regionId2) + : attr(attribute), + ctx(context), + region(regionId), + region2(regionId2), + lookAhead(false), + dynamic(false), + dynamicChild(false), + firstNonSpace(false), + onlyConsume(false), + column (-1), + alwaysStartEnable (true), + customStartEnable (false) +{ +} + +KateHlItem::~KateHlItem() +{ + //kdDebug(13010)<<"In hlItem::~KateHlItem()"<<endl; + for (uint i=0; i < subItems.size(); i++) + delete subItems[i]; +} + +void KateHlItem::dynamicSubstitute(QString &str, const QStringList *args) +{ + for (uint i = 0; i < str.length() - 1; ++i) + { + if (str[i] == '%') + { + char c = str[i + 1].latin1(); + if (c == '%') + str.replace(i, 1, ""); + else if (c >= '0' && c <= '9') + { + if ((uint)(c - '0') < args->size()) + { + str.replace(i, 2, (*args)[c - '0']); + i += ((*args)[c - '0']).length() - 1; + } + else + { + str.replace(i, 2, ""); + --i; + } + } + } + } +} +//END + +//BEGIN KateHlCharDetect +KateHlCharDetect::KateHlCharDetect(int attribute, int context, signed char regionId,signed char regionId2, QChar c) + : KateHlItem(attribute,context,regionId,regionId2) + , sChar(c) +{ +} + +int KateHlCharDetect::checkHgl(const QString& text, int offset, int /*len*/) +{ + if (text[offset] == sChar) + return offset + 1; + + return 0; +} + +KateHlItem *KateHlCharDetect::clone(const QStringList *args) +{ + char c = sChar.latin1(); + + if (c < '0' || c > '9' || (unsigned)(c - '0') >= args->size()) + return this; + + KateHlCharDetect *ret = new KateHlCharDetect(attr, ctx, region, region2, (*args)[c - '0'][0]); + ret->dynamicChild = true; + return ret; +} +//END + +//BEGIN KateHl2CharDetect +KateHl2CharDetect::KateHl2CharDetect(int attribute, int context, signed char regionId,signed char regionId2, QChar ch1, QChar ch2) + : KateHlItem(attribute,context,regionId,regionId2) + , sChar1 (ch1) + , sChar2 (ch2) +{ +} + +int KateHl2CharDetect::checkHgl(const QString& text, int offset, int len) +{ + if ((len >= 2) && text[offset++] == sChar1 && text[offset++] == sChar2) + return offset; + + return 0; +} + +KateHlItem *KateHl2CharDetect::clone(const QStringList *args) +{ + char c1 = sChar1.latin1(); + char c2 = sChar2.latin1(); + + if (c1 < '0' || c1 > '9' || (unsigned)(c1 - '0') >= args->size()) + return this; + + if (c2 < '0' || c2 > '9' || (unsigned)(c2 - '0') >= args->size()) + return this; + + KateHl2CharDetect *ret = new KateHl2CharDetect(attr, ctx, region, region2, (*args)[c1 - '0'][0], (*args)[c2 - '0'][0]); + ret->dynamicChild = true; + return ret; +} +//END + +//BEGIN KateHlStringDetect +KateHlStringDetect::KateHlStringDetect(int attribute, int context, signed char regionId,signed char regionId2,const QString &s, bool inSensitive) + : KateHlItem(attribute, context,regionId,regionId2) + , str(inSensitive ? s.upper() : s) + , strLen (str.length()) + , _inSensitive(inSensitive) +{ +} + +int KateHlStringDetect::checkHgl(const QString& text, int offset, int len) +{ + if (len < strLen) + return 0; + + if (_inSensitive) + { + for (int i=0; i < strLen; i++) + if (text[offset++].upper() != str[i]) + return 0; + + return offset; + } + else + { + for (int i=0; i < strLen; i++) + if (text[offset++] != str[i]) + return 0; + + return offset; + } + + return 0; +} + +KateHlItem *KateHlStringDetect::clone(const QStringList *args) +{ + QString newstr = str; + + dynamicSubstitute(newstr, args); + + if (newstr == str) + return this; + + KateHlStringDetect *ret = new KateHlStringDetect(attr, ctx, region, region2, newstr, _inSensitive); + ret->dynamicChild = true; + return ret; +} +//END + +//BEGIN KateHlRangeDetect +KateHlRangeDetect::KateHlRangeDetect(int attribute, int context, signed char regionId,signed char regionId2, QChar ch1, QChar ch2) + : KateHlItem(attribute,context,regionId,regionId2) + , sChar1 (ch1) + , sChar2 (ch2) +{ +} + +int KateHlRangeDetect::checkHgl(const QString& text, int offset, int len) +{ + if (text[offset] == sChar1) + { + do + { + offset++; + len--; + if (len < 1) return 0; + } + while (text[offset] != sChar2); + + return offset + 1; + } + return 0; +} +//END + +//BEGIN KateHlKeyword +KateHlKeyword::KateHlKeyword (int attribute, int context, signed char regionId,signed char regionId2, bool insensitive, const QString& delims) + : KateHlItem(attribute,context,regionId,regionId2) + , _insensitive(insensitive) + , deliminators(delims) + , minLen (0xFFFFFF) + , maxLen (0) +{ + alwaysStartEnable = false; + customStartEnable = true; +} + +KateHlKeyword::~KateHlKeyword () +{ + for (uint i=0; i < dict.size(); ++i) + delete dict[i]; +} + +void KateHlKeyword::addList(const QStringList& list) +{ + for(uint i=0; i < list.count(); ++i) + { + int len = list[i].length(); + + if (minLen > len) + minLen = len; + + if (maxLen < len) + maxLen = len; + + if ((uint)len >= dict.size()) + { + uint oldSize = dict.size(); + dict.resize (len+1); + + for (uint m=oldSize; m < dict.size(); ++m) + dict[m] = 0; + } + + if (!dict[len]) + dict[len] = new QDict<bool> (17, !_insensitive); + + dict[len]->insert(list[i], &trueBool); + } +} + +int KateHlKeyword::checkHgl(const QString& text, int offset, int len) +{ + int offset2 = offset; + int wordLen = 0; + + while ((len > wordLen) && !kateInsideString (deliminators, text[offset2])) + { + offset2++; + wordLen++; + + if (wordLen > maxLen) return 0; + } + + if (wordLen < minLen) return 0; + + if ( dict[wordLen] && dict[wordLen]->find(QConstString(text.unicode() + offset, wordLen).string()) ) + return offset2; + + return 0; +} +//END + +//BEGIN KateHlInt +KateHlInt::KateHlInt(int attribute, int context, signed char regionId,signed char regionId2) + : KateHlItem(attribute,context,regionId,regionId2) +{ + alwaysStartEnable = false; +} + +int KateHlInt::checkHgl(const QString& text, int offset, int len) +{ + int offset2 = offset; + + while ((len > 0) && text[offset2].isDigit()) + { + offset2++; + len--; + } + + if (offset2 > offset) + { + if (len > 0) + { + for (uint i=0; i < subItems.size(); i++) + { + if ( (offset = subItems[i]->checkHgl(text, offset2, len)) ) + return offset; + } + } + + return offset2; + } + + return 0; +} +//END + +//BEGIN KateHlFloat +KateHlFloat::KateHlFloat(int attribute, int context, signed char regionId,signed char regionId2) + : KateHlItem(attribute,context, regionId,regionId2) +{ + alwaysStartEnable = false; +} + +int KateHlFloat::checkHgl(const QString& text, int offset, int len) +{ + bool b = false; + bool p = false; + + while ((len > 0) && text[offset].isDigit()) + { + offset++; + len--; + b = true; + } + + if ((len > 0) && (p = (text[offset] == '.'))) + { + offset++; + len--; + + while ((len > 0) && text[offset].isDigit()) + { + offset++; + len--; + b = true; + } + } + + if (!b) + return 0; + + if ((len > 0) && ((text[offset] & 0xdf) == 'E')) + { + offset++; + len--; + } + else + { + if (!p) + return 0; + else + { + if (len > 0) + { + for (uint i=0; i < subItems.size(); i++) + { + int offset2 = subItems[i]->checkHgl(text, offset, len); + + if (offset2) + return offset2; + } + } + + return offset; + } + } + + if ((len > 0) && (text[offset] == '-' || text[offset] =='+')) + { + offset++; + len--; + } + + b = false; + + while ((len > 0) && text[offset].isDigit()) + { + offset++; + len--; + b = true; + } + + if (b) + { + if (len > 0) + { + for (uint i=0; i < subItems.size(); i++) + { + int offset2 = subItems[i]->checkHgl(text, offset, len); + + if (offset2) + return offset2; + } + } + + return offset; + } + + return 0; +} +//END + +//BEGIN KateHlCOct +KateHlCOct::KateHlCOct(int attribute, int context, signed char regionId,signed char regionId2) + : KateHlItem(attribute,context,regionId,regionId2) +{ + alwaysStartEnable = false; +} + +int KateHlCOct::checkHgl(const QString& text, int offset, int len) +{ + if (text[offset] == '0') + { + offset++; + len--; + + int offset2 = offset; + + while ((len > 0) && (text[offset2] >= '0' && text[offset2] <= '7')) + { + offset2++; + len--; + } + + if (offset2 > offset) + { + if ((len > 0) && ((text[offset2] & 0xdf) == 'L' || (text[offset] & 0xdf) == 'U' )) + offset2++; + + return offset2; + } + } + + return 0; +} +//END + +//BEGIN KateHlCHex +KateHlCHex::KateHlCHex(int attribute, int context,signed char regionId,signed char regionId2) + : KateHlItem(attribute,context,regionId,regionId2) +{ + alwaysStartEnable = false; +} + +int KateHlCHex::checkHgl(const QString& text, int offset, int len) +{ + if ((len > 1) && (text[offset++] == '0') && ((text[offset++] & 0xdf) == 'X' )) + { + len -= 2; + + int offset2 = offset; + + while ((len > 0) && (text[offset2].isDigit() || ((text[offset2] & 0xdf) >= 'A' && (text[offset2] & 0xdf) <= 'F'))) + { + offset2++; + len--; + } + + if (offset2 > offset) + { + if ((len > 0) && ((text[offset2] & 0xdf) == 'L' || (text[offset2] & 0xdf) == 'U' )) + offset2++; + + return offset2; + } + } + + return 0; +} +//END + +//BEGIN KateHlCFloat +KateHlCFloat::KateHlCFloat(int attribute, int context, signed char regionId,signed char regionId2) + : KateHlFloat(attribute,context,regionId,regionId2) +{ + alwaysStartEnable = false; +} + +int KateHlCFloat::checkIntHgl(const QString& text, int offset, int len) +{ + int offset2 = offset; + + while ((len > 0) && text[offset].isDigit()) { + offset2++; + len--; + } + + if (offset2 > offset) + return offset2; + + return 0; +} + +int KateHlCFloat::checkHgl(const QString& text, int offset, int len) +{ + int offset2 = KateHlFloat::checkHgl(text, offset, len); + + if (offset2) + { + if ((text[offset2] & 0xdf) == 'F' ) + offset2++; + + return offset2; + } + else + { + offset2 = checkIntHgl(text, offset, len); + + if (offset2 && ((text[offset2] & 0xdf) == 'F' )) + return ++offset2; + else + return 0; + } +} +//END + +//BEGIN KateHlAnyChar +KateHlAnyChar::KateHlAnyChar(int attribute, int context, signed char regionId,signed char regionId2, const QString& charList) + : KateHlItem(attribute, context,regionId,regionId2) + , _charList(charList) +{ +} + +int KateHlAnyChar::checkHgl(const QString& text, int offset, int) +{ + if (kateInsideString (_charList, text[offset])) + return ++offset; + + return 0; +} +//END + +//BEGIN KateHlRegExpr +KateHlRegExpr::KateHlRegExpr( int attribute, int context, signed char regionId,signed char regionId2, QString regexp, bool insensitive, bool minimal) + : KateHlItem(attribute, context, regionId,regionId2) + , handlesLinestart (regexp.startsWith("^")) + , _regexp(regexp) + , _insensitive(insensitive) + , _minimal(minimal) +{ + if (!handlesLinestart) + regexp.prepend("^"); + + Expr = new QRegExp(regexp, !_insensitive); + Expr->setMinimal(_minimal); +} + +int KateHlRegExpr::checkHgl(const QString& text, int offset, int /*len*/) +{ + if (offset && handlesLinestart) + return 0; + + int offset2 = Expr->search( text, offset, QRegExp::CaretAtOffset ); + + if (offset2 == -1) return 0; + + return (offset + Expr->matchedLength()); +} + +QStringList *KateHlRegExpr::capturedTexts() +{ + return new QStringList(Expr->capturedTexts()); +} + +KateHlItem *KateHlRegExpr::clone(const QStringList *args) +{ + QString regexp = _regexp; + QStringList escArgs = *args; + + for (QStringList::Iterator it = escArgs.begin(); it != escArgs.end(); ++it) + { + (*it).replace(QRegExp("(\\W)"), "\\\\1"); + } + + dynamicSubstitute(regexp, &escArgs); + + if (regexp == _regexp) + return this; + + // kdDebug (13010) << "clone regexp: " << regexp << endl; + + KateHlRegExpr *ret = new KateHlRegExpr(attr, ctx, region, region2, regexp, _insensitive, _minimal); + ret->dynamicChild = true; + return ret; +} +//END + +//BEGIN KateHlLineContinue +KateHlLineContinue::KateHlLineContinue(int attribute, int context, signed char regionId,signed char regionId2) + : KateHlItem(attribute,context,regionId,regionId2) { +} + +int KateHlLineContinue::checkHgl(const QString& text, int offset, int len) +{ + if ((len == 1) && (text[offset] == '\\')) + return ++offset; + + return 0; +} +//END + +//BEGIN KateHlCStringChar +KateHlCStringChar::KateHlCStringChar(int attribute, int context,signed char regionId,signed char regionId2) + : KateHlItem(attribute,context,regionId,regionId2) { +} + +// checks for C escaped chars \n and escaped hex/octal chars +static int checkEscapedChar(const QString& text, int offset, int& len) +{ + int i; + if (text[offset] == '\\' && len > 1) + { + offset++; + len--; + + switch(text[offset]) + { + case 'a': // checks for control chars + case 'b': // we want to fall through + case 'e': + case 'f': + + case 'n': + case 'r': + case 't': + case 'v': + case '\'': + case '\"': + case '?' : // added ? ANSI C classifies this as an escaped char + case '\\': + offset++; + len--; + break; + + case 'x': // if it's like \xff + offset++; // eat the x + len--; + // these for loops can probably be + // replaced with something else but + // for right now they work + // check for hexdigits + for (i = 0; (len > 0) && (i < 2) && (text[offset] >= '0' && text[offset] <= '9' || (text[offset] & 0xdf) >= 'A' && (text[offset] & 0xdf) <= 'F'); i++) + { + offset++; + len--; + } + + if (i == 0) + return 0; // takes care of case '\x' + + break; + + case '0': case '1': case '2': case '3' : + case '4': case '5': case '6': case '7' : + for (i = 0; (len > 0) && (i < 3) && (text[offset] >='0'&& text[offset] <='7'); i++) + { + offset++; + len--; + } + break; + + default: + return 0; + } + + return offset; + } + + return 0; +} + +int KateHlCStringChar::checkHgl(const QString& text, int offset, int len) +{ + return checkEscapedChar(text, offset, len); +} +//END + +//BEGIN KateHlCChar +KateHlCChar::KateHlCChar(int attribute, int context,signed char regionId,signed char regionId2) + : KateHlItem(attribute,context,regionId,regionId2) { +} + +int KateHlCChar::checkHgl(const QString& text, int offset, int len) +{ + if ((len > 1) && (text[offset] == '\'') && (text[offset+1] != '\'')) + { + int oldl; + oldl = len; + + len--; + + int offset2 = checkEscapedChar(text, offset + 1, len); + + if (!offset2) + { + if (oldl > 2) + { + offset2 = offset + 2; + len = oldl - 2; + } + else + { + return 0; + } + } + + if ((len > 0) && (text[offset2] == '\'')) + return ++offset2; + } + + return 0; +} +//END + +//BEGIN KateHl2CharDetect +KateHl2CharDetect::KateHl2CharDetect(int attribute, int context, signed char regionId,signed char regionId2, const QChar *s) + : KateHlItem(attribute,context,regionId,regionId2) { + sChar1 = s[0]; + sChar2 = s[1]; + } +//END KateHl2CharDetect + +KateHlItemData::KateHlItemData(const QString name, int defStyleNum) + : name(name), defStyleNum(defStyleNum) { +} + +KateHlData::KateHlData(const QString &wildcards, const QString &mimetypes, const QString &identifier, int priority) + : wildcards(wildcards), mimetypes(mimetypes), identifier(identifier), priority(priority) +{ +} + +//BEGIN KateHlContext +KateHlContext::KateHlContext (const QString &_hlId, int attribute, int lineEndContext, int _lineBeginContext, bool _fallthrough, + int _fallthroughContext, bool _dynamic, bool _noIndentationBasedFolding) +{ + hlId = _hlId; + attr = attribute; + ctx = lineEndContext; + lineBeginContext = _lineBeginContext; + fallthrough = _fallthrough; + ftctx = _fallthroughContext; + dynamic = _dynamic; + dynamicChild = false; + noIndentationBasedFolding=_noIndentationBasedFolding; + if (_noIndentationBasedFolding) kdDebug(13010)<<QString("**********************_noIndentationBasedFolding is TRUE*****************")<<endl; + +} + +KateHlContext *KateHlContext::clone(const QStringList *args) +{ + KateHlContext *ret = new KateHlContext(hlId, attr, ctx, lineBeginContext, fallthrough, ftctx, false,noIndentationBasedFolding); + + for (uint n=0; n < items.size(); ++n) + { + KateHlItem *item = items[n]; + KateHlItem *i = (item->dynamic ? item->clone(args) : item); + ret->items.append(i); + } + + ret->dynamicChild = true; + + return ret; +} + +KateHlContext::~KateHlContext() +{ + if (dynamicChild) + { + for (uint n=0; n < items.size(); ++n) + { + if (items[n]->dynamicChild) + delete items[n]; + } + } +} +//END + +//BEGIN KateHighlighting +KateHighlighting::KateHighlighting(const KateSyntaxModeListItem *def) : refCount(0) +{ + m_attributeArrays.setAutoDelete (true); + + errorsAndWarnings = ""; + building=false; + noHl = false; + m_foldingIndentationSensitive = false; + folding=false; + internalIDList.setAutoDelete(true); + + if (def == 0) + { + noHl = true; + iName = "None"; // not translated internal name (for config and more) + iNameTranslated = i18n("None"); // user visible name + iSection = ""; + m_priority = 0; + iHidden = false; + m_additionalData.insert( "none", new HighlightPropertyBag ); + m_additionalData["none"]->deliminator = stdDeliminator; + m_additionalData["none"]->wordWrapDeliminator = stdDeliminator; + m_hlIndex[0] = "none"; + } + else + { + iName = def->name; + iNameTranslated = def->nameTranslated; + iSection = def->section; + iHidden = def->hidden; + iWildcards = def->extension; + iMimetypes = def->mimetype; + identifier = def->identifier; + iVersion=def->version; + iAuthor=def->author; + iLicense=def->license; + m_priority=def->priority.toInt(); + } + + deliminator = stdDeliminator; +} + +KateHighlighting::~KateHighlighting() +{ + // cu contexts + for (uint i=0; i < m_contexts.size(); ++i) + delete m_contexts[i]; + m_contexts.clear (); +} + +void KateHighlighting::generateContextStack(int *ctxNum, int ctx, QMemArray<short>* ctxs, int *prevLine) +{ + //kdDebug(13010)<<QString("Entering generateContextStack with %1").arg(ctx)<<endl; + while (true) + { + if (ctx >= 0) + { + (*ctxNum) = ctx; + + ctxs->resize (ctxs->size()+1, QGArray::SpeedOptim); + (*ctxs)[ctxs->size()-1]=(*ctxNum); + + return; + } + else + { + if (ctx == -1) + { + (*ctxNum)=( (ctxs->isEmpty() ) ? 0 : (*ctxs)[ctxs->size()-1]); + } + else + { + int size = ctxs->size() + ctx + 1; + + if (size > 0) + { + ctxs->resize (size, QGArray::SpeedOptim); + (*ctxNum)=(*ctxs)[size-1]; + } + else + { + ctxs->resize (0, QGArray::SpeedOptim); + (*ctxNum)=0; + } + + ctx = 0; + + if ((*prevLine) >= (int)(ctxs->size()-1)) + { + *prevLine=ctxs->size()-1; + + if ( ctxs->isEmpty() ) + return; + + KateHlContext *c = contextNum((*ctxs)[ctxs->size()-1]); + if (c && (c->ctx != -1)) + { + //kdDebug(13010)<<"PrevLine > size()-1 and ctx!=-1)"<<endl; + ctx = c->ctx; + + continue; + } + } + } + + return; + } + } +} + +/** + * Creates a new dynamic context or reuse an old one if it has already been created. + */ +int KateHighlighting::makeDynamicContext(KateHlContext *model, const QStringList *args) +{ + QPair<KateHlContext *, QString> key(model, args->front()); + short value; + + if (dynamicCtxs.contains(key)) + value = dynamicCtxs[key]; + else + { + kdDebug(13010) << "new stuff: " << startctx << endl; + + KateHlContext *newctx = model->clone(args); + + m_contexts.push_back (newctx); + + value = startctx++; + dynamicCtxs[key] = value; + KateHlManager::self()->incDynamicCtxs(); + } + + // kdDebug(13010) << "Dynamic context: using context #" << value << " (for model " << model << " with args " << *args << ")" << endl; + + return value; +} + +/** + * Drop all dynamic contexts. Shall be called with extreme care, and shall be immediatly + * followed by a full HL invalidation. + */ +void KateHighlighting::dropDynamicContexts() +{ + for (uint i=base_startctx; i < m_contexts.size(); ++i) + delete m_contexts[i]; + + m_contexts.resize (base_startctx); + + dynamicCtxs.clear(); + startctx = base_startctx; +} + +/** + * Parse the text and fill in the context array and folding list array + * + * @param prevLine The previous line, the context array is picked up from that if present. + * @param textLine The text line to parse + * @param foldingList will be filled + * @param ctxChanged will be set to reflect if the context changed + */ +void KateHighlighting::doHighlight ( KateTextLine *prevLine, + KateTextLine *textLine, + QMemArray<uint>* foldingList, + bool *ctxChanged ) +{ + if (!textLine) + return; + + if (noHl) + { + if (textLine->length() > 0) + memset (textLine->attributes(), 0, textLine->length()); + + return; + } + + // duplicate the ctx stack, only once ! + QMemArray<short> ctx; + ctx.duplicate (prevLine->ctxArray()); + + int ctxNum = 0; + int previousLine = -1; + KateHlContext *context; + + if (ctx.isEmpty()) + { + // If the stack is empty, we assume to be in Context 0 (Normal) + context = contextNum(ctxNum); + } + else + { + // There does an old context stack exist -> find the context at the line start + ctxNum = ctx[ctx.size()-1]; //context ID of the last character in the previous line + + //kdDebug(13010) << "\t\tctxNum = " << ctxNum << " contextList[ctxNum] = " << contextList[ctxNum] << endl; // ellis + + //if (lineContinue) kdDebug(13010)<<QString("The old context should be %1").arg((int)ctxNum)<<endl; + + if (!(context = contextNum(ctxNum))) + context = contextNum(0); + + //kdDebug(13010)<<"test1-2-1-text2"<<endl; + + previousLine=ctx.size()-1; //position of the last context ID of th previous line within the stack + + // hl continue set or not ??? + if (prevLine->hlLineContinue()) + { + prevLine--; + } + else + { + generateContextStack(&ctxNum, context->ctx, &ctx, &previousLine); //get stack ID to use + + if (!(context = contextNum(ctxNum))) + context = contextNum(0); + } + + //kdDebug(13010)<<"test1-2-1-text4"<<endl; + + //if (lineContinue) kdDebug(13010)<<QString("The new context is %1").arg((int)ctxNum)<<endl; + } + + // text, for programming convenience :) + QChar lastChar = ' '; + const QString& text = textLine->string(); + const int len = textLine->length(); + + // calc at which char the first char occurs, set it to lenght of line if never + const int firstChar = textLine->firstChar(); + const int startNonSpace = (firstChar == -1) ? len : firstChar; + + // last found item + KateHlItem *item = 0; + + // loop over the line, offset gives current offset + int offset = 0; + while (offset < len) + { + bool anItemMatched = false; + bool standardStartEnableDetermined = false; + bool customStartEnableDetermined = false; + + uint index = 0; + for (item = context->items.empty() ? 0 : context->items[0]; item; item = (++index < context->items.size()) ? context->items[index] : 0 ) + { + // does we only match if we are firstNonSpace? + if (item->firstNonSpace && (offset > startNonSpace)) + continue; + + // have we a column specified? if yes, only match at this column + if ((item->column != -1) && (item->column != offset)) + continue; + + if (!item->alwaysStartEnable) + { + if (item->customStartEnable) + { + if (customStartEnableDetermined || kateInsideString (m_additionalData[context->hlId]->deliminator, lastChar)) + customStartEnableDetermined = true; + else + continue; + } + else + { + if (standardStartEnableDetermined || kateInsideString (stdDeliminator, lastChar)) + standardStartEnableDetermined = true; + else + continue; + } + } + + int offset2 = item->checkHgl(text, offset, len-offset); + + if (offset2 <= offset) + continue; + // BUG 144599: Ignore a context change that would push the same context + // without eating anything... this would be an infinite loop! + if ( item->lookAhead && item->ctx == ctxNum ) + continue; + + if (item->region2) + { + // kdDebug(13010)<<QString("Region mark 2 detected: %1").arg(item->region2)<<endl; + if ( !foldingList->isEmpty() && ((item->region2 < 0) && (*foldingList)[foldingList->size()-2] == -item->region2 ) ) + { + foldingList->resize (foldingList->size()-2, QGArray::SpeedOptim); + } + else + { + foldingList->resize (foldingList->size()+2, QGArray::SpeedOptim); + (*foldingList)[foldingList->size()-2] = (uint)item->region2; + if (item->region2<0) //check not really needed yet + (*foldingList)[foldingList->size()-1] = offset2; + else + (*foldingList)[foldingList->size()-1] = offset; + } + + } + + if (item->region) + { + // kdDebug(13010)<<QString("Region mark detected: %1").arg(item->region)<<endl; + + /* if ( !foldingList->isEmpty() && ((item->region < 0) && (*foldingList)[foldingList->size()-1] == -item->region ) ) + { + foldingList->resize (foldingList->size()-1, QGArray::SpeedOptim); + } + else*/ + { + foldingList->resize (foldingList->size()+2, QGArray::SpeedOptim); + (*foldingList)[foldingList->size()-2] = item->region; + if (item->region<0) //check not really needed yet + (*foldingList)[foldingList->size()-1] = offset2; + else + (*foldingList)[foldingList->size()-1] = offset; + } + + } + + // regenerate context stack if needed + if (item->ctx != -1) + { + generateContextStack (&ctxNum, item->ctx, &ctx, &previousLine); + context = contextNum(ctxNum); + } + + // dynamic context: substitute the model with an 'instance' + if (context->dynamic) + { + QStringList *lst = item->capturedTexts(); + if (lst != 0) + { + // Replace the top of the stack and the current context + int newctx = makeDynamicContext(context, lst); + if (ctx.size() > 0) + ctx[ctx.size() - 1] = newctx; + ctxNum = newctx; + context = contextNum(ctxNum); + } + delete lst; + } + + // dominik: look ahead w/o changing offset? + if (!item->lookAhead) + { + if (offset2 > len) + offset2 = len; + + // even set attributes ;) + memset ( textLine->attributes()+offset + , item->onlyConsume ? context->attr : item->attr + , offset2-offset); + + offset = offset2; + lastChar = text[offset-1]; + } + + anItemMatched = true; + break; + } + + // something matched, continue loop + if (anItemMatched) + continue; + + // nothing found: set attribute of one char + // anders: unless this context does not want that! + if ( context->fallthrough ) + { + // set context to context->ftctx. + generateContextStack(&ctxNum, context->ftctx, &ctx, &previousLine); //regenerate context stack + context=contextNum(ctxNum); + //kdDebug(13010)<<"context num after fallthrough at col "<<z<<": "<<ctxNum<<endl; + // the next is nessecary, as otherwise keyword (or anything using the std delimitor check) + // immediately after fallthrough fails. Is it bad? + // jowenn, can you come up with a nicer way to do this? + /* if (offset) + lastChar = text[offset - 1]; + else + lastChar = '\\';*/ + continue; + } + else + { + *(textLine->attributes() + offset) = context->attr; + lastChar = text[offset]; + offset++; + } + } + + // has the context stack changed ? + if (ctx == textLine->ctxArray()) + { + if (ctxChanged) + (*ctxChanged) = false; + } + else + { + if (ctxChanged) + (*ctxChanged) = true; + + // assign ctx stack ! + textLine->setContext(ctx); + } + + // write hl continue flag + textLine->setHlLineContinue (item && item->lineContinue()); + + if (m_foldingIndentationSensitive) { + bool noindent=false; + for(int i=ctx.size()-1; i>=0; --i) { + if (contextNum(ctx[i])->noIndentationBasedFolding) { + noindent=true; + break; + } + } + textLine->setNoIndentBasedFolding(noindent); + } +} + +void KateHighlighting::loadWildcards() +{ + KConfig *config = KateHlManager::self()->getKConfig(); + config->setGroup("Highlighting " + iName); + + QString extensionString = config->readEntry("Wildcards", iWildcards); + + if (extensionSource != extensionString) { + regexpExtensions.clear(); + plainExtensions.clear(); + + extensionSource = extensionString; + + static QRegExp sep("\\s*;\\s*"); + + QStringList l = QStringList::split( sep, extensionSource ); + + static QRegExp boringExpression("\\*\\.[\\d\\w]+"); + + for( QStringList::Iterator it = l.begin(); it != l.end(); ++it ) + if (boringExpression.exactMatch(*it)) + plainExtensions.append((*it).mid(1)); + else + regexpExtensions.append(QRegExp((*it), true, true)); + } +} + +QValueList<QRegExp>& KateHighlighting::getRegexpExtensions() +{ + return regexpExtensions; +} + +QStringList& KateHighlighting::getPlainExtensions() +{ + return plainExtensions; +} + +QString KateHighlighting::getMimetypes() +{ + KConfig *config = KateHlManager::self()->getKConfig(); + config->setGroup("Highlighting " + iName); + + return config->readEntry("Mimetypes", iMimetypes); +} + +int KateHighlighting::priority() +{ + KConfig *config = KateHlManager::self()->getKConfig(); + config->setGroup("Highlighting " + iName); + + return config->readNumEntry("Priority", m_priority); +} + +KateHlData *KateHighlighting::getData() +{ + KConfig *config = KateHlManager::self()->getKConfig(); + config->setGroup("Highlighting " + iName); + + KateHlData *hlData = new KateHlData( + config->readEntry("Wildcards", iWildcards), + config->readEntry("Mimetypes", iMimetypes), + config->readEntry("Identifier", identifier), + config->readNumEntry("Priority", m_priority)); + + return hlData; +} + +void KateHighlighting::setData(KateHlData *hlData) +{ + KConfig *config = KateHlManager::self()->getKConfig(); + config->setGroup("Highlighting " + iName); + + config->writeEntry("Wildcards",hlData->wildcards); + config->writeEntry("Mimetypes",hlData->mimetypes); + config->writeEntry("Priority",hlData->priority); +} + +void KateHighlighting::getKateHlItemDataList (uint schema, KateHlItemDataList &list) +{ + KConfig *config = KateHlManager::self()->getKConfig(); + config->setGroup("Highlighting " + iName + " - Schema " + KateFactory::self()->schemaManager()->name(schema)); + + list.clear(); + createKateHlItemData(list); + + for (KateHlItemData *p = list.first(); p != 0L; p = list.next()) + { + QStringList s = config->readListEntry(p->name); + +// kdDebug(13010)<<p->name<<s.count()<<endl; + if (s.count()>0) + { + + while(s.count()<9) s<<""; + p->clear(); + + QString tmp=s[0]; if (!tmp.isEmpty()) p->defStyleNum=tmp.toInt(); + + QRgb col; + + tmp=s[1]; if (!tmp.isEmpty()) { + col=tmp.toUInt(0,16); p->setTextColor(col); } + + tmp=s[2]; if (!tmp.isEmpty()) { + col=tmp.toUInt(0,16); p->setSelectedTextColor(col); } + + tmp=s[3]; if (!tmp.isEmpty()) p->setBold(tmp!="0"); + + tmp=s[4]; if (!tmp.isEmpty()) p->setItalic(tmp!="0"); + + tmp=s[5]; if (!tmp.isEmpty()) p->setStrikeOut(tmp!="0"); + + tmp=s[6]; if (!tmp.isEmpty()) p->setUnderline(tmp!="0"); + + tmp=s[7]; if (!tmp.isEmpty()) { + col=tmp.toUInt(0,16); p->setBGColor(col); } + + tmp=s[8]; if (!tmp.isEmpty()) { + col=tmp.toUInt(0,16); p->setSelectedBGColor(col); } + + } + } +} + +/** + * Saves the KateHlData attribute definitions to the config file. + * + * @param schema The id of the schema group to save + * @param list KateHlItemDataList containing the data to be used + */ +void KateHighlighting::setKateHlItemDataList(uint schema, KateHlItemDataList &list) +{ + KConfig *config = KateHlManager::self()->getKConfig(); + config->setGroup("Highlighting " + iName + " - Schema " + + KateFactory::self()->schemaManager()->name(schema)); + + QStringList settings; + + for (KateHlItemData *p = list.first(); p != 0L; p = list.next()) + { + settings.clear(); + settings<<QString::number(p->defStyleNum,10); + settings<<(p->itemSet(KateAttribute::TextColor)?QString::number(p->textColor().rgb(),16):""); + settings<<(p->itemSet(KateAttribute::SelectedTextColor)?QString::number(p->selectedTextColor().rgb(),16):""); + settings<<(p->itemSet(KateAttribute::Weight)?(p->bold()?"1":"0"):""); + settings<<(p->itemSet(KateAttribute::Italic)?(p->italic()?"1":"0"):""); + settings<<(p->itemSet(KateAttribute::StrikeOut)?(p->strikeOut()?"1":"0"):""); + settings<<(p->itemSet(KateAttribute::Underline)?(p->underline()?"1":"0"):""); + settings<<(p->itemSet(KateAttribute::BGColor)?QString::number(p->bgColor().rgb(),16):""); + settings<<(p->itemSet(KateAttribute::SelectedBGColor)?QString::number(p->selectedBGColor().rgb(),16):""); + settings<<"---"; + config->writeEntry(p->name,settings); + } +} + +/** + * Increase the usage count, and trigger initialization if needed. + */ +void KateHighlighting::use() +{ + if (refCount == 0) + init(); + + refCount++; +} + +/** + * Decrease the usage count, and trigger cleanup if needed. + */ +void KateHighlighting::release() +{ + refCount--; + + if (refCount == 0) + done(); +} + +/** + * Initialize a context for the first time. + */ + +void KateHighlighting::init() +{ + if (noHl) + return; + + // cu contexts + for (uint i=0; i < m_contexts.size(); ++i) + delete m_contexts[i]; + m_contexts.clear (); + + makeContextList(); +} + + +/** + * If the there is no document using the highlighting style free the complete + * context structure. + */ +void KateHighlighting::done() +{ + if (noHl) + return; + + // cu contexts + for (uint i=0; i < m_contexts.size(); ++i) + delete m_contexts[i]; + m_contexts.clear (); + + internalIDList.clear(); +} + +/** + * KateHighlighting - createKateHlItemData + * This function reads the itemData entries from the config file, which specifies the + * default attribute styles for matched items/contexts. + * + * @param list A reference to the internal list containing the parsed default config + */ +void KateHighlighting::createKateHlItemData(KateHlItemDataList &list) +{ + // If no highlighting is selected we need only one default. + if (noHl) + { + list.append(new KateHlItemData(i18n("Normal Text"), KateHlItemData::dsNormal)); + return; + } + + // If the internal list isn't already available read the config file + if (internalIDList.isEmpty()) + makeContextList(); + + list=internalIDList; +} + +/** + * Adds the styles of the currently parsed highlight to the itemdata list + */ +void KateHighlighting::addToKateHlItemDataList() +{ + //Tell the syntax document class which file we want to parse and which data group + KateHlManager::self()->syntax->setIdentifier(buildIdentifier); + KateSyntaxContextData *data = KateHlManager::self()->syntax->getGroupInfo("highlighting","itemData"); + + //begin with the real parsing + while (KateHlManager::self()->syntax->nextGroup(data)) + { + // read all attributes + QString color = KateHlManager::self()->syntax->groupData(data,QString("color")); + QString selColor = KateHlManager::self()->syntax->groupData(data,QString("selColor")); + QString bold = KateHlManager::self()->syntax->groupData(data,QString("bold")); + QString italic = KateHlManager::self()->syntax->groupData(data,QString("italic")); + QString underline = KateHlManager::self()->syntax->groupData(data,QString("underline")); + QString strikeOut = KateHlManager::self()->syntax->groupData(data,QString("strikeOut")); + QString bgColor = KateHlManager::self()->syntax->groupData(data,QString("backgroundColor")); + QString selBgColor = KateHlManager::self()->syntax->groupData(data,QString("selBackgroundColor")); + + KateHlItemData* newData = new KateHlItemData( + buildPrefix+KateHlManager::self()->syntax->groupData(data,QString("name")).simplifyWhiteSpace(), + getDefStyleNum(KateHlManager::self()->syntax->groupData(data,QString("defStyleNum")))); + + /* here the custom style overrides are specified, if needed */ + if (!color.isEmpty()) newData->setTextColor(QColor(color)); + if (!selColor.isEmpty()) newData->setSelectedTextColor(QColor(selColor)); + if (!bold.isEmpty()) newData->setBold( IS_TRUE(bold) ); + if (!italic.isEmpty()) newData->setItalic( IS_TRUE(italic) ); + // new attributes for the new rendering view + if (!underline.isEmpty()) newData->setUnderline( IS_TRUE(underline) ); + if (!strikeOut.isEmpty()) newData->setStrikeOut( IS_TRUE(strikeOut) ); + if (!bgColor.isEmpty()) newData->setBGColor(QColor(bgColor)); + if (!selBgColor.isEmpty()) newData->setSelectedBGColor(QColor(selBgColor)); + + internalIDList.append(newData); + } + + //clean up + if (data) + KateHlManager::self()->syntax->freeGroupInfo(data); +} + +/** + * KateHighlighting - lookupAttrName + * This function is a helper for makeContextList and createKateHlItem. It looks the given + * attribute name in the itemData list up and returns it's index + * + * @param name the attribute name to lookup + * @param iDl the list containing all available attributes + * + * @return The index of the attribute, or 0 if the attribute isn't found + */ +int KateHighlighting::lookupAttrName(const QString& name, KateHlItemDataList &iDl) +{ + for (uint i = 0; i < iDl.count(); i++) + if (iDl.at(i)->name == buildPrefix+name) + return i; + + kdDebug(13010)<<"Couldn't resolve itemDataName:"<<name<<endl; + return 0; +} + +/** + * KateHighlighting - createKateHlItem + * This function is a helper for makeContextList. It parses the xml file for + * information. + * + * @param data Data about the item read from the xml file + * @param iDl List of all available itemData entries. + * Needed for attribute name->index translation + * @param RegionList list of code folding region names + * @param ContextNameList list of context names + * + * @return A pointer to the newly created item object + */ +KateHlItem *KateHighlighting::createKateHlItem(KateSyntaxContextData *data, + KateHlItemDataList &iDl, + QStringList *RegionList, + QStringList *ContextNameList) +{ + // No highlighting -> exit + if (noHl) + return 0; + + // get the (tagname) itemd type + QString dataname=KateHlManager::self()->syntax->groupItemData(data,QString("")); + + // code folding region handling: + QString beginRegionStr=KateHlManager::self()->syntax->groupItemData(data,QString("beginRegion")); + QString endRegionStr=KateHlManager::self()->syntax->groupItemData(data,QString("endRegion")); + + signed char regionId=0; + signed char regionId2=0; + + if (!beginRegionStr.isEmpty()) + { + regionId = RegionList->findIndex(beginRegionStr); + + if (regionId==-1) // if the region name doesn't already exist, add it to the list + { + (*RegionList)<<beginRegionStr; + regionId = RegionList->findIndex(beginRegionStr); + } + + regionId++; + + kdDebug(13010) << "########### BEG REG: " << beginRegionStr << " NUM: " << regionId << endl; + } + + if (!endRegionStr.isEmpty()) + { + regionId2 = RegionList->findIndex(endRegionStr); + + if (regionId2==-1) // if the region name doesn't already exist, add it to the list + { + (*RegionList)<<endRegionStr; + regionId2 = RegionList->findIndex(endRegionStr); + } + + regionId2 = -regionId2 - 1; + + kdDebug(13010) << "########### END REG: " << endRegionStr << " NUM: " << regionId2 << endl; + } + + int attr = 0; + QString tmpAttr=KateHlManager::self()->syntax->groupItemData(data,QString("attribute")).simplifyWhiteSpace(); + bool onlyConsume = tmpAttr.isEmpty(); + + // only relevant for non consumer + if (!onlyConsume) + { + if (QString("%1").arg(tmpAttr.toInt())==tmpAttr) + { + errorsAndWarnings+=i18n( + "<B>%1</B>: Deprecated syntax. Attribute (%2) not addressed by symbolic name<BR>"). + arg(buildIdentifier).arg(tmpAttr); + attr=tmpAttr.toInt(); + } + else + attr=lookupAttrName(tmpAttr,iDl); + } + + // Info about context switch + int context = -1; + QString unresolvedContext; + QString tmpcontext=KateHlManager::self()->syntax->groupItemData(data,QString("context")); + if (!tmpcontext.isEmpty()) + context=getIdFromString(ContextNameList, tmpcontext,unresolvedContext); + + // Get the char parameter (eg DetectChar) + char chr; + if (! KateHlManager::self()->syntax->groupItemData(data,QString("char")).isEmpty()) + chr= (KateHlManager::self()->syntax->groupItemData(data,QString("char")).latin1())[0]; + else + chr=0; + + // Get the String parameter (eg. StringDetect) + QString stringdata=KateHlManager::self()->syntax->groupItemData(data,QString("String")); + + // Get a second char parameter (char1) (eg Detect2Chars) + char chr1; + if (! KateHlManager::self()->syntax->groupItemData(data,QString("char1")).isEmpty()) + chr1= (KateHlManager::self()->syntax->groupItemData(data,QString("char1")).latin1())[0]; + else + chr1=0; + + // Will be removed eventually. Atm used for StringDetect, keyword and RegExp + const QString & insensitive_str = KateHlManager::self()->syntax->groupItemData(data,QString("insensitive")); + bool insensitive = IS_TRUE( insensitive_str ); + + // for regexp only + bool minimal = IS_TRUE( KateHlManager::self()->syntax->groupItemData(data,QString("minimal")) ); + + // dominik: look ahead and do not change offset. so we can change contexts w/o changing offset1. + bool lookAhead = IS_TRUE( KateHlManager::self()->syntax->groupItemData(data,QString("lookAhead")) ); + + bool dynamic= IS_TRUE(KateHlManager::self()->syntax->groupItemData(data,QString("dynamic")) ); + + bool firstNonSpace = IS_TRUE(KateHlManager::self()->syntax->groupItemData(data,QString("firstNonSpace")) ); + + int column = -1; + QString colStr = KateHlManager::self()->syntax->groupItemData(data,QString("column")); + if (!colStr.isEmpty()) + column = colStr.toInt(); + + //Create the item corresponding to it's type and set it's parameters + KateHlItem *tmpItem; + + if (dataname=="keyword") + { + bool keywordInsensitive = insensitive_str.isEmpty() ? !casesensitive : insensitive; + KateHlKeyword *keyword=new KateHlKeyword(attr,context,regionId,regionId2,keywordInsensitive, + m_additionalData[ buildIdentifier ]->deliminator); + + //Get the entries for the keyword lookup list + keyword->addList(KateHlManager::self()->syntax->finddata("highlighting",stringdata)); + tmpItem=keyword; + } + else if (dataname=="Float") tmpItem= (new KateHlFloat(attr,context,regionId,regionId2)); + else if (dataname=="Int") tmpItem=(new KateHlInt(attr,context,regionId,regionId2)); + else if (dataname=="DetectChar") tmpItem=(new KateHlCharDetect(attr,context,regionId,regionId2,chr)); + else if (dataname=="Detect2Chars") tmpItem=(new KateHl2CharDetect(attr,context,regionId,regionId2,chr,chr1)); + else if (dataname=="RangeDetect") tmpItem=(new KateHlRangeDetect(attr,context,regionId,regionId2, chr, chr1)); + else if (dataname=="LineContinue") tmpItem=(new KateHlLineContinue(attr,context,regionId,regionId2)); + else if (dataname=="StringDetect") tmpItem=(new KateHlStringDetect(attr,context,regionId,regionId2,stringdata,insensitive)); + else if (dataname=="AnyChar") tmpItem=(new KateHlAnyChar(attr,context,regionId,regionId2,stringdata)); + else if (dataname=="RegExpr") tmpItem=(new KateHlRegExpr(attr,context,regionId,regionId2,stringdata, insensitive, minimal)); + else if (dataname=="HlCChar") tmpItem= ( new KateHlCChar(attr,context,regionId,regionId2)); + else if (dataname=="HlCHex") tmpItem= (new KateHlCHex(attr,context,regionId,regionId2)); + else if (dataname=="HlCOct") tmpItem= (new KateHlCOct(attr,context,regionId,regionId2)); + else if (dataname=="HlCFloat") tmpItem= (new KateHlCFloat(attr,context,regionId,regionId2)); + else if (dataname=="HlCStringChar") tmpItem= (new KateHlCStringChar(attr,context,regionId,regionId2)); + else if (dataname=="DetectSpaces") tmpItem= (new KateHlDetectSpaces(attr,context,regionId,regionId2)); + else if (dataname=="DetectIdentifier") tmpItem= (new KateHlDetectIdentifier(attr,context,regionId,regionId2)); + else + { + // oops, unknown type. Perhaps a spelling error in the xml file + return 0; + } + + // set lookAhead & dynamic properties + tmpItem->lookAhead = lookAhead; + tmpItem->dynamic = dynamic; + tmpItem->firstNonSpace = firstNonSpace; + tmpItem->column = column; + tmpItem->onlyConsume = onlyConsume; + + if (!unresolvedContext.isEmpty()) + { + unresolvedContextReferences.insert(&(tmpItem->ctx),unresolvedContext); + } + + return tmpItem; +} + +QString KateHighlighting::hlKeyForAttrib( int i ) const +{ + // find entry. This is faster than QMap::find. m_hlIndex always has an entry + // for key '0' (it is "none"), so the result is always valid. + int k = 0; + QMap<int,QString>::const_iterator it = m_hlIndex.constEnd(); + while ( it != m_hlIndex.constBegin() ) + { + --it; + k = it.key(); + if ( i >= k ) + break; + } + return it.data(); +} + +bool KateHighlighting::isInWord( QChar c, int attrib ) const +{ + return m_additionalData[ hlKeyForAttrib( attrib ) ]->deliminator.find(c) < 0 + && !c.isSpace() && c != '"' && c != '\''; +} + +bool KateHighlighting::canBreakAt( QChar c, int attrib ) const +{ + static const QString& sq = KGlobal::staticQString("\"'"); + return (m_additionalData[ hlKeyForAttrib( attrib ) ]->wordWrapDeliminator.find(c) != -1) && (sq.find(c) == -1); +} + +signed char KateHighlighting::commentRegion(int attr) const { + QString commentRegion=m_additionalData[ hlKeyForAttrib( attr ) ]->multiLineRegion; + return (commentRegion.isEmpty()?0:(commentRegion.toShort())); +} + +bool KateHighlighting::canComment( int startAttrib, int endAttrib ) const +{ + QString k = hlKeyForAttrib( startAttrib ); + return ( k == hlKeyForAttrib( endAttrib ) && + ( ( !m_additionalData[k]->multiLineCommentStart.isEmpty() && !m_additionalData[k]->multiLineCommentEnd.isEmpty() ) || + ! m_additionalData[k]->singleLineCommentMarker.isEmpty() ) ); +} + +QString KateHighlighting::getCommentStart( int attrib ) const +{ + return m_additionalData[ hlKeyForAttrib( attrib) ]->multiLineCommentStart; +} + +QString KateHighlighting::getCommentEnd( int attrib ) const +{ + return m_additionalData[ hlKeyForAttrib( attrib ) ]->multiLineCommentEnd; +} + +QString KateHighlighting::getCommentSingleLineStart( int attrib ) const +{ + return m_additionalData[ hlKeyForAttrib( attrib) ]->singleLineCommentMarker; +} + +KateHighlighting::CSLPos KateHighlighting::getCommentSingleLinePosition( int attrib ) const +{ + return m_additionalData[ hlKeyForAttrib( attrib) ]->singleLineCommentPosition; +} + + +/** + * Helper for makeContextList. It parses the xml file for + * information, how single or multi line comments are marked + */ +void KateHighlighting::readCommentConfig() +{ + KateHlManager::self()->syntax->setIdentifier(buildIdentifier); + KateSyntaxContextData *data=KateHlManager::self()->syntax->getGroupInfo("general","comment"); + + QString cmlStart="", cmlEnd="", cmlRegion="", cslStart=""; + CSLPos cslPosition=CSLPosColumn0; + + if (data) + { + while (KateHlManager::self()->syntax->nextGroup(data)) + { + if (KateHlManager::self()->syntax->groupData(data,"name")=="singleLine") + { + cslStart=KateHlManager::self()->syntax->groupData(data,"start"); + QString cslpos=KateHlManager::self()->syntax->groupData(data,"position"); + if (cslpos=="afterwhitespace") + cslPosition=CSLPosAfterWhitespace; + else + cslPosition=CSLPosColumn0; + } + else if (KateHlManager::self()->syntax->groupData(data,"name")=="multiLine") + { + cmlStart=KateHlManager::self()->syntax->groupData(data,"start"); + cmlEnd=KateHlManager::self()->syntax->groupData(data,"end"); + cmlRegion=KateHlManager::self()->syntax->groupData(data,"region"); + } + } + + KateHlManager::self()->syntax->freeGroupInfo(data); + } + + m_additionalData[buildIdentifier]->singleLineCommentMarker = cslStart; + m_additionalData[buildIdentifier]->singleLineCommentPosition = cslPosition; + m_additionalData[buildIdentifier]->multiLineCommentStart = cmlStart; + m_additionalData[buildIdentifier]->multiLineCommentEnd = cmlEnd; + m_additionalData[buildIdentifier]->multiLineRegion = cmlRegion; +} + +/** + * Helper for makeContextList. It parses the xml file for information, + * if keywords should be treated case(in)sensitive and creates the keyword + * delimiter list. Which is the default list, without any given weak deliminiators + */ +void KateHighlighting::readGlobalKeywordConfig() +{ + deliminator = stdDeliminator; + // Tell the syntax document class which file we want to parse + kdDebug(13010)<<"readGlobalKeywordConfig:BEGIN"<<endl; + + KateHlManager::self()->syntax->setIdentifier(buildIdentifier); + KateSyntaxContextData *data = KateHlManager::self()->syntax->getConfig("general","keywords"); + + if (data) + { + kdDebug(13010)<<"Found global keyword config"<<endl; + + if ( IS_TRUE( KateHlManager::self()->syntax->groupItemData(data,QString("casesensitive")) ) ) + casesensitive=true; + else + casesensitive=false; + + //get the weak deliminators + weakDeliminator=(KateHlManager::self()->syntax->groupItemData(data,QString("weakDeliminator"))); + + kdDebug(13010)<<"weak delimiters are: "<<weakDeliminator<<endl; + + // remove any weakDelimitars (if any) from the default list and store this list. + for (uint s=0; s < weakDeliminator.length(); s++) + { + int f = deliminator.find (weakDeliminator[s]); + + if (f > -1) + deliminator.remove (f, 1); + } + + QString addDelim = (KateHlManager::self()->syntax->groupItemData(data,QString("additionalDeliminator"))); + + if (!addDelim.isEmpty()) + deliminator=deliminator+addDelim; + + KateHlManager::self()->syntax->freeGroupInfo(data); + } + else + { + //Default values + casesensitive=true; + weakDeliminator=QString(""); + } + + kdDebug(13010)<<"readGlobalKeywordConfig:END"<<endl; + + kdDebug(13010)<<"delimiterCharacters are: "<<deliminator<<endl; + + m_additionalData[buildIdentifier]->deliminator = deliminator; +} + +/** + * Helper for makeContextList. It parses the xml file for any wordwrap + * deliminators, characters * at which line can be broken. In case no keyword + * tag is found in the xml file, the wordwrap deliminators list defaults to the + * standard denominators. In case a keyword tag is defined, but no + * wordWrapDeliminator attribute is specified, the deliminator list as computed + * in readGlobalKeywordConfig is used. + * + * @return the computed delimiter string. + */ +void KateHighlighting::readWordWrapConfig() +{ + // Tell the syntax document class which file we want to parse + kdDebug(13010)<<"readWordWrapConfig:BEGIN"<<endl; + + KateHlManager::self()->syntax->setIdentifier(buildIdentifier); + KateSyntaxContextData *data = KateHlManager::self()->syntax->getConfig("general","keywords"); + + QString wordWrapDeliminator = stdDeliminator; + if (data) + { + kdDebug(13010)<<"Found global keyword config"<<endl; + + wordWrapDeliminator = (KateHlManager::self()->syntax->groupItemData(data,QString("wordWrapDeliminator"))); + //when no wordWrapDeliminator is defined use the deliminator list + if ( wordWrapDeliminator.length() == 0 ) wordWrapDeliminator = deliminator; + + kdDebug(13010) << "word wrap deliminators are " << wordWrapDeliminator << endl; + + KateHlManager::self()->syntax->freeGroupInfo(data); + } + + kdDebug(13010)<<"readWordWrapConfig:END"<<endl; + + m_additionalData[buildIdentifier]->wordWrapDeliminator = wordWrapDeliminator; +} + +void KateHighlighting::readIndentationConfig() +{ + m_indentation = ""; + + KateHlManager::self()->syntax->setIdentifier(buildIdentifier); + KateSyntaxContextData *data = KateHlManager::self()->syntax->getConfig("general","indentation"); + + if (data) + { + m_indentation = (KateHlManager::self()->syntax->groupItemData(data,QString("mode"))); + + KateHlManager::self()->syntax->freeGroupInfo(data); + } +} + +void KateHighlighting::readFoldingConfig() +{ + // Tell the syntax document class which file we want to parse + kdDebug(13010)<<"readfoldignConfig:BEGIN"<<endl; + + KateHlManager::self()->syntax->setIdentifier(buildIdentifier); + KateSyntaxContextData *data = KateHlManager::self()->syntax->getConfig("general","folding"); + + if (data) + { + kdDebug(13010)<<"Found global keyword config"<<endl; + + if ( IS_TRUE( KateHlManager::self()->syntax->groupItemData(data,QString("indentationsensitive")) ) ) + m_foldingIndentationSensitive=true; + else + m_foldingIndentationSensitive=false; + + KateHlManager::self()->syntax->freeGroupInfo(data); + } + else + { + //Default values + m_foldingIndentationSensitive = false; + } + + kdDebug(13010)<<"readfoldingConfig:END"<<endl; + + kdDebug(13010)<<"############################ use indent for fold are: "<<m_foldingIndentationSensitive<<endl; +} + +void KateHighlighting::createContextNameList(QStringList *ContextNameList,int ctx0) +{ + kdDebug(13010)<<"creatingContextNameList:BEGIN"<<endl; + + if (ctx0 == 0) + ContextNameList->clear(); + + KateHlManager::self()->syntax->setIdentifier(buildIdentifier); + + KateSyntaxContextData *data=KateHlManager::self()->syntax->getGroupInfo("highlighting","context"); + + int id=ctx0; + + if (data) + { + while (KateHlManager::self()->syntax->nextGroup(data)) + { + QString tmpAttr=KateHlManager::self()->syntax->groupData(data,QString("name")).simplifyWhiteSpace(); + if (tmpAttr.isEmpty()) + { + tmpAttr=QString("!KATE_INTERNAL_DUMMY! %1").arg(id); + errorsAndWarnings +=i18n("<B>%1</B>: Deprecated syntax. Context %2 has no symbolic name<BR>").arg(buildIdentifier).arg(id-ctx0); + } + else tmpAttr=buildPrefix+tmpAttr; + (*ContextNameList)<<tmpAttr; + id++; + } + KateHlManager::self()->syntax->freeGroupInfo(data); + } + kdDebug(13010)<<"creatingContextNameList:END"<<endl; + +} + +int KateHighlighting::getIdFromString(QStringList *ContextNameList, QString tmpLineEndContext, /*NO CONST*/ QString &unres) +{ + unres=""; + int context; + if ((tmpLineEndContext=="#stay") || (tmpLineEndContext.simplifyWhiteSpace().isEmpty())) + context=-1; + + else if (tmpLineEndContext.startsWith("#pop")) + { + context=-1; + for(;tmpLineEndContext.startsWith("#pop");context--) + { + tmpLineEndContext.remove(0,4); + kdDebug(13010)<<"#pop found"<<endl; + } + } + + else if ( tmpLineEndContext.contains("##")) + { + int o = tmpLineEndContext.find("##"); + // FIXME at least with 'foo##bar'-style contexts the rules are picked up + // but the default attribute is not + QString tmp=tmpLineEndContext.mid(o+2); + if (!embeddedHls.contains(tmp)) embeddedHls.insert(tmp,KateEmbeddedHlInfo()); + unres=tmp+':'+tmpLineEndContext.left(o); + context=0; + } + + else + { + context=ContextNameList->findIndex(buildPrefix+tmpLineEndContext); + if (context==-1) + { + context=tmpLineEndContext.toInt(); + errorsAndWarnings+=i18n( + "<B>%1</B>:Deprecated syntax. Context %2 not addressed by a symbolic name" + ).arg(buildIdentifier).arg(tmpLineEndContext); + } +//#warning restructure this the name list storage. +// context=context+buildContext0Offset; + } + return context; +} + +/** + * The most important initialization function for each highlighting. It's called + * each time a document gets a highlighting style assigned. parses the xml file + * and creates a corresponding internal structure + */ +void KateHighlighting::makeContextList() +{ + if (noHl) // if this a highlighting for "normal texts" only, tere is no need for a context list creation + return; + + embeddedHls.clear(); + unresolvedContextReferences.clear(); + RegionList.clear(); + ContextNameList.clear(); + + // prepare list creation. To reuse as much code as possible handle this + // highlighting the same way as embedded onces + embeddedHls.insert(iName,KateEmbeddedHlInfo()); + + bool something_changed; + // the context "0" id is 0 for this hl, all embedded context "0"s have offsets + startctx=base_startctx=0; + // inform everybody that we are building the highlighting contexts and itemlists + building=true; + + do + { + kdDebug(13010)<<"**************** Outer loop in make ContextList"<<endl; + kdDebug(13010)<<"**************** Hl List count:"<<embeddedHls.count()<<endl; + something_changed=false; //assume all "embedded" hls have already been loaded + for (KateEmbeddedHlInfos::const_iterator it=embeddedHls.begin(); it!=embeddedHls.end();++it) + { + if (!it.data().loaded) // we found one, we still have to load + { + kdDebug(13010)<<"**************** Inner loop in make ContextList"<<endl; + QString identifierToUse; + kdDebug(13010)<<"Trying to open highlighting definition file: "<< it.key()<<endl; + if (iName==it.key()) // the own identifier is known + identifierToUse=identifier; + else // all others have to be looked up + identifierToUse=KateHlManager::self()->identifierForName(it.key()); + + kdDebug(13010)<<"Location is:"<< identifierToUse<<endl; + + buildPrefix=it.key()+':'; // attribute names get prefixed by the names + // of the highlighting definitions they belong to + + if (identifierToUse.isEmpty() ) + kdDebug(13010)<<"OHOH, unknown highlighting description referenced"<<endl; + + kdDebug(13010)<<"setting ("<<it.key()<<") to loaded"<<endl; + + //mark hl as loaded + it=embeddedHls.insert(it.key(),KateEmbeddedHlInfo(true,startctx)); + //set class member for context 0 offset, so we don't need to pass it around + buildContext0Offset=startctx; + //parse one hl definition file + startctx=addToContextList(identifierToUse,startctx); + + if (noHl) return; // an error occurred + + base_startctx = startctx; + something_changed=true; // something has been loaded + } + } + } while (something_changed); // as long as there has been another file parsed + // repeat everything, there could be newly added embedded hls. + + + // at this point all needed highlighing (sub)definitions are loaded. It's time + // to resolve cross file references (if there are any) + kdDebug(13010)<<"Unresolved contexts, which need attention: "<<unresolvedContextReferences.count()<<endl; + + //optimize this a littlebit + for (KateHlUnresolvedCtxRefs::iterator unresIt=unresolvedContextReferences.begin(); + unresIt!=unresolvedContextReferences.end();++unresIt) + { + QString incCtx = unresIt.data(); + kdDebug(13010)<<"Context "<<incCtx<<" is unresolved"<<endl; + // only resolve '##Name' contexts here; handleKateHlIncludeRules() can figure + // out 'Name##Name'-style inclusions, but we screw it up + if (incCtx.endsWith(":")) { + kdDebug(13010)<<"Looking up context0 for ruleset "<<incCtx<<endl; + incCtx = incCtx.left(incCtx.length()-1); + //try to find the context0 id for a given unresolvedReference + KateEmbeddedHlInfos::const_iterator hlIt=embeddedHls.find(incCtx); + if (hlIt!=embeddedHls.end()) + *(unresIt.key())=hlIt.data().context0; + } + } + + // eventually handle KateHlIncludeRules items, if they exist. + // This has to be done after the cross file references, because it is allowed + // to include the context0 from a different definition, than the one the rule + // belongs to + handleKateHlIncludeRules(); + + embeddedHls.clear(); //save some memory. + unresolvedContextReferences.clear(); //save some memory + RegionList.clear(); // I think you get the idea ;) + ContextNameList.clear(); + + + // if there have been errors show them + if (!errorsAndWarnings.isEmpty()) + KMessageBox::detailedSorry(0L,i18n( + "There were warning(s) and/or error(s) while parsing the syntax " + "highlighting configuration."), + errorsAndWarnings, i18n("Kate Syntax Highlighting Parser")); + + // we have finished + building=false; +} + +void KateHighlighting::handleKateHlIncludeRules() +{ + // if there are noe include rules to take care of, just return + kdDebug(13010)<<"KateHlIncludeRules, which need attention: " <<includeRules.count()<<endl; + if (includeRules.isEmpty()) return; + + buildPrefix=""; + QString dummy; + + // By now the context0 references are resolved, now more or less only inner + // file references are resolved. If we decide that arbitrary inclusion is + // needed, this doesn't need to be changed, only the addToContextList + // method. + + //resolove context names + for (KateHlIncludeRules::iterator it=includeRules.begin();it!=includeRules.end();) + { + if ((*it)->incCtx==-1) // context unresolved ? + { + + if ((*it)->incCtxN.isEmpty()) + { + // no context name given, and no valid context id set, so this item is + // going to be removed + KateHlIncludeRules::iterator it1=it; + ++it1; + delete (*it); + includeRules.remove(it); + it=it1; + } + else + { + // resolve name to id + (*it)->incCtx=getIdFromString(&ContextNameList,(*it)->incCtxN,dummy); + kdDebug(13010)<<"Resolved "<<(*it)->incCtxN<< " to "<<(*it)->incCtx<<" for include rule"<<endl; + // It would be good to look here somehow, if the result is valid + } + } + else ++it; //nothing to do, already resolved (by the cross defintion reference resolver) + } + + // now that all KateHlIncludeRule items should be valid and completely resolved, + // do the real inclusion of the rules. + // recursiveness is needed, because context 0 could include context 1, which + // itself includes context 2 and so on. + // In that case we have to handle context 2 first, then 1, 0 + //TODO: catch circular references: eg 0->1->2->3->1 + while (!includeRules.isEmpty()) + handleKateHlIncludeRulesRecursive(includeRules.begin(),&includeRules); +} + +void KateHighlighting::handleKateHlIncludeRulesRecursive(KateHlIncludeRules::iterator it, KateHlIncludeRules *list) +{ + if (it==list->end()) return; //invalid iterator, shouldn't happen, but better have a rule prepared ;) + + KateHlIncludeRules::iterator it1=it; + int ctx=(*it1)->ctx; + + // find the last entry for the given context in the KateHlIncludeRules list + // this is need if one context includes more than one. This saves us from + // updating all insert positions: + // eg: context 0: + // pos 3 - include context 2 + // pos 5 - include context 3 + // During the building of the includeRules list the items are inserted in + // ascending order, now we need it descending to make our life easier. + while ((it!=list->end()) && ((*it)->ctx==ctx)) + { + it1=it; + ++it; + } + + // iterate over each include rule for the context the function has been called for. + while ((it1!=list->end()) && ((*it1)->ctx==ctx)) + { + int ctx1=(*it1)->incCtx; + + //let's see, if the the included context includes other contexts + for (KateHlIncludeRules::iterator it2=list->begin();it2!=list->end();++it2) + { + if ((*it2)->ctx==ctx1) + { + //yes it does, so first handle that include rules, since we want to + // include those subincludes too + handleKateHlIncludeRulesRecursive(it2,list); + break; + } + } + + // if the context we want to include had sub includes, they are already inserted there. + KateHlContext *dest=m_contexts[ctx]; + KateHlContext *src=m_contexts[ctx1]; +// kdDebug(3010)<<"linking included rules from "<<ctx<<" to "<<ctx1<<endl; + + // If so desired, change the dest attribute to the one of the src. + // Required to make commenting work, if text matched by the included context + // is a different highlight than the host context. + if ( (*it1)->includeAttrib ) + dest->attr = src->attr; + + // insert the included context's rules starting at position p + int p=(*it1)->pos; + + // remember some stuff + int oldLen = dest->items.size(); + uint itemsToInsert = src->items.size(); + + // resize target + dest->items.resize (oldLen + itemsToInsert); + + // move old elements + for (int i=oldLen-1; i >= p; --i) + dest->items[i+itemsToInsert] = dest->items[i]; + + // insert new stuff + for (uint i=0; i < itemsToInsert; ++i ) + dest->items[p+i] = src->items[i]; + + it=it1; //backup the iterator + --it1; //move to the next entry, which has to be take care of + delete (*it); //free the already handled data structure + list->remove(it); // remove it from the list + } +} + +/** + * Add one highlight to the contextlist. + * + * @return the number of contexts after this is added. + */ +int KateHighlighting::addToContextList(const QString &ident, int ctx0) +{ + kdDebug(13010)<<"=== Adding hl with ident '"<<ident<<"'"<<endl; + + buildIdentifier=ident; + KateSyntaxContextData *data, *datasub; + KateHlItem *c; + + QString dummy; + + // Let the syntax document class know, which file we'd like to parse + if (!KateHlManager::self()->syntax->setIdentifier(ident)) + { + noHl=true; + KMessageBox::information(0L,i18n( + "Since there has been an error parsing the highlighting description, " + "this highlighting will be disabled")); + return 0; + } + + // only read for the own stuff + if (identifier == ident) + { + readIndentationConfig (); + } + + RegionList<<"!KateInternal_TopLevel!"; + + m_hlIndex[internalIDList.count()] = ident; + m_additionalData.insert( ident, new HighlightPropertyBag ); + + // fill out the propertybag + readCommentConfig(); + readGlobalKeywordConfig(); + readWordWrapConfig(); + + readFoldingConfig (); + + QString ctxName; + + // This list is needed for the translation of the attribute parameter, + // if the itemData name is given instead of the index + addToKateHlItemDataList(); + KateHlItemDataList iDl = internalIDList; + + createContextNameList(&ContextNameList,ctx0); + + + kdDebug(13010)<<"Parsing Context structure"<<endl; + //start the real work + data=KateHlManager::self()->syntax->getGroupInfo("highlighting","context"); + uint i=buildContext0Offset; + if (data) + { + while (KateHlManager::self()->syntax->nextGroup(data)) + { + kdDebug(13010)<<"Found a context in file, building structure now"<<endl; + //BEGIN - Translation of the attribute parameter + QString tmpAttr=KateHlManager::self()->syntax->groupData(data,QString("attribute")).simplifyWhiteSpace(); + int attr; + if (QString("%1").arg(tmpAttr.toInt())==tmpAttr) + attr=tmpAttr.toInt(); + else + attr=lookupAttrName(tmpAttr,iDl); + //END - Translation of the attribute parameter + + ctxName=buildPrefix+KateHlManager::self()->syntax->groupData(data,QString("lineEndContext")).simplifyWhiteSpace(); + + QString tmpLineEndContext=KateHlManager::self()->syntax->groupData(data,QString("lineEndContext")).simplifyWhiteSpace(); + int context; + + context=getIdFromString(&ContextNameList, tmpLineEndContext,dummy); + + QString tmpNIBF = KateHlManager::self()->syntax->groupData(data, QString("noIndentationBasedFolding") ); + bool noIndentationBasedFolding=IS_TRUE(tmpNIBF); + + //BEGIN get fallthrough props + bool ft = false; + int ftc = 0; // fallthrough context + if ( i > 0 ) // fallthrough is not smart in context 0 + { + QString tmpFt = KateHlManager::self()->syntax->groupData(data, QString("fallthrough") ); + if ( IS_TRUE(tmpFt) ) + ft = true; + if ( ft ) + { + QString tmpFtc = KateHlManager::self()->syntax->groupData( data, QString("fallthroughContext") ); + + ftc=getIdFromString(&ContextNameList, tmpFtc,dummy); + if (ftc == -1) ftc =0; + + kdDebug(13010)<<"Setting fall through context (context "<<i<<"): "<<ftc<<endl; + } + } + //END falltrhough props + + bool dynamic = false; + QString tmpDynamic = KateHlManager::self()->syntax->groupData(data, QString("dynamic") ); + if ( tmpDynamic.lower() == "true" || tmpDynamic.toInt() == 1 ) + dynamic = true; + + KateHlContext *ctxNew = new KateHlContext ( + ident, + attr, + context, + (KateHlManager::self()->syntax->groupData(data,QString("lineBeginContext"))).isEmpty()?-1: + (KateHlManager::self()->syntax->groupData(data,QString("lineBeginContext"))).toInt(), + ft, ftc, dynamic,noIndentationBasedFolding); + + m_contexts.push_back (ctxNew); + + kdDebug(13010) << "INDEX: " << i << " LENGTH " << m_contexts.size()-1 << endl; + + //Let's create all items for the context + while (KateHlManager::self()->syntax->nextItem(data)) + { +// kdDebug(13010)<< "In make Contextlist: Item:"<<endl; + + // KateHlIncludeRules : add a pointer to each item in that context + // TODO add a attrib includeAttrib + QString tag = KateHlManager::self()->syntax->groupItemData(data,QString("")); + if ( tag == "IncludeRules" ) //if the new item is an Include rule, we have to take special care + { + QString incCtx = KateHlManager::self()->syntax->groupItemData( data, QString("context")); + QString incAttrib = KateHlManager::self()->syntax->groupItemData( data, QString("includeAttrib")); + bool includeAttrib = IS_TRUE( incAttrib ); + // only context refernces of type Name, ##Name, and Subname##Name are allowed + if (incCtx.startsWith("##") || (!incCtx.startsWith("#"))) + { + int incCtxi = incCtx.find("##"); + //#stay, #pop is not interesting here + if (incCtxi >= 0) + { + QString incSet = incCtx.mid(incCtxi + 2); + QString incCtxN = incSet + ":" + incCtx.left(incCtxi); + + //a cross highlighting reference + kdDebug(13010)<<"Cross highlight reference <IncludeRules>, context "<<incCtxN<<endl; + KateHlIncludeRule *ir=new KateHlIncludeRule(i,m_contexts[i]->items.count(),incCtxN,includeAttrib); + + //use the same way to determine cross hl file references as other items do + if (!embeddedHls.contains(incSet)) + embeddedHls.insert(incSet,KateEmbeddedHlInfo()); + else + kdDebug(13010)<<"Skipping embeddedHls.insert for "<<incCtxN<<endl; + + unresolvedContextReferences.insert(&(ir->incCtx), incCtxN); + + includeRules.append(ir); + } + else + { + // a local reference -> just initialize the include rule structure + incCtx=buildPrefix+incCtx.simplifyWhiteSpace(); + includeRules.append(new KateHlIncludeRule(i,m_contexts[i]->items.count(),incCtx, includeAttrib)); + } + } + + continue; + } + // TODO -- can we remove the block below?? +#if 0 + QString tag = KateHlManager::self()->syntax->groupKateHlItemData(data,QString("")); + if ( tag == "IncludeRules" ) { + // attrib context: the index (jowenn, i think using names here + // would be a cool feat, goes for mentioning the context in + // any item. a map or dict?) + int ctxId = getIdFromString(&ContextNameList, + KateHlManager::self()->syntax->groupKateHlItemData( data, QString("context")),dummy); // the index is *required* + if ( ctxId > -1) { // we can even reuse rules of 0 if we want to:) + kdDebug(13010)<<"makeContextList["<<i<<"]: including all items of context "<<ctxId<<endl; + if ( ctxId < (int) i ) { // must be defined + for ( c = m_contexts[ctxId]->items.first(); c; c = m_contexts[ctxId]->items.next() ) + m_contexts[i]->items.append(c); + } + else + kdDebug(13010)<<"Context "<<ctxId<<"not defined. You can not include the rules of an undefined context"<<endl; + } + continue; // while nextItem + } +#endif + c=createKateHlItem(data,iDl,&RegionList,&ContextNameList); + if (c) + { + m_contexts[i]->items.append(c); + + // Not supported completely atm and only one level. Subitems.(all have + // to be matched to at once) + datasub=KateHlManager::self()->syntax->getSubItems(data); + bool tmpbool; + if (tmpbool=KateHlManager::self()->syntax->nextItem(datasub)) + { + for (;tmpbool;tmpbool=KateHlManager::self()->syntax->nextItem(datasub)) + { + c->subItems.resize (c->subItems.size()+1); + c->subItems[c->subItems.size()-1] = createKateHlItem(datasub,iDl,&RegionList,&ContextNameList); + } } + KateHlManager::self()->syntax->freeGroupInfo(datasub); + // end of sublevel + } + } + i++; + } + } + + KateHlManager::self()->syntax->freeGroupInfo(data); + + if (RegionList.count()!=1) + folding=true; + + folding = folding || m_foldingIndentationSensitive; + + //BEGIN Resolve multiline region if possible + if (!m_additionalData[ ident ]->multiLineRegion.isEmpty()) { + long commentregionid=RegionList.findIndex( m_additionalData[ ident ]->multiLineRegion ); + if (-1==commentregionid) { + errorsAndWarnings+=i18n( + "<B>%1</B>: Specified multiline comment region (%2) could not be resolved<BR>" + ).arg(buildIdentifier).arg( m_additionalData[ ident ]->multiLineRegion ); + m_additionalData[ ident ]->multiLineRegion = QString(); + kdDebug(13010)<<"ERROR comment region attribute could not be resolved"<<endl; + + } else { + m_additionalData[ ident ]->multiLineRegion=QString::number(commentregionid+1); + kdDebug(13010)<<"comment region resolved to:"<<m_additionalData[ ident ]->multiLineRegion<<endl; + } + } + //END Resolve multiline region if possible + return i; +} + +void KateHighlighting::clearAttributeArrays () +{ + for ( QIntDictIterator< QMemArray<KateAttribute> > it( m_attributeArrays ); it.current(); ++it ) + { + // k, schema correct, let create the data + KateAttributeList defaultStyleList; + defaultStyleList.setAutoDelete(true); + KateHlManager::self()->getDefaults(it.currentKey(), defaultStyleList); + + KateHlItemDataList itemDataList; + getKateHlItemDataList(it.currentKey(), itemDataList); + + uint nAttribs = itemDataList.count(); + QMemArray<KateAttribute> *array = it.current(); + array->resize (nAttribs); + + for (uint z = 0; z < nAttribs; z++) + { + KateHlItemData *itemData = itemDataList.at(z); + KateAttribute n = *defaultStyleList.at(itemData->defStyleNum); + + if (itemData && itemData->isSomethingSet()) + n += *itemData; + + array->at(z) = n; + } + } +} + +QMemArray<KateAttribute> *KateHighlighting::attributes (uint schema) +{ + QMemArray<KateAttribute> *array; + + // found it, allready floating around + if ((array = m_attributeArrays[schema])) + return array; + + // ohh, not found, check if valid schema number + if (!KateFactory::self()->schemaManager()->validSchema(schema)) + { + // uhh, not valid :/, stick with normal default schema, it's always there ! + return attributes (0); + } + + // k, schema correct, let create the data + KateAttributeList defaultStyleList; + defaultStyleList.setAutoDelete(true); + KateHlManager::self()->getDefaults(schema, defaultStyleList); + + KateHlItemDataList itemDataList; + getKateHlItemDataList(schema, itemDataList); + + uint nAttribs = itemDataList.count(); + array = new QMemArray<KateAttribute> (nAttribs); + + for (uint z = 0; z < nAttribs; z++) + { + KateHlItemData *itemData = itemDataList.at(z); + KateAttribute n = *defaultStyleList.at(itemData->defStyleNum); + + if (itemData && itemData->isSomethingSet()) + n += *itemData; + + array->at(z) = n; + } + + m_attributeArrays.insert(schema, array); + + return array; +} + +void KateHighlighting::getKateHlItemDataListCopy (uint schema, KateHlItemDataList &outlist) +{ + KateHlItemDataList itemDataList; + getKateHlItemDataList(schema, itemDataList); + + outlist.clear (); + outlist.setAutoDelete (true); + for (uint z=0; z < itemDataList.count(); z++) + outlist.append (new KateHlItemData (*itemDataList.at(z))); +} + +//END + +//BEGIN KateHlManager +KateHlManager::KateHlManager() + : QObject() + , m_config ("katesyntaxhighlightingrc", false, false) + , commonSuffixes (QStringList::split(";", ".orig;.new;~;.bak;.BAK")) + , syntax (new KateSyntaxDocument()) + , dynamicCtxsCount(0) + , forceNoDCReset(false) +{ + hlList.setAutoDelete(true); + hlDict.setAutoDelete(false); + + KateSyntaxModeList modeList = syntax->modeList(); + for (uint i=0; i < modeList.count(); i++) + { + KateHighlighting *hl = new KateHighlighting(modeList[i]); + + uint insert = 0; + for (; insert <= hlList.count(); insert++) + { + if (insert == hlList.count()) + break; + + if ( QString(hlList.at(insert)->section() + hlList.at(insert)->nameTranslated()).lower() + > QString(hl->section() + hl->nameTranslated()).lower() ) + break; + } + + hlList.insert (insert, hl); + hlDict.insert (hl->name(), hl); + } + + // Normal HL + KateHighlighting *hl = new KateHighlighting(0); + hlList.prepend (hl); + hlDict.insert (hl->name(), hl); + + lastCtxsReset.start(); +} + +KateHlManager::~KateHlManager() +{ + delete syntax; +} + +static KStaticDeleter<KateHlManager> sdHlMan; + +KateHlManager *KateHlManager::self() +{ + if ( !s_self ) + sdHlMan.setObject(s_self, new KateHlManager ()); + + return s_self; +} + +KateHighlighting *KateHlManager::getHl(int n) +{ + if (n < 0 || n >= (int) hlList.count()) + n = 0; + + return hlList.at(n); +} + +int KateHlManager::nameFind(const QString &name) +{ + int z (hlList.count() - 1); + for (; z > 0; z--) + if (hlList.at(z)->name() == name) + return z; + + return z; +} + +int KateHlManager::detectHighlighting (KateDocument *doc) +{ + int hl = wildcardFind( doc->url().filename() ); + if ( hl < 0 ) + hl = mimeFind ( doc ); + + return hl; +} + +int KateHlManager::wildcardFind(const QString &fileName) +{ + int result = -1; + if ((result = realWildcardFind(fileName)) != -1) + return result; + + int length = fileName.length(); + QString backupSuffix = KateDocumentConfig::global()->backupSuffix(); + if (fileName.endsWith(backupSuffix)) { + if ((result = realWildcardFind(fileName.left(length - backupSuffix.length()))) != -1) + return result; + } + + for (QStringList::Iterator it = commonSuffixes.begin(); it != commonSuffixes.end(); ++it) { + if (*it != backupSuffix && fileName.endsWith(*it)) { + if ((result = realWildcardFind(fileName.left(length - (*it).length()))) != -1) + return result; + } + } + + return -1; +} + +int KateHlManager::realWildcardFind(const QString &fileName) +{ + static QRegExp sep("\\s*;\\s*"); + + QPtrList<KateHighlighting> highlights; + + for (KateHighlighting *highlight = hlList.first(); highlight != 0L; highlight = hlList.next()) { + highlight->loadWildcards(); + + for (QStringList::Iterator it = highlight->getPlainExtensions().begin(); it != highlight->getPlainExtensions().end(); ++it) + if (fileName.endsWith((*it))) + highlights.append(highlight); + + for (int i = 0; i < (int)highlight->getRegexpExtensions().count(); i++) { + QRegExp re = highlight->getRegexpExtensions()[i]; + if (re.exactMatch(fileName)) + highlights.append(highlight); + } + } + + if ( !highlights.isEmpty() ) + { + int pri = -1; + int hl = -1; + + for (KateHighlighting *highlight = highlights.first(); highlight != 0L; highlight = highlights.next()) + { + if (highlight->priority() > pri) + { + pri = highlight->priority(); + hl = hlList.findRef (highlight); + } + } + return hl; + } + + return -1; +} + +int KateHlManager::mimeFind( KateDocument *doc ) +{ + static QRegExp sep("\\s*;\\s*"); + + KMimeType::Ptr mt = doc->mimeTypeForContent(); + + QPtrList<KateHighlighting> highlights; + + for (KateHighlighting *highlight = hlList.first(); highlight != 0L; highlight = hlList.next()) + { + QStringList l = QStringList::split( sep, highlight->getMimetypes() ); + + for( QStringList::Iterator it = l.begin(); it != l.end(); ++it ) + { + if ( *it == mt->name() ) // faster than a regexp i guess? + highlights.append (highlight); + } + } + + if ( !highlights.isEmpty() ) + { + int pri = -1; + int hl = -1; + + for (KateHighlighting *highlight = highlights.first(); highlight != 0L; highlight = highlights.next()) + { + if (highlight->priority() > pri) + { + pri = highlight->priority(); + hl = hlList.findRef (highlight); + } + } + + return hl; + } + + return -1; +} + +uint KateHlManager::defaultStyles() +{ + return 14; +} + +QString KateHlManager::defaultStyleName(int n, bool translateNames) +{ + static QStringList names; + static QStringList translatedNames; + + if (names.isEmpty()) + { + names << "Normal"; + names << "Keyword"; + names << "Data Type"; + names << "Decimal/Value"; + names << "Base-N Integer"; + names << "Floating Point"; + names << "Character"; + names << "String"; + names << "Comment"; + names << "Others"; + names << "Alert"; + names << "Function"; + // this next one is for denoting the beginning/end of a user defined folding region + names << "Region Marker"; + // this one is for marking invalid input + names << "Error"; + + translatedNames << i18n("Normal"); + translatedNames << i18n("Keyword"); + translatedNames << i18n("Data Type"); + translatedNames << i18n("Decimal/Value"); + translatedNames << i18n("Base-N Integer"); + translatedNames << i18n("Floating Point"); + translatedNames << i18n("Character"); + translatedNames << i18n("String"); + translatedNames << i18n("Comment"); + translatedNames << i18n("Others"); + translatedNames << i18n("Alert"); + translatedNames << i18n("Function"); + // this next one is for denoting the beginning/end of a user defined folding region + translatedNames << i18n("Region Marker"); + // this one is for marking invalid input + translatedNames << i18n("Error"); + } + + return translateNames ? translatedNames[n] : names[n]; +} + +void KateHlManager::getDefaults(uint schema, KateAttributeList &list) +{ + list.setAutoDelete(true); + + KateAttribute* normal = new KateAttribute(); + normal->setTextColor(Qt::black); + normal->setSelectedTextColor(Qt::white); + list.append(normal); + + KateAttribute* keyword = new KateAttribute(); + keyword->setTextColor(Qt::black); + keyword->setSelectedTextColor(Qt::white); + keyword->setBold(true); + list.append(keyword); + + KateAttribute* dataType = new KateAttribute(); + dataType->setTextColor(Qt::darkRed); + dataType->setSelectedTextColor(Qt::white); + list.append(dataType); + + KateAttribute* decimal = new KateAttribute(); + decimal->setTextColor(Qt::blue); + decimal->setSelectedTextColor(Qt::cyan); + list.append(decimal); + + KateAttribute* basen = new KateAttribute(); + basen->setTextColor(Qt::darkCyan); + basen->setSelectedTextColor(Qt::cyan); + list.append(basen); + + KateAttribute* floatAttribute = new KateAttribute(); + floatAttribute->setTextColor(Qt::darkMagenta); + floatAttribute->setSelectedTextColor(Qt::cyan); + list.append(floatAttribute); + + KateAttribute* charAttribute = new KateAttribute(); + charAttribute->setTextColor(Qt::magenta); + charAttribute->setSelectedTextColor(Qt::magenta); + list.append(charAttribute); + + KateAttribute* string = new KateAttribute(); + string->setTextColor(QColor::QColor("#D00")); + string->setSelectedTextColor(Qt::red); + list.append(string); + + KateAttribute* comment = new KateAttribute(); + comment->setTextColor(Qt::darkGray); + comment->setSelectedTextColor(Qt::gray); + comment->setItalic(true); + list.append(comment); + + KateAttribute* others = new KateAttribute(); + others->setTextColor(Qt::darkGreen); + others->setSelectedTextColor(Qt::green); + list.append(others); + + KateAttribute* alert = new KateAttribute(); + alert->setTextColor(Qt::black); + alert->setSelectedTextColor( QColor::QColor("#FCC") ); + alert->setBold(true); + alert->setBGColor( QColor::QColor("#FCC") ); + list.append(alert); + + KateAttribute* functionAttribute = new KateAttribute(); + functionAttribute->setTextColor(Qt::darkBlue); + functionAttribute->setSelectedTextColor(Qt::white); + list.append(functionAttribute); + + KateAttribute* regionmarker = new KateAttribute(); + regionmarker->setTextColor(Qt::white); + regionmarker->setBGColor(Qt::gray); + regionmarker->setSelectedTextColor(Qt::gray); + list.append(regionmarker); + + KateAttribute* error = new KateAttribute(); + error->setTextColor(Qt::red); + error->setUnderline(true); + error->setSelectedTextColor(Qt::red); + list.append(error); + + KConfig *config = KateHlManager::self()->self()->getKConfig(); + config->setGroup("Default Item Styles - Schema " + KateFactory::self()->schemaManager()->name(schema)); + + for (uint z = 0; z < defaultStyles(); z++) + { + KateAttribute *i = list.at(z); + QStringList s = config->readListEntry(defaultStyleName(z)); + if (!s.isEmpty()) + { + while( s.count()<8) + s << ""; + + QString tmp; + QRgb col; + + tmp=s[0]; if (!tmp.isEmpty()) { + col=tmp.toUInt(0,16); i->setTextColor(col); } + + tmp=s[1]; if (!tmp.isEmpty()) { + col=tmp.toUInt(0,16); i->setSelectedTextColor(col); } + + tmp=s[2]; if (!tmp.isEmpty()) i->setBold(tmp!="0"); + + tmp=s[3]; if (!tmp.isEmpty()) i->setItalic(tmp!="0"); + + tmp=s[4]; if (!tmp.isEmpty()) i->setStrikeOut(tmp!="0"); + + tmp=s[5]; if (!tmp.isEmpty()) i->setUnderline(tmp!="0"); + + tmp=s[6]; if (!tmp.isEmpty()) { + if ( tmp != "-" ) + { + col=tmp.toUInt(0,16); + i->setBGColor(col); + } + else + i->clearAttribute(KateAttribute::BGColor); + } + tmp=s[7]; if (!tmp.isEmpty()) { + if ( tmp != "-" ) + { + col=tmp.toUInt(0,16); + i->setSelectedBGColor(col); + } + else + i->clearAttribute(KateAttribute::SelectedBGColor); + } + } + } +} + +void KateHlManager::setDefaults(uint schema, KateAttributeList &list) +{ + KConfig *config = KateHlManager::self()->self()->getKConfig(); + config->setGroup("Default Item Styles - Schema " + KateFactory::self()->schemaManager()->name(schema)); + + for (uint z = 0; z < defaultStyles(); z++) + { + QStringList settings; + KateAttribute *i = list.at(z); + + settings<<(i->itemSet(KateAttribute::TextColor)?QString::number(i->textColor().rgb(),16):""); + settings<<(i->itemSet(KateAttribute::SelectedTextColor)?QString::number(i->selectedTextColor().rgb(),16):""); + settings<<(i->itemSet(KateAttribute::Weight)?(i->bold()?"1":"0"):""); + settings<<(i->itemSet(KateAttribute::Italic)?(i->italic()?"1":"0"):""); + settings<<(i->itemSet(KateAttribute::StrikeOut)?(i->strikeOut()?"1":"0"):""); + settings<<(i->itemSet(KateAttribute::Underline)?(i->underline()?"1":"0"):""); + settings<<(i->itemSet(KateAttribute::BGColor)?QString::number(i->bgColor().rgb(),16):"-"); + settings<<(i->itemSet(KateAttribute::SelectedBGColor)?QString::number(i->selectedBGColor().rgb(),16):"-"); + settings<<"---"; + + config->writeEntry(defaultStyleName(z),settings); + } + + emit changed(); +} + +int KateHlManager::highlights() +{ + return (int) hlList.count(); +} + +QString KateHlManager::hlName(int n) +{ + return hlList.at(n)->name(); +} + +QString KateHlManager::hlNameTranslated(int n) +{ + return hlList.at(n)->nameTranslated(); +} + +QString KateHlManager::hlSection(int n) +{ + return hlList.at(n)->section(); +} + +bool KateHlManager::hlHidden(int n) +{ + return hlList.at(n)->hidden(); +} + +QString KateHlManager::identifierForName(const QString& name) +{ + KateHighlighting *hl = 0; + + if ((hl = hlDict[name])) + return hl->getIdentifier (); + + return QString(); +} + +bool KateHlManager::resetDynamicCtxs() +{ + if (forceNoDCReset) + return false; + + if (lastCtxsReset.elapsed() < KATE_DYNAMIC_CONTEXTS_RESET_DELAY) + return false; + + KateHighlighting *hl; + for (hl = hlList.first(); hl; hl = hlList.next()) + hl->dropDynamicContexts(); + + dynamicCtxsCount = 0; + lastCtxsReset.start(); + + return true; +} +//END + +//BEGIN KateHighlightAction +void KateViewHighlightAction::init() +{ + m_doc = 0; + subMenus.setAutoDelete( true ); + + connect(popupMenu(),SIGNAL(aboutToShow()),this,SLOT(slotAboutToShow())); +} + +void KateViewHighlightAction::updateMenu (Kate::Document *doc) +{ + m_doc = doc; +} + +void KateViewHighlightAction::slotAboutToShow() +{ + Kate::Document *doc=m_doc; + int count = KateHlManager::self()->highlights(); + + for (int z=0; z<count; z++) + { + QString hlName = KateHlManager::self()->hlNameTranslated (z); + QString hlSection = KateHlManager::self()->hlSection (z); + + if (!KateHlManager::self()->hlHidden(z)) + { + if ( !hlSection.isEmpty() && (names.contains(hlName) < 1) ) + { + if (subMenusName.contains(hlSection) < 1) + { + subMenusName << hlSection; + QPopupMenu *menu = new QPopupMenu (); + subMenus.append(menu); + popupMenu()->insertItem ( '&' + hlSection, menu); + } + + int m = subMenusName.findIndex (hlSection); + names << hlName; + subMenus.at(m)->insertItem ( '&' + hlName, this, SLOT(setHl(int)), 0, z); + } + else if (names.contains(hlName) < 1) + { + names << hlName; + popupMenu()->insertItem ( '&' + hlName, this, SLOT(setHl(int)), 0, z); + } + } + } + + if (!doc) return; + + for (uint i=0;i<subMenus.count();i++) + { + for (uint i2=0;i2<subMenus.at(i)->count();i2++) + { + subMenus.at(i)->setItemChecked(subMenus.at(i)->idAt(i2),false); + } + } + popupMenu()->setItemChecked (0, false); + + int i = subMenusName.findIndex (KateHlManager::self()->hlSection(doc->hlMode())); + if (i >= 0 && subMenus.at(i)) + subMenus.at(i)->setItemChecked (doc->hlMode(), true); + else + popupMenu()->setItemChecked (0, true); +} + +void KateViewHighlightAction::setHl (int mode) +{ + Kate::Document *doc=m_doc; + + if (doc) + doc->setHlMode((uint)mode); +} +//END KateViewHighlightAction + +// kate: space-indent on; indent-width 2; replace-tabs on; |