You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3474 lines
100 KiB
3474 lines
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 <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 <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 *tqunicode = str.tqunicode();
|
|
const uint len = str.length();
|
|
for (uint i=0; i < len; i++)
|
|
if (tqunicode[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]->tqfind(TQConstString(text.tqunicode() + 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) >= '0' && text.at(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 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->tqcapturedTexts());
|
|
}
|
|
|
|
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) && (text.at(offset) >= '0' && 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) && (text.at(offset) >='0'&& 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.tqcontains(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 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)<<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()
|
|
{
|
|
KConfig *config = KateHlManager::self()->getKConfig();
|
|
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()
|
|
{
|
|
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())
|
|
{
|
|
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)
|
|
{
|
|
KConfig *config = KateHlManager::self()->getKConfig();
|
|
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->tqfindIndex(beginRegionStr);
|
|
|
|
if (regionId==-1) // if the region name doesn't already exist, add it to the list
|
|
{
|
|
(*RegionList)<<beginRegionStr;
|
|
regionId = RegionList->tqfindIndex(beginRegionStr);
|
|
}
|
|
|
|
regionId++;
|
|
|
|
kdDebug(13010) << "########### BEG REG: " << beginRegionStr << " NUM: " << regionId << endl;
|
|
}
|
|
|
|
if (!endRegionStr.isEmpty())
|
|
{
|
|
regionId2 = RegionList->tqfindIndex(endRegionStr);
|
|
|
|
if (regionId2==-1) // if the region name doesn't already exist, add it to the list
|
|
{
|
|
(*RegionList)<<endRegionStr;
|
|
regionId2 = RegionList->tqfindIndex(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.tqfind(c) < 0
|
|
&& !c.isSpace() && c != '"' && c != '\'';
|
|
}
|
|
|
|
bool KateHighlighting::canBreakAt( TQChar c, int attrib ) const
|
|
{
|
|
static const TQString& sq = KGlobal::staticQString("\"'");
|
|
return (m_additionalData[ hlKeyForAttrib( attrib ) ]->wordWrapDeliminator.tqfind(c) != -1) && (sq.tqfind(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.tqfind (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.tqcontains("##"))
|
|
{
|
|
int o = tmpLineEndContext.tqfind("##");
|
|
// 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.tqcontains(tmp)) embeddedHls.insert(tmp,KateEmbeddedHlInfo());
|
|
unres=tmp+':'+tmpLineEndContext.left(o);
|
|
context=0;
|
|
}
|
|
|
|
else
|
|
{
|
|
context=ContextNameList->tqfindIndex(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.tqfind(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)
|
|
{
|
|
//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 TQString &ident, int ctx0)
|
|
{
|
|
kdDebug(13010)<<"=== Adding hl with ident '"<<ident<<"'"<<endl;
|
|
|
|
buildIdentifier=ident;
|
|
KateSyntaxContextData *data, *datasub;
|
|
KateHlItem *c;
|
|
|
|
TQString 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 ();
|
|
|
|
TQString 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
|
|
TQString tmpAttr=KateHlManager::self()->syntax->groupData(data,TQString("attribute")).simplifyWhiteSpace();
|
|
int attr;
|
|
if (TQString("%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,TQString("lineEndContext")).simplifyWhiteSpace();
|
|
|
|
TQString tmpLineEndContext=KateHlManager::self()->syntax->groupData(data,TQString("lineEndContext")).simplifyWhiteSpace();
|
|
int context;
|
|
|
|
context=getIdFromString(&ContextNameList, tmpLineEndContext,dummy);
|
|
|
|
TQString tmpNIBF = KateHlManager::self()->syntax->groupData(data, TQString("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
|
|
{
|
|
TQString tmpFt = KateHlManager::self()->syntax->groupData(data, TQString("fallthrough") );
|
|
if ( IS_TRUE(tmpFt) )
|
|
ft = true;
|
|
if ( ft )
|
|
{
|
|
TQString tmpFtc = KateHlManager::self()->syntax->groupData( data, TQString("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;
|
|
TQString tmpDynamic = KateHlManager::self()->syntax->groupData(data, TQString("dynamic") );
|
|
if ( tmpDynamic.lower() == "true" || tmpDynamic.toInt() == 1 )
|
|
dynamic = true;
|
|
|
|
KateHlContext *ctxNew = new KateHlContext (
|
|
ident,
|
|
attr,
|
|
context,
|
|
(KateHlManager::self()->syntax->groupData(data,TQString("lineBeginContext"))).isEmpty()?-1:
|
|
(KateHlManager::self()->syntax->groupData(data,TQString("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
|
|
TQString tag = KateHlManager::self()->syntax->groupItemData(data,TQString(""));
|
|
if ( tag == "IncludeRules" ) //if the new item is an Include rule, we have to take special care
|
|
{
|
|
TQString incCtx = KateHlManager::self()->syntax->groupItemData( data, TQString("context"));
|
|
TQString incAttrib = KateHlManager::self()->syntax->groupItemData( data, TQString("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.tqfind("##");
|
|
//#stay, #pop is not interesting here
|
|
if (incCtxi >= 0)
|
|
{
|
|
TQString incSet = incCtx.mid(incCtxi + 2);
|
|
TQString 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.tqcontains(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
|
|
TQString tag = KateHlManager::self()->syntax->groupKateHlItemData(data,TQString(""));
|
|
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, TQString("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.tqfindIndex( 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 = TQString();
|
|
kdDebug(13010)<<"ERROR comment region attribute could not be resolved"<<endl;
|
|
|
|
} else {
|
|
m_additionalData[ ident ]->multiLineRegion=TQString::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 ( TQIntDictIterator< TQMemArray<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();
|
|
TQMemArray<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;
|
|
}
|
|
}
|
|
}
|
|
|
|
TQMemArray<KateAttribute> *KateHighlighting::attributes (uint schema)
|
|
{
|
|
TQMemArray<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 TQMemArray<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()
|
|
: TQObject()
|
|
, m_config ("katesyntaxhighlightingrc", false, false)
|
|
, commonSuffixes (TQStringList::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 ( TQString(hlList.at(insert)->section() + hlList.at(insert)->nameTranslated()).lower()
|
|
> TQString(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 TQString &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 TQString &fileName)
|
|
{
|
|
int result = -1;
|
|
if ((result = realWildcardFind(fileName)) != -1)
|
|
return result;
|
|
|
|
int length = fileName.length();
|
|
TQString backupSuffix = KateDocumentConfig::global()->backupSuffix();
|
|
if (fileName.endsWith(backupSuffix)) {
|
|
if ((result = realWildcardFind(fileName.left(length - backupSuffix.length()))) != -1)
|
|
return result;
|
|
}
|
|
|
|
for (TQStringList::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 TQString &fileName)
|
|
{
|
|
static TQRegExp sep("\\s*;\\s*");
|
|
|
|
TQPtrList<KateHighlighting> highlights;
|
|
|
|
for (KateHighlighting *highlight = hlList.first(); highlight != 0L; highlight = hlList.next()) {
|
|
highlight->loadWildcards();
|
|
|
|
for (TQStringList::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++) {
|
|
TQRegExp 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.tqfindRef (highlight);
|
|
}
|
|
}
|
|
return hl;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
int KateHlManager::mimeFind( KateDocument *doc )
|
|
{
|
|
static TQRegExp sep("\\s*;\\s*");
|
|
|
|
KMimeType::Ptr mt = doc->mimeTypeForContent();
|
|
|
|
TQPtrList<KateHighlighting> highlights;
|
|
|
|
for (KateHighlighting *highlight = hlList.first(); highlight != 0L; highlight = hlList.next())
|
|
{
|
|
TQStringList l = TQStringList::split( sep, highlight->getMimetypes() );
|
|
|
|
for( TQStringList::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.tqfindRef (highlight);
|
|
}
|
|
}
|
|
|
|
return hl;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
uint KateHlManager::defaultStyles()
|
|
{
|
|
return 14;
|
|
}
|
|
|
|
TQString KateHlManager::defaultStyleName(int n, bool translateNames)
|
|
{
|
|
static TQStringList names;
|
|
static TQStringList 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(TQColor("#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( TQColor("#FCC") );
|
|
alert->setBold(true);
|
|
alert->setBGColor( TQColor("#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);
|
|
TQStringList s = config->readListEntry(defaultStyleName(z));
|
|
if (!s.isEmpty())
|
|
{
|
|
while( s.count()<8)
|
|
s << "";
|
|
|
|
TQString 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++)
|
|
{
|
|
TQStringList settings;
|
|
KateAttribute *i = list.at(z);
|
|
|
|
settings<<(i->itemSet(KateAttribute::TextColor)?TQString::number(i->textColor().rgb(),16):"");
|
|
settings<<(i->itemSet(KateAttribute::SelectedTextColor)?TQString::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)?TQString::number(i->bgColor().rgb(),16):"-");
|
|
settings<<(i->itemSet(KateAttribute::SelectedBGColor)?TQString::number(i->selectedBGColor().rgb(),16):"-");
|
|
settings<<"---";
|
|
|
|
config->writeEntry(defaultStyleName(z),settings);
|
|
}
|
|
|
|
emit changed();
|
|
}
|
|
|
|
int KateHlManager::highlights()
|
|
{
|
|
return (int) hlList.count();
|
|
}
|
|
|
|
TQString KateHlManager::hlName(int n)
|
|
{
|
|
return hlList.at(n)->name();
|
|
}
|
|
|
|
TQString KateHlManager::hlNameTranslated(int n)
|
|
{
|
|
return hlList.at(n)->nameTranslated();
|
|
}
|
|
|
|
TQString KateHlManager::hlSection(int n)
|
|
{
|
|
return hlList.at(n)->section();
|
|
}
|
|
|
|
bool KateHlManager::hlHidden(int n)
|
|
{
|
|
return hlList.at(n)->hidden();
|
|
}
|
|
|
|
TQString KateHlManager::identifierForName(const TQString& name)
|
|
{
|
|
KateHighlighting *hl = 0;
|
|
|
|
if ((hl = hlDict[name]))
|
|
return hl->getIdentifier ();
|
|
|
|
return TQString();
|
|
}
|
|
|
|
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(),TQT_SIGNAL(aboutToShow()),this,TQT_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++)
|
|
{
|
|
TQString hlName = KateHlManager::self()->hlNameTranslated (z);
|
|
TQString hlSection = KateHlManager::self()->hlSection (z);
|
|
|
|
if (!KateHlManager::self()->hlHidden(z))
|
|
{
|
|
if ( !hlSection.isEmpty() && (names.tqcontains(hlName) < 1) )
|
|
{
|
|
if (subMenusName.tqcontains(hlSection) < 1)
|
|
{
|
|
subMenusName << hlSection;
|
|
TQPopupMenu *menu = new TQPopupMenu ();
|
|
subMenus.append(menu);
|
|
popupMenu()->insertItem ( '&' + hlSection, menu);
|
|
}
|
|
|
|
int m = subMenusName.tqfindIndex (hlSection);
|
|
names << hlName;
|
|
subMenus.at(m)->insertItem ( '&' + hlName, this, TQT_SLOT(setHl(int)), 0, z);
|
|
}
|
|
else if (names.tqcontains(hlName) < 1)
|
|
{
|
|
names << hlName;
|
|
popupMenu()->insertItem ( '&' + hlName, this, TQT_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.tqfindIndex (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;
|