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., 51 Franklin Street, Fifth Floor,
00020    Boston, MA 02110-1301, 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   const QChar *unicode = str.unicode();
00069   const uint len = str.length();
00070   for (uint i=0; i < len; i++)
00071     if (unicode[i] == ch)
00072       return true;
00073 
00074   return false;
00075 }
00076 
00077 class KateHlItem
00078 {
00079   public:
00080     KateHlItem(int attribute, int context,signed char regionId, signed char regionId2);
00081     virtual ~KateHlItem();
00082 
00083   public:
00084     // caller must keep in mind: LEN > 0 is a must !!!!!!!!!!!!!!!!!!!!!1
00085     // Now, the function returns the offset detected, or 0 if no match is found.
00086     // bool linestart isn't needed, this is equivalent to offset == 0.
00087     virtual int checkHgl(const QString& text, int offset, int len) = 0;
00088 
00089     virtual bool lineContinue(){return false;}
00090 
00091     virtual QStringList *capturedTexts() {return 0;}
00092     virtual KateHlItem *clone(const QStringList *) {return this;}
00093 
00094     static void dynamicSubstitute(QString& str, const QStringList *args);
00095 
00096     QMemArray<KateHlItem*> subItems;
00097     int attr;
00098     int ctx;
00099     signed char region;
00100     signed char region2;
00101 
00102     bool lookAhead;
00103 
00104     bool dynamic;
00105     bool dynamicChild;
00106     bool firstNonSpace;
00107     bool onlyConsume;
00108     int column;
00109 
00110     // start enable flags, nicer than the virtual methodes
00111     // saves function calls
00112     bool alwaysStartEnable;
00113     bool customStartEnable;
00114 };
00115 
00116 class KateHlContext
00117 {
00118   public:
00119     KateHlContext(const QString &_hlId, int attribute, int lineEndContext,int _lineBeginContext,
00120                   bool _fallthrough, int _fallthroughContext, bool _dynamic,bool _noIndentationBasedFolding);
00121     virtual ~KateHlContext();
00122     KateHlContext *clone(const QStringList *args);
00123 
00124     QValueVector<KateHlItem*> items;
00125     QString hlId; 
00126     int attr;
00127     int ctx;
00128     int lineBeginContext;
00134     bool fallthrough;
00135     int ftctx; // where to go after no rules matched
00136 
00137     bool dynamic;
00138     bool dynamicChild;
00139     bool noIndentationBasedFolding;
00140 };
00141 
00142 class KateEmbeddedHlInfo
00143 {
00144   public:
00145     KateEmbeddedHlInfo() {loaded=false;context0=-1;}
00146     KateEmbeddedHlInfo(bool l, int ctx0) {loaded=l;context0=ctx0;}
00147 
00148   public:
00149     bool loaded;
00150     int context0;
00151 };
00152 
00153 class KateHlIncludeRule
00154 {
00155   public:
00156     KateHlIncludeRule(int ctx_=0, uint pos_=0, const QString &incCtxN_="", bool incAttrib=false)
00157       : ctx(ctx_)
00158       , pos( pos_)
00159       , incCtxN( incCtxN_ )
00160       , includeAttrib( incAttrib )
00161     {
00162       incCtx=-1;
00163     }
00164     //KateHlIncludeRule(int ctx_, uint  pos_, bool incAttrib) {ctx=ctx_;pos=pos_;incCtx=-1;incCtxN="";includeAttrib=incAttrib}
00165 
00166   public:
00167     int ctx;
00168     uint pos;
00169     int incCtx;
00170     QString incCtxN;
00171     bool includeAttrib;
00172 };
00173 
00174 class KateHlCharDetect : public KateHlItem
00175 {
00176   public:
00177     KateHlCharDetect(int attribute, int context,signed char regionId,signed char regionId2, QChar);
00178 
00179     virtual int checkHgl(const QString& text, int offset, int len);
00180     virtual KateHlItem *clone(const QStringList *args);
00181 
00182   private:
00183     QChar sChar;
00184 };
00185 
00186 class KateHl2CharDetect : public KateHlItem
00187 {
00188   public:
00189     KateHl2CharDetect(int attribute, int context, signed char regionId,signed char regionId2,  QChar ch1, QChar ch2);
00190     KateHl2CharDetect(int attribute, int context,signed char regionId,signed char regionId2,  const QChar *ch);
00191 
00192     virtual int checkHgl(const QString& text, int offset, int len);
00193     virtual KateHlItem *clone(const QStringList *args);
00194 
00195   private:
00196     QChar sChar1;
00197     QChar sChar2;
00198 };
00199 
00200 class KateHlStringDetect : public KateHlItem
00201 {
00202   public:
00203     KateHlStringDetect(int attribute, int context, signed char regionId,signed char regionId2, const QString &, bool inSensitive=false);
00204 
00205     virtual int checkHgl(const QString& text, int offset, int len);
00206     virtual KateHlItem *clone(const QStringList *args);
00207 
00208   private:
00209     const QString str;
00210     const int strLen;
00211     const bool _inSensitive;
00212 };
00213 
00214 class KateHlRangeDetect : public KateHlItem
00215 {
00216   public:
00217     KateHlRangeDetect(int attribute, int context, signed char regionId,signed char regionId2, QChar ch1, QChar ch2);
00218 
00219     virtual int checkHgl(const QString& text, int offset, int len);
00220 
00221   private:
00222     QChar sChar1;
00223     QChar sChar2;
00224 };
00225 
00226 class KateHlKeyword : public KateHlItem
00227 {
00228   public:
00229     KateHlKeyword(int attribute, int context,signed char regionId,signed char regionId2, bool casesensitive, const QString& delims);
00230     virtual ~KateHlKeyword ();
00231 
00232     void addList(const QStringList &);
00233     virtual int checkHgl(const QString& text, int offset, int len);
00234 
00235   private:
00236     QMemArray< QDict<bool>* > dict;
00237     bool _caseSensitive;
00238     const QString& deliminators;
00239     int minLen;
00240     int maxLen;
00241 };
00242 
00243 class KateHlInt : public KateHlItem
00244 {
00245   public:
00246     KateHlInt(int attribute, int context, signed char regionId,signed char regionId2);
00247 
00248     virtual int checkHgl(const QString& text, int offset, int len);
00249 };
00250 
00251 class KateHlFloat : public KateHlItem
00252 {
00253   public:
00254     KateHlFloat(int attribute, int context, signed char regionId,signed char regionId2);
00255     virtual ~KateHlFloat () {}
00256 
00257     virtual int checkHgl(const QString& text, int offset, int len);
00258 };
00259 
00260 class KateHlCFloat : public KateHlFloat
00261 {
00262   public:
00263     KateHlCFloat(int attribute, int context, signed char regionId,signed char regionId2);
00264 
00265     virtual int checkHgl(const QString& text, int offset, int len);
00266     int checkIntHgl(const QString& text, int offset, int len);
00267 };
00268 
00269 class KateHlCOct : public KateHlItem
00270 {
00271   public:
00272     KateHlCOct(int attribute, int context, signed char regionId,signed char regionId2);
00273 
00274     virtual int checkHgl(const QString& text, int offset, int len);
00275 };
00276 
00277 class KateHlCHex : public KateHlItem
00278 {
00279   public:
00280     KateHlCHex(int attribute, int context, signed char regionId,signed char regionId2);
00281 
00282     virtual int checkHgl(const QString& text, int offset, int len);
00283 };
00284 
00285 class KateHlLineContinue : public KateHlItem
00286 {
00287   public:
00288     KateHlLineContinue(int attribute, int context, signed char regionId,signed char regionId2);
00289 
00290     virtual bool endEnable(QChar c) {return c == '\0';}
00291     virtual int checkHgl(const QString& text, int offset, int len);
00292     virtual bool lineContinue(){return true;}
00293 };
00294 
00295 class KateHlCStringChar : public KateHlItem
00296 {
00297   public:
00298     KateHlCStringChar(int attribute, int context, signed char regionId,signed char regionId2);
00299 
00300     virtual int checkHgl(const QString& text, int offset, int len);
00301 };
00302 
00303 class KateHlCChar : public KateHlItem
00304 {
00305   public:
00306     KateHlCChar(int attribute, int context,signed char regionId,signed char regionId2);
00307 
00308     virtual int checkHgl(const QString& text, int offset, int len);
00309 };
00310 
00311 class KateHlAnyChar : public KateHlItem
00312 {
00313   public:
00314     KateHlAnyChar(int attribute, int context, signed char regionId,signed char regionId2, const QString& charList);
00315 
00316     virtual int checkHgl(const QString& text, int offset, int len);
00317 
00318   private:
00319     const QString _charList;
00320 };
00321 
00322 class KateHlRegExpr : public KateHlItem
00323 {
00324   public:
00325     KateHlRegExpr(int attribute, int context,signed char regionId,signed char regionId2 ,QString expr, bool insensitive, bool minimal);
00326     ~KateHlRegExpr() { delete Expr; };
00327 
00328     virtual int checkHgl(const QString& text, int offset, int len);
00329     virtual QStringList *capturedTexts();
00330     virtual KateHlItem *clone(const QStringList *args);
00331 
00332   private:
00333     QRegExp *Expr;
00334     bool handlesLinestart;
00335     QString _regexp;
00336     bool _insensitive;
00337     bool _minimal;
00338 };
00339 
00340 class KateHlDetectSpaces : public KateHlItem
00341 {
00342   public:
00343     KateHlDetectSpaces (int attribute, int context,signed char regionId,signed char regionId2)
00344       : KateHlItem(attribute,context,regionId,regionId2) {}
00345 
00346     virtual int checkHgl(const QString& text, int offset, int len)
00347     {
00348       int len2 = offset + len;
00349       while ((offset < len2) && text[offset].isSpace()) offset++;
00350       return offset;
00351     }
00352 };
00353 
00354 class KateHlDetectIdentifier : public KateHlItem
00355 {
00356   public:
00357     KateHlDetectIdentifier (int attribute, int context,signed char regionId,signed char regionId2)
00358       : KateHlItem(attribute,context,regionId,regionId2) { alwaysStartEnable = false; }
00359 
00360     virtual int checkHgl(const QString& text, int offset, int len)
00361     {
00362       // first char should be a letter or underscore
00363       if ( text[offset].isLetter() || text[offset] == QChar ('_') )
00364       {
00365         // memorize length
00366         int len2 = offset+len;
00367 
00368         // one char seen
00369         offset++;
00370 
00371         // now loop for all other thingies
00372         while (
00373                (offset < len2)
00374                && (text[offset].isLetterOrNumber() || (text[offset] == QChar ('_')))
00375               )
00376           offset++;
00377 
00378         return offset;
00379       }
00380 
00381       return 0;
00382     }
00383 };
00384 
00385 //END
00386 
00387 //BEGIN STATICS
00388 KateHlManager *KateHlManager::s_self = 0;
00389 
00390 static const bool trueBool = true;
00391 static const QString stdDeliminator = QString (" \t.():!+,-<=>%&*/;?[]^{|}~\\");
00392 //END
00393 
00394 //BEGIN NON MEMBER FUNCTIONS
00395 static KateHlItemData::ItemStyles getDefStyleNum(QString name)
00396 {
00397   if (name=="dsNormal") return KateHlItemData::dsNormal;
00398   else if (name=="dsKeyword") return KateHlItemData::dsKeyword;
00399   else if (name=="dsDataType") return KateHlItemData::dsDataType;
00400   else if (name=="dsDecVal") return KateHlItemData::dsDecVal;
00401   else if (name=="dsBaseN") return KateHlItemData::dsBaseN;
00402   else if (name=="dsFloat") return KateHlItemData::dsFloat;
00403   else if (name=="dsChar") return KateHlItemData::dsChar;
00404   else if (name=="dsString") return KateHlItemData::dsString;
00405   else if (name=="dsComment") return KateHlItemData::dsComment;
00406   else if (name=="dsOthers")  return KateHlItemData::dsOthers;
00407   else if (name=="dsAlert") return KateHlItemData::dsAlert;
00408   else if (name=="dsFunction") return KateHlItemData::dsFunction;
00409   else if (name=="dsRegionMarker") return KateHlItemData::dsRegionMarker;
00410   else if (name=="dsError") return KateHlItemData::dsError;
00411 
00412   return KateHlItemData::dsNormal;
00413 }
00414 //END
00415 
00416 //BEGIN KateHlItem
00417 KateHlItem::KateHlItem(int attribute, int context,signed char regionId,signed char regionId2)
00418   : attr(attribute),
00419     ctx(context),
00420     region(regionId),
00421     region2(regionId2),
00422     lookAhead(false),
00423     dynamic(false),
00424     dynamicChild(false),
00425     firstNonSpace(false),
00426     onlyConsume(false),
00427     column (-1),
00428     alwaysStartEnable (true),
00429     customStartEnable (false)
00430 {
00431 }
00432 
00433 KateHlItem::~KateHlItem()
00434 {
00435   //kdDebug(13010)<<"In hlItem::~KateHlItem()"<<endl;
00436   for (uint i=0; i < subItems.size(); i++)
00437     delete subItems[i];
00438 }
00439 
00440 void KateHlItem::dynamicSubstitute(QString &str, const QStringList *args)
00441 {
00442   for (uint i = 0; i < str.length() - 1; ++i)
00443   {
00444     if (str[i] == '%')
00445     {
00446       char c = str[i + 1].latin1();
00447       if (c == '%')
00448         str.replace(i, 1, "");
00449       else if (c >= '0' && c <= '9')
00450       {
00451         if ((uint)(c - '0') < args->size())
00452         {
00453           str.replace(i, 2, (*args)[c - '0']);
00454           i += ((*args)[c - '0']).length() - 1;
00455         }
00456         else
00457         {
00458           str.replace(i, 2, "");
00459           --i;
00460         }
00461       }
00462     }
00463   }
00464 }
00465 //END
00466 
00467 //BEGIN KateHlCharDetect
00468 KateHlCharDetect::KateHlCharDetect(int attribute, int context, signed char regionId,signed char regionId2, QChar c)
00469   : KateHlItem(attribute,context,regionId,regionId2)
00470   , sChar(c)
00471 {
00472 }
00473 
00474 int KateHlCharDetect::checkHgl(const QString& text, int offset, int /*len*/)
00475 {
00476   if (text[offset] == sChar)
00477     return offset + 1;
00478 
00479   return 0;
00480 }
00481 
00482 KateHlItem *KateHlCharDetect::clone(const QStringList *args)
00483 {
00484   char c = sChar.latin1();
00485 
00486   if (c < '0' || c > '9' || (unsigned)(c - '0') >= args->size())
00487     return this;
00488 
00489   KateHlCharDetect *ret = new KateHlCharDetect(attr, ctx, region, region2, (*args)[c - '0'][0]);
00490   ret->dynamicChild = true;
00491   return ret;
00492 }
00493 //END
00494 
00495 //BEGIN KateHl2CharDetect
00496 KateHl2CharDetect::KateHl2CharDetect(int attribute, int context, signed char regionId,signed char regionId2, QChar ch1, QChar ch2)
00497   : KateHlItem(attribute,context,regionId,regionId2)
00498   , sChar1 (ch1)
00499   , sChar2 (ch2)
00500 {
00501 }
00502 
00503 int KateHl2CharDetect::checkHgl(const QString& text, int offset, int len)
00504 {
00505   if ((len >= 2) && text[offset++] == sChar1 && text[offset++] == sChar2)
00506     return offset;
00507 
00508   return 0;
00509 }
00510 
00511 KateHlItem *KateHl2CharDetect::clone(const QStringList *args)
00512 {
00513   char c1 = sChar1.latin1();
00514   char c2 = sChar2.latin1();
00515 
00516   if (c1 < '0' || c1 > '9' || (unsigned)(c1 - '0') >= args->size())
00517     return this;
00518 
00519   if (c2 < '0' || c2 > '9' || (unsigned)(c2 - '0') >= args->size())
00520     return this;
00521 
00522   KateHl2CharDetect *ret = new KateHl2CharDetect(attr, ctx, region, region2, (*args)[c1 - '0'][0], (*args)[c2 - '0'][0]);
00523   ret->dynamicChild = true;
00524   return ret;
00525 }
00526 //END
00527 
00528 //BEGIN KateHlStringDetect
00529 KateHlStringDetect::KateHlStringDetect(int attribute, int context, signed char regionId,signed char regionId2,const QString &s, bool inSensitive)
00530   : KateHlItem(attribute, context,regionId,regionId2)
00531   , str(inSensitive ? s.upper() : s)
00532   , strLen (str.length())
00533   , _inSensitive(inSensitive)
00534 {
00535 }
00536 
00537 int KateHlStringDetect::checkHgl(const QString& text, int offset, int len)
00538 {
00539   if (len < strLen)
00540     return 0;
00541 
00542   if (_inSensitive)
00543   {
00544     for (int i=0; i < strLen; i++)
00545       if (text[offset++].upper() != str[i])
00546         return 0;
00547 
00548     return offset;
00549   }
00550   else
00551   {
00552     for (int i=0; i < strLen; i++)
00553       if (text[offset++] != str[i])
00554         return 0;
00555 
00556     return offset;
00557   }
00558 
00559   return 0;
00560 }
00561 
00562 KateHlItem *KateHlStringDetect::clone(const QStringList *args)
00563 {
00564   QString newstr = str;
00565 
00566   dynamicSubstitute(newstr, args);
00567 
00568   if (newstr == str)
00569     return this;
00570 
00571   KateHlStringDetect *ret = new KateHlStringDetect(attr, ctx, region, region2, newstr, _inSensitive);
00572   ret->dynamicChild = true;
00573   return ret;
00574 }
00575 //END
00576 
00577 //BEGIN KateHlRangeDetect
00578 KateHlRangeDetect::KateHlRangeDetect(int attribute, int context, signed char regionId,signed char regionId2, QChar ch1, QChar ch2)
00579   : KateHlItem(attribute,context,regionId,regionId2)
00580   , sChar1 (ch1)
00581   , sChar2 (ch2)
00582 {
00583 }
00584 
00585 int KateHlRangeDetect::checkHgl(const QString& text, int offset, int len)
00586 {
00587   if (text[offset] == sChar1)
00588   {
00589     do
00590     {
00591       offset++;
00592       len--;
00593       if (len < 1) return 0;
00594     }
00595     while (text[offset] != sChar2);
00596 
00597     return offset + 1;
00598   }
00599   return 0;
00600 }
00601 //END
00602 
00603 //BEGIN KateHlKeyword
00604 KateHlKeyword::KateHlKeyword (int attribute, int context, signed char regionId,signed char regionId2, bool casesensitive, const QString& delims)
00605   : KateHlItem(attribute,context,regionId,regionId2)
00606   , _caseSensitive(casesensitive)
00607   , deliminators(delims)
00608   , minLen (0xFFFFFF)
00609   , maxLen (0)
00610 {
00611   alwaysStartEnable = false;
00612   customStartEnable = true;
00613 }
00614 
00615 KateHlKeyword::~KateHlKeyword ()
00616 {
00617   for (uint i=0; i < dict.size(); ++i)
00618     delete dict[i];
00619 }
00620 
00621 void KateHlKeyword::addList(const QStringList& list)
00622 {
00623   for(uint i=0; i < list.count(); ++i)
00624   {
00625     int len = list[i].length();
00626 
00627     if (minLen > len)
00628       minLen = len;
00629 
00630     if (maxLen < len)
00631       maxLen = len;
00632 
00633     if ((uint)len >= dict.size())
00634     {
00635       uint oldSize = dict.size();
00636       dict.resize (len+1);
00637 
00638       for (uint m=oldSize; m < dict.size(); ++m)
00639         dict[m] = 0;
00640     }
00641 
00642     if (!dict[len])
00643       dict[len] = new QDict<bool> (17, _caseSensitive);
00644 
00645     dict[len]->insert(list[i], &trueBool);
00646   }
00647 }
00648 
00649 int KateHlKeyword::checkHgl(const QString& text, int offset, int len)
00650 {
00651   int offset2 = offset;
00652   int wordLen = 0;
00653 
00654   while ((len > wordLen) && !kateInsideString (deliminators, text[offset2]))
00655   {
00656     offset2++;
00657     wordLen++;
00658 
00659     if (wordLen > maxLen) return 0;
00660   }
00661 
00662   if (wordLen < minLen) return 0;
00663 
00664   if ( dict[wordLen] && dict[wordLen]->find(QConstString(text.unicode() + offset, wordLen).string()) )
00665     return offset2;
00666 
00667   return 0;
00668 }
00669 //END
00670 
00671 //BEGIN KateHlInt
00672 KateHlInt::KateHlInt(int attribute, int context, signed char regionId,signed char regionId2)
00673   : KateHlItem(attribute,context,regionId,regionId2)
00674 {
00675   alwaysStartEnable = false;
00676 }
00677 
00678 int KateHlInt::checkHgl(const QString& text, int offset, int len)
00679 {
00680   int offset2 = offset;
00681 
00682   while ((len > 0) && text[offset2].isDigit())
00683   {
00684     offset2++;
00685     len--;
00686   }
00687 
00688   if (offset2 > offset)
00689   {
00690     if (len > 0)
00691     {
00692       for (uint i=0; i < subItems.size(); i++)
00693       {
00694         if ( (offset = subItems[i]->checkHgl(text, offset2, len)) )
00695           return offset;
00696       }
00697     }
00698 
00699     return offset2;
00700   }
00701 
00702   return 0;
00703 }
00704 //END
00705 
00706 //BEGIN KateHlFloat
00707 KateHlFloat::KateHlFloat(int attribute, int context, signed char regionId,signed char regionId2)
00708   : KateHlItem(attribute,context, regionId,regionId2)
00709 {
00710   alwaysStartEnable = false;
00711 }
00712 
00713 int KateHlFloat::checkHgl(const QString& text, int offset, int len)
00714 {
00715   bool b = false;
00716   bool p = false;
00717 
00718   while ((len > 0) && text[offset].isDigit())
00719   {
00720     offset++;
00721     len--;
00722     b = true;
00723   }
00724 
00725   if ((len > 0) && (p = (text[offset] == '.')))
00726   {
00727     offset++;
00728     len--;
00729 
00730     while ((len > 0) && text[offset].isDigit())
00731     {
00732       offset++;
00733       len--;
00734       b = true;
00735     }
00736   }
00737 
00738   if (!b)
00739     return 0;
00740 
00741   if ((len > 0) && ((text[offset] & 0xdf) == 'E'))
00742   {
00743     offset++;
00744     len--;
00745   }
00746   else
00747   {
00748     if (!p)
00749       return 0;
00750     else
00751     {
00752       if (len > 0)
00753       {
00754         for (uint i=0; i < subItems.size(); i++)
00755         {
00756           int offset2 = subItems[i]->checkHgl(text, offset, len);
00757 
00758           if (offset2)
00759             return offset2;
00760         }
00761       }
00762 
00763       return offset;
00764     }
00765   }
00766 
00767   if ((len > 0) && (text[offset] == '-' || text[offset] =='+'))
00768   {
00769     offset++;
00770     len--;
00771   }
00772 
00773   b = false;
00774 
00775   while ((len > 0) && text[offset].isDigit())
00776   {
00777     offset++;
00778     len--;
00779     b = true;
00780   }
00781 
00782   if (b)
00783   {
00784     if (len > 0)
00785     {
00786       for (uint i=0; i < subItems.size(); i++)
00787       {
00788         int offset2 = subItems[i]->checkHgl(text, offset, len);
00789 
00790         if (offset2)
00791           return offset2;
00792       }
00793     }
00794 
00795     return offset;
00796   }
00797 
00798   return 0;
00799 }
00800 //END
00801 
00802 //BEGIN KateHlCOct
00803 KateHlCOct::KateHlCOct(int attribute, int context, signed char regionId,signed char regionId2)
00804   : KateHlItem(attribute,context,regionId,regionId2)
00805 {
00806   alwaysStartEnable = false;
00807 }
00808 
00809 int KateHlCOct::checkHgl(const QString& text, int offset, int len)
00810 {
00811   if (text[offset] == '0')
00812   {
00813     offset++;
00814     len--;
00815 
00816     int offset2 = offset;
00817 
00818     while ((len > 0) && (text[offset2] >= '0' && text[offset2] <= '7'))
00819     {
00820       offset2++;
00821       len--;
00822     }
00823 
00824     if (offset2 > offset)
00825     {
00826       if ((len > 0) && ((text[offset2] & 0xdf) == 'L' || (text[offset] & 0xdf) == 'U' ))
00827         offset2++;
00828 
00829       return offset2;
00830     }
00831   }
00832 
00833   return 0;
00834 }
00835 //END
00836 
00837 //BEGIN KateHlCHex
00838 KateHlCHex::KateHlCHex(int attribute, int context,signed char regionId,signed char regionId2)
00839   : KateHlItem(attribute,context,regionId,regionId2)
00840 {
00841   alwaysStartEnable = false;
00842 }
00843 
00844 int KateHlCHex::checkHgl(const QString& text, int offset, int len)
00845 {
00846   if ((len > 1) && (text[offset++] == '0') && ((text[offset++] & 0xdf) == 'X' ))
00847   {
00848     len -= 2;
00849 
00850     int offset2 = offset;
00851 
00852     while ((len > 0) && (text[offset2].isDigit() || ((text[offset2] & 0xdf) >= 'A' && (text[offset2] & 0xdf) <= 'F')))
00853     {
00854       offset2++;
00855       len--;
00856     }
00857 
00858     if (offset2 > offset)
00859     {
00860       if ((len > 0) && ((text[offset2] & 0xdf) == 'L' || (text[offset2] & 0xdf) == 'U' ))
00861         offset2++;
00862 
00863       return offset2;
00864     }
00865   }
00866 
00867   return 0;
00868 }
00869 //END
00870 
00871 //BEGIN KateHlCFloat
00872 KateHlCFloat::KateHlCFloat(int attribute, int context, signed char regionId,signed char regionId2)
00873   : KateHlFloat(attribute,context,regionId,regionId2)
00874 {
00875   alwaysStartEnable = false;
00876 }
00877 
00878 int KateHlCFloat::checkIntHgl(const QString& text, int offset, int len)
00879 {
00880   int offset2 = offset;
00881 
00882   while ((len > 0) && text[offset].isDigit()) {
00883     offset2++;
00884     len--;
00885   }
00886 
00887   if (offset2 > offset)
00888      return offset2;
00889 
00890   return 0;
00891 }
00892 
00893 int KateHlCFloat::checkHgl(const QString& text, int offset, int len)
00894 {
00895   int offset2 = KateHlFloat::checkHgl(text, offset, len);
00896 
00897   if (offset2)
00898   {
00899     if ((text[offset2] & 0xdf) == 'F' )
00900       offset2++;
00901 
00902     return offset2;
00903   }
00904   else
00905   {
00906     offset2 = checkIntHgl(text, offset, len);
00907 
00908     if (offset2 && ((text[offset2] & 0xdf) == 'F' ))
00909       return ++offset2;
00910     else
00911       return 0;
00912   }
00913 }
00914 //END
00915 
00916 //BEGIN KateHlAnyChar
00917 KateHlAnyChar::KateHlAnyChar(int attribute, int context, signed char regionId,signed char regionId2, const QString& charList)
00918   : KateHlItem(attribute, context,regionId,regionId2)
00919   , _charList(charList)
00920 {
00921 }
00922 
00923 int KateHlAnyChar::checkHgl(const QString& text, int offset, int)
00924 {
00925   if (kateInsideString (_charList, text[offset]))
00926     return ++offset;
00927 
00928   return 0;
00929 }
00930 //END
00931 
00932 //BEGIN KateHlRegExpr
00933 KateHlRegExpr::KateHlRegExpr( int attribute, int context, signed char regionId,signed char regionId2, QString regexp, bool insensitive, bool minimal)
00934   : KateHlItem(attribute, context, regionId,regionId2)
00935   , handlesLinestart (regexp.startsWith("^"))
00936   , _regexp(regexp)
00937   , _insensitive(insensitive)
00938   , _minimal(minimal)
00939 {
00940   if (!handlesLinestart)
00941     regexp.prepend("^");
00942 
00943   Expr = new QRegExp(regexp, !_insensitive);
00944   Expr->setMinimal(_minimal);
00945 }
00946 
00947 int KateHlRegExpr::checkHgl(const QString& text, int offset, int /*len*/)
00948 {
00949   if (offset && handlesLinestart)
00950     return 0;
00951 
00952   int offset2 = Expr->search( text, offset, QRegExp::CaretAtOffset );
00953 
00954   if (offset2 == -1) return 0;
00955 
00956   return (offset + Expr->matchedLength());
00957 }
00958 
00959 QStringList *KateHlRegExpr::capturedTexts()
00960 {
00961   return new QStringList(Expr->capturedTexts());
00962 }
00963 
00964 KateHlItem *KateHlRegExpr::clone(const QStringList *args)
00965 {
00966   QString regexp = _regexp;
00967   QStringList escArgs = *args;
00968 
00969   for (QStringList::Iterator it = escArgs.begin(); it != escArgs.end(); ++it)
00970   {
00971     (*it).replace(QRegExp("(\\W)"), "\\\\1");
00972   }
00973 
00974   dynamicSubstitute(regexp, &escArgs);
00975 
00976   if (regexp == _regexp)
00977     return this;
00978 
00979   // kdDebug (13010) << "clone regexp: " << regexp << endl;
00980 
00981   KateHlRegExpr *ret = new KateHlRegExpr(attr, ctx, region, region2, regexp, _insensitive, _minimal);
00982   ret->dynamicChild = true;
00983   return ret;
00984 }
00985 //END
00986 
00987 //BEGIN KateHlLineContinue
00988 KateHlLineContinue::KateHlLineContinue(int attribute, int context, signed char regionId,signed char regionId2)
00989   : KateHlItem(attribute,context,regionId,regionId2) {
00990 }
00991 
00992 int KateHlLineContinue::checkHgl(const QString& text, int offset, int len)
00993 {
00994   if ((len == 1) && (text[offset] == '\\'))
00995     return ++offset;
00996 
00997   return 0;
00998 }
00999 //END
01000 
01001 //BEGIN KateHlCStringChar
01002 KateHlCStringChar::KateHlCStringChar(int attribute, int context,signed char regionId,signed char regionId2)
01003   : KateHlItem(attribute,context,regionId,regionId2) {
01004 }
01005 
01006 // checks for C escaped chars \n and escaped hex/octal chars
01007 static int checkEscapedChar(const QString& text, int offset, int& len)
01008 {
01009   int i;
01010   if (text[offset] == '\\' && len > 1)
01011   {
01012     offset++;
01013     len--;
01014 
01015     switch(text[offset])
01016     {
01017       case  'a': // checks for control chars
01018       case  'b': // we want to fall through
01019       case  'e':
01020       case  'f':
01021 
01022       case  'n':
01023       case  'r':
01024       case  't':
01025       case  'v':
01026       case '\'':
01027       case '\"':
01028       case '?' : // added ? ANSI C classifies this as an escaped char
01029       case '\\':
01030         offset++;
01031         len--;
01032         break;
01033 
01034       case 'x': // if it's like \xff
01035         offset++; // eat the x
01036         len--;
01037         // these for loops can probably be
01038         // replaced with something else but
01039         // for right now they work
01040         // check for hexdigits
01041         for (i = 0; (len > 0) && (i < 2) && (text[offset] >= '0' && text[offset] <= '9' || (text[offset] & 0xdf) >= 'A' && (text[offset] & 0xdf) <= 'F'); i++)
01042         {
01043           offset++;
01044           len--;
01045         }
01046 
01047         if (i == 0)
01048           return 0; // takes care of case '\x'
01049 
01050         break;
01051 
01052       case '0': case '1': case '2': case '3' :
01053       case '4': case '5': case '6': case '7' :
01054         for (i = 0; (len > 0) && (i < 3) && (text[offset] >='0'&& text[offset] <='7'); i++)
01055         {
01056           offset++;
01057           len--;
01058         }
01059         break;
01060 
01061       default:
01062         return 0;
01063     }
01064 
01065     return offset;
01066   }
01067 
01068   return 0;
01069 }
01070 
01071 int KateHlCStringChar::checkHgl(const QString& text, int offset, int len)
01072 {
01073   return checkEscapedChar(text, offset, len);
01074 }
01075 //END
01076 
01077 //BEGIN KateHlCChar
01078 KateHlCChar::KateHlCChar(int attribute, int context,signed char regionId,signed char regionId2)
01079   : KateHlItem(attribute,context,regionId,regionId2) {
01080 }
01081 
01082 int KateHlCChar::checkHgl(const QString& text, int offset, int len)
01083 {
01084   if ((len > 1) && (text[offset] == '\'') && (text[offset+1] != '\''))
01085   {
01086     int oldl;
01087     oldl = len;
01088 
01089     len--;
01090 
01091     int offset2 = checkEscapedChar(text, offset + 1, len);
01092 
01093     if (!offset2)
01094     {
01095       if (oldl > 2)
01096       {
01097         offset2 = offset + 2;
01098         len = oldl - 2;
01099       }
01100       else
01101       {
01102         return 0;
01103       }
01104     }
01105 
01106     if ((len > 0) && (text[offset2] == '\''))
01107       return ++offset2;
01108   }
01109 
01110   return 0;
01111 }
01112 //END
01113 
01114 //BEGIN KateHl2CharDetect
01115 KateHl2CharDetect::KateHl2CharDetect(int attribute, int context, signed char regionId,signed char regionId2, const QChar *s)
01116   : KateHlItem(attribute,context,regionId,regionId2) {
01117   sChar1 = s[0];
01118   sChar2 = s[1];
01119   }
01120 //END KateHl2CharDetect
01121 
01122 KateHlItemData::KateHlItemData(const QString  name, int defStyleNum)
01123   : name(name), defStyleNum(defStyleNum) {
01124 }
01125 
01126 KateHlData::KateHlData(const QString &wildcards, const QString &mimetypes, const QString &identifier, int priority)
01127   : wildcards(wildcards), mimetypes(mimetypes), identifier(identifier), priority(priority)
01128 {
01129 }
01130 
01131 //BEGIN KateHlContext
01132 KateHlContext::KateHlContext (const QString &_hlId, int attribute, int lineEndContext, int _lineBeginContext, bool _fallthrough,
01133     int _fallthroughContext, bool _dynamic, bool _noIndentationBasedFolding)
01134 {
01135   hlId = _hlId;
01136   attr = attribute;
01137   ctx = lineEndContext;
01138   lineBeginContext = _lineBeginContext;
01139   fallthrough = _fallthrough;
01140   ftctx = _fallthroughContext;
01141   dynamic = _dynamic;
01142   dynamicChild = false;
01143   noIndentationBasedFolding=_noIndentationBasedFolding;
01144   if (_noIndentationBasedFolding) kdDebug(13010)<<QString("**********************_noIndentationBasedFolding is TRUE*****************")<<endl;
01145 
01146 }
01147 
01148 KateHlContext *KateHlContext::clone(const QStringList *args)
01149 {
01150   KateHlContext *ret = new KateHlContext(hlId, attr, ctx, lineBeginContext, fallthrough, ftctx, false,noIndentationBasedFolding);
01151 
01152   for (uint n=0; n < items.size(); ++n)
01153   {
01154     KateHlItem *item = items[n];
01155     KateHlItem *i = (item->dynamic ? item->clone(args) : item);
01156     ret->items.append(i);
01157   }
01158 
01159   ret->dynamicChild = true;
01160 
01161   return ret;
01162 }
01163 
01164 KateHlContext::~KateHlContext()
01165 {
01166   if (dynamicChild)
01167   {
01168     for (uint n=0; n < items.size(); ++n)
01169     {
01170       if (items[n]->dynamicChild)
01171         delete items[n];
01172     }
01173   }
01174 }
01175 //END
01176 
01177 //BEGIN KateHighlighting
01178 KateHighlighting::KateHighlighting(const KateSyntaxModeListItem *def) : refCount(0)
01179 {
01180   m_attributeArrays.setAutoDelete (true);
01181 
01182   errorsAndWarnings = "";
01183   building=false;
01184   noHl = false;
01185   m_foldingIndentationSensitive = false;
01186   folding=false;
01187   internalIDList.setAutoDelete(true);
01188 
01189   if (def == 0)
01190   {
01191     noHl = true;
01192     iName = "None"; // not translated internal name (for config and more)
01193     iNameTranslated = i18n("None"); // user visible name
01194     iSection = "";
01195     m_priority = 0;
01196     iHidden = false;
01197     m_additionalData.insert( "none", new HighlightPropertyBag );
01198     m_additionalData["none"]->deliminator = stdDeliminator;
01199     m_additionalData["none"]->wordWrapDeliminator = stdDeliminator;
01200     m_hlIndex[0] = "none";
01201   }
01202   else
01203   {
01204     iName = def->name;
01205     iNameTranslated = def->nameTranslated;
01206     iSection = def->section;
01207     iHidden = def->hidden;
01208     iWildcards = def->extension;
01209     iMimetypes = def->mimetype;
01210     identifier = def->identifier;
01211     iVersion=def->version;
01212     iAuthor=def->author;
01213     iLicense=def->license;
01214     m_priority=def->priority.toInt();
01215   }
01216 
01217    deliminator = stdDeliminator;
01218 }
01219 
01220 KateHighlighting::~KateHighlighting()
01221 {
01222   // cu contexts
01223   for (uint i=0; i < m_contexts.size(); ++i)
01224     delete m_contexts[i];
01225   m_contexts.clear ();
01226 }
01227 
01228 void KateHighlighting::generateContextStack(int *ctxNum, int ctx, QMemArray<short>* ctxs, int *prevLine)
01229 {
01230   //kdDebug(13010)<<QString("Entering generateContextStack with %1").arg(ctx)<<endl;
01231   while (true)
01232   {
01233     if (ctx >= 0)
01234     {
01235       (*ctxNum) = ctx;
01236 
01237       ctxs->resize (ctxs->size()+1, QGArray::SpeedOptim);
01238       (*ctxs)[ctxs->size()-1]=(*ctxNum);
01239 
01240       return;
01241     }
01242     else
01243     {
01244       if (ctx == -1)
01245       {
01246         (*ctxNum)=( (ctxs->isEmpty() ) ? 0 : (*ctxs)[ctxs->size()-1]);
01247       }
01248       else
01249       {
01250         int size = ctxs->size() + ctx + 1;
01251 
01252         if (size > 0)
01253         {
01254           ctxs->resize (size, QGArray::SpeedOptim);
01255           (*ctxNum)=(*ctxs)[size-1];
01256         }
01257         else
01258         {
01259           ctxs->resize (0, QGArray::SpeedOptim);
01260           (*ctxNum)=0;
01261         }
01262 
01263         ctx = 0;
01264 
01265         if ((*prevLine) >= (int)(ctxs->size()-1))
01266         {
01267           *prevLine=ctxs->size()-1;
01268 
01269           if ( ctxs->isEmpty() )
01270             return;
01271 
01272           KateHlContext *c = contextNum((*ctxs)[ctxs->size()-1]);
01273           if (c && (c->ctx != -1))
01274           {
01275             //kdDebug(13010)<<"PrevLine > size()-1 and ctx!=-1)"<<endl;
01276             ctx = c->ctx;
01277 
01278             continue;
01279           }
01280         }
01281       }
01282 
01283       return;
01284     }
01285   }
01286 }
01287 
01291 int KateHighlighting::makeDynamicContext(KateHlContext *model, const QStringList *args)
01292 {
01293   QPair<KateHlContext *, QString> key(model, args->front());
01294   short value;
01295 
01296   if (dynamicCtxs.contains(key))
01297     value = dynamicCtxs[key];
01298   else
01299   {
01300     kdDebug(13010) << "new stuff: " << startctx << endl;
01301 
01302     KateHlContext *newctx = model->clone(args);
01303 
01304     m_contexts.push_back (newctx);
01305 
01306     value = startctx++;
01307     dynamicCtxs[key] = value;
01308     KateHlManager::self()->incDynamicCtxs();
01309   }
01310 
01311   // kdDebug(13010) << "Dynamic context: using context #" << value << " (for model " << model << " with args " << *args << ")" << endl;
01312 
01313   return value;
01314 }
01315 
01320 void KateHighlighting::dropDynamicContexts()
01321 {
01322   for (uint i=base_startctx; i < m_contexts.size(); ++i)
01323     delete m_contexts[i];
01324 
01325   m_contexts.resize (base_startctx);
01326 
01327   dynamicCtxs.clear();
01328   startctx = base_startctx;
01329 }
01330 
01339 void KateHighlighting::doHighlight ( KateTextLine *prevLine,
01340                                      KateTextLine *textLine,
01341                                      QMemArray<uint>* foldingList,
01342                                      bool *ctxChanged )
01343 {
01344   if (!textLine)
01345     return;
01346 
01347   if (noHl)
01348   {
01349     if (textLine->length() > 0)
01350       memset (textLine->attributes(), 0, textLine->length());
01351 
01352     return;
01353   }