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