TDE core libraries
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
 
 
 
 
 
 

3473 rindas
100 KiB

/* 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 <tdeconfig.h>
#include <tdeglobal.h>
#include <kinstance.h>
#include <kmimetype.h>
#include <tdelocale.h>
#include <kregexp.h>
#include <tdepopupmenu.h>
#include <tdeglobalsettings.h>
#include <kdebug.h>
#include <kstandarddirs.h>
#include <tdemessagebox.h>
#include <kstaticdeleter.h>
#include <tdeapplication.h>
#include <tqstringlist.h>
#include <tqtextstream.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 TQString. if x is "true" or "1" this expression returns "true"
#define IS_TRUE(x) x.lower() == TQString("true") || x.toInt() == 1
//END defines
//BEGIN Prviate HL classes
inline bool kateInsideString (const TQString &str, TQChar ch)
{
const TQChar *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 TQString& text, int offset, int len) = 0;
virtual bool lineContinue(){return false;}
virtual TQStringList *capturedTexts() {return 0;}
virtual KateHlItem *clone(const TQStringList *) {return this;}
static void dynamicSubstitute(TQString& str, const TQStringList *args);
TQMemArray<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 TQString &_hlId, int attribute, int lineEndContext,int _lineBeginContext,
bool _fallthrough, int _fallthroughContext, bool _dynamic,bool _noIndentationBasedFolding);
virtual ~KateHlContext();
KateHlContext *clone(const TQStringList *args);
TQValueVector<KateHlItem*> items;
TQString 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 TQString &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;
TQString incCtxN;
bool includeAttrib;
};
class KateHlCharDetect : public KateHlItem
{
public:
KateHlCharDetect(int attribute, int context,signed char regionId,signed char regionId2, TQChar);
virtual int checkHgl(const TQString& text, int offset, int len);
virtual KateHlItem *clone(const TQStringList *args);
private:
TQChar sChar;
};
class KateHl2CharDetect : public KateHlItem
{
public:
KateHl2CharDetect(int attribute, int context, signed char regionId,signed char regionId2, TQChar ch1, TQChar ch2);
KateHl2CharDetect(int attribute, int context,signed char regionId,signed char regionId2, const TQChar *ch);
virtual int checkHgl(const TQString& text, int offset, int len);
virtual KateHlItem *clone(const TQStringList *args);
private:
TQChar sChar1;
TQChar sChar2;
};
class KateHlStringDetect : public KateHlItem
{
public:
KateHlStringDetect(int attribute, int context, signed char regionId,signed char regionId2, const TQString &, bool inSensitive=false);
virtual int checkHgl(const TQString& text, int offset, int len);
virtual KateHlItem *clone(const TQStringList *args);
private:
const TQString str;
const int strLen;
const bool _inSensitive;
};
class KateHlRangeDetect : public KateHlItem
{
public:
KateHlRangeDetect(int attribute, int context, signed char regionId,signed char regionId2, TQChar ch1, TQChar ch2);
virtual int checkHgl(const TQString& text, int offset, int len);
private:
TQChar sChar1;
TQChar sChar2;
};
class KateHlKeyword : public KateHlItem
{
public:
KateHlKeyword(int attribute, int context,signed char regionId,signed char regionId2, bool insensitive, const TQString& delims);
virtual ~KateHlKeyword ();
void addList(const TQStringList &);
virtual int checkHgl(const TQString& text, int offset, int len);
private:
TQMemArray< TQDict<bool>* > dict;
bool _insensitive;
const TQString& 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 TQString& 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 TQString& 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 TQString& text, int offset, int len);
int checkIntHgl(const TQString& 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 TQString& 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 TQString& text, int offset, int len);
};
class KateHlLineContinue : public KateHlItem
{
public:
KateHlLineContinue(int attribute, int context, signed char regionId,signed char regionId2);
virtual bool endEnable(TQChar c) {return c == '\0';}
virtual int checkHgl(const TQString& 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 TQString& 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 TQString& text, int offset, int len);
};
class KateHlAnyChar : public KateHlItem
{
public:
KateHlAnyChar(int attribute, int context, signed char regionId,signed char regionId2, const TQString& charList);
virtual int checkHgl(const TQString& text, int offset, int len);
private:
const TQString _charList;
};
class KateHlRegExpr : public KateHlItem
{
public:
KateHlRegExpr(int attribute, int context,signed char regionId,signed char regionId2 ,TQString expr, bool insensitive, bool minimal);
~KateHlRegExpr() { delete Expr; };
virtual int checkHgl(const TQString& text, int offset, int len);
virtual TQStringList *capturedTexts();
virtual KateHlItem *clone(const TQStringList *args);
private:
TQRegExp *Expr;
bool handlesLinestart;
TQString _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 TQString& 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 TQString& text, int offset, int len)
{
// first char should be a letter or underscore
if ( text[offset].isLetter() || text[offset] == TQChar ('_') )
{
// memorize length
int len2 = offset+len;
// one char seen
offset++;
// now loop for all other thingies
while (
(offset < len2)
&& (text[offset].isLetterOrNumber() || (text[offset] == TQChar ('_')))
)
offset++;
return offset;
}
return 0;
}
};
//END
//BEGIN STATICS
KateHlManager *KateHlManager::s_self = 0;
static const bool trueBool = true;
static const TQString stdDeliminator = TQString (" \t.():!+,-<=>%&*/;?[]^{|}~\\");
//END
//BEGIN NON MEMBER FUNCTIONS
static KateHlItemData::ItemStyles getDefStyleNum(TQString 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(TQString &str, const TQStringList *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, TQChar c)
: KateHlItem(attribute,context,regionId,regionId2)
, sChar(c)
{
}
int KateHlCharDetect::checkHgl(const TQString& text, int offset, int /*len*/)
{
if (text[offset] == sChar)
return offset + 1;
return 0;
}
KateHlItem *KateHlCharDetect::clone(const TQStringList *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, TQChar ch1, TQChar ch2)
: KateHlItem(attribute,context,regionId,regionId2)
, sChar1 (ch1)
, sChar2 (ch2)
{
}
int KateHl2CharDetect::checkHgl(const TQString& text, int offset, int len)
{
if ((len >= 2) && text[offset++] == sChar1 && text[offset++] == sChar2)
return offset;
return 0;
}
KateHlItem *KateHl2CharDetect::clone(const TQStringList *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 TQString &s, bool inSensitive)
: KateHlItem(attribute, context,regionId,regionId2)
, str(inSensitive ? s.upper() : s)
, strLen (str.length())
, _inSensitive(inSensitive)
{
}
int KateHlStringDetect::checkHgl(const TQString& 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 TQStringList *args)
{
TQString 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, TQChar ch1, TQChar ch2)
: KateHlItem(attribute,context,regionId,regionId2)
, sChar1 (ch1)
, sChar2 (ch2)
{
}
int KateHlRangeDetect::checkHgl(const TQString& 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 TQString& 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 TQStringList& 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 TQDict<bool> (17, !_insensitive);
dict[len]->insert(list[i], &trueBool);
}
}
int KateHlKeyword::checkHgl(const TQString& 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(TQConstString(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 TQString& 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 TQString& 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 TQString& text, int offset, int len)
{
if (text[offset] == '0')
{
offset++;
len--;
int offset2 = offset;
while ((len > 0) && (text.at(offset2) >= TQChar('0') && text.at(offset2) <= TQChar('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 TQString& 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 TQString& 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 TQString& 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 TQString& charList)
: KateHlItem(attribute, context,regionId,regionId2)
, _charList(charList)
{
}
int KateHlAnyChar::checkHgl(const TQString& 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, TQString 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 TQRegExp(regexp, !_insensitive);
Expr->setMinimal(_minimal);
}
int KateHlRegExpr::checkHgl(const TQString& text, int offset, int /*len*/)
{
if (offset && handlesLinestart)
return 0;
int offset2 = Expr->search( text, offset, TQRegExp::CaretAtOffset );
if (offset2 == -1) return 0;
return (offset + Expr->matchedLength());
}
TQStringList *KateHlRegExpr::capturedTexts()
{
return new TQStringList(Expr->capturedTexts());
}
KateHlItem *KateHlRegExpr::clone(const TQStringList *args)
{
TQString regexp = _regexp;
TQStringList escArgs = *args;
for (TQStringList::Iterator it = escArgs.begin(); it != escArgs.end(); ++it)
{
(*it).replace(TQRegExp("(\\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 TQString& 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 TQString& 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) && (static_cast<const char>(text.at(offset)) >= '0' && static_cast<const char>(text.at(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) && (static_cast<const char>(text.at(offset)) >= '0' && static_cast<const char>(text.at(offset)) <= '7'); i++)
{
offset++;
len--;
}
break;
default:
return 0;
}
return offset;
}
return 0;
}
int KateHlCStringChar::checkHgl(const TQString& 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 TQString& 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 TQChar *s)
: KateHlItem(attribute,context,regionId,regionId2) {
sChar1 = s[0];
sChar2 = s[1];
}
//END KateHl2CharDetect
KateHlItemData::KateHlItemData(const TQString name, int defStyleNum)
: name(name), defStyleNum(defStyleNum) {
}
KateHlData::KateHlData(const TQString &wildcards, const TQString &mimetypes, const TQString &identifier, int priority)
: wildcards(wildcards), mimetypes(mimetypes), identifier(identifier), priority(priority)
{
}
//BEGIN KateHlContext
KateHlContext::KateHlContext (const TQString &_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)<<TQString("**********************_noIndentationBasedFolding is TRUE*****************")<<endl;
}
KateHlContext *KateHlContext::clone(const TQStringList *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, TQMemArray<short>* ctxs, int *prevLine)
{
//kdDebug(13010)<<TQString("Entering generateContextStack with %1").arg(ctx)<<endl;
while (true)
{
if (ctx >= 0)
{
(*ctxNum) = ctx;
ctxs->resize (ctxs->size()+1, TQGArray::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, TQGArray::SpeedOptim);
(*ctxNum)=(*ctxs)[size-1];
}
else
{
ctxs->resize (0, TQGArray::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 TQStringList *args)
{
QPair<KateHlContext *, TQString> 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,
TQMemArray<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 !
TQMemArray<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)<<TQString("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)<<TQString("The new context is %1").arg((int)ctxNum)<<endl;
}
// text, for programming convenience :)
TQChar lastChar = ' ';
const TQString& text = textLine->string();
const int len = textLine->length();
// calc at which char the first char occurs, set it to length 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)<<TQString("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, TQGArray::SpeedOptim);
}
else
{
foldingList->resize (foldingList->size()+2, TQGArray::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)<<TQString("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, TQGArray::SpeedOptim);
}
else*/
{
foldingList->resize (foldingList->size()+2, TQGArray::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)
{
TQStringList *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()
{
TDEConfig *config = KateHlManager::self()->getTDEConfig();
config->setGroup("Highlighting " + iName);
TQString extensionString = config->readEntry("Wildcards", iWildcards);
if (extensionSource != extensionString) {
regexpExtensions.clear();
plainExtensions.clear();
extensionSource = extensionString;
static TQRegExp sep("\\s*;\\s*");
TQStringList l = TQStringList::split( sep, extensionSource );
static TQRegExp boringExpression("\\*\\.[\\d\\w]+");
for( TQStringList::Iterator it = l.begin(); it != l.end(); ++it )
if (boringExpression.exactMatch(*it))
plainExtensions.append((*it).mid(1));
else
regexpExtensions.append(TQRegExp((*it), true, true));
}
}
TQValueList<TQRegExp>& KateHighlighting::getRegexpExtensions()
{
return regexpExtensions;
}
TQStringList& KateHighlighting::getPlainExtensions()
{
return plainExtensions;
}
TQString KateHighlighting::getMimetypes()
{
TDEConfig *config = KateHlManager::self()->getTDEConfig();
config->setGroup("Highlighting " + iName);
return config->readEntry("Mimetypes", iMimetypes);
}
int KateHighlighting::priority()
{
TDEConfig *config = KateHlManager::self()->getTDEConfig();
config->setGroup("Highlighting " + iName);
return config->readNumEntry("Priority", m_priority);
}
KateHlData *KateHighlighting::getData()
{
TDEConfig *config = KateHlManager::self()->getTDEConfig();
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)
{
TDEConfig *config = KateHlManager::self()->getTDEConfig();
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)
{
TDEConfig *config = KateHlManager::self()->getTDEConfig();
config->setGroup("Highlighting " + iName + " - Schema " + KateFactory::self()->schemaManager()->name(schema));
list.clear();
createKateHlItemData(list);
for (KateHlItemData *p = list.first(); p != 0L; p = list.next())
{
TQStringList s = config->readListEntry(p->name);
// kdDebug(13010)<<p->name<<s.count()<<endl;
if (s.count()>0)
{
while(s.count()<9) s<<"";
p->clear();
TQString 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)
{
TDEConfig *config = KateHlManager::self()->getTDEConfig();
config->setGroup("Highlighting " + iName + " - Schema "
+ KateFactory::self()->schemaManager()->name(schema));
TQStringList settings;
for (KateHlItemData *p = list.first(); p != 0L; p = list.next())
{
settings.clear();
settings<<TQString::number(p->defStyleNum,10);
settings<<(p->itemSet(KateAttribute::TextColor)?TQString::number(p->textColor().rgb(),16):"");
settings<<(p->itemSet(KateAttribute::SelectedTextColor)?TQString::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)?TQString::number(p->bgColor().rgb(),16):"");
settings<<(p->itemSet(KateAttribute::SelectedBGColor)?TQString::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
TQString color = KateHlManager::self()->syntax->groupData(data,TQString("color"));
TQString selColor = KateHlManager::self()->syntax->groupData(data,TQString("selColor"));
TQString bold = KateHlManager::self()->syntax->groupData(data,TQString("bold"));
TQString italic = KateHlManager::self()->syntax->groupData(data,TQString("italic"));
TQString underline = KateHlManager::self()->syntax->groupData(data,TQString("underline"));
TQString strikeOut = KateHlManager::self()->syntax->groupData(data,TQString("strikeOut"));
TQString bgColor = KateHlManager::self()->syntax->groupData(data,TQString("backgroundColor"));
TQString selBgColor = KateHlManager::self()->syntax->groupData(data,TQString("selBackgroundColor"));
KateHlItemData* newData = new KateHlItemData(
buildPrefix+KateHlManager::self()->syntax->groupData(data,TQString("name")).simplifyWhiteSpace(),
getDefStyleNum(KateHlManager::self()->syntax->groupData(data,TQString("defStyleNum"))));
/* here the custom style overrides are specified, if needed */
if (!color.isEmpty()) newData->setTextColor(TQColor(color));
if (!selColor.isEmpty()) newData->setSelectedTextColor(TQColor(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(TQColor(bgColor));
if (!selBgColor.isEmpty()) newData->setSelectedBGColor(TQColor(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 TQString& 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,
TQStringList *RegionList,
TQStringList *ContextNameList)
{
// No highlighting -> exit
if (noHl)
return 0;
// get the (tagname) itemd type
TQString dataname=KateHlManager::self()->syntax->groupItemData(data,TQString(""));
// code folding region handling:
TQString beginRegionStr=KateHlManager::self()->syntax->groupItemData(data,TQString("beginRegion"));
TQString endRegionStr=KateHlManager::self()->syntax->groupItemData(data,TQString("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;
TQString tmpAttr=KateHlManager::self()->syntax->groupItemData(data,TQString("attribute")).simplifyWhiteSpace();
bool onlyConsume = tmpAttr.isEmpty();
// only relevant for non consumer
if (!onlyConsume)
{
if (TQString("%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;
TQString unresolvedContext;
TQString tmpcontext=KateHlManager::self()->syntax->groupItemData(data,TQString("context"));
if (!tmpcontext.isEmpty())
context=getIdFromString(ContextNameList, tmpcontext,unresolvedContext);
// Get the char parameter (eg DetectChar)
char chr;
if (! KateHlManager::self()->syntax->groupItemData(data,TQString("char")).isEmpty())
chr= (KateHlManager::self()->syntax->groupItemData(data,TQString("char")).latin1())[0];
else
chr=0;
// Get the String parameter (eg. StringDetect)
TQString stringdata=KateHlManager::self()->syntax->groupItemData(data,TQString("String"));
// Get a second char parameter (char1) (eg Detect2Chars)
char chr1;
if (! KateHlManager::self()->syntax->groupItemData(data,TQString("char1")).isEmpty())
chr1= (KateHlManager::self()->syntax->groupItemData(data,TQString("char1")).latin1())[0];
else
chr1=0;
// Will be removed eventually. Atm used for StringDetect, keyword and RegExp
const TQString & insensitive_str = KateHlManager::self()->syntax->groupItemData(data,TQString("insensitive"));
bool insensitive = IS_TRUE( insensitive_str );
// for regexp only
bool minimal = IS_TRUE( KateHlManager::self()->syntax->groupItemData(data,TQString("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,TQString("lookAhead")) );
bool dynamic= IS_TRUE(KateHlManager::self()->syntax->groupItemData(data,TQString("dynamic")) );
bool firstNonSpace = IS_TRUE(KateHlManager::self()->syntax->groupItemData(data,TQString("firstNonSpace")) );
int column = -1;
TQString colStr = KateHlManager::self()->syntax->groupItemData(data,TQString("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;
}
TQString KateHighlighting::hlKeyForAttrib( int i ) const
{
// find entry. This is faster than TQMap::find. m_hlIndex always has an entry
// for key '0' (it is "none"), so the result is always valid.
int k = 0;
TQMap<int,TQString>::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( TQChar c, int attrib ) const
{
return m_additionalData[ hlKeyForAttrib( attrib ) ]->deliminator.find(c) < 0
&& !c.isSpace() && c != '"' && c != '\'';
}
bool KateHighlighting::canBreakAt( TQChar c, int attrib ) const
{
static const TQString& sq = TDEGlobal::staticQString("\"'");
return (m_additionalData[ hlKeyForAttrib( attrib ) ]->wordWrapDeliminator.find(c) != -1) && (sq.find(c) == -1);
}
signed char KateHighlighting::commentRegion(int attr) const {
TQString commentRegion=m_additionalData[ hlKeyForAttrib( attr ) ]->multiLineRegion;
return (commentRegion.isEmpty()?0:(commentRegion.toShort()));
}
bool KateHighlighting::canComment( int startAttrib, int endAttrib ) const
{
TQString k = hlKeyForAttrib( startAttrib );
return ( k == hlKeyForAttrib( endAttrib ) &&
( ( !m_additionalData[k]->multiLineCommentStart.isEmpty() && !m_additionalData[k]->multiLineCommentEnd.isEmpty() ) ||
! m_additionalData[k]->singleLineCommentMarker.isEmpty() ) );
}
TQString KateHighlighting::getCommentStart( int attrib ) const
{
return m_additionalData[ hlKeyForAttrib( attrib) ]->multiLineCommentStart;
}
TQString KateHighlighting::getCommentEnd( int attrib ) const
{
return m_additionalData[ hlKeyForAttrib( attrib ) ]->multiLineCommentEnd;
}
TQString 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");
TQString 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");
TQString 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,TQString("casesensitive")) ) )
casesensitive=true;
else
casesensitive=false;
//get the weak deliminators
weakDeliminator=(KateHlManager::self()->syntax->groupItemData(data,TQString("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);
}
TQString addDelim = (KateHlManager::self()->syntax->groupItemData(data,TQString("additionalDeliminator")));
if (!addDelim.isEmpty())
deliminator=deliminator+addDelim;
KateHlManager::self()->syntax->freeGroupInfo(data);
}
else
{
//Default values
casesensitive=true;
weakDeliminator=TQString("");
}
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");
TQString wordWrapDeliminator = stdDeliminator;
if (data)
{
kdDebug(13010)<<"Found global keyword config"<<endl;
wordWrapDeliminator = (KateHlManager::self()->syntax->groupItemData(data,TQString("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,TQString("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,TQString("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(TQStringList *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))
{
TQString tmpAttr=KateHlManager::self()->syntax->groupData(data,TQString("name")).simplifyWhiteSpace();
if (tmpAttr.isEmpty())
{
tmpAttr=TQString("!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(TQStringList *ContextNameList, TQString tmpLineEndContext, /*NO CONST*/ TQString &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
TQString 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;
TQString 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)
{
TQString 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="";
TQString 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)
{