kate Library API Documentation

katehighlight.cpp

00001 /* This file is part of the KDE libraries
00002    Copyright (C) 2003, 2004 Anders Lund <anders@alweb.dk>
00003    Copyright (C) 2003 Hamish Rodda <rodda@kde.org>
00004    Copyright (C) 2001,2002 Joseph Wenninger <jowenn@kde.org>
00005    Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org>
00006    Copyright (C) 1999 Jochen Wilhelmy <digisnap@cs.tu-berlin.de>
00007 
00008    This library is free software; you can redistribute it and/or
00009    modify it under the terms of the GNU Library General Public
00010    License version 2 as published by the Free Software Foundation.
00011 
00012    This library is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015    Library General Public License for more details.
00016 
00017    You should have received a copy of the GNU Library General Public License
00018    along with this library; see the file COPYING.LIB.  If not, write to
00019    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00020    Boston, MA 02111-1307, USA.
00021 */
00022 
00023 //BEGIN INCLUDES
00024 #include "katehighlight.h"
00025 #include "katehighlight.moc"
00026 
00027 #include "katetextline.h"
00028 #include "katedocument.h"
00029 #include "katesyntaxdocument.h"
00030 #include "katerenderer.h"
00031 #include "katefactory.h"
00032 #include "kateschema.h"
00033 #include "kateconfig.h"
00034 
00035 #include <kconfig.h>
00036 #include <kglobal.h>
00037 #include <kinstance.h>
00038 #include <kmimetype.h>
00039 #include <klocale.h>
00040 #include <kregexp.h>
00041 #include <kpopupmenu.h>
00042 #include <kglobalsettings.h>
00043 #include <kdebug.h>
00044 #include <kstandarddirs.h>
00045 #include <kmessagebox.h>
00046 #include <kstaticdeleter.h>
00047 #include <kapplication.h>
00048 
00049 #include <qstringlist.h>
00050 #include <qtextstream.h>
00051 //END
00052 
00053 //BEGIN defines
00054 // same as in kmimemagic, no need to feed more data
00055 #define KATE_HL_HOWMANY 1024
00056 
00057 // min. x seconds between two dynamic contexts reset
00058 static const int KATE_DYNAMIC_CONTEXTS_RESET_DELAY = 30 * 1000;
00059 
00060 // x is a QString. if x is "true" or "1" this expression returns "true"
00061 #define IS_TRUE(x) x.lower() == QString("true") || x.toInt() == 1
00062 //END defines
00063 
00064 //BEGIN  Prviate HL classes
00065 
00066 inline bool kateInsideString (const QString &str, QChar ch)
00067 {
00068   for (uint i=0; i < str.length(); i++)
00069     if (*(str.unicode()+i) == ch)
00070       return true;
00071 
00072   return false;
00073 }
00074 
00075 class KateHlItem
00076 {
00077   public:
00078     KateHlItem(int attribute, int context,signed char regionId, signed char regionId2);
00079     virtual ~KateHlItem();
00080 
00081   public:
00082     // caller must keep in mind: LEN > 0 is a must !!!!!!!!!!!!!!!!!!!!!1
00083     // Now, the function returns the offset detected, or 0 if no match is found.
00084     // bool linestart isn't needed, this is equivalent to offset == 0.
00085     virtual int checkHgl(const QString& text, int offset, int len) = 0;
00086 
00087     virtual bool lineContinue(){return false;}
00088 
00089     virtual QStringList *capturedTexts() {return 0;}
00090     virtual KateHlItem *clone(const QStringList *) {return this;}
00091 
00092     static void dynamicSubstitute(QString& str, const QStringList *args);
00093 
00094     QMemArray<KateHlItem*> subItems;
00095     int attr;
00096     int ctx;
00097     signed char region;
00098     signed char region2;
00099 
00100     bool lookAhead;
00101 
00102     bool dynamic;
00103     bool dynamicChild;
00104     bool firstNonSpace;
00105     bool onlyConsume;
00106     int column;
00107 
00108     // start enable flags, nicer than the virtual methodes
00109     // saves function calls
00110     bool alwaysStartEnable;
00111     bool customStartEnable;
00112 };
00113 
00114 class KateHlContext
00115 {
00116   public:
00117     KateHlContext(const QString &_hlId, int attribute, int lineEndContext,int _lineBeginContext,
00118                   bool _fallthrough, int _fallthroughContext, bool _dynamic);
00119     virtual ~KateHlContext();
00120     KateHlContext *clone(const QStringList *args);
00121 
00122     QValueVector<KateHlItem*> items;
00123     QString hlId; 
00124     int attr;
00125     int ctx;
00126     int lineBeginContext;
00132     bool fallthrough;
00133     int ftctx; // where to go after no rules matched
00134 
00135     bool dynamic;
00136     bool dynamicChild;
00137 };
00138 
00139 class KateEmbeddedHlInfo
00140 {
00141   public:
00142     KateEmbeddedHlInfo() {loaded=false;context0=-1;}
00143     KateEmbeddedHlInfo(bool l, int ctx0) {loaded=l;context0=ctx0;}
00144 
00145   public:
00146     bool loaded;
00147     int context0;
00148 };
00149 
00150 class KateHlIncludeRule
00151 {
00152   public:
00153     KateHlIncludeRule(int ctx_=0, uint pos_=0, const QString &incCtxN_="", bool incAttrib=false)
00154       : ctx(ctx_)
00155       , pos( pos_)
00156       , incCtxN( incCtxN_ )
00157       , includeAttrib( incAttrib )
00158     {
00159       incCtx=-1;
00160     }
00161     //KateHlIncludeRule(int ctx_, uint  pos_, bool incAttrib) {ctx=ctx_;pos=pos_;incCtx=-1;incCtxN="";includeAttrib=incAttrib}
00162 
00163   public:
00164     int ctx;
00165     uint pos;
00166     int incCtx;
00167     QString incCtxN;
00168     bool includeAttrib;
00169 };
00170 
00171 class KateHlCharDetect : public KateHlItem
00172 {
00173   public:
00174     KateHlCharDetect(int attribute, int context,signed char regionId,signed char regionId2, QChar);
00175 
00176     virtual int checkHgl(const QString& text, int offset, int len);
00177     virtual KateHlItem *clone(const QStringList *args);
00178 
00179   private:
00180     QChar sChar;
00181 };
00182 
00183 class KateHl2CharDetect : public KateHlItem
00184 {
00185   public:
00186     KateHl2CharDetect(int attribute, int context, signed char regionId,signed char regionId2,  QChar ch1, QChar ch2);
00187     KateHl2CharDetect(int attribute, int context,signed char regionId,signed char regionId2,  const QChar *ch);
00188 
00189     virtual int checkHgl(const QString& text, int offset, int len);
00190     virtual KateHlItem *clone(const QStringList *args);
00191 
00192   private:
00193     QChar sChar1;
00194     QChar sChar2;
00195 };
00196 
00197 class KateHlStringDetect : public KateHlItem
00198 {
00199   public:
00200     KateHlStringDetect(int attribute, int context, signed char regionId,signed char regionId2, const QString &, bool inSensitive=false);
00201 
00202     virtual int checkHgl(const QString& text, int offset, int len);
00203     virtual KateHlItem *clone(const QStringList *args);
00204 
00205   private:
00206     const QString str;
00207     const int strLen;
00208     const bool _inSensitive;
00209 };
00210 
00211 class KateHlRangeDetect : public KateHlItem
00212 {
00213   public:
00214     KateHlRangeDetect(int attribute, int context, signed char regionId,signed char regionId2, QChar ch1, QChar ch2);
00215 
00216     virtual int checkHgl(const QString& text, int offset, int len);
00217 
00218   private:
00219     QChar sChar1;
00220     QChar sChar2;
00221 };
00222 
00223 class KateHlKeyword : public KateHlItem
00224 {
00225   public:
00226     KateHlKeyword(int attribute, int context,signed char regionId,signed char regionId2, bool casesensitive, const QString& delims);
00227     virtual ~KateHlKeyword ();
00228 
00229     void addList(const QStringList &);
00230     virtual int checkHgl(const QString& text, int offset, int len);
00231 
00232   private:
00233     QMemArray< QDict<bool>* > dict;
00234     bool _caseSensitive;
00235     const QString& deliminators;
00236     int minLen;
00237     int maxLen;
00238 };
00239 
00240 class KateHlInt : public KateHlItem
00241 {
00242   public:
00243     KateHlInt(int attribute, int context, signed char regionId,signed char regionId2);
00244 
00245     virtual int checkHgl(const QString& text, int offset, int len);
00246 };
00247 
00248 class KateHlFloat : public KateHlItem
00249 {
00250   public:
00251     KateHlFloat(int attribute, int context, signed char regionId,signed char regionId2);
00252     virtual ~KateHlFloat () {}
00253 
00254     virtual int checkHgl(const QString& text, int offset, int len);
00255 };
00256 
00257 class KateHlCFloat : public KateHlFloat
00258 {
00259   public:
00260     KateHlCFloat(int attribute, int context, signed char regionId,signed char regionId2);
00261 
00262     virtual int checkHgl(const QString& text, int offset, int len);
00263     int checkIntHgl(const QString& text, int offset, int len);
00264 };
00265 
00266 class KateHlCOct : public KateHlItem
00267 {
00268   public:
00269     KateHlCOct(int attribute, int context, signed char regionId,signed char regionId2);
00270 
00271     virtual int checkHgl(const QString& text, int offset, int len);
00272 };
00273 
00274 class KateHlCHex : public KateHlItem
00275 {
00276   public:
00277     KateHlCHex(int attribute, int context, signed char regionId,signed char regionId2);
00278 
00279     virtual int checkHgl(const QString& text, int offset, int len);
00280 };
00281 
00282 class KateHlLineContinue : public KateHlItem
00283 {
00284   public:
00285     KateHlLineContinue(int attribute, int context, signed char regionId,signed char regionId2);
00286 
00287     virtual bool endEnable(QChar c) {return c == '\0';}
00288     virtual int checkHgl(const QString& text, int offset, int len);
00289     virtual bool lineContinue(){return true;}
00290 };
00291 
00292 class KateHlCStringChar : public KateHlItem
00293 {
00294   public:
00295     KateHlCStringChar(int attribute, int context, signed char regionId,signed char regionId2);
00296 
00297     virtual int checkHgl(const QString& text, int offset, int len);
00298 };
00299 
00300 class KateHlCChar : public KateHlItem
00301 {
00302   public:
00303     KateHlCChar(int attribute, int context,signed char regionId,signed char regionId2);
00304 
00305     virtual int checkHgl(const QString& text, int offset, int len);
00306 };
00307 
00308 class KateHlAnyChar : public KateHlItem
00309 {
00310   public:
00311     KateHlAnyChar(int attribute, int context, signed char regionId,signed char regionId2, const QString& charList);
00312 
00313     virtual int checkHgl(const QString& text, int offset, int len);
00314 
00315   private:
00316     const QString _charList;
00317 };
00318 
00319 class KateHlRegExpr : public KateHlItem
00320 {
00321   public:
00322     KateHlRegExpr(int attribute, int context,signed char regionId,signed char regionId2 ,QString expr, bool insensitive, bool minimal);
00323     ~KateHlRegExpr() { delete Expr; };
00324 
00325     virtual int checkHgl(const QString& text, int offset, int len);
00326     virtual QStringList *capturedTexts();
00327     virtual KateHlItem *clone(const QStringList *args);
00328 
00329   private:
00330     QRegExp *Expr;
00331     bool handlesLinestart;
00332     QString _regexp;
00333     bool _insensitive;
00334     bool _minimal;
00335 };
00336 
00337 class KateHlDetectSpaces : public KateHlItem
00338 {
00339   public:
00340     KateHlDetectSpaces (int attribute, int context,signed char regionId,signed char regionId2)
00341       : KateHlItem(attribute,context,regionId,regionId2) {}
00342 
00343     virtual int checkHgl(const QString& text, int offset, int len)
00344     {
00345       int len2 = offset + len;
00346       while ((offset < len2) && text[offset].isSpace()) offset++;
00347       return offset;
00348     }
00349 };
00350 
00351 class KateHlDetectIdentifier : public KateHlItem
00352 {
00353   public:
00354     KateHlDetectIdentifier (int attribute, int context,signed char regionId,signed char regionId2)
00355       : KateHlItem(attribute,context,regionId,regionId2) { alwaysStartEnable = false; }
00356 
00357     virtual int checkHgl(const QString& text, int offset, int len)
00358     {
00359       // first char should be a letter or underscore
00360       if ( text[offset].isLetter() || text[offset] == QChar ('_') )
00361       {
00362         // memorize length
00363         int len2 = offset+len;
00364 
00365         // one char seen
00366         offset++;
00367 
00368         // now loop for all other thingies
00369         while (
00370                (offset < len2)
00371                && (text[offset].isLetterOrNumber() || (text[offset] == QChar ('_')))
00372               )
00373           offset++;
00374 
00375         return offset;
00376       }
00377 
00378       return 0;
00379     }
00380 };
00381 
00382 //END
00383 
00384 //BEGIN STATICS
00385 KateHlManager *KateHlManager::s_self = 0;
00386 
00387 static const bool trueBool = true;
00388 static const QString stdDeliminator = QString (" \t.():!+,-<=>%&*/;?[]^{|}~\\");
00389 //END
00390 
00391 //BEGIN NON MEMBER FUNCTIONS
00392 static KateHlItemData::ItemStyles getDefStyleNum(QString name)
00393 {
00394   if (name=="dsNormal") return KateHlItemData::dsNormal;
00395   else if (name=="dsKeyword") return KateHlItemData::dsKeyword;
00396   else if (name=="dsDataType") return KateHlItemData::dsDataType;
00397   else if (name=="dsDecVal") return KateHlItemData::dsDecVal;
00398   else if (name=="dsBaseN") return KateHlItemData::dsBaseN;
00399   else if (name=="dsFloat") return KateHlItemData::dsFloat;
00400   else if (name=="dsChar") return KateHlItemData::dsChar;
00401   else if (name=="dsString") return KateHlItemData::dsString;
00402   else if (name=="dsComment") return KateHlItemData::dsComment;
00403   else if (name=="dsOthers")  return KateHlItemData::dsOthers;
00404   else if (name=="dsAlert") return KateHlItemData::dsAlert;
00405   else if (name=="dsFunction") return KateHlItemData::dsFunction;
00406   else if (name=="dsRegionMarker") return KateHlItemData::dsRegionMarker;
00407   else if (name=="dsError") return KateHlItemData::dsError;
00408 
00409   return KateHlItemData::dsNormal;
00410 }
00411 //END
00412 
00413 //BEGIN KateHlItem
00414 KateHlItem::KateHlItem(int attribute, int context,signed char regionId,signed char regionId2)
00415   : attr(attribute),
00416     ctx(context),
00417     region(regionId),
00418     region2(regionId2),
00419     lookAhead(false),
00420     dynamic(false),
00421     dynamicChild(false),
00422     firstNonSpace(false),
00423     onlyConsume(false),
00424     column (-1),
00425     alwaysStartEnable (true),
00426     customStartEnable (false)
00427 {
00428 }
00429 
00430 KateHlItem::~KateHlItem()
00431 {
00432   //kdDebug(13010)<<"In hlItem::~KateHlItem()"<<endl;
00433   for (uint i=0; i < subItems.size(); i++)
00434     delete subItems[i];
00435 }
00436 
00437 void KateHlItem::dynamicSubstitute(QString &str, const QStringList *args)
00438 {
00439   for (uint i = 0; i < str.length() - 1; ++i)
00440   {
00441     if (str[i] == '%')
00442     {
00443       char c = str[i + 1].latin1();
00444       if (c == '%')
00445         str.replace(i, 1, "");
00446       else if (c >= '0' && c <= '9')
00447       {
00448         if ((uint)(c - '0') < args->size())
00449         {
00450           str.replace(i, 2, (*args)[c - '0']);
00451           i += ((*args)[c - '0']).length() - 1;
00452         }
00453         else
00454         {
00455           str.replace(i, 2, "");
00456           --i;
00457         }
00458       }
00459     }
00460   }
00461 }
00462 //END
00463 
00464 //BEGIN KateHlCharDetect
00465 KateHlCharDetect::KateHlCharDetect(int attribute, int context, signed char regionId,signed char regionId2, QChar c)
00466   : KateHlItem(attribute,context,regionId,regionId2)
00467   , sChar(c)
00468 {
00469 }
00470 
00471 int KateHlCharDetect::checkHgl(const QString& text, int offset, int /*len*/)
00472 {
00473   if (text[offset] == sChar)
00474     return offset + 1;
00475 
00476   return 0;
00477 }
00478 
00479 KateHlItem *KateHlCharDetect::clone(const QStringList *args)
00480 {
00481   char c = sChar.latin1();
00482 
00483   if (c < '0' || c > '9' || (unsigned)(c - '0') >= args->size())
00484     return this;
00485 
00486   KateHlCharDetect *ret = new KateHlCharDetect(attr, ctx, region, region2, (*args)[c - '0'][0]);
00487   ret->dynamicChild = true;
00488   return ret;
00489 }
00490 //END
00491 
00492 //BEGIN KateHl2CharDetect
00493 KateHl2CharDetect::KateHl2CharDetect(int attribute, int context, signed char regionId,signed char regionId2, QChar ch1, QChar ch2)
00494   : KateHlItem(attribute,context,regionId,regionId2)
00495   , sChar1 (ch1)
00496   , sChar2 (ch2)
00497 {
00498 }
00499 
00500 int KateHl2CharDetect::checkHgl(const QString& text, int offset, int len)
00501 {
00502   if ((len >= 2) && text[offset++] == sChar1 && text[offset++] == sChar2)
00503     return offset;
00504 
00505   return 0;
00506 }
00507 
00508 KateHlItem *KateHl2CharDetect::clone(const QStringList *args)
00509 {
00510   char c1 = sChar1.latin1();
00511   char c2 = sChar2.latin1();
00512 
00513   if (c1 < '0' || c1 > '9' || (unsigned)(c1 - '0') >= args->size())
00514     return this;
00515 
00516   if (c2 < '0' || c2 > '9' || (unsigned)(c2 - '0') >= args->size())
00517     return this;
00518 
00519   KateHl2CharDetect *ret = new KateHl2CharDetect(attr, ctx, region, region2, (*args)[c1 - '0'][0], (*args)[c2 - '0'][0]);
00520   ret->dynamicChild = true;
00521   return ret;
00522 }
00523 //END
00524 
00525 //BEGIN KateHlStringDetect
00526 KateHlStringDetect::KateHlStringDetect(int attribute, int context, signed char regionId,signed char regionId2,const QString &s, bool inSensitive)
00527   : KateHlItem(attribute, context,regionId,regionId2)
00528   , str(inSensitive ? s.upper() : s)
00529   , strLen (str.length())
00530   , _inSensitive(inSensitive)
00531 {
00532 }
00533 
00534 int KateHlStringDetect::checkHgl(const QString& text, int offset, int len)
00535 {
00536   if (len < strLen)
00537     return 0;
00538 
00539   if (_inSensitive)
00540   {
00541     for (int i=0; i < strLen; i++)
00542       if (text[offset++].upper() != str[i])
00543         return 0;
00544 
00545     return offset;
00546   }
00547   else
00548   {
00549     for (int i=0; i < strLen; i++)
00550       if (text[offset++] != str[i])
00551         return 0;
00552 
00553     return offset;
00554   }
00555 
00556   return 0;
00557 }
00558 
00559 KateHlItem *KateHlStringDetect::clone(const QStringList *args)
00560 {
00561   QString newstr = str;
00562 
00563   dynamicSubstitute(newstr, args);
00564 
00565   if (newstr == str)
00566     return this;
00567 
00568   KateHlStringDetect *ret = new KateHlStringDetect(attr, ctx, region, region2, newstr, _inSensitive);
00569   ret->dynamicChild = true;
00570   return ret;
00571 }
00572 //END
00573 
00574 //BEGIN KateHlRangeDetect
00575 KateHlRangeDetect::KateHlRangeDetect(int attribute, int context, signed char regionId,signed char regionId2, QChar ch1, QChar ch2)
00576   : KateHlItem(attribute,context,regionId,regionId2)
00577   , sChar1 (ch1)
00578   , sChar2 (ch2)
00579 {
00580 }
00581 
00582 int KateHlRangeDetect::checkHgl(const QString& text, int offset, int len)
00583 {
00584   if (text[offset] == sChar1)
00585   {
00586     do
00587     {
00588       offset++;
00589       len--;
00590       if (len < 1) return 0;
00591     }
00592     while (text[offset] != sChar2);
00593 
00594     return offset + 1;
00595   }
00596   return 0;
00597 }
00598 //END
00599 
00600 //BEGIN KateHlKeyword
00601 KateHlKeyword::KateHlKeyword (int attribute, int context, signed char regionId,signed char regionId2, bool casesensitive, const QString& delims)
00602   : KateHlItem(attribute,context,regionId,regionId2)
00603   , _caseSensitive(casesensitive)
00604   , deliminators(delims)
00605   , minLen (0xFFFFFF)
00606   , maxLen (0)
00607 {
00608   alwaysStartEnable = false;
00609   customStartEnable = true;
00610 }
00611 
00612 KateHlKeyword::~KateHlKeyword ()
00613 {
00614   for (uint i=0; i < dict.size(); ++i)
00615     delete dict[i];
00616 }
00617 
00618 void KateHlKeyword::addList(const QStringList& list)
00619 {
00620   for(uint i=0; i < list.count(); ++i)
00621   {
00622     int len = list[i].length();
00623 
00624     if (minLen > len)
00625       minLen = len;
00626 
00627     if (maxLen < len)
00628       maxLen = len;
00629 
00630     if ((uint)len >= dict.size())
00631     {
00632       uint oldSize = dict.size();
00633       dict.resize (len+1);
00634 
00635       for (uint m=oldSize; m < dict.size(); ++m)
00636         dict[m] = 0;
00637     }
00638 
00639     if (!dict[len])
00640       dict[len] = new QDict<bool> (17, _caseSensitive);
00641 
00642     dict[len]->insert(list[i], &trueBool);
00643   }
00644 }
00645 
00646 int KateHlKeyword::checkHgl(const QString& text, int offset, int len)
00647 {
00648   int offset2 = offset;
00649   int wordLen = 0;
00650 
00651   while ((len > wordLen) && !kateInsideString (deliminators, text[offset2]))
00652   {
00653     offset2++;
00654     wordLen++;
00655 
00656     if (wordLen > maxLen) return 0;
00657   }
00658 
00659   if (wordLen < minLen) return 0;
00660 
00661   if ( dict[wordLen] && dict[wordLen]->find(QConstString(text.unicode() + offset, wordLen).string()) )
00662     return offset2;
00663 
00664   return 0;
00665 }
00666 //END
00667 
00668 //BEGIN KateHlInt
00669 KateHlInt::KateHlInt(int attribute, int context, signed char regionId,signed char regionId2)
00670   : KateHlItem(attribute,context,regionId,regionId2)
00671 {
00672   alwaysStartEnable = false;
00673 }
00674 
00675 int KateHlInt::checkHgl(const QString& text, int offset, int len)
00676 {
00677   int offset2 = offset;
00678 
00679   while ((len > 0) && text[offset2].isDigit())
00680   {
00681     offset2++;
00682     len--;
00683   }
00684 
00685   if (offset2 > offset)
00686   {
00687     if (len > 0)
00688     {
00689       for (uint i=0; i < subItems.size(); i++)
00690       {
00691         if ( (offset = subItems[i]->checkHgl(text, offset2, len)) )
00692           return offset;
00693       }
00694     }
00695 
00696     return offset2;
00697   }
00698 
00699   return 0;
00700 }
00701 //END
00702 
00703 //BEGIN KateHlFloat
00704 KateHlFloat::KateHlFloat(int attribute, int context, signed char regionId,signed char regionId2)
00705   : KateHlItem(attribute,context, regionId,regionId2)
00706 {
00707   alwaysStartEnable = false;
00708 }
00709 
00710 int KateHlFloat::checkHgl(const QString& text, int offset, int len)
00711 {
00712   bool b = false;
00713   bool p = false;
00714 
00715   while ((len > 0) && text[offset].isDigit())
00716   {
00717     offset++;
00718     len--;
00719     b = true;
00720   }
00721 
00722   if ((len > 0) && (p = (text[offset] == '.')))
00723   {
00724     offset++;
00725     len--;
00726 
00727     while ((len > 0) && text[offset].isDigit())
00728     {
00729       offset++;
00730       len--;
00731       b = true;
00732     }
00733   }
00734 
00735   if (!b)
00736     return 0;
00737 
00738   if ((len > 0) && ((text[offset] & 0xdf) == 'E'))
00739   {
00740     offset++;
00741     len--;
00742   }
00743   else
00744   {
00745     if (!p)
00746       return 0;
00747     else
00748     {
00749       if (len > 0)
00750       {
00751         for (uint i=0; i < subItems.size(); i++)
00752         {
00753           int offset2 = subItems[i]->checkHgl(text, offset, len);
00754 
00755           if (offset2)
00756             return offset2;
00757         }
00758       }
00759 
00760       return offset;
00761     }
00762   }
00763 
00764   if ((len > 0) && (text[offset] == '-' || text[offset] =='+'))
00765   {
00766     offset++;
00767     len--;
00768   }
00769 
00770   b = false;
00771 
00772   while ((len > 0) && text[offset].isDigit())
00773   {
00774     offset++;
00775     len--;
00776     b = true;
00777   }
00778 
00779   if (b)
00780   {
00781     if (len > 0)
00782     {
00783       for (uint i=0; i < subItems.size(); i++)
00784       {
00785         int offset2 = subItems[i]->checkHgl(text, offset, len);
00786 
00787         if (offset2)
00788           return offset2;
00789       }
00790     }
00791 
00792     return offset;
00793   }
00794 
00795   return 0;
00796 }
00797 //END
00798 
00799 //BEGIN KateHlCOct
00800 KateHlCOct::KateHlCOct(int attribute, int context, signed char regionId,signed char regionId2)
00801   : KateHlItem(attribute,context,regionId,regionId2)
00802 {
00803   alwaysStartEnable = false;
00804 }
00805 
00806 int KateHlCOct::checkHgl(const QString& text, int offset, int len)
00807 {
00808   if (text[offset] == '0')
00809   {
00810     offset++;
00811     len--;
00812 
00813     int offset2 = offset;
00814 
00815     while ((len > 0) && (text[offset2] >= '0' && text[offset2] <= '7'))
00816     {
00817       offset2++;
00818       len--;
00819     }
00820 
00821     if (offset2 > offset)
00822     {
00823       if ((len > 0) && ((text[offset2] & 0xdf) == 'L' || (text[offset] & 0xdf) == 'U' ))
00824         offset2++;
00825 
00826       return offset2;
00827     }
00828   }
00829 
00830   return 0;
00831 }
00832 //END
00833 
00834 //BEGIN KateHlCHex
00835 KateHlCHex::KateHlCHex(int attribute, int context,signed char regionId,signed char regionId2)
00836   : KateHlItem(attribute,context,regionId,regionId2)
00837 {
00838   alwaysStartEnable = false;
00839 }
00840 
00841 int KateHlCHex::checkHgl(const QString& text, int offset, int len)
00842 {
00843   if ((len > 1) && (text[offset++] == '0') && ((text[offset++] & 0xdf) == 'X' ))
00844   {
00845     len -= 2;
00846 
00847     int offset2 = offset;
00848 
00849     while ((len > 0) && (text[offset2].isDigit() || ((text[offset2] & 0xdf) >= 'A' && (text[offset2] & 0xdf) <= 'F')))
00850     {
00851       offset2++;
00852       len--;
00853     }
00854 
00855     if (offset2 > offset)
00856     {
00857       if ((len > 0) && ((text[offset2] & 0xdf) == 'L' || (text[offset2] & 0xdf) == 'U' ))
00858         offset2++;
00859 
00860       return offset2;
00861     }
00862   }
00863 
00864   return 0;
00865 }
00866 //END
00867 
00868 //BEGIN KateHlCFloat
00869 KateHlCFloat::KateHlCFloat(int attribute, int context, signed char regionId,signed char regionId2)
00870   : KateHlFloat(attribute,context,regionId,regionId2)
00871 {
00872   alwaysStartEnable = false;
00873 }
00874 
00875 int KateHlCFloat::checkIntHgl(const QString& text, int offset, int len)
00876 {
00877   int offset2 = offset;
00878 
00879   while ((len > 0) && text[offset].isDigit()) {
00880     offset2++;
00881     len--;
00882   }
00883 
00884   if (offset2 > offset)
00885      return offset2;
00886 
00887   return 0;
00888 }
00889 
00890 int KateHlCFloat::checkHgl(const QString& text, int offset, int len)
00891 {
00892   int offset2 = KateHlFloat::checkHgl(text, offset, len);
00893 
00894   if (offset2)
00895   {
00896     if ((text[offset2] & 0xdf) == 'F' )
00897       offset2++;
00898 
00899     return offset2;
00900   }
00901   else
00902   {
00903     offset2 = checkIntHgl(text, offset, len);
00904 
00905     if (offset2 && ((text[offset2] & 0xdf) == 'F' ))
00906       return ++offset2;
00907     else
00908       return 0;
00909   }
00910 }
00911 //END
00912 
00913 //BEGIN KateHlAnyChar
00914 KateHlAnyChar::KateHlAnyChar(int attribute, int context, signed char regionId,signed char regionId2, const QString& charList)
00915   : KateHlItem(attribute, context,regionId,regionId2)
00916   , _charList(charList)
00917 {
00918 }
00919 
00920 int KateHlAnyChar::checkHgl(const QString& text, int offset, int)
00921 {
00922   if (kateInsideString (_charList, text[offset]))
00923     return ++offset;
00924 
00925   return 0;
00926 }
00927 //END
00928 
00929 //BEGIN KateHlRegExpr
00930 KateHlRegExpr::KateHlRegExpr( int attribute, int context, signed char regionId,signed char regionId2, QString regexp, bool insensitive, bool minimal)
00931   : KateHlItem(attribute, context, regionId,regionId2)
00932   , handlesLinestart (regexp.startsWith("^"))
00933   , _regexp(regexp)
00934   , _insensitive(insensitive)
00935   , _minimal(minimal)
00936 {
00937   if (!handlesLinestart)
00938     regexp.prepend("^");
00939 
00940   Expr = new QRegExp(regexp, !_insensitive);
00941   Expr->setMinimal(_minimal);
00942 }
00943 
00944 int KateHlRegExpr::checkHgl(const QString& text, int offset, int /*len*/)
00945 {
00946   if (offset && handlesLinestart)
00947     return 0;
00948 
00949   int offset2 = Expr->search( text, offset, QRegExp::CaretAtOffset );
00950 
00951   if (offset2 == -1) return 0;
00952 
00953   return (offset + Expr->matchedLength());
00954 }
00955 
00956 QStringList *KateHlRegExpr::capturedTexts()
00957 {
00958   return new QStringList(Expr->capturedTexts());
00959 }
00960 
00961 KateHlItem *KateHlRegExpr::clone(const QStringList *args)
00962 {
00963   QString regexp = _regexp;
00964   QStringList escArgs = *args;
00965 
00966   for (QStringList::Iterator it = escArgs.begin(); it != escArgs.end(); ++it)
00967   {
00968     (*it).replace(QRegExp("(\\W)"), "\\\\1");
00969   }
00970 
00971   dynamicSubstitute(regexp, &escArgs);
00972 
00973   if (regexp == _regexp)
00974     return this;
00975 
00976   // kdDebug (13010) << "clone regexp: " << regexp << endl;
00977 
00978   KateHlRegExpr *ret = new KateHlRegExpr(attr, ctx, region, region2, regexp, _insensitive, _minimal);
00979   ret->dynamicChild = true;
00980   return ret;
00981 }
00982 //END
00983 
00984 //BEGIN KateHlLineContinue
00985 KateHlLineContinue::KateHlLineContinue(int attribute, int context, signed char regionId,signed char regionId2)
00986   : KateHlItem(attribute,context,regionId,regionId2) {
00987 }
00988 
00989 int KateHlLineContinue::checkHgl(const QString& text, int offset, int len)
00990 {
00991   if ((len == 1) && (text[offset] == '\\'))
00992     return ++offset;
00993 
00994   return 0;
00995 }
00996 //END
00997 
00998 //BEGIN KateHlCStringChar
00999 KateHlCStringChar::KateHlCStringChar(int attribute, int context,signed char regionId,signed char regionId2)
01000   : KateHlItem(attribute,context,regionId,regionId2) {
01001 }
01002 
01003 // checks for C escaped chars \n and escaped hex/octal chars
01004 static int checkEscapedChar(const QString& text, int offset, int& len)
01005 {
01006   int i;
01007   if (text[offset] == '\\' && len > 1)
01008   {
01009     offset++;
01010     len--;
01011 
01012     switch(text[offset])
01013     {
01014       case  'a': // checks for control chars
01015       case  'b': // we want to fall through
01016       case  'e':
01017       case  'f':
01018 
01019       case  'n':
01020       case  'r':
01021       case  't':
01022       case  'v':
01023       case '\'':
01024       case '\"':
01025       case '?' : // added ? ANSI C classifies this as an escaped char
01026       case '\\':
01027         offset++;
01028         len--;
01029         break;
01030 
01031       case 'x': // if it's like \xff
01032         offset++; // eat the x
01033         len--;
01034         // these for loops can probably be
01035         // replaced with something else but
01036         // for right now they work
01037         // check for hexdigits
01038         for (i = 0; (len > 0) && (i < 2) && (text[offset] >= '0' && text[offset] <= '9' || (text[offset] & 0xdf) >= 'A' && (text[offset] & 0xdf) <= 'F'); i++)
01039         {
01040           offset++;
01041           len--;
01042         }
01043 
01044         if (i == 0)
01045           return 0; // takes care of case '\x'
01046 
01047         break;
01048 
01049       case '0': case '1': case '2': case '3' :
01050       case '4': case '5': case '6': case '7' :
01051         for (i = 0; (len > 0) && (i < 3) && (text[offset] >='0'&& text[offset] <='7'); i++)
01052         {
01053           offset++;
01054           len--;
01055         }
01056         break;
01057 
01058       default:
01059         return 0;
01060     }
01061 
01062     return offset;
01063   }
01064 
01065   return 0;
01066 }
01067 
01068 int KateHlCStringChar::checkHgl(const QString& text, int offset, int len)
01069 {
01070   return checkEscapedChar(text, offset, len);
01071 }
01072 //END
01073 
01074 //BEGIN KateHlCChar
01075 KateHlCChar::KateHlCChar(int attribute, int context,signed char regionId,signed char regionId2)
01076   : KateHlItem(attribute,context,regionId,regionId2) {
01077 }
01078 
01079 int KateHlCChar::checkHgl(const QString& text, int offset, int len)
01080 {
01081   if ((len > 1) && (text[offset] == '\'') && (text[offset+1] != '\''))
01082   {
01083     int oldl;
01084     oldl = len;
01085 
01086     len--;
01087 
01088     int offset2 = checkEscapedChar(text, offset + 1, len);
01089 
01090     if (!offset2)
01091     {
01092       if (oldl > 2)
01093       {
01094         offset2 = offset + 2;
01095         len = oldl - 2;
01096       }
01097       else
01098       {
01099         return 0;
01100       }
01101     }
01102 
01103     if ((len > 0) && (text[offset2] == '\''))
01104       return ++offset2;
01105   }
01106 
01107   return 0;
01108 }
01109 //END
01110 
01111 //BEGIN KateHl2CharDetect
01112 KateHl2CharDetect::KateHl2CharDetect(int attribute, int context, signed char regionId,signed char regionId2, const QChar *s)
01113   : KateHlItem(attribute,context,regionId,regionId2) {
01114   sChar1 = s[0];
01115   sChar2 = s[1];
01116   }
01117 //END KateHl2CharDetect
01118 
01119 KateHlItemData::KateHlItemData(const QString  name, int defStyleNum)
01120   : name(name), defStyleNum(defStyleNum) {
01121 }
01122 
01123 KateHlData::KateHlData(const QString &wildcards, const QString &mimetypes, const QString &identifier, int priority)
01124   : wildcards(wildcards), mimetypes(mimetypes), identifier(identifier), priority(priority)
01125 {
01126 }
01127 
01128 //BEGIN KateHlContext
01129 KateHlContext::KateHlContext (const QString &_hlId, int attribute, int lineEndContext, int _lineBeginContext, bool _fallthrough, int _fallthroughContext, bool _dynamic)
01130 {
01131   hlId = _hlId;
01132   attr = attribute;
01133   ctx = lineEndContext;
01134   lineBeginContext = _lineBeginContext;
01135   fallthrough = _fallthrough;
01136   ftctx = _fallthroughContext;
01137   dynamic = _dynamic;
01138   dynamicChild = false;
01139 }
01140 
01141 KateHlContext *KateHlContext::clone(const QStringList *args)
01142 {
01143   KateHlContext *ret = new KateHlContext(hlId, attr, ctx, lineBeginContext, fallthrough, ftctx, false);
01144 
01145   for (uint n=0; n < items.size(); ++n)
01146   {
01147     KateHlItem *item = items[n];
01148     KateHlItem *i = (item->dynamic ? item->clone(args) : item);
01149     ret->items.append(i);
01150   }
01151 
01152   ret->dynamicChild = true;
01153 
01154   return ret;
01155 }
01156 
01157 KateHlContext::~KateHlContext()
01158 {
01159   if (dynamicChild)
01160   {
01161     for (uint n=0; n < items.size(); ++n)
01162     {
01163       if (items[n]->dynamicChild)
01164         delete items[n];
01165     }
01166   }
01167 }
01168 //END
01169 
01170 //BEGIN KateHighlighting
01171 KateHighlighting::KateHighlighting(const KateSyntaxModeListItem *def) : refCount(0)
01172 {
01173   m_attributeArrays.setAutoDelete (true);
01174 
01175   errorsAndWarnings = "";
01176   building=false;
01177   noHl = false;
01178   m_foldingIndentationSensitive = false;
01179   folding=false;
01180   internalIDList.setAutoDelete(true);
01181 
01182   if (def == 0)
01183   {
01184     noHl = true;
01185     iName = "None"; // not translated internal name (for config and more)
01186     iNameTranslated = i18n("None"); // user visible name
01187     iSection = "";
01188     m_priority = 0;
01189     iHidden = false;
01190     m_additionalData.insert( "none", new HighlightPropertyBag );
01191     m_additionalData["none"]->deliminator = stdDeliminator;
01192     m_additionalData["none"]->wordWrapDeliminator = stdDeliminator;
01193     m_hlIndex[0] = "none";
01194   }
01195   else
01196   {
01197     iName = def->name;
01198     iNameTranslated = def->nameTranslated;
01199     iSection = def->section;
01200     iHidden = def->hidden;
01201     iWildcards = def->extension;
01202     iMimetypes = def->mimetype;
01203     identifier = def->identifier;
01204     iVersion=def->version;
01205     iAuthor=def->author;
01206     iLicense=def->license;
01207     m_priority=def->priority.toInt();
01208   }
01209 
01210    deliminator = stdDeliminator;
01211 }
01212 
01213 KateHighlighting::~KateHighlighting()
01214 {
01215   for (uint i=0; i < m_contexts.size(); ++i)
01216     delete m_contexts[i];
01217 }
01218 
01219 void KateHighlighting::generateContextStack(int *ctxNum, int ctx, QMemArray<short>* ctxs, int *prevLine)
01220 {
01221   //kdDebug(13010)<<QString("Entering generateContextStack with %1").arg(ctx)<<endl;
01222   while (true)
01223   {
01224     if (ctx >= 0)
01225     {
01226       (*ctxNum) = ctx;
01227 
01228       ctxs->resize (ctxs->size()+1, QGArray::SpeedOptim);
01229       (*ctxs)[ctxs->size()-1]=(*ctxNum);
01230 
01231       return;
01232     }
01233     else
01234     {
01235       if (ctx == -1)
01236       {
01237         (*ctxNum)=( (ctxs->isEmpty() ) ? 0 : (*ctxs)[ctxs->size()-1]);
01238       }
01239       else
01240       {
01241         int size = ctxs->size() + ctx + 1;
01242 
01243         if (size > 0)
01244         {
01245           ctxs->resize (size, QGArray::SpeedOptim);
01246           (*ctxNum)=(*ctxs)[size-1];
01247         }
01248         else
01249         {
01250           ctxs->resize (0, QGArray::SpeedOptim);
01251           (*ctxNum)=0;
01252         }
01253 
01254         ctx = 0;
01255 
01256         if ((*prevLine) >= (int)(ctxs->size()-1))
01257         {
01258           *prevLine=ctxs->size()-1;
01259 
01260           if ( ctxs->isEmpty() )
01261             return;
01262 
01263           KateHlContext *c = contextNum((*ctxs)[ctxs->size()-1]);
01264           if (c && (c->ctx != -1))
01265           {
01266             //kdDebug(13010)<<"PrevLine > size()-1 and ctx!=-1)"<<endl;
01267             ctx = c->ctx;
01268 
01269             continue;
01270           }
01271         }
01272       }
01273 
01274       return;
01275     }
01276   }
01277 }
01278 
01282 int KateHighlighting::makeDynamicContext(KateHlContext *model, const QStringList *args)
01283 {
01284   QPair<KateHlContext *, QString> key(model, args->front());
01285   short value;
01286 
01287   if (dynamicCtxs.contains(key))
01288     value = dynamicCtxs[key];
01289   else
01290   {
01291     kdDebug(13010) << "new stuff: " << startctx << endl;
01292 
01293     KateHlContext *newctx = model->clone(args);
01294 
01295     m_contexts.push_back (newctx);
01296 
01297     value = startctx++;
01298     dynamicCtxs[key] = value;
01299     KateHlManager::self()->incDynamicCtxs();
01300   }
01301 
01302   // kdDebug(13010) << "Dynamic context: using context #" << value << " (for model " << model << " with args " << *args << ")" << endl;
01303 
01304   return value;
01305 }
01306 
01311 void KateHighlighting::dropDynamicContexts()
01312 {
01313   for (uint i=base_startctx; i < m_contexts.size(); ++i)
01314     delete m_contexts[i];
01315 
01316   m_contexts.resize (base_startctx);
01317 
01318   dynamicCtxs.clear();
01319   startctx = base_startctx;
01320 }
01321 
01330 void KateHighlighting::doHighlight ( KateTextLine *prevLine,
01331                                      KateTextLine *textLine,
01332                                      QMemArray<uint>* foldingList,
01333                                      bool *ctxChanged )
01334 {
01335   if (!textLine)
01336     return;
01337 
01338   if (noHl)
01339   {
01340     if (textLine->length() > 0)
01341       memset (textLine->attributes(), 0, textLine->length());
01342 
01343     return;
01344   }
01345 
01346   // duplicate the ctx stack, only once !
01347   QMemArray<short> ctx;
01348   ctx.duplicate (prevLine->ctxArray());
01349 
01350   int ctxNum = 0;
01351   int previousLine = -1;
01352   KateHlContext *context;
01353 
01354   if (ctx.isEmpty())
01355   {
01356     // If the stack is empty, we assume to be in Context 0 (Normal)
01357     context = contextNum(ctxNum);
01358   }
01359   else
01360   {
01361     // There does an old context stack exist -> find the context at the line start
01362     ctxNum = ctx[ctx.size()-1]; //context ID of the last character in the previous line
01363 
01364     //kdDebug(13010) << "\t\tctxNum = " << ctxNum << " contextList[ctxNum] = " << contextList[ctxNum] << endl; // ellis
01365 
01366     //if (lineContinue)   kdDebug(13010)<<QString("The old context should be %1").arg((int)ctxNum)<<endl;
01367 
01368     if (!(context = contextNum(ctxNum)))
01369       context = contextNum(0);
01370 
01371     //kdDebug(13010)<<"test1-2-1-text2"<<endl;
01372 
01373     previousLine=ctx.size()-1; //position of the last context ID of th previous line within the stack
01374 
01375     // hl continue set or not ???
01376     if (prevLine->hlLineContinue())
01377     {
01378       prevLine--;
01379     }
01380     else
01381     {
01382       generateContextStack(&ctxNum, context->ctx, &ctx, &previousLine); //get stack ID to use
01383 
01384       if (!(context = contextNum(ctxNum)))
01385         context = contextNum(0);
01386     }
01387 
01388     //kdDebug(13010)<<"test1-2-1-text4"<<endl;
01389 
01390     //if (lineContinue)   kdDebug(13010)<<QString("The new context is %1").arg((int)ctxNum)<<endl;
01391   }
01392 
01393   // text, for programming convenience :)
01394   QChar lastChar = ' ';
01395   const QString& text = textLine->string();
01396   const int len = textLine->length();
01397 
01398   // calc at which char the first char occurs, set it to lenght of line if never
01399   const int firstChar = textLine->firstChar();
01400   const int startNonSpace = (firstChar == -1) ? len : firstChar;
01401 
01402   // last found item
01403   KateHlItem *item = 0;
01404 
01405   // loop over the line, offset gives current offset
01406   int offset = 0;
01407   while (offset < len)
01408   {
01409     bool anItemMatched = false;
01410     bool standardStartEnableDetermined = false;
01411     bool customStartEnableDetermined = false;
01412 
01413     uint index = 0;
01414     for (item = context->items.empty() ? 0 : context->items[0]; item; item = (++index < context->items.size()) ? context->items[index] : 0 )
01415     {
01416       // does we only match if we are firstNonSpace?
01417       if (item->firstNonSpace && (offset > startNonSpace))
01418         continue;
01419 
01420       // have we a column specified? if yes, only match at this column
01421       if ((item->column != -1) && (item->column != offset))
01422         continue;
01423 
01424       if (!item->alwaysStartEnable)
01425       {
01426         if (item->customStartEnable)
01427         {
01428             if (customStartEnableDetermined || kateInsideString (m_additionalData[context->hlId]->deliminator, lastChar))
01429             customStartEnableDetermined = true;
01430           else
01431             continue;
01432         }
01433         else
01434         {
01435           if (standardStartEnableDetermined || kateInsideString (stdDeliminator, lastChar))
01436             standardStartEnableDetermined = true;
01437           else
01438             continue;
01439         }
01440       }
01441 
01442       int offset2 = item->checkHgl(text, offset, len-offset);
01443 
01444       if (offset2 <= offset)
01445         continue;
01446 
01447       if (item->region2)
01448       {
01449         // kdDebug(13010)<<QString("Region mark 2 detected: %1").arg(item->region2)<<endl;
01450         if ( !foldingList->isEmpty() && ((item->region2 < 0) && (*foldingList)[foldingList->size()-2] == -item->region2 ) )
01451         {
01452           foldingList->resize (foldingList->size()-2, QGArray::SpeedOptim);
01453         }
01454         else
01455         {
01456           foldingList->resize (foldingList->size()+2, QGArray::SpeedOptim);
01457           (*foldingList)[foldingList->size()-2] = (uint)item->region2;
01458           if (item->region2<0) //check not really needed yet
01459             (*foldingList)[foldingList->size()-1] = offset2;
01460           else
01461           (*foldingList)[foldingList->size()-1] = offset;
01462         }
01463 
01464       }
01465 
01466       if (item->region)
01467       {
01468         // kdDebug(13010)<<QString("Region mark detected: %1").arg(item->region)<<endl;
01469 
01470       /* if ( !foldingList->isEmpty() && ((item->region < 0) && (*foldingList)[foldingList->size()-1] == -item->region ) )
01471         {
01472           foldingList->resize (foldingList->size()-1, QGArray::SpeedOptim);
01473         }
01474         else*/
01475         {
01476           foldingList->resize (foldingList->size()+2, QGArray::SpeedOptim);
01477           (*foldingList)[foldingList->size()-2] = item->region;
01478           if (item->region<0) //check not really needed yet
01479             (*foldingList)[foldingList->size()-1] = offset2;
01480           else
01481             (*foldingList)[foldingList->size()-1] = offset;
01482         }
01483 
01484       }
01485 
01486       // regenerate context stack if needed
01487       if (item->ctx != -1)
01488       {
01489         generateContextStack (&ctxNum, item->ctx, &ctx, &previousLine);
01490         context = contextNum(ctxNum);
01491       }
01492 
01493       // dynamic context: substitute the model with an 'instance'
01494       if (context->dynamic)
01495       {
01496         QStringList *lst = item->capturedTexts();
01497         if (lst != 0)
01498         {
01499           // Replace the top of the stack and the current context
01500           int newctx = makeDynamicContext(context, lst);
01501           if (ctx.size() > 0)
01502             ctx[ctx.size() - 1] = newctx;
01503           ctxNum = newctx;
01504           context = contextNum(ctxNum);
01505         }
01506         delete lst;
01507       }
01508 
01509       // dominik: look ahead w/o changing offset?
01510       if (!item->lookAhead)
01511       {
01512         if (offset2 > len)
01513           offset2 = len;
01514 
01515         // even set attributes ;)
01516         memset ( textLine->attributes()+offset
01517                , item->onlyConsume ? context->attr : item->attr
01518                , len-offset);
01519 
01520         offset = offset2;
01521         lastChar = text[offset-1];
01522       }
01523 
01524       anItemMatched = true;
01525       break;
01526     }
01527 
01528     // something matched, continue loop
01529     if (anItemMatched)
01530       continue;
01531 
01532     // nothing found: set attribute of one char
01533     // anders: unless this context does not want that!
01534     if ( context->fallthrough )
01535     {
01536     // set context to context->ftctx.
01537       generateContextStack(&ctxNum, context->ftctx, &ctx, &previousLine);  //regenerate context stack
01538       context=contextNum(ctxNum);
01539     //kdDebug(13010)<<"context num after fallthrough at col "<<z<<": "<<ctxNum<<endl;
01540     // the next is nessecary, as otherwise keyword (or anything using the std delimitor check)
01541     // immediately after fallthrough fails. Is it bad?
01542     // jowenn, can you come up with a nicer way to do this?
01543     /*  if (offset)
01544         lastChar = text[offset - 1];
01545       else
01546         lastChar = '\\';*/
01547       continue;
01548     }
01549     else
01550     {
01551       *(textLine->attributes() + offset) = context->attr;
01552       lastChar = text[offset];
01553       offset++;
01554     }
01555   }
01556 
01557   // has the context stack changed ?
01558   if (ctx == textLine->ctxArray())
01559   {
01560     if (ctxChanged)
01561       (*ctxChanged) = false;
01562   }
01563   else
01564   {
01565     if (ctxChanged)
01566       (*ctxChanged) = true;
01567 
01568     // assign ctx stack !
01569     textLine->setContext(ctx);
01570   }
01571 
01572   // write hl continue flag
01573   textLine->setHlLineContinue (item && item->lineContinue());
01574 }
01575 
01576 void KateHighlighting::loadWildcards()
01577 {
01578   KConfig *config = KateHlManager::self()->getKConfig();
01579   config->setGroup("Highlighting " + iName);
01580 
01581   QString extensionString = config->readEntry("Wildcards", iWildcards);
01582 
01583   if (extensionSource != extensionString) {
01584     regexpExtensions.clear();
01585     plainExtensions.clear();
01586 
01587     extensionSource = extensionString;
01588 
01589     static QRegExp sep("\\s*;\\s*");
01590 
01591     QStringList l = QStringList::split( sep, extensionSource );
01592 
01593     static QRegExp boringExpression("\\*\\.[\\d\\w]+");
01594 
01595     for( QStringList::Iterator it = l.begin(); it != l.end(); ++it )
01596       if (boringExpression.exactMatch(*it))
01597         plainExtensions.append((*it).mid(1));
01598       else
01599         regexpExtensions.append(QRegExp((*it), true, true));
01600   }
01601 }
01602 
01603 QValueList<QRegExp>& KateHighlighting::getRegexpExtensions()
01604 {
01605   return regexpExtensions;
01606 }
01607 
01608 QStringList& KateHighlighting::getPlainExtensions()
01609 {
01610   return plainExtensions;
01611 }
01612 
01613 QString KateHighlighting::getMimetypes()
01614 {
01615   KConfig *config = KateHlManager::self()->getKConfig();
01616   config->setGroup("Highlighting " + iName);
01617 
01618   return config->readEntry("Mimetypes", iMimetypes);
01619 }
01620 
01621 int KateHighlighting::priority()
01622 {
01623   KConfig *config = KateHlManager::self()->getKConfig();
01624   config->setGroup("Highlighting " + iName);
01625 
01626   return config->readNumEntry("Priority", m_priority);
01627 }
01628 
01629 KateHlData *KateHighlighting::getData()
01630 {
01631   KConfig *config = KateHlManager::self()->getKConfig();
01632   config->setGroup("Highlighting " + iName);
01633 
01634   KateHlData *hlData = new KateHlData(
01635   config->readEntry("Wildcards", iWildcards),
01636   config->readEntry("Mimetypes", iMimetypes),
01637   config->readEntry("Identifier", identifier),
01638   config->readNumEntry("Priority", m_priority));
01639 
01640  return hlData;
01641 }
01642 
01643 void KateHighlighting::setData(KateHlData *hlData)
01644 {
01645   KConfig *config = KateHlManager::self()->getKConfig();
01646   config->setGroup("Highlighting " + iName);
01647 
01648   config->writeEntry("Wildcards",hlData->wildcards);
01649   config->writeEntry("Mimetypes",hlData->mimetypes);
01650   config->writeEntry("Priority",hlData->priority);
01651 }
01652 
01653 void KateHighlighting::getKateHlItemDataList (uint schema, KateHlItemDataList &list)
01654 {
01655   KConfig *config = KateHlManager::self()->getKConfig();
01656   config->setGroup("Highlighting " + iName + " - Schema " + KateFactory::self()->schemaManager()->name(schema));
01657 
01658   list.clear();
01659   createKateHlItemData(list);
01660 
01661   for (KateHlItemData *p = list.first(); p != 0L; p = list.next())
01662   {
01663     QStringList s = config->readListEntry(p->name);
01664 
01665 //    kdDebug(13010)<<p->name<<s.count()<<endl;
01666     if (s.count()>0)
01667     {
01668 
01669       while(s.count()<9) s<<"";
01670       p->clear();
01671 
01672       QString tmp=s[0]; if (!tmp.isEmpty()) p->defStyleNum=tmp.toInt();
01673 
01674       QRgb col;
01675 
01676       tmp=s[1]; if (!tmp.isEmpty()) {
01677          col=tmp.toUInt(0,16); p->setTextColor(col); }
01678 
01679       tmp=s[2]; if (!tmp.isEmpty()) {
01680          col=tmp.toUInt(0,16); p->setSelectedTextColor(col); }
01681 
01682       tmp=s[3]; if (!tmp.isEmpty()) p->setBold(tmp!="0");
01683 
01684       tmp=s[4]; if (!tmp.isEmpty()) p->setItalic(tmp!="0");
01685 
01686       tmp=s[5]; if (!tmp.isEmpty()) p->setStrikeOut(tmp!="0");
01687 
01688       tmp=s[6]; if (!tmp.isEmpty()) p->setUnderline(tmp!="0");
01689 
01690       tmp=s[7]; if (!tmp.isEmpty()) {
01691          col=tmp.toUInt(0,16); p->setBGColor(col); }
01692 
01693       tmp=s[8]; if (!tmp.isEmpty()) {
01694          col=tmp.toUInt(0,16); p->setSelectedBGColor(col); }
01695 
01696     }
01697   }
01698 }
01699 
01706 void KateHighlighting::setKateHlItemDataList(uint schema, KateHlItemDataList &list)
01707 {
01708   KConfig *config = KateHlManager::self()->getKConfig();
01709   config->setGroup("Highlighting " + iName + " - Schema "
01710       + KateFactory::self()->schemaManager()->name(schema));
01711 
01712   QStringList settings;
01713 
01714   for (KateHlItemData *p = list.first(); p != 0L; p = list.next())
01715   {
01716     settings.clear();
01717     settings<<QString::number(p->defStyleNum,10);
01718     settings<<(p->itemSet(KateAttribute::TextColor)?QString::number(p->textColor().rgb(),16):"");
01719     settings<<(p->itemSet(KateAttribute::SelectedTextColor)?QString::number(p->selectedTextColor().rgb(),16):"");
01720     settings<<(p->itemSet(KateAttribute::Weight)?(p->bold()?"1":"0"):"");
01721     settings<<(p->itemSet(KateAttribute::Italic)?(p->italic()?"1":"0"):"");
01722     settings<<(p->itemSet(KateAttribute::StrikeOut)?(p->strikeOut()?"1":"0"):"");
01723     settings<<(p->itemSet(KateAttribute::Underline)?(p->underline()?"1":"0"):"");
01724     settings<<(p->itemSet(KateAttribute::BGColor)?QString::number(p->bgColor().rgb(),16):"");
01725     settings<<(p->itemSet(KateAttribute::SelectedBGColor)?QString::number(p->selectedBGColor().rgb(),16):"");
01726     settings<<"---";
01727     config->writeEntry(p->name,settings);
01728   }
01729 }
01730 
01734 void KateHighlighting::use()
01735 {
01736   if (refCount == 0)
01737     init();
01738 
01739   refCount++;
01740 }
01741 
01745 void KateHighlighting::release()
01746 {
01747   refCount--;
01748 
01749   if (refCount == 0)
01750     done();
01751 }
01752 
01757 void KateHighlighting::init()
01758 {
01759   if (noHl)
01760     return;
01761 
01762   m_contexts.clear ();
01763   makeContextList();
01764 }
01765 
01766 
01771 void KateHighlighting::done()
01772 {
01773   if (noHl)
01774     return;
01775 
01776   m_contexts.clear ();
01777   internalIDList.clear();
01778 }
01779 
01787 void KateHighlighting::createKateHlItemData(KateHlItemDataList &list)
01788 {
01789   // If no highlighting is selected we need only one default.
01790   if (noHl)
01791   {
01792     list.append(new KateHlItemData(i18n("Normal Text"), KateHlItemData::dsNormal));
01793     return;
01794   }
01795 
01796   // If the internal list isn't already available read the config file
01797   if (internalIDList.isEmpty())
01798     makeContextList();
01799 
01800   list=internalIDList;
01801 }
01802 
01806 void KateHighlighting::addToKateHlItemDataList()
01807 {
01808   //Tell the syntax document class which file we want to parse and which data group
01809   KateHlManager::self()->syntax->setIdentifier(buildIdentifier);
01810   KateSyntaxContextData *data = KateHlManager::self()->syntax->getGroupInfo("highlighting","itemData");
01811 
01812   //begin with the real parsing
01813   while (KateHlManager::self()->syntax->nextGroup(data))
01814   {
01815     // read all attributes
01816     QString color = KateHlManager::self()->syntax->groupData(data,QString("color"));
01817     QString selColor = KateHlManager::self()->syntax->groupData(data,QString("selColor"));
01818     QString bold = KateHlManager::self()->syntax->groupData(data,QString("bold"));
01819     QString italic = KateHlManager::self()->syntax->groupData(data,QString("italic"));
01820     QString underline = KateHlManager::self()->syntax->groupData(data,QString("underline"));
01821     QString strikeOut = KateHlManager::self()->syntax->groupData(data,QString("strikeOut"));
01822     QString bgColor = KateHlManager::self()->syntax->groupData(data,QString("backgroundColor"));
01823     QString selBgColor = KateHlManager::self()->syntax->groupData(data,QString("selBackgroundColor"));
01824 
01825     KateHlItemData* newData = new KateHlItemData(
01826             buildPrefix+KateHlManager::self()->syntax->groupData(data,QString("name")).simplifyWhiteSpace(),
01827             getDefStyleNum(KateHlManager::self()->syntax->groupData(data,QString("defStyleNum"))));
01828 
01829     /* here the custom style overrides are specified, if needed */
01830     if (!color.isEmpty()) newData->setTextColor(QColor(color));
01831     if (!selColor.isEmpty()) newData->setSelectedTextColor(QColor(selColor));
01832     if (!bold.isEmpty()) newData->setBold( IS_TRUE(bold) );
01833     if (!italic.isEmpty()) newData->setItalic( IS_TRUE(italic) );
01834     // new attributes for the new rendering view
01835     if (!underline.isEmpty()) newData->setUnderline( IS_TRUE(underline) );
01836     if (!strikeOut.isEmpty()) newData->setStrikeOut( IS_TRUE(strikeOut) );
01837     if (!bgColor.isEmpty()) newData->setBGColor(QColor(bgColor));
01838     if (!selBgColor.isEmpty()) newData->setSelectedBGColor(QColor(selBgColor));
01839 
01840     internalIDList.append(newData);
01841   }
01842 
01843   //clean up
01844   if (data)
01845     KateHlManager::self()->syntax->freeGroupInfo(data);
01846 }
01847 
01858 int  KateHighlighting::lookupAttrName(const QString& name, KateHlItemDataList &iDl)
01859 {
01860   for (uint i = 0; i < iDl.count(); i++)
01861     if (iDl.at(i)->name == buildPrefix+name)
01862       return i;
01863 
01864   kdDebug(13010)<<"Couldn't resolve itemDataName:"<<name<<endl;
01865   return 0;
01866 }
01867 
01881 KateHlItem *KateHighlighting::createKateHlItem(KateSyntaxContextData *data,
01882                                                KateHlItemDataList &iDl,
01883                                                QStringList *RegionList,
01884                                                QStringList *ContextNameList)
01885 {
01886   // No highlighting -> exit
01887   if (noHl)
01888     return 0;
01889 
01890   // get the (tagname) itemd type
01891   QString dataname=KateHlManager::self()->syntax->groupItemData(data,QString(""));
01892 
01893   // code folding region handling:
01894   QString beginRegionStr=KateHlManager::self()->syntax->groupItemData(data,QString("beginRegion"));
01895   QString endRegionStr=KateHlManager::self()->syntax->groupItemData(data,QString("endRegion"));
01896 
01897   signed char regionId=0;
01898   signed char regionId2=0;
01899 
01900   if (!beginRegionStr.isEmpty())
01901   {
01902     regionId = RegionList->findIndex(beginRegionStr);
01903 
01904     if (regionId==-1) // if the region name doesn't already exist, add it to the list
01905     {
01906       (*RegionList)<<beginRegionStr;
01907       regionId = RegionList->findIndex(beginRegionStr);
01908     }
01909 
01910     regionId++;
01911 
01912     kdDebug(13010) << "########### BEG REG: "  << beginRegionStr << " NUM: " << regionId << endl;
01913   }
01914 
01915   if (!endRegionStr.isEmpty())
01916   {
01917     regionId2 = RegionList->findIndex(endRegionStr);
01918 
01919     if (regionId2==-1) // if the region name doesn't already exist, add it to the list
01920     {
01921       (*RegionList)<<endRegionStr;
01922       regionId2 = RegionList->findIndex(endRegionStr);
01923     }
01924 
01925     regionId2 = -regionId2 - 1;
01926 
01927     kdDebug(13010) << "########### END REG: "  << endRegionStr << " NUM: " << regionId2 << endl;
01928   }
01929 
01930   int attr = 0;
01931   QString tmpAttr=KateHlManager::self()->syntax->groupItemData(data,QString("attribute")).simplifyWhiteSpace();
01932   bool onlyConsume = tmpAttr.isEmpty();
01933 
01934   // only relevant for non consumer
01935   if (!onlyConsume)
01936   {
01937     if (QString("%1").arg(tmpAttr.toInt())==tmpAttr)
01938     {
01939       errorsAndWarnings+=i18n(
01940           "<B>%1</B>: Deprecated syntax. Attribute (%2) not addressed by symbolic name<BR>").
01941       arg(buildIdentifier).arg(tmpAttr);
01942       attr=tmpAttr.toInt();
01943     }
01944     else
01945       attr=lookupAttrName(tmpAttr,iDl);
01946   }
01947 
01948   // Info about context switch
01949   int context = -1;
01950   QString unresolvedContext;
01951   QString tmpcontext=KateHlManager::self()->syntax->groupItemData(data,QString("context"));
01952   if (!tmpcontext.isEmpty())
01953     context=getIdFromString(ContextNameList, tmpcontext,unresolvedContext);
01954 
01955   // Get the char parameter (eg DetectChar)
01956   char chr;
01957   if (! KateHlManager::self()->syntax->groupItemData(data,QString("char")).isEmpty())
01958     chr= (KateHlManager::self()->syntax->groupItemData(data,QString("char")).latin1())[0];
01959   else
01960     chr=0;
01961 
01962   // Get the String parameter (eg. StringDetect)
01963   QString stringdata=KateHlManager::self()->syntax->groupItemData(data,QString("String"));
01964 
01965   // Get a second char parameter (char1) (eg Detect2Chars)
01966   char chr1;
01967   if (! KateHlManager::self()->syntax->groupItemData(data,QString("char1")).isEmpty())
01968     chr1= (KateHlManager::self()->syntax->groupItemData(data,QString("char1")).latin1())[0];
01969   else
01970     chr1=0;
01971 
01972   // Will be removed eventuall. Atm used for StringDetect and RegExp
01973   bool insensitive = IS_TRUE( KateHlManager::self()->syntax->groupItemData(data,QString("insensitive")) );
01974 
01975   // for regexp only
01976   bool minimal = IS_TRUE( KateHlManager::self()->syntax->groupItemData(data,QString("minimal")) );
01977 
01978   // dominik: look ahead and do not change offset. so we can change contexts w/o changing offset1.
01979   bool lookAhead = IS_TRUE( KateHlManager::self()->syntax->groupItemData(data,QString("lookAhead")) );
01980 
01981   bool dynamic= IS_TRUE(KateHlManager::self()->syntax->groupItemData(data,QString("dynamic")) );
01982 
01983   bool firstNonSpace = IS_TRUE(KateHlManager::self()->syntax->groupItemData(data,QString("firstNonSpace")) );
01984 
01985   int column = -1;
01986   QString colStr = KateHlManager::self()->syntax->groupItemData(data,QString("column"));
01987   if (!colStr.isEmpty())
01988     column = colStr.toInt();
01989 
01990   //Create the item corresponding to it's type and set it's parameters
01991   KateHlItem *tmpItem;
01992 
01993   if (dataname=="keyword")
01994   {
01995     KateHlKeyword *keyword=new KateHlKeyword(attr,context,regionId,regionId2,casesensitive,
01996                                              m_additionalData[ buildIdentifier ]->deliminator);
01997 
01998     //Get the entries for the keyword lookup list
01999     keyword->addList(KateHlManager::self()->syntax->finddata("highlighting",stringdata));
02000     tmpItem=keyword;
02001   }
02002   else if (dataname=="Float") tmpItem= (new KateHlFloat(attr,context,regionId,regionId2));
02003   else if (dataname=="Int") tmpItem=(new KateHlInt(attr,context,regionId,regionId2));
02004   else if (dataname=="DetectChar") tmpItem=(new KateHlCharDetect(attr,context,regionId,regionId2,chr));
02005   else if (dataname=="Detect2Chars") tmpItem=(new KateHl2CharDetect(attr,context,regionId,regionId2,chr,chr1));
02006   else if (dataname=="RangeDetect") tmpItem=(new KateHlRangeDetect(attr,context,regionId,regionId2, chr, chr1));
02007   else if (dataname=="LineContinue") tmpItem=(new KateHlLineContinue(attr,context,regionId,regionId2));
02008   else if (dataname=="StringDetect") tmpItem=(new KateHlStringDetect(attr,context,regionId,regionId2,stringdata,insensitive));
02009   else if (dataname=="AnyChar") tmpItem=(new KateHlAnyChar(attr,context,regionId,regionId2,stringdata));
02010   else if (dataname=="RegExpr") tmpItem=(new KateHlRegExpr(attr,context,regionId,regionId2,stringdata, insensitive, minimal));
02011   else if (dataname=="HlCChar") tmpItem= ( new KateHlCChar(attr,context,regionId,regionId2));
02012   else if (dataname=="HlCHex") tmpItem= (new KateHlCHex(attr,context,regionId,regionId2));
02013   else if (dataname=="HlCOct") tmpItem= (new KateHlCOct(attr,context,regionId,regionId2));
02014   else if (dataname=="HlCFloat") tmpItem= (new KateHlCFloat(attr,context,regionId,regionId2));
02015   else if (dataname=="HlCStringChar") tmpItem= (new KateHlCStringChar(attr,context,regionId,regionId2));
02016   else if (dataname=="DetectSpaces") tmpItem= (new KateHlDetectSpaces(attr,context,regionId,regionId2));
02017   else if (dataname=="DetectIdentifier") tmpItem= (new KateHlDetectIdentifier(attr,context,regionId,regionId2));
02018   else
02019   {
02020     // oops, unknown type. Perhaps a spelling error in the xml file
02021     return 0;
02022   }
02023 
02024   // set lookAhead & dynamic properties
02025   tmpItem->lookAhead = lookAhead;
02026   tmpItem->dynamic = dynamic;
02027   tmpItem->firstNonSpace = firstNonSpace;
02028   tmpItem->column = column;
02029   tmpItem->onlyConsume = onlyConsume;
02030 
02031   if (!unresolvedContext.isEmpty())
02032   {
02033     unresolvedContextReferences.insert(&(tmpItem->ctx),unresolvedContext);
02034   }
02035 
02036   return tmpItem;
02037 }
02038 
02039 QString KateHighlighting::hlKeyForAttrib( int i ) const
02040 {
02041   int k = 0;
02042   QMap<int,QString>::const_iterator it = m_hlIndex.constEnd();
02043   while ( it != m_hlIndex.constBegin() )
02044   {
02045     --it;
02046     k = it.key();
02047     if ( i >= k )
02048       break;
02049   }
02050   return it.data();
02051 }
02052 
02053 bool KateHighlighting::isInWord( QChar c, int attrib ) const
02054 {
02055   static const QString& sq = KGlobal::staticQString(" \"'");
02056   return m_additionalData[ hlKeyForAttrib( attrib ) ]->deliminator.find(c) < 0 && sq.find(c) < 0;
02057 }
02058 
02059 bool KateHighlighting::canBreakAt( QChar c, int attrib ) const
02060 {
02061   static const QString& sq = KGlobal::staticQString("\"'");
02062   return (m_additionalData[ hlKeyForAttrib( attrib ) ]->wordWrapDeliminator.find(c) != -1) && (sq.find(c) == -1);
02063 }
02064 
02065 signed char KateHighlighting::commentRegion(int attr) const {
02066   QString commentRegion=m_additionalData[ hlKeyForAttrib( attr ) ]->multiLineRegion;
02067   return (commentRegion.isEmpty()?0:(commentRegion.toShort()));
02068 }
02069 
02070 bool KateHighlighting::canComment( int startAttrib, int endAttrib ) const
02071 {
02072   QString k = hlKeyForAttrib( startAttrib );
02073   return ( k == hlKeyForAttrib( endAttrib ) &&
02074       ( ( !m_additionalData[k]->multiLineCommentStart.isEmpty() && !m_additionalData[k]->multiLineCommentEnd.isEmpty() ) ||
02075        ! m_additionalData[k]->singleLineCommentMarker.isEmpty() ) );
02076 }
02077 
02078 QString KateHighlighting::getCommentStart( int attrib ) const
02079 {
02080   return m_additionalData[ hlKeyForAttrib( attrib) ]->multiLineCommentStart;
02081 }
02082 
02083 QString KateHighlighting::getCommentEnd( int attrib ) const
02084 {
02085   return m_additionalData[ hlKeyForAttrib( attrib ) ]->multiLineCommentEnd;
02086 }
02087 
02088 QString KateHighlighting::getCommentSingleLineStart( int attrib ) const
02089 {
02090   return m_additionalData[ hlKeyForAttrib( attrib) ]->singleLineCommentMarker;
02091 }
02092 
02097 void KateHighlighting::readCommentConfig()
02098 {
02099   KateHlManager::self()->syntax->setIdentifier(buildIdentifier);
02100   KateSyntaxContextData *data=KateHlManager::self()->syntax->getGroupInfo("general","comment");
02101 
02102   QString cmlStart, cmlEnd, cmlRegion, cslStart  ;
02103 
02104   if (data)
02105   {
02106     while  (KateHlManager::self()->syntax->nextGroup(data))
02107     {
02108       if (KateHlManager::self()->syntax->groupData(data,"name")=="singleLine")
02109         cslStart=KateHlManager::self()->syntax->groupData(data,"start");
02110 
02111       if (KateHlManager::self()->syntax->groupData(data,"name")=="multiLine")
02112       {
02113         cmlStart=KateHlManager::self()->syntax->groupData(data,"start");
02114         cmlEnd=KateHlManager::self()->syntax->groupData(data,"end");
02115         cmlRegion=KateHlManager::self()->syntax->groupData(data,"region");
02116       }
02117     }
02118 
02119     KateHlManager::self()->syntax->freeGroupInfo(data);
02120   }
02121   else
02122   {
02123     cslStart = "";
02124     cmlStart = "";
02125     cmlEnd = "";
02126     cmlRegion = "";
02127   }
02128   m_additionalData[buildIdentifier]->singleLineCommentMarker = cslStart;
02129   m_additionalData[buildIdentifier]->multiLineCommentStart = cmlStart;
02130   m_additionalData[buildIdentifier]->multiLineCommentEnd = cmlEnd;
02131   m_additionalData[buildIdentifier]->multiLineRegion = cmlRegion;
02132 }
02133 
02139 void KateHighlighting::readGlobalKeywordConfig()
02140 {
02141   deliminator = stdDeliminator;
02142   // Tell the syntax document class which file we want to parse
02143   kdDebug(13010)<<"readGlobalKeywordConfig:BEGIN"<<endl;
02144 
02145   KateHlManager::self()->syntax->setIdentifier(buildIdentifier);
02146   KateSyntaxContextData *data = KateHlManager::self()->syntax->getConfig("general","keywords");
02147 
02148   if (data)
02149   {
02150     kdDebug(13010)<<"Found global keyword config"<<endl;
02151 
02152     if (KateHlManager::self()->syntax->groupItemData(data,QString("casesensitive"))!="0")
02153       casesensitive=true;
02154     else
02155       casesensitive=false;
02156 
02157     //get the weak deliminators
02158     weakDeliminator=(KateHlManager::self()->syntax->groupItemData(data,QString("weakDeliminator")));
02159 
02160     kdDebug(13010)<<"weak delimiters are: "<<weakDeliminator<<endl;
02161 
02162     // remove any weakDelimitars (if any) from the default list and store this list.
02163     for (uint s=0; s < weakDeliminator.length(); s++)
02164     {
02165       int f = deliminator.find (weakDeliminator[s]);
02166 
02167       if (f > -1)
02168         deliminator.remove (f, 1);
02169     }
02170 
02171     QString addDelim = (KateHlManager::self()->syntax->groupItemData(data,QString("additionalDeliminator")));
02172 
02173     if (!addDelim.isEmpty())
02174       deliminator=deliminator+addDelim;
02175 
02176     KateHlManager::self()->syntax->freeGroupInfo(data);
02177   }
02178   else
02179   {
02180     //Default values
02181     casesensitive=true;
02182     weakDeliminator=QString("");
02183   }
02184 
02185   kdDebug(13010)<<"readGlobalKeywordConfig:END"<<endl;
02186 
02187   kdDebug(13010)<<"delimiterCharacters are: "<<deliminator<<endl;
02188 
02189   m_additionalData[buildIdentifier]->deliminator = deliminator;
02190 }
02191 
02202 void KateHighlighting::readWordWrapConfig()
02203 {
02204   // Tell the syntax document class which file we want to parse
02205   kdDebug(13010)<<"readWordWrapConfig:BEGIN"<<endl;
02206 
02207   KateHlManager::self()->syntax->setIdentifier(buildIdentifier);
02208   KateSyntaxContextData *data = KateHlManager::self()->syntax->getConfig("general","keywords");
02209 
02210   QString wordWrapDeliminator = stdDeliminator;
02211   if (data)
02212   {
02213     kdDebug(13010)<<"Found global keyword config"<<endl;
02214 
02215     wordWrapDeliminator = (KateHlManager::self()->syntax->groupItemData(data,QString("wordWrapDeliminator")));
02216     //when no wordWrapDeliminator is defined use the deliminator list
02217     if ( wordWrapDeliminator.length() == 0 ) wordWrapDeliminator = deliminator;
02218 
02219     kdDebug(13010) << "word wrap deliminators are " << wordWrapDeliminator << endl;
02220 
02221     KateHlManager::self()->syntax->freeGroupInfo(data);
02222   }
02223 
02224   kdDebug(13010)<<"readWordWrapConfig:END"<<endl;
02225 
02226   m_additionalData[buildIdentifier]->wordWrapDeliminator = wordWrapDeliminator;
02227 }
02228 
02229 void KateHighlighting::readIndentationConfig()
02230 {
02231   m_indentation = "";
02232 
02233   KateHlManager::self()->syntax->setIdentifier(buildIdentifier);
02234   KateSyntaxContextData *data = KateHlManager::self()->syntax->getConfig("general","indentation");
02235 
02236   if (data)
02237   {
02238     m_indentation = (KateHlManager::self()->syntax->groupItemData(data,QString("mode")));
02239 
02240     KateHlManager::self()->syntax->freeGroupInfo(data);
02241   }
02242 }
02243 
02244 void KateHighlighting::readFoldingConfig()
02245 {
02246   // Tell the syntax document class which file we want to parse
02247   kdDebug(13010)<<"readfoldignConfig:BEGIN"<<endl;
02248 
02249   KateHlManager::self()->syntax->setIdentifier(buildIdentifier);
02250   KateSyntaxContextData *data = KateHlManager::self()->syntax->getConfig("general","folding");
02251 
02252   if (data)
02253   {
02254     kdDebug(13010)<<"Found global keyword config"<<endl;
02255 
02256     if (KateHlManager::self()->syntax->groupItemData(data,QString("indentationsensitive"))!="1")
02257       m_foldingIndentationSensitive=false;
02258     else
02259       m_foldingIndentationSensitive=true;
02260 
02261     KateHlManager::self()->syntax->freeGroupInfo(data);
02262   }
02263   else
02264   {
02265     //Default values
02266     m_foldingIndentationSensitive = false;
02267   }
02268 
02269   kdDebug(13010)<<"readfoldingConfig:END"<<endl;
02270 
02271   kdDebug(13010)<<"############################ use indent for fold are: "<<m_foldingIndentationSensitive<<endl;
02272 }
02273 
02274 void  KateHighlighting::createContextNameList(QStringList *ContextNameList,int ctx0)
02275 {
02276   kdDebug(13010)<<"creatingContextNameList:BEGIN"<<endl;
02277 
02278   if (ctx0 == 0)
02279       ContextNameList->clear();
02280 
02281   KateHlManager::self()->syntax->setIdentifier(buildIdentifier);
02282 
02283   KateSyntaxContextData *data=KateHlManager::self()->syntax->getGroupInfo("highlighting","context");
02284 
02285   int id=ctx0;
02286 
02287   if (data)
02288   {
02289      while (KateHlManager::self()->syntax->nextGroup(data))
02290      {
02291           QString tmpAttr=KateHlManager::self()->syntax->groupData(data,QString("name")).simplifyWhiteSpace();
02292     if (tmpAttr.isEmpty())
02293     {
02294      tmpAttr=QString("!KATE_INTERNAL_DUMMY! %1").arg(id);
02295      errorsAndWarnings +=i18n("<B>%1</B>: Deprecated syntax. Context %2 has no symbolic name<BR>").arg(buildIdentifier).arg(id-ctx0);
02296     }
02297           else tmpAttr=buildPrefix+tmpAttr;
02298     (*ContextNameList)<<tmpAttr;
02299           id++;
02300      }
02301      KateHlManager::self()->syntax->freeGroupInfo(data);
02302   }
02303   kdDebug(13010)<<"creatingContextNameList:END"<<endl;
02304 
02305 }
02306 
02307 int KateHighlighting::getIdFromString(QStringList *ContextNameList, QString tmpLineEndContext, /*NO CONST*/ QString &unres)
02308 {
02309   unres="";
02310   int context;
02311   if ((tmpLineEndContext=="#stay") || (tmpLineEndContext.simplifyWhiteSpace().isEmpty()))
02312     context=-1;
02313 
02314   else if (tmpLineEndContext.startsWith("#pop"))
02315   {
02316     context=-1;
02317     for(;tmpLineEndContext.startsWith("#pop");context--)
02318     {
02319       tmpLineEndContext.remove(0,4);
02320       kdDebug(13010)<<"#pop found"<<endl;
02321     }
02322   }
02323 
02324   else if ( tmpLineEndContext.startsWith("##"))
02325   {
02326     QString tmp=tmpLineEndContext.right(tmpLineEndContext.length()-2);
02327     if (!embeddedHls.contains(tmp))  embeddedHls.insert(tmp,KateEmbeddedHlInfo());
02328     unres=tmp;
02329     context=0;
02330   }
02331 
02332   else
02333   {
02334     context=ContextNameList->findIndex(buildPrefix+tmpLineEndContext);
02335     if (context==-1)
02336     {
02337       context=tmpLineEndContext.toInt();
02338       errorsAndWarnings+=i18n(
02339         "<B>%1</B>:Deprecated syntax. Context %2 not addressed by a symbolic name"
02340         ).arg(buildIdentifier).arg(tmpLineEndContext);
02341     }
02342 //#warning restructure this the name list storage.
02343 //    context=context+buildContext0Offset;
02344   }
02345   return context;
02346 }
02347 
02353 void KateHighlighting::makeContextList()
02354 {
02355   if (noHl)  // if this a highlighting for "normal texts" only, tere is no need for a context list creation
02356     return;
02357 
02358   embeddedHls.clear();
02359   unresolvedContextReferences.clear();
02360   RegionList.clear();
02361   ContextNameList.clear();
02362 
02363   // prepare list creation. To reuse as much code as possible handle this
02364   // highlighting the same way as embedded onces
02365   embeddedHls.insert(iName,KateEmbeddedHlInfo());
02366 
02367   bool something_changed;
02368   // the context "0" id is 0 for this hl, all embedded context "0"s have offsets
02369   startctx=base_startctx=0;
02370   // inform everybody that we are building the highlighting contexts and itemlists
02371   building=true;
02372 
02373   do
02374   {
02375     kdDebug(13010)<<"**************** Outter loop in make ContextList"<<endl;
02376     kdDebug(13010)<<"**************** Hl List count:"<<embeddedHls.count()<<endl;
02377     something_changed=false; //assume all "embedded" hls have already been loaded
02378     for (KateEmbeddedHlInfos::const_iterator it=embeddedHls.begin(); it!=embeddedHls.end();++it)
02379     {
02380       if (!it.data().loaded)  // we found one, we still have to load
02381       {
02382         kdDebug(13010)<<"**************** Inner loop in make ContextList"<<endl;
02383         QString identifierToUse;
02384         kdDebug(13010)<<"Trying to open highlighting definition file: "<< it.key()<<endl;
02385         if (iName==it.key()) // the own identifier is known
02386           identifierToUse=identifier;
02387         else                 // all others have to be looked up
02388           identifierToUse=KateHlManager::self()->identifierForName(it.key());
02389 
02390         kdDebug(13010)<<"Location is:"<< identifierToUse<<endl;
02391 
02392         buildPrefix=it.key()+':';  // attribute names get prefixed by the names
02393                                    // of the highlighting definitions they belong to
02394 
02395         if (identifierToUse.isEmpty() )
02396           kdDebug(13010)<<"OHOH, unknown highlighting description referenced"<<endl;
02397 
02398         kdDebug(13010)<<"setting ("<<it.key()<<") to loaded"<<endl;
02399 
02400         //mark hl as loaded
02401         it=embeddedHls.insert(it.key(),KateEmbeddedHlInfo(true,startctx));
02402         //set class member for context 0 offset, so we don't need to pass it around
02403         buildContext0Offset=startctx;
02404         //parse one hl definition file
02405         startctx=addToContextList(identifierToUse,startctx);
02406 
02407         if (noHl) return;  // an error occurred
02408 
02409         base_startctx = startctx;
02410         something_changed=true; // something has been loaded
02411       }
02412     }
02413   } while (something_changed);  // as long as there has been another file parsed
02414                   // repeat everything, there could be newly added embedded hls.
02415 
02416 
02417   // at this point all needed highlighing (sub)definitions are loaded. It's time
02418   // to resolve cross file  references (if there are any )
02419   kdDebug(13010)<<"Unresolved contexts, which need attention: "<<unresolvedContextReferences.count()<<endl;
02420 
02421   //optimize this a littlebit
02422   for (KateHlUnresolvedCtxRefs::iterator unresIt=unresolvedContextReferences.begin();
02423     unresIt!=unresolvedContextReferences.end();++unresIt)
02424   {
02425     //try to find the context0 id for a given unresolvedReference
02426     KateEmbeddedHlInfos::const_iterator hlIt=embeddedHls.find(unresIt.data());
02427     if (hlIt!=embeddedHls.end())
02428       *(unresIt.key())=hlIt.data().context0;
02429   }
02430 
02431   // eventually handle KateHlIncludeRules items, if they exist.
02432   // This has to be done after the cross file references, because it is allowed
02433   // to include the context0 from a different definition, than the one the rule
02434   // belongs to
02435   handleKateHlIncludeRules();
02436 
02437   embeddedHls.clear(); //save some memory.
02438   unresolvedContextReferences.clear(); //save some memory
02439   RegionList.clear();  // I think you get the idea ;)
02440   ContextNameList.clear();
02441 
02442 
02443   // if there have been errors show them
02444   if (!errorsAndWarnings.isEmpty())
02445   KMessageBox::detailedSorry(0L,i18n(
02446         "There were warning(s) and/or error(s) while parsing the syntax "
02447         "highlighting configuration."),
02448         errorsAndWarnings, i18n("Kate Syntax Highlighting Parser"));
02449 
02450   // we have finished
02451   building=false;
02452 }
02453 
02454 void KateHighlighting::handleKateHlIncludeRules()
02455 {
02456   // if there are noe include rules to take care of, just return
02457   kdDebug(13010)<<"KateHlIncludeRules, which need attention: " <<includeRules.count()<<endl;
02458   if (includeRules.isEmpty()) return;
02459 
02460   buildPrefix="";
02461   QString dummy;
02462 
02463   // By now the context0 references are resolved, now more or less only inner
02464   // file references are resolved. If we decide that arbitrary inclusion is
02465   // needed, this doesn't need to be changed, only the addToContextList
02466   // method.
02467 
02468   //resolove context names
02469   for (KateHlIncludeRules::iterator it=includeRules.begin();it!=includeRules.end();)
02470   {
02471     if ((*it)->incCtx==-1) // context unresolved ?
02472     {
02473 
02474       if ((*it)->incCtxN.isEmpty())
02475       {
02476         // no context name given, and no valid context id set, so this item is
02477         // going to be removed
02478         KateHlIncludeRules::iterator it1=it;
02479         ++it1;
02480         delete (*it);
02481         includeRules.remove(it);
02482         it=it1;
02483       }
02484       else
02485       {
02486         // resolve name to id
02487         (*it)->incCtx=getIdFromString(&ContextNameList,(*it)->incCtxN,dummy);
02488         kdDebug(13010)<<"Resolved "<<(*it)->incCtxN<< " to "<<(*it)->incCtx<<" for include rule"<<endl;
02489         // It would be good to look here somehow, if the result is valid
02490       }
02491     }
02492     else ++it; //nothing to do, already resolved (by the cross defintion reference resolver
02493   }
02494 
02495   // now that all KateHlIncludeRule items should be valid and completely resolved,
02496   // do the real inclusion of the rules.
02497   // recursiveness is needed, because context 0 could include context 1, which
02498   // itself includes context 2 and so on.
02499   //  In that case we have to handle context 2 first, then 1, 0
02500   //TODO: catch circular references: eg 0->1->2->3->1
02501   while (!includeRules.isEmpty())
02502     handleKateHlIncludeRulesRecursive(includeRules.begin(),&includeRules);
02503 }
02504 
02505 void KateHighlighting::handleKateHlIncludeRulesRecursive(KateHlIncludeRules::iterator it, KateHlIncludeRules *list)
02506 {
02507   if (it==list->end()) return;  //invalid iterator, shouldn't happen, but better have a rule prepared ;)
02508 
02509   KateHlIncludeRules::iterator it1=it;
02510   int ctx=(*it1)->ctx;
02511 
02512   // find the last entry for the given context in the KateHlIncludeRules list
02513   // this is need if one context includes more than one. This saves us from
02514   // updating all insert positions:
02515   // eg: context 0:
02516   // pos 3 - include context 2
02517   // pos 5 - include context 3
02518   // During the building of the includeRules list the items are inserted in
02519   // ascending order, now we need it descending to make our life easier.
02520   while ((it!=list->end()) && ((*it)->ctx==ctx))
02521   {
02522     it1=it;
02523     ++it;
02524   }
02525 
02526   // iterate over each include rule for the context the function has been called for.
02527   while ((it1!=list->end()) && ((*it1)->ctx==ctx))
02528   {
02529     int ctx1=(*it1)->incCtx;
02530 
02531     //let's see, if the the included context includes other contexts
02532     for (KateHlIncludeRules::iterator it2=list->begin();it2!=list->end();++it2)
02533     {
02534       if ((*it2)->ctx==ctx1)
02535       {
02536         //yes it does, so first handle that include rules, since we want to
02537         // include those subincludes too
02538         handleKateHlIncludeRulesRecursive(it2,list);
02539         break;
02540       }
02541     }
02542 
02543     // if the context we want to include had sub includes, they are already inserted there.
02544     KateHlContext *dest=m_contexts[ctx];
02545     KateHlContext *src=m_contexts[ctx1];
02546 //     kdDebug(3010)<<"linking included rules from "<<ctx<<" to "<<ctx1<<endl;
02547 
02548     // If so desired, change the dest attribute to the one of the src.
02549     // Required to make commenting work, if text matched by the included context
02550     // is a different highlight than the host context.
02551     if ( (*it1)->includeAttrib )
02552       dest->attr = src->attr;
02553 
02554     // insert the included context's rules starting at position p
02555     int p=(*it1)->pos;
02556 
02557     // remember some stuff
02558     int oldLen = dest->items.size();
02559     uint itemsToInsert = src->items.size();
02560 
02561     // resize target
02562     dest->items.resize (oldLen + itemsToInsert);
02563 
02564     // move old elements
02565     for (int i=oldLen-1; i >= p; --i)
02566       dest->items[i+itemsToInsert] = dest->items[i];
02567 
02568     // insert new stuff
02569     for (uint i=0; i < itemsToInsert; ++i  )
02570       dest->items[p+i] = src->items[i];
02571 
02572     it=it1; //backup the iterator
02573     --it1;  //move to the next entry, which has to be take care of
02574     delete (*it); //free the already handled data structure
02575     list->remove(it); // remove it from the list
02576   }
02577 }
02578 
02584 int KateHighlighting::addToContextList(const QString &ident, int ctx0)
02585 {
02586   kdDebug(13010)<<"=== Adding hl with ident '"<<ident<<"'"<<endl;
02587 
02588   buildIdentifier=ident;
02589   KateSyntaxContextData *data, *datasub;
02590   KateHlItem *c;
02591 
02592   QString dummy;
02593 
02594   // Let the syntax document class know, which file we'd like to parse
02595   if (!KateHlManager::self()->syntax->setIdentifier(ident))
02596   {
02597     noHl=true;
02598     KMessageBox::information(0L,i18n(
02599         "Since there has been an error parsing the highlighting description, "
02600         "this highlighting will be disabled"));
02601     return 0;
02602   }
02603 
02604   // only read for the own stuff
02605   if (identifier == ident)
02606   {
02607     readIndentationConfig ();
02608   }
02609 
02610   RegionList<<"!KateInternal_TopLevel!";
02611 
02612   m_hlIndex[internalIDList.count()] = ident;
02613   m_additionalData.insert( ident, new HighlightPropertyBag );
02614 
02615   // fill out the propertybag
02616   readCommentConfig();
02617   readGlobalKeywordConfig();
02618   readWordWrapConfig();
02619 
02620   readFoldingConfig ();
02621 
02622   QString ctxName;
02623 
02624   // This list is needed for the translation of the attribute parameter,
02625   // if the itemData name is given instead of the index
02626   addToKateHlItemDataList();
02627   KateHlItemDataList iDl = internalIDList;
02628 
02629   createContextNameList(&ContextNameList,ctx0);
02630 
02631 
02632   kdDebug(13010)<<"Parsing Context structure"<<endl;
02633   //start the real work
02634   data=KateHlManager::self()->syntax->getGroupInfo("highlighting","context");
02635   uint i=buildContext0Offset;
02636   if (data)
02637   {
02638     while (KateHlManager::self()->syntax->nextGroup(data))
02639     {
02640       kdDebug(13010)<<"Found a context in file, building structure now"<<endl;
02641       //BEGIN - Translation of the attribute parameter
02642       QString tmpAttr=KateHlManager::self()->syntax->groupData(data,QString("attribute")).simplifyWhiteSpace();
02643       int attr;
02644       if (QString("%1").arg(tmpAttr.toInt())==tmpAttr)
02645         attr=tmpAttr.toInt();
02646       else
02647         attr=lookupAttrName(tmpAttr,iDl);
02648       //END - Translation of the attribute parameter
02649 
02650       ctxName=buildPrefix+KateHlManager::self()->syntax->groupData(data,QString("lineEndContext")).simplifyWhiteSpace();
02651 
02652       QString tmpLineEndContext=KateHlManager::self()->syntax->groupData(data,QString("lineEndContext")).simplifyWhiteSpace();
02653       int context;
02654 
02655       context=getIdFromString(&ContextNameList, tmpLineEndContext,dummy);
02656 
02657       //BEGIN get fallthrough props
02658       bool ft = false;
02659       int ftc = 0; // fallthrough context
02660       if ( i > 0 )  // fallthrough is not smart in context 0
02661       {
02662         QString tmpFt = KateHlManager::self()->syntax->groupData(data, QString("fallthrough") );
02663         if ( IS_TRUE(tmpFt) )
02664           ft = true;
02665         if ( ft )
02666         {
02667           QString tmpFtc = KateHlManager::self()->syntax->groupData( data, QString("fallthroughContext") );
02668 
02669           ftc=getIdFromString(&ContextNameList, tmpFtc,dummy);
02670           if (ftc == -1) ftc =0;
02671 
02672           kdDebug(13010)<<"Setting fall through context (context "<<i<<"): "<<ftc<<endl;
02673         }
02674       }
02675       //END falltrhough props
02676 
02677       bool dynamic = false;
02678       QString tmpDynamic = KateHlManager::self()->syntax->groupData(data, QString("dynamic") );
02679       if ( tmpDynamic.lower() == "true" ||  tmpDynamic.toInt() == 1 )
02680         dynamic = true;
02681 
02682       KateHlContext *ctxNew = new KateHlContext (
02683         ident,
02684         attr,
02685         context,
02686         (KateHlManager::self()->syntax->groupData(data,QString("lineBeginContext"))).isEmpty()?-1:
02687         (KateHlManager::self()->syntax->groupData(data,QString("lineBeginContext"))).toInt(),
02688         ft, ftc, dynamic);
02689 
02690       m_contexts.push_back (ctxNew);
02691 
02692       kdDebug(13010) << "INDEX: " << i << " LENGTH " << m_contexts.size()-1 << endl;
02693 
02694       //Let's create all items for the context
02695       while (KateHlManager::self()->syntax->nextItem(data))
02696       {
02697 //    kdDebug(13010)<< "In make Contextlist: Item:"<<endl;
02698 
02699       // KateHlIncludeRules : add a pointer to each item in that context
02700         // TODO add a attrib includeAttrib
02701       QString tag = KateHlManager::self()->syntax->groupItemData(data,QString(""));
02702       if ( tag == "IncludeRules" ) //if the new item is an Include rule, we have to take special care
02703       {
02704         QString incCtx = KateHlManager::self()->syntax->groupItemData( data, QString("context"));
02705         QString incAttrib = KateHlManager::self()->syntax->groupItemData( data, QString("includeAttrib"));
02706         bool includeAttrib = ( incAttrib.lower() == "true" || incAttrib.toInt() == 1 );
02707         // only context refernces of type NAME and ##Name are allowed
02708         if (incCtx.startsWith("##") || (!incCtx.startsWith("#")))
02709         {
02710           //#stay, #pop is not interesting here
02711           if (!incCtx.startsWith("#"))
02712           {
02713             // a local reference -> just initialize the include rule structure
02714             incCtx=buildPrefix+incCtx.simplifyWhiteSpace();
02715             includeRules.append(new KateHlIncludeRule(i,m_contexts[i]->items.count(),incCtx, includeAttrib));
02716           }
02717           else
02718           {
02719             //a cross highlighting reference
02720             kdDebug(13010)<<"Cross highlight reference <IncludeRules>"<<endl;
02721             KateHlIncludeRule *ir=new KateHlIncludeRule(i,m_contexts[i]->items.count(),"",includeAttrib);
02722 
02723             //use the same way to determine cross hl file references as other items do
02724             if (!embeddedHls.contains(incCtx.right(incCtx.length()-2)))
02725               embeddedHls.insert(incCtx.right(incCtx.length()-2),KateEmbeddedHlInfo());
02726 
02727             unresolvedContextReferences.insert(&(ir->incCtx),
02728                 incCtx.right(incCtx.length()-2));
02729 
02730             includeRules.append(ir);
02731           }
02732         }
02733 
02734         continue;
02735       }
02736       // TODO -- can we remove the block below??
02737 #if 0
02738                 QString tag = KateHlManager::self()->syntax->groupKateHlItemData(data,QString(""));
02739                 if ( tag == "IncludeRules" ) {
02740                   // attrib context: the index (jowenn, i think using names here
02741                   // would be a cool feat, goes for mentioning the context in
02742                   // any item. a map or dict?)
02743                   int ctxId = getIdFromString(&ContextNameList,
02744                                                KateHlManager::self()->syntax->groupKateHlItemData( data, QString("context")),dummy); // the index is *required*
02745                   if ( ctxId > -1) { // we can even reuse rules of 0 if we want to:)
02746                     kdDebug(13010)<<"makeContextList["<<i<<"]: including all items of context "<<ctxId<<endl;
02747                     if ( ctxId < (int) i ) { // must be defined
02748                       for ( c = m_contexts[ctxId]->items.first(); c; c = m_contexts[ctxId]->items.next() )
02749                         m_contexts[i]->items.append(c);
02750                     }
02751                     else
02752                       kdDebug(13010)<<"Context "<<ctxId<<"not defined. You can not include the rules of an undefined context"<<endl;
02753                   }
02754                   continue; // while nextItem
02755                 }
02756 #endif
02757       c=createKateHlItem(data,iDl,&RegionList,&ContextNameList);
02758       if (c)
02759       {
02760         m_contexts[i]->items.append(c);
02761 
02762         // Not supported completely atm and only one level. Subitems.(all have
02763         // to be matched to at once)
02764         datasub=KateHlManager::self()->syntax->getSubItems(data);
02765         bool tmpbool;
02766         if (tmpbool=KateHlManager::self()->syntax->nextItem(datasub))
02767         {
02768           for (;tmpbool;tmpbool=KateHlManager::self()->syntax->nextItem(datasub))
02769           {
02770             c->subItems.resize (c->subItems.size()+1);
02771             c->subItems[c->subItems.size()-1] = createKateHlItem(datasub,iDl,&RegionList,&ContextNameList);
02772           }                             }
02773           KateHlManager::self()->syntax->freeGroupInfo(datasub);
02774                               // end of sublevel
02775         }
02776       }
02777       i++;
02778     }
02779   }
02780 
02781   KateHlManager::self()->syntax->freeGroupInfo(data);
02782 
02783   if (RegionList.count()!=1)
02784     folding=true;
02785 
02786   folding = folding || m_foldingIndentationSensitive;
02787 
02788   //BEGIN Resolve multiline region if possible
02789   if (!m_additionalData[ ident ]->multiLineRegion.isEmpty()) {
02790     long commentregionid=RegionList.findIndex( m_additionalData[ ident ]->multiLineRegion );
02791     if (-1==commentregionid) {
02792       errorsAndWarnings+=i18n(
02793           "<B>%1</B>: Specified multiline comment region (%2) could not be resolved<BR>"
02794                              ).arg(buildIdentifier).arg( m_additionalData[ ident ]->multiLineRegion );
02795       m_additionalData[ ident ]->multiLineRegion = QString();
02796       kdDebug(13010)<<"ERROR comment region attribute could not be resolved"<<endl;
02797 
02798     } else {
02799       m_additionalData[ ident ]->multiLineRegion=QString::number(commentregionid+1);
02800       kdDebug(13010)<<"comment region resolved to:"<<m_additionalData[ ident ]->multiLineRegion<<endl;
02801     }
02802   }
02803   //END Resolve multiline region if possible
02804   return i;
02805 }
02806 
02807 void KateHighlighting::clearAttributeArrays ()
02808 {
02809   for ( QIntDictIterator< QMemArray<KateAttribute> > it( m_attributeArrays ); it.current(); ++it )
02810   {
02811     // k, schema correct, let create the data
02812     KateAttributeList defaultStyleList;
02813     defaultStyleList.setAutoDelete(true);
02814     KateHlManager::self()->getDefaults(it.currentKey(), defaultStyleList);
02815 
02816     KateHlItemDataList itemDataList;
02817     getKateHlItemDataList(it.currentKey(), itemDataList);
02818 
02819     uint nAttribs = itemDataList.count();
02820     QMemArray<KateAttribute> *array = it.current();
02821     array->resize (nAttribs);
02822 
02823     for (uint z = 0; z < nAttribs; z++)
02824     {
02825       KateHlItemData *itemData = itemDataList.at(z);
02826       KateAttribute n = *defaultStyleList.at(itemData->defStyleNum);
02827 
02828       if (itemData && itemData->isSomethingSet())
02829         n += *itemData;
02830 
02831       array->at(z) = n;
02832     }
02833   }
02834 }
02835 
02836 QMemArray<KateAttribute> *KateHighlighting::attributes (uint schema)
02837 {
02838   QMemArray<KateAttribute> *array;
02839 
02840   // found it, allready floating around
02841   if ((array = m_attributeArrays[schema]))
02842     return array;
02843 
02844   // ohh, not found, check if valid schema number
02845   if (!KateFactory::self()->schemaManager()->validSchema(schema))
02846   {
02847     // uhh, not valid :/, stick with normal default schema, it's always there !
02848     return attributes (0);
02849   }
02850 
02851   // k, schema correct, let create the data
02852   KateAttributeList defaultStyleList;
02853   defaultStyleList.setAutoDelete(true);
02854   KateHlManager::self()->getDefaults(schema, defaultStyleList);
02855 
02856   KateHlItemDataList itemDataList;
02857   getKateHlItemDataList(schema, itemDataList);
02858 
02859   uint nAttribs = itemDataList.count();
02860   array = new QMemArray<KateAttribute> (nAttribs);
02861 
02862   for (uint z = 0; z < nAttribs; z++)
02863   {
02864     KateHlItemData *itemData = itemDataList.at(z);
02865     KateAttribute n = *defaultStyleList.at(itemData->defStyleNum);
02866 
02867     if (itemData && itemData->isSomethingSet())
02868       n += *itemData;
02869 
02870     array->at(z) = n;
02871   }
02872 
02873   m_attributeArrays.insert(schema, array);
02874 
02875   return array;
02876 }
02877 
02878 void KateHighlighting::getKateHlItemDataListCopy (uint schema, KateHlItemDataList &outlist)
02879 {
02880   KateHlItemDataList itemDataList;
02881   getKateHlItemDataList(schema, itemDataList);
02882 
02883   outlist.clear ();
02884   outlist.setAutoDelete (true);
02885   for (uint z=0; z < itemDataList.count(); z++)
02886     outlist.append (new KateHlItemData (*itemDataList.at(z)));
02887 }
02888 
02889 //END
02890 
02891 //BEGIN KateHlManager
02892 KateHlManager::KateHlManager()
02893   : QObject()
02894   , m_config ("katesyntaxhighlightingrc", false, false)
02895   , commonSuffixes (QStringList::split(";", ".orig;.new;~;.bak;.BAK"))
02896   , syntax (new KateSyntaxDocument())
02897   , dynamicCtxsCount(0)
02898   , forceNoDCReset(false)
02899 {
02900   hlList.setAutoDelete(true);
02901   hlDict.setAutoDelete(false);
02902 
02903   KateSyntaxModeList modeList = syntax->modeList();
02904   for (uint i=0; i < modeList.count(); i++)
02905   {
02906     KateHighlighting *hl = new KateHighlighting(modeList[i]);
02907 
02908     uint insert = 0;
02909     for (; insert <= hlList.count(); insert++)
02910     {
02911       if (insert == hlList.count())
02912         break;
02913 
02914       if ( QString(hlList.at(insert)->section() + hlList.at(insert)->nameTranslated()).lower()
02915             > QString(hl->section() + hl->nameTranslated()).lower() )
02916         break;
02917     }
02918 
02919     hlList.insert (insert, hl);
02920     hlDict.insert (hl->name(), hl);
02921   }
02922 
02923   // Normal HL
02924   KateHighlighting *hl = new KateHighlighting(0);
02925   hlList.prepend (hl);
02926   hlDict.insert (hl->name(), hl);
02927 
02928   lastCtxsReset.start();
02929 }
02930 
02931 KateHlManager::~KateHlManager()
02932 {
02933   delete syntax;
02934 }
02935 
02936 static KStaticDeleter<KateHlManager> sdHlMan;
02937 
02938 KateHlManager *KateHlManager::self()
02939 {
02940   if ( !s_self )
02941     sdHlMan.setObject(s_self, new KateHlManager ());
02942 
02943   return s_self;
02944 }
02945 
02946 KateHighlighting *KateHlManager::getHl(int n)
02947 {
02948   if (n < 0 || n >= (int) hlList.count())
02949     n = 0;
02950 
02951   return hlList.at(n);
02952 }
02953 
02954 int KateHlManager::nameFind(const QString &name)
02955 {
02956   int z (hlList.count() - 1);
02957   for (; z > 0; z--)
02958     if (hlList.at(z)->name() == name)
02959       return z;
02960 
02961   return z;
02962 }
02963 
02964 int KateHlManager::detectHighlighting (KateDocument *doc)
02965 {
02966   int hl = wildcardFind( doc->url().filename() );
02967   if ( hl < 0 )
02968     hl = mimeFind ( doc );
02969 
02970   return hl;
02971 }
02972 
02973 int KateHlManager::wildcardFind(const QString &fileName)
02974 {
02975   int result = -1;
02976   if ((result = realWildcardFind(fileName)) != -1)
02977     return result;
02978 
02979   int length = fileName.length();
02980   QString backupSuffix = KateDocumentConfig::global()->backupSuffix();
02981   if (fileName.endsWith(backupSuffix)) {
02982     if ((result = realWildcardFind(fileName.left(length - backupSuffix.length()))) != -1)
02983       return result;
02984   }
02985 
02986   for (QStringList::Iterator it = commonSuffixes.begin(); it != commonSuffixes.end(); ++it) {
02987     if (*it != backupSuffix && fileName.endsWith(*it)) {
02988       if ((result = realWildcardFind(fileName.left(length - (*it).length()))) != -1)
02989         return result;
02990     }
02991   }
02992 
02993   return -1;
02994 }
02995 
02996 int KateHlManager::realWildcardFind(const QString &fileName)
02997 {
02998   static QRegExp sep("\\s*;\\s*");
02999 
03000   QPtrList<KateHighlighting> highlights;
03001 
03002   for (KateHighlighting *highlight = hlList.first(); highlight != 0L; highlight = hlList.next()) {
03003     highlight->loadWildcards();
03004 
03005     for (QStringList::Iterator it = highlight->getPlainExtensions().begin(); it != highlight->getPlainExtensions().end(); ++it)
03006       if (fileName.endsWith((*it)))
03007         highlights.append(highlight);
03008 
03009     for (int i = 0; i < (int)highlight->getRegexpExtensions().count(); i++) {
03010       QRegExp re = highlight->getRegexpExtensions()[i];
03011       if (re.exactMatch(fileName))
03012         highlights.append(highlight);
03013     }
03014   }
03015 
03016   if ( !highlights.isEmpty() )
03017   {
03018     int pri = -1;
03019     int hl = -1;
03020 
03021     for (KateHighlighting *highlight = highlights.first(); highlight != 0L; highlight = highlights.next())
03022     {
03023       if (highlight->priority() > pri)
03024       {
03025         pri = highlight->priority();
03026         hl = hlList.findRef (highlight);
03027       }
03028     }
03029     return hl;
03030   }
03031 
03032   return -1;
03033 }
03034 
03035 int KateHlManager::mimeFind( KateDocument *doc )
03036 {
03037   static QRegExp sep("\\s*;\\s*");
03038 
03039   KMimeType::Ptr mt = doc->mimeTypeForContent();
03040 
03041   QPtrList<KateHighlighting> highlights;
03042 
03043   for (KateHighlighting *highlight = hlList.first(); highlight != 0L; highlight = hlList.next())
03044   {
03045     QStringList l = QStringList::split( sep, highlight->getMimetypes() );
03046 
03047     for( QStringList::Iterator it = l.begin(); it != l.end(); ++it )
03048     {
03049       if ( *it == mt->name() ) // faster than a regexp i guess?
03050         highlights.append (highlight);
03051     }
03052   }
03053 
03054   if ( !highlights.isEmpty() )
03055   {
03056     int pri = -1;
03057     int hl = -1;
03058 
03059     for (KateHighlighting *highlight = highlights.first(); highlight != 0L; highlight = highlights.next())
03060     {
03061       if (highlight->priority() > pri)
03062       {
03063         pri = highlight->priority();
03064         hl = hlList.findRef (highlight);
03065       }
03066     }
03067 
03068     return hl;
03069   }
03070 
03071   return -1;
03072 }
03073 
03074 uint KateHlManager::defaultStyles()
03075 {
03076   return 14;
03077 }
03078 
03079 QString KateHlManager::defaultStyleName(int n, bool translateNames)
03080 {
03081   static QStringList names;
03082   static QStringList translatedNames;
03083 
03084   if (names.isEmpty())
03085   {
03086     names << "Normal";
03087     names << "Keyword";
03088     names << "Data Type";
03089     names << "Decimal/Value";
03090     names << "Base-N Integer";
03091     names << "Floating Point";
03092     names << "Character";
03093     names << "String";
03094     names << "Comment";
03095     names << "Others";
03096     names << "Alert";
03097     names << "Function";
03098     // this next one is for denoting the beginning/end of a user defined folding region
03099     names << "Region Marker";
03100     // this one is for marking invalid input
03101     names << "Error";
03102 
03103     translatedNames << i18n("Normal");
03104     translatedNames << i18n("Keyword");
03105     translatedNames << i18n("Data Type");
03106     translatedNames << i18n("Decimal/Value");
03107     translatedNames << i18n("Base-N Integer");
03108     translatedNames << i18n("Floating Point");
03109     translatedNames << i18n("Character");
03110     translatedNames << i18n("String");
03111     translatedNames << i18n("Comment");
03112     translatedNames << i18n("Others");
03113     translatedNames << i18n("Alert");
03114     translatedNames << i18n("Function");
03115     // this next one is for denoting the beginning/end of a user defined folding region
03116     translatedNames << i18n("Region Marker");
03117     // this one is for marking invalid input
03118     translatedNames << i18n("Error");
03119   }
03120 
03121   return translateNames ? translatedNames[n] : names[n];
03122 }
03123 
03124 void KateHlManager::getDefaults(uint schema, KateAttributeList &list)
03125 {
03126   list.setAutoDelete(true);
03127 
03128   KateAttribute* normal = new KateAttribute();
03129   normal->setTextColor(Qt::black);
03130   normal->setSelectedTextColor(Qt::white);
03131   list.append(normal);
03132 
03133   KateAttribute* keyword = new KateAttribute();
03134   keyword->setTextColor(Qt::black);
03135   keyword->setSelectedTextColor(Qt::white);
03136   keyword->setBold(true);
03137   list.append(keyword);
03138 
03139   KateAttribute* dataType = new KateAttribute();
03140   dataType->setTextColor(Qt::darkRed);
03141   dataType->setSelectedTextColor(Qt::white);
03142   list.append(dataType);
03143 
03144   KateAttribute* decimal = new KateAttribute();
03145   decimal->setTextColor(Qt::blue);
03146   decimal->setSelectedTextColor(Qt::cyan);
03147   list.append(decimal);
03148 
03149   KateAttribute* basen = new KateAttribute();
03150   basen->setTextColor(Qt::darkCyan);
03151   basen->setSelectedTextColor(Qt::cyan);
03152   list.append(basen);
03153 
03154   KateAttribute* floatAttribute = new KateAttribute();
03155   floatAttribute->setTextColor(Qt::darkMagenta);
03156   floatAttribute->setSelectedTextColor(Qt::cyan);
03157   list.append(floatAttribute);
03158 
03159   KateAttribute* charAttribute = new KateAttribute();
03160   charAttribute->setTextColor(Qt::magenta);
03161   charAttribute->setSelectedTextColor(Qt::magenta);
03162   list.append(charAttribute);
03163 
03164   KateAttribute* string = new KateAttribute();
03165   string->setTextColor(QColor::QColor("#D00"));
03166   string->setSelectedTextColor(Qt::red);
03167   list.append(string);
03168 
03169   KateAttribute* comment = new KateAttribute();
03170   comment->setTextColor(Qt::darkGray);
03171   comment->setSelectedTextColor(Qt::gray);
03172   comment->setItalic(true);
03173   list.append(comment);
03174 
03175   KateAttribute* others = new KateAttribute();
03176   others->setTextColor(Qt::darkGreen);
03177   others->setSelectedTextColor(Qt::green);
03178   list.append(others);
03179 
03180   KateAttribute* alert = new KateAttribute();
03181   alert->setTextColor(Qt::white);
03182   alert->setSelectedTextColor( QColor::QColor("#FCC") );
03183   alert->setBold(true);
03184   alert->setBGColor( QColor::QColor("#FCC") );
03185   list.append(alert);
03186 
03187   KateAttribute* functionAttribute = new KateAttribute();
03188   functionAttribute->setTextColor(Qt::darkBlue);
03189   functionAttribute->setSelectedTextColor(Qt::white);
03190   list.append(functionAttribute);
03191 
03192   KateAttribute* regionmarker = new KateAttribute();
03193   regionmarker->setTextColor(Qt::white);
03194   regionmarker->setBGColor(Qt::gray);
03195   regionmarker->setSelectedTextColor(Qt::gray);
03196   list.append(regionmarker);
03197 
03198   KateAttribute* error = new KateAttribute();
03199   error->setTextColor(Qt::red);
03200   error->setUnderline(true);
03201   error->setSelectedTextColor(Qt::red);
03202   list.append(error);
03203 
03204   KConfig *config = KateHlManager::self()->self()->getKConfig();
03205   config->setGroup("Default Item Styles - Schema " + KateFactory::self()->schemaManager()->name(schema));
03206 
03207   for (uint z = 0; z < defaultStyles(); z++)
03208   {
03209     KateAttribute *i = list.at(z);
03210     QStringList s = config->readListEntry(defaultStyleName(z));
03211     if (!s.isEmpty())
03212     {
03213       while( s.count()<8)
03214         s << "";
03215 
03216       QString tmp;
03217       QRgb col;
03218 
03219       tmp=s[0]; if (!tmp.isEmpty()) {
03220          col=tmp.toUInt(0,16); i->setTextColor(col); }
03221 
03222       tmp=s[1]; if (!tmp.isEmpty()) {
03223          col=tmp.toUInt(0,16); i->setSelectedTextColor(col); }
03224 
03225       tmp=s[2]; if (!tmp.isEmpty()) i->setBold(tmp!="0");
03226 
03227       tmp=s[3]; if (!tmp.isEmpty()) i->setItalic(tmp!="0");
03228 
03229       tmp=s[4]; if (!tmp.isEmpty()) i->setStrikeOut(tmp!="0");
03230 
03231       tmp=s[5]; if (!tmp.isEmpty()) i->setUnderline(tmp!="0");
03232 
03233       tmp=s[6]; if (!tmp.isEmpty()) {
03234         if ( tmp != "-" )
03235         {
03236           col=tmp.toUInt(0,16);
03237           i->setBGColor(col);
03238         }
03239         else
03240           i->clearAttribute(KateAttribute::BGColor);
03241       }
03242       tmp=s[7]; if (!tmp.isEmpty()) {
03243         if ( tmp != "-" )
03244         {
03245           col=tmp.toUInt(0,16);
03246           i->setSelectedBGColor(col);
03247         }
03248         else
03249           i->clearAttribute(KateAttribute::SelectedBGColor);
03250       }
03251     }
03252   }
03253 }
03254 
03255 void KateHlManager::setDefaults(uint schema, KateAttributeList &list)
03256 {
03257   KConfig *config =  KateHlManager::self()->self()->getKConfig();
03258   config->setGroup("Default Item Styles - Schema " + KateFactory::self()->schemaManager()->name(schema));
03259 
03260   for (uint z = 0; z < defaultStyles(); z++)
03261   {
03262     QStringList settings;
03263     KateAttribute *i = list.at(z);
03264 
03265     settings<<(i->itemSet(KateAttribute::TextColor)?QString::number(i->textColor().rgb(),16):"");
03266     settings<<(i->itemSet(KateAttribute::SelectedTextColor)?QString::number(i->selectedTextColor().rgb(),16):"");
03267     settings<<(i->itemSet(KateAttribute::Weight)?(i->bold()?"1":"0"):"");
03268     settings<<(i->itemSet(KateAttribute::Italic)?(i->italic()?"1":"0"):"");
03269     settings<<(i->itemSet(KateAttribute::StrikeOut)?(i->strikeOut()?"1":"0"):"");
03270     settings<<(i->itemSet(KateAttribute::Underline)?(i->underline()?"1":"0"):"");
03271     settings<<(i->itemSet(KateAttribute::BGColor)?QString::number(i->bgColor().rgb(),16):"-");
03272     settings<<(i->itemSet(KateAttribute::SelectedBGColor)?QString::number(i->selectedBGColor().rgb(),16):"-");
03273     settings<<"---";
03274 
03275     config->writeEntry(defaultStyleName(z),settings);
03276   }
03277 
03278   emit changed();
03279 }
03280 
03281 int KateHlManager::highlights()
03282 {
03283   return (int) hlList.count();
03284 }
03285 
03286 QString KateHlManager::hlName(int n)
03287 {
03288   return hlList.at(n)->name();
03289 }
03290 
03291 QString KateHlManager::hlNameTranslated(int n)
03292 {
03293   return hlList.at(n)->nameTranslated();
03294 }
03295 
03296 QString KateHlManager::hlSection(int n)
03297 {
03298   return hlList.at(n)->section();
03299 }
03300 
03301 bool KateHlManager::hlHidden(int n)
03302 {
03303   return hlList.at(n)->hidden();
03304 }
03305 
03306 QString KateHlManager::identifierForName(const QString& name)
03307 {
03308   KateHighlighting *hl = 0;
03309 
03310   if ((hl = hlDict[name]))
03311     return hl->getIdentifier ();
03312 
03313   return QString();
03314 }
03315 
03316 bool KateHlManager::resetDynamicCtxs()
03317 {
03318   if (forceNoDCReset)
03319     return false;
03320 
03321   if (lastCtxsReset.elapsed() < KATE_DYNAMIC_CONTEXTS_RESET_DELAY)
03322     return false;
03323 
03324   KateHighlighting *hl;
03325   for (hl = hlList.first(); hl; hl = hlList.next())
03326     hl->dropDynamicContexts();
03327 
03328   dynamicCtxsCount = 0;
03329   lastCtxsReset.start();
03330 
03331   return true;
03332 }
03333 //END
03334 
03335 //BEGIN KateHighlightAction
03336 void KateViewHighlightAction::init()
03337 {
03338   m_doc = 0;
03339   subMenus.setAutoDelete( true );
03340 
03341   connect(popupMenu(),SIGNAL(aboutToShow()),this,SLOT(slotAboutToShow()));
03342 }
03343 
03344 void KateViewHighlightAction::updateMenu (Kate::Document *doc)
03345 {
03346   m_doc = doc;
03347 }
03348 
03349 void KateViewHighlightAction::slotAboutToShow()
03350 {
03351   Kate::Document *doc=m_doc;
03352   int count = KateHlManager::self()->highlights();
03353 
03354   for (int z=0; z<count; z++)
03355   {
03356     QString hlName = KateHlManager::self()->hlNameTranslated (z);
03357     QString hlSection = KateHlManager::self()->hlSection (z);
03358 
03359     if (!KateHlManager::self()->hlHidden(z))
03360     {
03361       if ( !hlSection.isEmpty() && (names.contains(hlName) < 1) )
03362       {
03363         if (subMenusName.contains(hlSection) < 1)
03364         {
03365           subMenusName << hlSection;
03366           QPopupMenu *menu = new QPopupMenu ();
03367           subMenus.append(menu);
03368           popupMenu()->insertItem ( '&' + hlSection, menu);
03369         }
03370 
03371         int m = subMenusName.findIndex (hlSection);
03372         names << hlName;
03373         subMenus.at(m)->insertItem ( '&' + hlName, this, SLOT(setHl(int)), 0,  z);
03374       }
03375       else if (names.contains(hlName) < 1)
03376       {
03377         names << hlName;
03378         popupMenu()->insertItem ( '&' + hlName, this, SLOT(setHl(int)), 0,  z);
03379       }
03380     }
03381   }
03382 
03383   if (!doc) return;
03384 
03385   for (uint i=0;i<subMenus.count();i++)
03386   {
03387     for (uint i2=0;i2<subMenus.at(i)->count();i2++)
03388     {
03389       subMenus.at(i)->setItemChecked(subMenus.at(i)->idAt(i2),false);
03390     }
03391   }
03392   popupMenu()->setItemChecked (0, false);
03393 
03394   int i = subMenusName.findIndex (KateHlManager::self()->hlSection(doc->hlMode()));
03395   if (i >= 0 && subMenus.at(i))
03396     subMenus.at(i)->setItemChecked (doc->hlMode(), true);
03397   else
03398     popupMenu()->setItemChecked (0, true);
03399 }
03400 
03401 void KateViewHighlightAction::setHl (int mode)
03402 {
03403   Kate::Document *doc=m_doc;
03404 
03405   if (doc)
03406     doc->setHlMode((uint)mode);
03407 }
03408 //END KateViewHighlightAction
03409 
03410 // kate: space-indent on; indent-width 2; replace-tabs on;
KDE Logo
This file is part of the documentation for kate Library Version 3.4.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Apr 28 01:42:34 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003