• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

Kate

katehighlight.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002    Copyright (C) 2007 Mirko Stocker <me@misto.ch>
00003    Copyright (C) 2003, 2004 Anders Lund <anders@alweb.dk>
00004    Copyright (C) 2003 Hamish Rodda <rodda@kde.org>
00005    Copyright (C) 2001,2002 Joseph Wenninger <jowenn@kde.org>
00006    Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org>
00007    Copyright (C) 1999 Jochen Wilhelmy <digisnap@cs.tu-berlin.de>
00008 
00009    This library is free software; you can redistribute it and/or
00010    modify it under the terms of the GNU Library General Public
00011    License version 2 as published by the Free Software Foundation.
00012 
00013    This library is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016    Library General Public License for more details.
00017 
00018    You should have received a copy of the GNU Library General Public License
00019    along with this library; see the file COPYING.LIB.  If not, write to
00020    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00021    Boston, MA 02110-1301, USA.
00022 */
00023 
00024 //BEGIN INCLUDES
00025 #include "katehighlight.h"
00026 
00027 #include "katehighlighthelpers.h"
00028 #include "katetextline.h"
00029 #include "katedocument.h"
00030 #include "katesyntaxdocument.h"
00031 #include "katerenderer.h"
00032 #include "kateglobal.h"
00033 #include "kateschema.h"
00034 #include "kateconfig.h"
00035 #include "kateextendedattribute.h"
00036 
00037 #include <kconfig.h>
00038 #include <kglobal.h>
00039 #include <kcomponentdata.h>
00040 #include <kmimetype.h>
00041 #include <klocale.h>
00042 #include <kmenu.h>
00043 #include <kglobalsettings.h>
00044 #include <kdebug.h>
00045 #include <kstandarddirs.h>
00046 #include <kmessagebox.h>
00047 #include <kapplication.h>
00048 
00049 #include <QtCore/QSet>
00050 #include <QtGui/QAction>
00051 #include <QtGui/QApplication>
00052 #include <QtCore/QStringList>
00053 #include <QtCore/QTextStream>
00054 //END
00055 
00056 //BEGIN defines
00057 // x is a QString. if x is "true" or "1" this expression returns "true"
00058 #define IS_TRUE(x) x.toLower() == QLatin1String("true") || x.toInt() == 1
00059 //END defines
00060 
00061 //BEGIN STATICS
00062 static const QString stdDeliminator = QString (" \t.():!+,-<=>%&*/;?[]^{|}~\\");
00063 //END
00064 
00065 //BEGIN KateHighlighting
00066 KateHighlighting::KateHighlighting(const KateSyntaxModeListItem *def) : refCount(0)
00067 {
00068   errorsAndWarnings = "";
00069   building=false;
00070   noHl = false;
00071   m_foldingIndentationSensitive = false;
00072   folding=false;
00073 
00074   if (def == 0)
00075   {
00076     noHl = true;
00077     iName = "None"; // not translated internal name (for config and more)
00078     iNameTranslated = i18nc("Syntax highlighting", "None"); // user visible name
00079     iSection = "";
00080     iHidden = false;
00081     m_additionalData.insert( "none", new HighlightPropertyBag );
00082     m_additionalData["none"]->deliminator = stdDeliminator;
00083     m_additionalData["none"]->wordWrapDeliminator = stdDeliminator;
00084     m_hlIndex[0] = "none";
00085   }
00086   else
00087   {
00088     iName = def->name;
00089     iNameTranslated = def->nameTranslated;
00090     iSection = def->section;
00091     iHidden = def->hidden;
00092     identifier = def->identifier;
00093     iVersion=def->version;
00094     iStyle = def->style;
00095     iAuthor=def->author;
00096     iLicense=def->license;
00097   }
00098 
00099    deliminator = stdDeliminator;
00100 }
00101 
00102 KateHighlighting::~KateHighlighting()
00103 {
00104   // cleanup ;)
00105   cleanup ();
00106 
00107   qDeleteAll(m_additionalData);
00108 }
00109 
00110 void KateHighlighting::cleanup ()
00111 {
00112   qDeleteAll (m_contexts);
00113   m_contexts.clear ();
00114 
00115   m_attributeArrays.clear ();
00116 
00117   internalIDList.clear();
00118 }
00119 
00120 KateHlContext *KateHighlighting::generateContextStack (QVector<short> &contextStack,
00121                                                        KateHlContextModification modification,
00122                                                        int &indexLastContextPreviousLine)
00123 {
00124   while (true)
00125   {
00126     switch (modification.type)
00127     {
00132       case KateHlContextModification::doNothing:
00133         return contextNum (contextStack.isEmpty() ? 0 : contextStack.last());
00134 
00139       case KateHlContextModification::doPush:
00140         contextStack.append (modification.newContext);
00141         return contextNum (modification.newContext);
00142 
00146       case KateHlContextModification::doPopsAndPush:
00147         // resize stack
00148         contextStack.resize ((modification.pops >= contextStack.size()) ? 0 : (contextStack.size() - modification.pops));
00149 
00150         // push imediate the new context....
00151         // don't handle the previous line stuff at all....
00152         // ### TODO ### think about this
00153         contextStack.append (modification.newContext);
00154         return contextNum (modification.newContext);
00155 
00159       default:
00160       {
00161         // resize stack
00162         contextStack.resize ((modification.pops >= contextStack.size()) ? 0 : (contextStack.size() - modification.pops));
00163 
00164         // handling of context of previous line....
00165         if (indexLastContextPreviousLine >= (contextStack.size()-1))
00166         {
00167           // set new index, if stack is empty, this is -1, done for eternity...
00168           indexLastContextPreviousLine = contextStack.size() - 1;
00169 
00170           // stack already empty, nothing to do...
00171           if ( contextStack.isEmpty() )
00172             return contextNum (0);
00173 
00174           KateHlContext *c = contextNum(contextStack.last());
00175 
00176           // this must be a valid context, or our context stack is borked....
00177           Q_ASSERT (c);
00178 
00179           // handle line end context as new modificationContext
00180           modification = c->lineEndContext;
00181           continue;
00182         }
00183 
00184         return contextNum (contextStack.isEmpty() ? 0 : contextStack.last());
00185       }
00186     }
00187   }
00188 
00189   // should never be reached
00190   Q_ASSERT (false);
00191 
00192   return contextNum (0);
00193 }
00194 
00198 int KateHighlighting::makeDynamicContext(KateHlContext *model, const QStringList *args)
00199 {
00200   QPair<KateHlContext *, QString> key(model, args->front());
00201   short value;
00202 
00203   if (dynamicCtxs.contains(key))
00204     value = dynamicCtxs[key];
00205   else
00206   {
00207     kDebug(13010) << "new stuff: " << startctx;
00208 
00209     KateHlContext *newctx = model->clone(args);
00210 
00211     m_contexts.push_back (newctx);
00212 
00213     value = startctx++;
00214     dynamicCtxs[key] = value;
00215     KateHlManager::self()->incDynamicCtxs();
00216   }
00217 
00218   // kDebug(13010) << "Dynamic context: using context #" << value << " (for model " << model << " with args " << *args << ")";
00219 
00220   return value;
00221 }
00222 
00227 void KateHighlighting::dropDynamicContexts()
00228 {
00229   for (int i=base_startctx; i < m_contexts.size(); ++i)
00230     delete m_contexts[i];
00231 
00232   m_contexts.resize (base_startctx);
00233 
00234   dynamicCtxs.clear();
00235   startctx = base_startctx;
00236 }
00237 
00246 void KateHighlighting::doHighlight ( KateTextLine *prevLine,
00247                                      KateTextLine *textLine,
00248                                      QVector<int> &foldingList,
00249                                      bool &ctxChanged )
00250 {
00251   if (!textLine)
00252     return;
00253 
00254   // in all cases, remove old hl, or we will grow to infinite ;)
00255   textLine->clearAttributes ();
00256 
00257   // no hl set, nothing to do more than the above cleaning ;)
00258   if (noHl) {
00259     textLine->addAttribute (0, textLine->length(), KateExtendedAttribute::dsNormal);
00260     return;
00261   }
00262 
00263   // duplicate the ctx stack, only once !
00264   QVector<short> ctx (prevLine->ctxArray());
00265 
00266   int previousLine = -1;
00267   KateHlContext *context;
00268 
00269   if (ctx.isEmpty())
00270   {
00271     // If the stack is empty, we assume to be in Context 0 (Normal)
00272     context = contextNum(0);
00273   }
00274   else
00275   {
00276     //kDebug(13010) << "\t\tctxNum = " << ctxNum << " contextList[ctxNum] = " << contextList[ctxNum]; // ellis
00277 
00278     //if (lineContinue)   kDebug(13010)<<QString("The old context should be %1").arg((int)ctxNum);
00279     context = contextNum(ctx.last());
00280 
00281     //kDebug(13010)<<"test1-2-1-text2";
00282 
00283     previousLine = ctx.size()-1; //position of the last context ID of th previous line within the stack
00284 
00285     // hl continue set or not ???
00286     if (prevLine->hlLineContinue())
00287     {
00288       prevLine--;
00289     }
00290     else
00291     {
00292       context = generateContextStack(ctx, context->lineEndContext, previousLine); //get stack ID to use
00293     }
00294 
00295     //kDebug(13010)<<"test1-2-1-text4";
00296 
00297     //if (lineContinue)   kDebug(13010)<<QString("The new context is %1").arg((int)ctxNum);
00298   }
00299 
00300   // text, for programming convenience :)
00301   QChar lastChar = ' ';
00302   const QString& text = textLine->string();
00303   const int len = textLine->length();
00304 
00305   // calc at which char the first char occurs, set it to length of line if never
00306   const int firstChar = textLine->firstChar();
00307   const int startNonSpace = (firstChar == -1) ? len : firstChar;
00308 
00309   // last found item
00310   KateHlItem *item = 0;
00311 
00312   // loop over the line, offset gives current offset
00313   int offset = 0;
00314   while (offset < len)
00315   {
00316     bool anItemMatched = false;
00317     bool standardStartEnableDetermined = false;
00318     bool customStartEnableDetermined = false;
00319 
00320     int index = 0;
00321     
00322     for (item = context->items.value(0, 0); item; item = context->items.value(++index, 0))
00323     {
00324       // does we only match if we are firstNonSpace?
00325       if (item->firstNonSpace && (offset > startNonSpace))
00326         continue;
00327 
00328       // have we a column specified? if yes, only match at this column
00329       if ((item->column != -1) && (item->column != offset))
00330         continue;
00331 
00332       if (!item->alwaysStartEnable)
00333       {
00334         if (item->customStartEnable)
00335         {
00336             if (customStartEnableDetermined || m_additionalData[context->hlId]->deliminator.contains(lastChar))
00337             customStartEnableDetermined = true;
00338           else
00339             continue;
00340         }
00341         else
00342         {
00343           if (standardStartEnableDetermined || stdDeliminator.contains(lastChar))
00344             standardStartEnableDetermined = true;
00345           else
00346             continue;
00347         }
00348       }
00349 
00350       int offset2 = item->checkHgl(text, offset, len-offset);
00351 
00352       if (offset2 <= offset)
00353         continue;
00354       // BUG 144599: Ignore a context change that would push the same context
00355       // without eating anything... this would be an infinite loop!
00356       if ( item->lookAhead && ( item->ctx.pops < 2 && item->ctx.newContext == ( ctx.isEmpty() ? 0 : ctx.last() ) ) )
00357         continue;
00358 
00359       if (item->region2)
00360       {
00361         // kDebug(13010)<<QString("Region mark 2 detected: %1").arg(item->region2);
00362         if ( !foldingList.isEmpty() && ((item->region2 < 0) && (int)foldingList[foldingList.size()-2] == -item->region2 ) )
00363         {
00364           foldingList.resize (foldingList.size()-2);
00365         }
00366         else
00367         {
00368           foldingList.resize (foldingList.size()+2);
00369           foldingList[foldingList.size()-2] = (uint)item->region2;
00370           if (item->region2<0) //check not really needed yet
00371             foldingList[foldingList.size()-1] = offset2;
00372           else
00373             foldingList[foldingList.size()-1] = offset;
00374         }
00375 
00376       }
00377 
00378       if (item->region)
00379       {
00380         // kDebug(13010)<<QString("Region mark detected: %1").arg(item->region);
00381 
00382       /* if ( !foldingList->isEmpty() && ((item->region < 0) && (*foldingList)[foldingList->size()-1] == -item->region ) )
00383         {
00384           foldingList->resize (foldingList->size()-1, QGArray::SpeedOptim);
00385         }
00386         else*/
00387         {
00388           foldingList.resize (foldingList.size()+2);
00389           foldingList[foldingList.size()-2] = item->region;
00390           if (item->region<0) //check not really needed yet
00391             foldingList[foldingList.size()-1] = offset2;
00392           else
00393             foldingList[foldingList.size()-1] = offset;
00394         }
00395 
00396       }
00397 
00398       // regenerate context stack if needed
00399       context = generateContextStack (ctx, item->ctx, previousLine);
00400 
00401       // dynamic context: substitute the model with an 'instance'
00402       if (context->dynamic)
00403       {
00404         QStringList *lst = item->capturedTexts();
00405         if (lst != 0)
00406         {
00407           // Replace the top of the stack and the current context
00408           int newctx = makeDynamicContext(context, lst);
00409           if (ctx.size() > 0)
00410             ctx[ctx.size() - 1] = newctx;
00411 
00412           context = contextNum(newctx);
00413         }
00414         delete lst;
00415       }
00416 
00417       // dominik: look ahead w/o changing offset?
00418       if (!item->lookAhead)
00419       {
00420         if (offset2 > len)
00421           offset2 = len;
00422 
00423         // even set attributes ;)
00424         int attribute = item->onlyConsume ? context->attr : item->attr;
00425         if (attribute > 0)
00426           textLine->addAttribute (offset, offset2-offset, attribute);
00427 
00428         offset = offset2;
00429         lastChar = text[offset-1];
00430       }
00431 
00432       anItemMatched = true;
00433       break;
00434     }
00435 
00436     // something matched, continue loop
00437     if (anItemMatched)
00438       continue;
00439 
00440     // nothing found: set attribute of one char
00441     // anders: unless this context does not want that!
00442     if ( context->fallthrough )
00443     {
00444     // set context to context->ftctx.
00445       context=generateContextStack(ctx, context->ftctx, previousLine);  //regenerate context stack
00446 
00447     //kDebug(13010)<<"context num after fallthrough at col "<<z<<": "<<ctxNum;
00448     // the next is necessary, as otherwise keyword (or anything using the std delimitor check)
00449     // immediately after fallthrough fails. Is it bad?
00450     // jowenn, can you come up with a nicer way to do this?
00451     /*  if (offset)
00452         lastChar = text[offset - 1];
00453       else
00454         lastChar = '\\';*/
00455       continue;
00456     }
00457     else
00458     {
00459       // set attribute if any
00460       if (context->attr > 0)
00461         textLine->addAttribute (offset, 1, context->attr);
00462 
00463       lastChar = text[offset];
00464       offset++;
00465     }
00466   }
00467 
00468   // has the context stack changed ?
00469   if (ctx == textLine->ctxArray())
00470   {
00471     ctxChanged = false;
00472   }
00473   else
00474   {
00475     ctxChanged = true;
00476 
00477     // assign ctx stack !
00478     textLine->setContext(ctx);
00479   }
00480 
00481   // write hl continue flag
00482   textLine->setHlLineContinue (item && item->lineContinue());
00483 
00484   if (m_foldingIndentationSensitive) {
00485     bool noindent=false;
00486     for(int i=ctx.size()-1; i>=0; --i) {
00487       if (contextNum(ctx[i])->noIndentationBasedFolding) {
00488         noindent=true;
00489         break;
00490       }
00491     }
00492     textLine->setNoIndentBasedFolding(noindent);
00493   }
00494 
00495   //set the dsNormal attribute if we haven't found anything else
00496   if(textLine->attributesList().empty()) {
00497     textLine->addAttribute (0, textLine->length(), KateExtendedAttribute::dsNormal);
00498   }
00499 }
00500 
00501 void KateHighlighting::getKateExtendedAttributeList (const QString &schema, QList<KateExtendedAttribute::Ptr> &list)
00502 {
00503   KConfigGroup config(KateHlManager::self()->getKConfig(),
00504                       "Highlighting " + iName + " - Schema " + schema);
00505 
00506   list.clear();
00507   createKateExtendedAttribute(list);
00508 
00509   foreach (KateExtendedAttribute::Ptr p, list)
00510   {
00511     Q_ASSERT(p);
00512 
00513     QStringList s = config.readEntry(p->name(), QStringList());
00514 
00515 //    kDebug(13010)<<p->name<<s.count();
00516     if (s.count()>0)
00517     {
00518 
00519       while(s.count()<9) s<<"";
00520       p->clear();
00521 
00522       QString tmp=s[0]; if (!tmp.isEmpty()) p->setDefaultStyleIndex(tmp.toInt());
00523 
00524       QRgb col;
00525 
00526       tmp=s[1]; if (!tmp.isEmpty()) {
00527          col=tmp.toUInt(0,16); p->setForeground(QColor(col)); }
00528 
00529       tmp=s[2]; if (!tmp.isEmpty()) {
00530          col=tmp.toUInt(0,16); p->setSelectedForeground(QColor(col)); }
00531 
00532       tmp=s[3]; if (!tmp.isEmpty()) p->setFontBold(tmp!="0");
00533 
00534       tmp=s[4]; if (!tmp.isEmpty()) p->setFontItalic(tmp!="0");
00535 
00536       tmp=s[5]; if (!tmp.isEmpty()) p->setFontStrikeOut(tmp!="0");
00537 
00538       tmp=s[6]; if (!tmp.isEmpty()) p->setFontUnderline(tmp!="0");
00539 
00540       tmp=s[7]; if (!tmp.isEmpty()) {
00541          col=tmp.toUInt(0,16); p->setBackground(QColor(col)); }
00542 
00543       tmp=s[8]; if (!tmp.isEmpty()) {
00544          col=tmp.toUInt(0,16); p->setSelectedBackground(QColor(col)); }
00545 
00546     }
00547   }
00548 }
00549 
00550 void KateHighlighting::getKateExtendedAttributeListCopy( const QString &schema, QList< KateExtendedAttribute::Ptr >& list )
00551 {
00552   QList<KateExtendedAttribute::Ptr> attributes;
00553   getKateExtendedAttributeList(schema, attributes);
00554 
00555   list.clear();
00556 
00557   foreach (const KateExtendedAttribute::Ptr &attribute, attributes)
00558     list.append(KateExtendedAttribute::Ptr(new KateExtendedAttribute(*attribute.data())));
00559 }
00560 
00561 
00568 void KateHighlighting::setKateExtendedAttributeList(uint schema, QList<KateExtendedAttribute::Ptr> &list)
00569 {
00570   KConfigGroup config(KateHlManager::self()->getKConfig(),
00571                       "Highlighting " + iName + " - Schema "
00572                       + KateGlobal::self()->schemaManager()->name(schema));
00573 
00574   QStringList settings;
00575 
00576   foreach (const KateExtendedAttribute::Ptr& p, list)
00577   {
00578     Q_ASSERT(p);
00579 
00580     settings.clear();
00581     settings<<QString::number(p->defaultStyleIndex(),10);
00582     settings<<(p->hasProperty(QTextFormat::ForegroundBrush)?QString::number(p->foreground().color().rgb(),16):"");
00583     settings<<(p->hasProperty(KTextEditor::Attribute::SelectedForeground)?QString::number(p->selectedForeground().color().rgb(),16):"");
00584     settings<<(p->hasProperty(QTextFormat::FontWeight)?(p->fontBold()?"1":"0"):"");
00585     settings<<(p->hasProperty(QTextFormat::FontItalic)?(p->fontItalic()?"1":"0"):"");
00586     settings<<(p->hasProperty(QTextFormat::FontStrikeOut)?(p->fontStrikeOut()?"1":"0"):"");
00587     settings<<(p->hasProperty(QTextFormat::FontUnderline)?(p->fontUnderline()?"1":"0"):"");
00588     settings<<(p->hasProperty(QTextFormat::BackgroundBrush)?QString::number(p->background().color().rgb(),16):"");
00589     settings<<(p->hasProperty(KTextEditor::Attribute::SelectedBackground)?QString::number(p->selectedBackground().color().rgb(),16):"");
00590     settings<<"---";
00591     config.writeEntry(p->name(),settings);
00592   }
00593 }
00594 
00598 void KateHighlighting::use()
00599 {
00600   if (refCount == 0)
00601     init();
00602 
00603   refCount++;
00604 }
00605 
00609 void KateHighlighting::release()
00610 {
00611   refCount--;
00612 
00613   if (refCount == 0)
00614     done();
00615 }
00616 
00621 void KateHighlighting::init()
00622 {
00623   if (noHl)
00624     return;
00625 
00626   // cu contexts
00627   for (int i=0; i < m_contexts.size(); ++i)
00628     delete m_contexts[i];
00629   m_contexts.clear ();
00630 
00631   makeContextList();
00632 }
00633 
00634 
00639 void KateHighlighting::done()
00640 {
00641   if (noHl)
00642     return;
00643 
00644   cleanup ();
00645 }
00646 
00654 void KateHighlighting::createKateExtendedAttribute(QList<KateExtendedAttribute::Ptr> &list)
00655 {
00656   // If no highlighting is selected we need only one default.
00657   if (noHl)
00658   {
00659     list.append(KateExtendedAttribute::Ptr(new KateExtendedAttribute(i18n("Normal Text"), KateExtendedAttribute::dsNormal)));
00660     return;
00661   }
00662 
00663   // If the internal list isn't already available read the config file
00664   if (internalIDList.isEmpty())
00665     makeContextList();
00666 
00667   list=internalIDList;
00668 }
00669 
00673 void KateHighlighting::addToKateExtendedAttributeList()
00674 {
00675   //Tell the syntax document class which file we want to parse and which data group
00676   KateHlManager::self()->syntax->setIdentifier(buildIdentifier);
00677   KateSyntaxContextData *data = KateHlManager::self()->syntax->getGroupInfo("highlighting","itemData");
00678 
00679   //begin with the real parsing
00680   while (KateHlManager::self()->syntax->nextGroup(data))
00681   {
00682     // read all attributes
00683     QString color = KateHlManager::self()->syntax->groupData(data,QString("color"));
00684     QString selColor = KateHlManager::self()->syntax->groupData(data,QString("selColor"));
00685     QString bold = KateHlManager::self()->syntax->groupData(data,QString("bold"));
00686     QString italic = KateHlManager::self()->syntax->groupData(data,QString("italic"));
00687     QString underline = KateHlManager::self()->syntax->groupData(data,QString("underline"));
00688     QString strikeOut = KateHlManager::self()->syntax->groupData(data,QString("strikeOut"));
00689     QString bgColor = KateHlManager::self()->syntax->groupData(data,QString("backgroundColor"));
00690     QString selBgColor = KateHlManager::self()->syntax->groupData(data,QString("selBackgroundColor"));
00691 
00692     KateExtendedAttribute::Ptr newData(new KateExtendedAttribute(
00693             buildPrefix+KateHlManager::self()->syntax->groupData(data,QString("name")).simplified(),
00694             KateExtendedAttribute::indexForStyleName(KateHlManager::self()->syntax->groupData(data,QString("defStyleNum")))));
00695 
00696     /* here the custom style overrides are specified, if needed */
00697     if (!color.isEmpty()) newData->setForeground(QColor(color));
00698     if (!selColor.isEmpty()) newData->setSelectedForeground(QColor(selColor));
00699     if (!bold.isEmpty()) newData->setFontBold( IS_TRUE(bold) );
00700     if (!italic.isEmpty()) newData->setFontItalic( IS_TRUE(italic) );
00701     // new attributes for the new rendering view
00702     if (!underline.isEmpty()) newData->setFontUnderline( IS_TRUE(underline) );
00703     if (!strikeOut.isEmpty()) newData->setFontStrikeOut( IS_TRUE(strikeOut) );
00704     if (!bgColor.isEmpty()) newData->setBackground(QColor(bgColor));
00705     if (!selBgColor.isEmpty()) newData->setSelectedBackground(QColor(selBgColor));
00706 
00707     internalIDList.append(newData);
00708   }
00709 
00710   //clean up
00711   if (data)
00712     KateHlManager::self()->syntax->freeGroupInfo(data);
00713 }
00714 
00725 int  KateHighlighting::lookupAttrName(const QString& name, QList<KateExtendedAttribute::Ptr> &iDl)
00726 {
00727   for (int i = 0; i < iDl.count(); i++)
00728     if (iDl.at(i)->name() == buildPrefix+name)
00729       return i;
00730 
00731   kDebug(13010)<<"Couldn't resolve itemDataName:"<<name;
00732   return 0;
00733 }
00734 
00748 KateHlItem *KateHighlighting::createKateHlItem(KateSyntaxContextData *data,
00749                                                QList<KateExtendedAttribute::Ptr> &iDl,
00750                                                QStringList *RegionList,
00751                                                QStringList *ContextNameList)
00752 {
00753   // No highlighting -> exit
00754   if (noHl)
00755     return 0;
00756 
00757   // get the (tagname) itemd type
00758   QString dataname=KateHlManager::self()->syntax->groupItemData(data,QString(""));
00759 
00760   // code folding region handling:
00761   QString beginRegionStr=KateHlManager::self()->syntax->groupItemData(data,QString("beginRegion"));
00762   QString endRegionStr=KateHlManager::self()->syntax->groupItemData(data,QString("endRegion"));
00763 
00764   signed char regionId=0;
00765   signed char regionId2=0;
00766 
00767   if (!beginRegionStr.isEmpty())
00768   {
00769     regionId = RegionList->indexOf(beginRegionStr);
00770 
00771     if (regionId==-1) // if the region name doesn't already exist, add it to the list
00772     {
00773       (*RegionList)<<beginRegionStr;
00774       regionId = RegionList->indexOf(beginRegionStr);
00775     }
00776 
00777     regionId++;
00778 
00779     kDebug(13010) << "########### BEG REG: "  << beginRegionStr << " NUM: " << regionId;
00780   }
00781 
00782   if (!endRegionStr.isEmpty())
00783   {
00784     regionId2 = RegionList->indexOf(endRegionStr);
00785 
00786     if (regionId2==-1) // if the region name doesn't already exist, add it to the list
00787     {
00788       (*RegionList)<<endRegionStr;
00789       regionId2 = RegionList->indexOf(endRegionStr);
00790     }
00791 
00792     regionId2 = -regionId2 - 1;
00793 
00794     kDebug(13010) << "########### END REG: "  << endRegionStr << " NUM: " << regionId2;
00795   }
00796 
00797   int attr = 0;
00798   QString tmpAttr=KateHlManager::self()->syntax->groupItemData(data,QString("attribute")).simplified();
00799   bool onlyConsume = tmpAttr.isEmpty();
00800 
00801   // only relevant for non consumer
00802   if (!onlyConsume)
00803   {
00804     if (QString("%1").arg(tmpAttr.toInt())==tmpAttr)
00805     {
00806       errorsAndWarnings+=i18n(
00807           "<b>%1</b>: Deprecated syntax. Attribute (%2) not addressed by symbolic name<br />",
00808       buildIdentifier, tmpAttr);
00809       attr=tmpAttr.toInt();
00810     }
00811     else
00812       attr=lookupAttrName(tmpAttr,iDl);
00813   }
00814 
00815   // Info about context switch
00816   KateHlContextModification context = -1;
00817   QString unresolvedContext;
00818   QString tmpcontext=KateHlManager::self()->syntax->groupItemData(data,QString("context"));
00819   if (!tmpcontext.isEmpty())
00820     context=getContextModificationFromString(ContextNameList, tmpcontext,unresolvedContext);
00821 
00822   // Get the char parameter (eg DetectChar)
00823   char chr;
00824   if (! KateHlManager::self()->syntax->groupItemData(data,QString("char")).isEmpty())
00825     chr= qPrintable((KateHlManager::self()->syntax->groupItemData(data,QString("char"))))[0];
00826   else
00827     chr=0;
00828 
00829   // Get the String parameter (eg. StringDetect)
00830   QString stringdata=KateHlManager::self()->syntax->groupItemData(data,QString("String"));
00831 
00832   // Get a second char parameter (char1) (eg Detect2Chars)
00833   char chr1;
00834   if (! KateHlManager::self()->syntax->groupItemData(data,QString("char1")).isEmpty())
00835     chr1= (KateHlManager::self()->syntax->groupItemData(data,QString("char1")).toLatin1())[0];
00836   else
00837     chr1=0;
00838 
00839   // Will be removed eventually. Atm used for StringDetect, keyword and RegExp
00840   const QString & insensitive_str = KateHlManager::self()->syntax->groupItemData(data,QString("insensitive"));
00841   bool insensitive = IS_TRUE( insensitive_str );
00842 
00843   // for regexp only
00844   bool minimal = IS_TRUE( KateHlManager::self()->syntax->groupItemData(data,QString("minimal")) );
00845 
00846   // dominik: look ahead and do not change offset. so we can change contexts w/o changing offset1.
00847   bool lookAhead = IS_TRUE( KateHlManager::self()->syntax->groupItemData(data,QString("lookAhead")) );
00848 
00849   bool dynamic= IS_TRUE(KateHlManager::self()->syntax->groupItemData(data,QString("dynamic")) );
00850 
00851   bool firstNonSpace = IS_TRUE(KateHlManager::self()->syntax->groupItemData(data,QString("firstNonSpace")) );
00852 
00853   int column = -1;
00854   QString colStr = KateHlManager::self()->syntax->groupItemData(data,QString("column"));
00855   if (!colStr.isEmpty())
00856     column = colStr.toInt();
00857 
00858   //Create the item corresponding to it's type and set it's parameters
00859   KateHlItem *tmpItem;
00860 
00861   if (dataname=="keyword")
00862   {
00863     bool keywordInsensitive = insensitive_str.isEmpty() ? !casesensitive : insensitive;
00864     KateHlKeyword *keyword=new KateHlKeyword(attr,context,regionId,regionId2,keywordInsensitive,
00865                                              m_additionalData[ buildIdentifier ]->deliminator);
00866 
00867     //Get the entries for the keyword lookup list
00868     keyword->addList(KateHlManager::self()->syntax->finddata("highlighting",stringdata));
00869     tmpItem=keyword;
00870   }
00871   else if (dataname=="Float") tmpItem= (new KateHlFloat(attr,context,regionId,regionId2));
00872   else if (dataname=="Int") tmpItem=(new KateHlInt(attr,context,regionId,regionId2));
00873   else if (dataname=="DetectChar") tmpItem=(new KateHlCharDetect(attr,context,regionId,regionId2,chr));
00874   else if (dataname=="Detect2Chars") tmpItem=(new KateHl2CharDetect(attr,context,regionId,regionId2,chr,chr1));
00875   else if (dataname=="RangeDetect") tmpItem=(new KateHlRangeDetect(attr,context,regionId,regionId2, chr, chr1));
00876   else if (dataname=="LineContinue") tmpItem=(new KateHlLineContinue(attr,context,regionId,regionId2));
00877   else if (dataname=="StringDetect") tmpItem=(new KateHlStringDetect(attr,context,regionId,regionId2,stringdata,insensitive));
00878   else if (dataname=="AnyChar") tmpItem=(new KateHlAnyChar(attr,context,regionId,regionId2,stringdata));
00879   else if (dataname=="RegExpr") tmpItem=(new KateHlRegExpr(attr,context,regionId,regionId2,stringdata, insensitive, minimal));
00880   else if (dataname=="HlCChar") tmpItem= ( new KateHlCChar(attr,context,regionId,regionId2));
00881   else if (dataname=="HlCHex") tmpItem= (new KateHlCHex(attr,context,regionId,regionId2));
00882   else if (dataname=="HlCOct") tmpItem= (new KateHlCOct(attr,context,regionId,regionId2));
00883   else if (dataname=="HlCFloat") tmpItem= (new KateHlCFloat(attr,context,regionId,regionId2));
00884   else if (dataname=="HlCStringChar") tmpItem= (new KateHlCStringChar(attr,context,regionId,regionId2));
00885   else if (dataname=="DetectSpaces") tmpItem= (new KateHlDetectSpaces(attr,context,regionId,regionId2));
00886   else if (dataname=="DetectIdentifier") tmpItem= (new KateHlDetectIdentifier(attr,context,regionId,regionId2));
00887   else
00888   {
00889     // oops, unknown type. Perhaps a spelling error in the xml file
00890     return 0;
00891   }
00892 
00893   // set lookAhead & dynamic properties
00894   tmpItem->lookAhead = lookAhead;
00895   tmpItem->dynamic = dynamic;
00896   tmpItem->firstNonSpace = firstNonSpace;
00897   tmpItem->column = column;
00898   tmpItem->onlyConsume = onlyConsume;
00899 
00900   if (!unresolvedContext.isEmpty())
00901   {
00902     unresolvedContextReferences.insert(&(tmpItem->ctx),unresolvedContext);
00903   }
00904 
00905   return tmpItem;
00906 }
00907 
00908 QString KateHighlighting::hlKeyForAttrib( int i ) const
00909 {
00910   // find entry. This is faster than QMap::find. m_hlIndex always has an entry
00911   // for key '0' (it is "none"), so the result is always valid.
00912   int k = 0;
00913   QMap<int,QString>::const_iterator it = m_hlIndex.constEnd();
00914   while ( it != m_hlIndex.constBegin() )
00915   {
00916     --it;
00917     k = it.key();
00918     if ( i >= k )
00919       break;
00920   }
00921   return it.value();
00922 }
00923 
00924 bool KateHighlighting::isInWord( QChar c, int attrib ) const
00925 {
00926   return m_additionalData[ hlKeyForAttrib( attrib ) ]->deliminator.indexOf(c) < 0
00927       && !c.isSpace()
00928       && c != QChar::fromLatin1('"') && c != QChar::fromLatin1('\'');
00929 }
00930 
00931 bool KateHighlighting::canBreakAt( QChar c, int attrib ) const
00932 {
00933   static const QString& sq = KGlobal::staticQString("\"'");
00934   return (m_additionalData[ hlKeyForAttrib( attrib ) ]->wordWrapDeliminator.indexOf(c) != -1) && (sq.indexOf(c) == -1);
00935 }
00936 
00937 QLinkedList<QRegExp> KateHighlighting::emptyLines(int attrib) const
00938 {
00939   kDebug(13010)<<"hlKeyForAttrib: "<<hlKeyForAttrib(attrib);
00940   return m_additionalData[hlKeyForAttrib(attrib)]->emptyLines;
00941 }
00942 
00943 signed char KateHighlighting::commentRegion(int attr) const {
00944   QString commentRegion=m_additionalData[ hlKeyForAttrib( attr ) ]->multiLineRegion;
00945   return (commentRegion.isEmpty()?0:(commentRegion.toShort()));
00946 }
00947 
00948 bool KateHighlighting::canComment( int startAttrib, int endAttrib ) const
00949 {
00950   QString k = hlKeyForAttrib( startAttrib );
00951   return ( k == hlKeyForAttrib( endAttrib ) &&
00952       ( ( !m_additionalData[k]->multiLineCommentStart.isEmpty() && !m_additionalData[k]->multiLineCommentEnd.isEmpty() ) ||
00953        ! m_additionalData[k]->singleLineCommentMarker.isEmpty() ) );
00954 }
00955 
00956 QString KateHighlighting::getCommentStart( int attrib ) const
00957 {
00958   return m_additionalData[ hlKeyForAttrib( attrib) ]->multiLineCommentStart;
00959 }
00960 
00961 QString KateHighlighting::getCommentEnd( int attrib ) const
00962 {
00963   return m_additionalData[ hlKeyForAttrib( attrib ) ]->multiLineCommentEnd;
00964 }
00965 
00966 QString KateHighlighting::getCommentSingleLineStart( int attrib ) const
00967 {
00968   return m_additionalData[ hlKeyForAttrib( attrib) ]->singleLineCommentMarker;
00969 }
00970 
00971 KateHighlighting::CSLPos KateHighlighting::getCommentSingleLinePosition( int attrib ) const
00972 {
00973   return m_additionalData[ hlKeyForAttrib( attrib) ]->singleLineCommentPosition;
00974 }
00975 
00976 
00981 void KateHighlighting::readCommentConfig()
00982 {
00983   KateHlManager::self()->syntax->setIdentifier(buildIdentifier);
00984   KateSyntaxContextData *data=KateHlManager::self()->syntax->getGroupInfo("general","comment");
00985 
00986   QString cmlStart="", cmlEnd="", cmlRegion="", cslStart="";
00987   CSLPos cslPosition=CSLPosColumn0;
00988 
00989   if (data)
00990   {
00991     while  (KateHlManager::self()->syntax->nextGroup(data))
00992     {
00993       if (KateHlManager::self()->syntax->groupData(data,"name")=="singleLine")
00994       {
00995         cslStart=KateHlManager::self()->syntax->groupData(data,"start");
00996         QString cslpos=KateHlManager::self()->syntax->groupData(data,"position");
00997         if (cslpos=="afterwhitespace")
00998           cslPosition=CSLPosAfterWhitespace;
00999         else
01000           cslPosition=CSLPosColumn0;
01001       }
01002       else if (KateHlManager::self()->syntax->groupData(data,"name")=="multiLine")
01003       {
01004         cmlStart=KateHlManager::self()->syntax->groupData(data,"start");
01005         cmlEnd=KateHlManager::self()->syntax->groupData(data,"end");
01006         cmlRegion=KateHlManager::self()->syntax->groupData(data,"region");
01007       }
01008     }
01009 
01010     KateHlManager::self()->syntax->freeGroupInfo(data);
01011   }
01012 
01013   m_additionalData[buildIdentifier]->singleLineCommentMarker = cslStart;
01014   m_additionalData[buildIdentifier]->singleLineCommentPosition = cslPosition;
01015   m_additionalData[buildIdentifier]->multiLineCommentStart = cmlStart;
01016   m_additionalData[buildIdentifier]->multiLineCommentEnd = cmlEnd;
01017   m_additionalData[buildIdentifier]->multiLineRegion = cmlRegion;
01018 }
01019 
01020 
01021 
01022 
01023 void KateHighlighting::readEmptyLineConfig()
01024 {
01025   KateHlManager::self()->syntax->setIdentifier(buildIdentifier);
01026   KateSyntaxContextData *data=KateHlManager::self()->syntax->getGroupInfo("general","emptyLine");
01027 
01028   QLinkedList<QRegExp> exprList;
01029 
01030   if (data)
01031   {
01032     while  (KateHlManager::self()->syntax->nextGroup(data))
01033     {
01034       kDebug(13010)<<"creating an empty line regular expression";
01035       QString regexprline=KateHlManager::self()->syntax->groupData(data,"regexpr");
01036       bool regexprcase=(KateHlManager::self()->syntax->groupData(data,"casesensitive").toUpper().compare("TRUE")==0);
01037       exprList.append(QRegExp(regexprline,regexprcase?Qt::CaseSensitive:Qt::CaseInsensitive));
01038     }
01039       KateHlManager::self()->syntax->freeGroupInfo(data);
01040   }
01041 
01042   m_additionalData[buildIdentifier]->emptyLines = exprList;
01043 }
01044 
01045 
01046 
01047 
01048 
01049 
01055 void KateHighlighting::readGlobalKeywordConfig()
01056 {
01057   deliminator = stdDeliminator;
01058   // Tell the syntax document class which file we want to parse
01059   kDebug(13010)<<"readGlobalKeywordConfig:BEGIN";
01060 
01061   KateHlManager::self()->syntax->setIdentifier(buildIdentifier);
01062   KateSyntaxContextData *data = KateHlManager::self()->syntax->getConfig("general","keywords");
01063 
01064   if (data)
01065   {
01066     kDebug(13010)<<"Found global keyword config";
01067 
01068     if ( IS_TRUE( KateHlManager::self()->syntax->groupItemData(data,QString("casesensitive")) ) )
01069       casesensitive=true;
01070     else
01071       casesensitive=false;
01072 
01073     //get the weak deliminators
01074     weakDeliminator=(KateHlManager::self()->syntax->groupItemData(data,QString("weakDeliminator")));
01075 
01076     kDebug(13010)<<"weak delimiters are: "<<weakDeliminator;
01077 
01078     // remove any weakDelimitars (if any) from the default list and store this list.
01079     for (int s=0; s < weakDeliminator.length(); s++)
01080     {
01081       int f = deliminator.indexOf (weakDeliminator[s]);
01082 
01083       if (f > -1)
01084         deliminator.remove (f, 1);
01085     }
01086 
01087     QString addDelim = (KateHlManager::self()->syntax->groupItemData(data,QString("additionalDeliminator")));
01088 
01089     if (!addDelim.isEmpty())
01090       deliminator=deliminator+addDelim;
01091 
01092     KateHlManager::self()->syntax->freeGroupInfo(data);
01093   }
01094   else
01095   {
01096     //Default values
01097     casesensitive=true;
01098     weakDeliminator=QString("");
01099   }
01100 
01101   kDebug(13010)<<"readGlobalKeywordConfig:END";
01102 
01103   kDebug(13010)<<"delimiterCharacters are: "<<deliminator;
01104 
01105   m_additionalData[buildIdentifier]->deliminator = deliminator;
01106 }
01107 
01118 void KateHighlighting::readWordWrapConfig()
01119 {
01120   // Tell the syntax document class which file we want to parse
01121   kDebug(13010)<<"readWordWrapConfig:BEGIN";
01122 
01123   KateHlManager::self()->syntax->setIdentifier(buildIdentifier);
01124   KateSyntaxContextData *data = KateHlManager::self()->syntax->getConfig("general","keywords");
01125 
01126   QString wordWrapDeliminator = stdDeliminator;
01127   if (data)
01128   {
01129     kDebug(13010)<<"Found global keyword config";
01130 
01131     wordWrapDeliminator = (KateHlManager::self()->syntax->groupItemData(data,QString("wordWrapDeliminator")));
01132     //when no wordWrapDeliminator is defined use the deliminator list
01133     if ( wordWrapDeliminator.length() == 0 ) wordWrapDeliminator = deliminator;
01134 
01135     kDebug(13010) << "word wrap deliminators are " << wordWrapDeliminator;
01136 
01137     KateHlManager::self()->syntax->freeGroupInfo(data);
01138   }
01139 
01140   kDebug(13010)<<"readWordWrapConfig:END";
01141 
01142   m_additionalData[buildIdentifier]->wordWrapDeliminator = wordWrapDeliminator;
01143 }
01144 
01145 void KateHighlighting::readIndentationConfig()
01146 {
01147   m_indentation = "";
01148 
01149   KateHlManager::self()->syntax->setIdentifier(buildIdentifier);
01150   KateSyntaxContextData *data = KateHlManager::self()->syntax->getConfig("general","indentation");
01151 
01152   if (data)
01153   {
01154     m_indentation = (KateHlManager::self()->syntax->groupItemData(data,QString("mode")));
01155 
01156     KateHlManager::self()->syntax->freeGroupInfo(data);
01157   }
01158 }
01159 
01160 void KateHighlighting::readFoldingConfig()
01161 {
01162   // Tell the syntax document class which file we want to parse
01163   kDebug(13010)<<"readfoldignConfig:BEGIN";
01164 
01165   KateHlManager::self()->syntax->setIdentifier(buildIdentifier);
01166   KateSyntaxContextData *data = KateHlManager::self()->syntax->getConfig("general","folding");
01167 
01168   if (data)
01169   {
01170     kDebug(13010)<<"Found global keyword config";
01171 
01172     if ( IS_TRUE( KateHlManager::self()->syntax->groupItemData(data,QString("indentationsensitive")) ) )
01173       m_foldingIndentationSensitive=true;
01174     else
01175       m_foldingIndentationSensitive=false;
01176 
01177     KateHlManager::self()->syntax->freeGroupInfo(data);
01178   }
01179   else
01180   {
01181     //Default values
01182     m_foldingIndentationSensitive = false;
01183   }
01184 
01185   kDebug(13010)<<"readfoldingConfig:END";
01186 
01187   kDebug(13010)<<"############################ use indent for fold are: "<<m_foldingIndentationSensitive;
01188 }
01189 
01190 void  KateHighlighting::createContextNameList(QStringList *ContextNameList,int ctx0)
01191 {
01192   kDebug(13010)<<"creatingContextNameList:BEGIN";
01193 
01194   if (ctx0 == 0)
01195       ContextNameList->clear();
01196 
01197   KateHlManager::self()->syntax->setIdentifier(buildIdentifier);
01198 
01199   KateSyntaxContextData *data=KateHlManager::self()->syntax->getGroupInfo("highlighting","context");
01200 
01201   int id=ctx0;
01202 
01203   if (data)
01204   {
01205      while (KateHlManager::self()->syntax->nextGroup(data))
01206      {
01207           QString tmpAttr=KateHlManager::self()->syntax->groupData(data,QString("name")).simplified();
01208     if (tmpAttr.isEmpty())
01209     {
01210      tmpAttr=QString("!KATE_INTERNAL_DUMMY! %1").arg(id);
01211      errorsAndWarnings +=i18n("<b>%1</b>: Deprecated syntax. Context %2 has no symbolic name<br />", buildIdentifier, id-ctx0);
01212     }
01213           else tmpAttr=buildPrefix+tmpAttr;
01214     (*ContextNameList)<<tmpAttr;
01215           id++;
01216      }
01217      KateHlManager::self()->syntax->freeGroupInfo(data);
01218   }
01219   kDebug(13010)<<"creatingContextNameList:END";
01220 
01221 }
01222 
01223 KateHlContextModification KateHighlighting::getContextModificationFromString(QStringList *ContextNameList, QString tmpLineEndContext, /*NO CONST*/ QString &unres)
01224 {
01225   // nothing unresolved
01226   unres = "";
01227 
01228   // context to push on stack
01229   int context = -1;
01230 
01231   // number of contexts to pop
01232   int pops = 0;
01233 
01234   // we allow arbitrary #stay and #pop at the start
01235   bool anyFound = false;
01236   while (tmpLineEndContext.startsWith("#stay") || tmpLineEndContext.startsWith("#pop"))
01237   {
01238     // ignore stay
01239     if (tmpLineEndContext.startsWith("#stay"))
01240     {
01241       tmpLineEndContext.remove (0, 5);
01242     }
01243     else // count the pops
01244     {
01245       ++pops;
01246       tmpLineEndContext.remove (0, 4);
01247     }
01248 
01249     anyFound = true;
01250   }
01251 
01255   if (anyFound && !tmpLineEndContext.isEmpty())
01256   {
01257     if (tmpLineEndContext.startsWith('!'))
01258       tmpLineEndContext.remove (0, 1);
01259   }
01260 
01264   if (tmpLineEndContext.isEmpty())
01265     return KateHlContextModification (context, pops);
01266 
01271   if ( tmpLineEndContext.contains("##"))
01272   {
01273     int o = tmpLineEndContext.indexOf("##");
01274     // FIXME at least with 'foo##bar'-style contexts the rules are picked up
01275     // but the default attribute is not
01276     QString tmp=tmpLineEndContext.mid(o+2);
01277     if (!embeddedHls.contains(tmp))  embeddedHls.insert(tmp,KateEmbeddedHlInfo());
01278     unres=tmp+':'+tmpLineEndContext.left(o);
01279     kDebug(13010) << "unres = " << unres;
01280     context=0;
01281   }
01282 
01283   else
01284   {
01285     context=ContextNameList->indexOf(buildPrefix+tmpLineEndContext);
01286     if (context==-1)
01287     {
01288       context=tmpLineEndContext.toInt();
01289       errorsAndWarnings+=i18n(
01290         "<B>%1</B>:Deprecated syntax. Context %2 not addressed by a symbolic name"
01291         , buildIdentifier, tmpLineEndContext);
01292     }
01293 //#warning restructure this the name list storage.
01294 //    context=context+buildContext0Offset;
01295   }
01296 
01297   return KateHlContextModification (context, pops);
01298 }
01299 
01305 void KateHighlighting::makeContextList()
01306 {
01307   if (noHl)  // if this a highlighting for "normal texts" only, tere is no need for a context list creation
01308     return;
01309 
01310   embeddedHls.clear();
01311   unresolvedContextReferences.clear();
01312   RegionList.clear();
01313   ContextNameList.clear();
01314 
01315   // prepare list creation. To reuse as much code as possible handle this
01316   // highlighting the same way as embedded onces
01317   embeddedHls.insert(iName,KateEmbeddedHlInfo());
01318 
01319   bool something_changed;
01320   // the context "0" id is 0 for this hl, all embedded context "0"s have offsets
01321   startctx=base_startctx=0;
01322   // inform everybody that we are building the highlighting contexts and itemlists
01323   building=true;
01324 
01325   do
01326   {
01327     kDebug(13010)<<"**************** Outer loop in make ContextList";
01328     kDebug(13010)<<"**************** Hl List count:"<<embeddedHls.count();
01329     something_changed=false; //assume all "embedded" hls have already been loaded
01330     for (KateEmbeddedHlInfos::iterator it=embeddedHls.begin(); it!=embeddedHls.end();++it)
01331     {
01332       if (!it.value().loaded)  // we found one, we still have to load
01333       {
01334         kDebug(13010)<<"**************** Inner loop in make ContextList";
01335         QString identifierToUse;
01336         kDebug(13010)<<"Trying to open highlighting definition file: "<< it.key();
01337         if (iName==it.key()) // the own identifier is known
01338           identifierToUse=identifier;
01339         else                 // all others have to be looked up
01340           identifierToUse=KateHlManager::self()->identifierForName(it.key());
01341 
01342         kDebug(13010)<<"Location is:"<< identifierToUse;
01343 
01344         buildPrefix=it.key()+':';  // attribute names get prefixed by the names
01345                                    // of the highlighting definitions they belong to
01346 
01347         if (identifierToUse.isEmpty() )
01348           kDebug(13010)<<"OHOH, unknown highlighting description referenced";
01349 
01350         kDebug(13010)<<"setting ("<<it.key()<<") to loaded";
01351 
01352         //mark hl as loaded
01353         it=embeddedHls.insert(it.key(),KateEmbeddedHlInfo(true,startctx));
01354         //set class member for context 0 offset, so we don't need to pass it around
01355         buildContext0Offset=startctx;
01356         //parse one hl definition file
01357         startctx=addToContextList(identifierToUse,startctx);
01358 
01359         if (noHl) return;  // an error occurred
01360 
01361         base_startctx = startctx;
01362         something_changed=true; // something has been loaded
01363       }
01364     }
01365   } while (something_changed);  // as long as there has been another file parsed
01366                   // repeat everything, there could be newly added embedded hls.
01367 
01368 
01369   // at this point all needed highlighing (sub)definitions are loaded. It's time
01370   // to resolve cross file  references (if there are any)
01371   kDebug(13010)<<"Unresolved contexts, which need attention: "<<unresolvedContextReferences.count();
01372 
01373   //optimize this a littlebit
01374   for (KateHlUnresolvedCtxRefs::iterator unresIt=unresolvedContextReferences.begin();
01375        unresIt != unresolvedContextReferences.end();
01376        ++unresIt)
01377   {
01378     QString incCtx = unresIt.value();
01379     kDebug(13010) << "Context " <<incCtx << " is unresolved";
01380 
01381     // only resolve '##Name' contexts here; handleKateHlIncludeRules() can figure
01382     // out 'Name##Name'-style inclusions, but we screw it up
01383     if (incCtx.endsWith(':')) {
01384       kDebug(13010)<<"Looking up context0 for ruleset "<<incCtx;
01385       incCtx = incCtx.left(incCtx.length()-1);
01386       //try to find the context0 id for a given unresolvedReference
01387       KateEmbeddedHlInfos::const_iterator hlIt=embeddedHls.constFind(incCtx);
01388       if (hlIt!=embeddedHls.constEnd())
01389         *(unresIt.key())=hlIt.value().context0;
01390     }
01391   }
01392 
01393   // eventually handle KateHlIncludeRules items, if they exist.
01394   // This has to be done after the cross file references, because it is allowed
01395   // to include the context0 from a different definition, than the one the rule
01396   // belongs to
01397   handleKateHlIncludeRules();
01398 
01399   embeddedHls.clear(); //save some memory.
01400   unresolvedContextReferences.clear(); //save some memory
01401   RegionList.clear();  // I think you get the idea ;)
01402   ContextNameList.clear();
01403 
01404 
01405   // if there have been errors show them
01406   if (!errorsAndWarnings.isEmpty())
01407   KMessageBox::detailedSorry(QApplication::activeWindow(),i18n(
01408         "There were warning(s) and/or error(s) while parsing the syntax "
01409         "highlighting configuration."),
01410         errorsAndWarnings, i18n("Kate Syntax Highlighting Parser"));
01411 
01412   // we have finished
01413   building=false;
01414 }
01415 
01416 void KateHighlighting::handleKateHlIncludeRules()
01417 {
01418   // if there are noe include rules to take care of, just return
01419   kDebug(13010)<<"KateHlIncludeRules, which need attention: " <<includeRules.size();
01420   if (includeRules.isEmpty()) return;
01421 
01422   buildPrefix="";
01423   QString dummy;
01424 
01425   // By now the context0 references are resolved, now more or less only inner
01426   // file references are resolved. If we decide that arbitrary inclusion is
01427   // needed, this doesn't need to be changed, only the addToContextList
01428   // method.
01429 
01430   //resolove context names
01431   for (KateHlIncludeRules::iterator it=includeRules.begin(); it!=includeRules.end(); )
01432   {
01433     if ((*it)->incCtx.newContext==-1) // context unresolved ?
01434     {
01435 
01436       if ((*it)->incCtxN.isEmpty())
01437       {
01438         // no context name given, and no valid context id set, so this item is
01439         // going to be removed
01440         KateHlIncludeRules::iterator it1=it;
01441         ++it1;
01442         delete (*it);
01443         includeRules.erase(it);
01444         it=it1;
01445       }
01446       else
01447       {
01448         // resolve name to id
01449         (*it)->incCtx=getContextModificationFromString(&ContextNameList,(*it)->incCtxN,dummy).newContext;
01450         kDebug(13010)<<"Resolved "<<(*it)->incCtxN<< " to "<<(*it)->incCtx.newContext<<" for include rule";
01451         // It would be good to look here somehow, if the result is valid
01452       }
01453     }
01454     else ++it; //nothing to do, already resolved (by the cross defintion reference resolver)
01455   }
01456 
01457   // now that all KateHlIncludeRule items should be valid and completely resolved,
01458   // do the real inclusion of the rules.
01459   // recursiveness is needed, because context 0 could include context 1, which
01460   // itself includes context 2 and so on.
01461   //  In that case we have to handle context 2 first, then 1, 0
01462   //TODO: catch circular references: eg 0->1->2->3->1
01463   while (!includeRules.isEmpty())
01464     handleKateHlIncludeRulesRecursive(0, &includeRules);
01465 }
01466 
01467 void KateHighlighting::handleKateHlIncludeRulesRecursive(int index, KateHlIncludeRules *list)
01468 {
01469   if (index < 0 || index >= list->count()) return;  //invalid iterator, shouldn't happen, but better have a rule prepared ;)
01470 
01471   int index1 = index;
01472   int ctx = list->at(index1)->ctx;
01473 
01474   // find the last entry for the given context in the KateHlIncludeRules list
01475   // this is need if one context includes more than one. This saves us from
01476   // updating all insert positions:
01477   // eg: context 0:
01478   // pos 3 - include context 2
01479   // pos 5 - include context 3
01480   // During the building of the includeRules list the items are inserted in
01481   // ascending order, now we need it descending to make our life easier.
01482   while (index < list->count() && list->at(index)->ctx == ctx)
01483   {
01484     index1 = index;
01485     ++index;
01486   }
01487 
01488   // iterate over each include rule for the context the function has been called for.
01489   while (index1 >= 0 && index1 < list->count() && list->at(index1)->ctx == ctx)
01490   {
01491     KateHlContextModification ctx1 = list->at(index1)->incCtx;
01492 
01493     //let's see, if the included context includes other contexts
01494     for (int index2 = 0; index2 < list->count(); ++index2)
01495     {
01496       if (list->at(index2)->ctx == ctx1.newContext)
01497       {
01498         //yes it does, so first handle that include rules, since we want to
01499         // include those subincludes too
01500         handleKateHlIncludeRulesRecursive(index2, list);
01501         break;
01502       }
01503     }
01504 
01505     // if the context we want to include had sub includes, they are already inserted there.
01506     KateHlContext *dest=m_contexts[ctx];
01507     KateHlContext *src=m_contexts[ctx1.newContext];
01508 //     kDebug(3010)<<"linking included rules from "<<ctx<<" to "<<ctx1;
01509 
01510     // If so desired, change the dest attribute to the one of the src.
01511     // Required to make commenting work, if text matched by the included context
01512     // is a different highlight than the host context.
01513     if ( list->at(index1)->includeAttrib )
01514       dest->attr = src->attr;
01515 
01516     // insert the included context's rules starting at position p
01517     int p = list->at(index1)->pos;
01518 
01519     // remember some stuff
01520     int oldLen = dest->items.size();
01521     uint itemsToInsert = src->items.size();
01522 
01523     // resize target
01524     dest->items.resize (oldLen + itemsToInsert);
01525 
01526     // move old elements
01527     for (int i=oldLen-1; i >= p; --i)
01528       dest->items[i+itemsToInsert] = dest->items[i];
01529 
01530     // insert new stuff
01531     for (uint i=0; i < itemsToInsert; ++i  )
01532       dest->items[p+i] = src->items[i];
01533 
01534     index = index1; //backup the iterator
01535     --index1;  //move to the next entry, which has to be take care of
01536     delete list->takeAt(index); //free + remove the already handled data structure
01537   }
01538 }
01539 
01545 int KateHighlighting::addToContextList(const QString &ident, int ctx0)
01546 {
01547   kDebug(13010)<<"=== Adding hl with ident '"<<ident<<"'";
01548 
01549   buildIdentifier=ident;
01550   KateSyntaxContextData *data, *datasub;
01551   KateHlItem *c;
01552 
01553   QString dummy;
01554 
01555   // Let the syntax document class know, which file we'd like to parse
01556   if (!KateHlManager::self()->syntax->setIdentifier(ident))
01557   {
01558     noHl=true;
01559     KMessageBox::information(QApplication::activeWindow(),i18n(
01560         "Since there has been an error parsing the highlighting description, "
01561         "this highlighting will be disabled"));
01562     return 0;
01563   }
01564 
01565   // only read for the own stuff
01566   if (identifier == ident)
01567   {
01568     readIndentationConfig ();
01569   }
01570 
01571   RegionList<<"!KateInternal_TopLevel!";
01572 
01573   m_hlIndex[internalIDList.count()] = ident;
01574   m_additionalData.insert( ident, new HighlightPropertyBag );
01575 
01576   // fill out the propertybag
01577   readCommentConfig();
01578   readEmptyLineConfig();
01579   readGlobalKeywordConfig();
01580   readWordWrapConfig();
01581 
01582   readFoldingConfig ();
01583 
01584   QString ctxName;
01585 
01586   // This list is needed for the translation of the attribute parameter,
01587   // if the itemData name is given instead of the index
01588   addToKateExtendedAttributeList();
01589   QList<KateExtendedAttribute::Ptr> iDl = internalIDList;
01590 
01591   createContextNameList(&ContextNameList,ctx0);
01592 
01593 
01594   kDebug(13010)<<"Parsing Context structure";
01595   //start the real work
01596   data=KateHlManager::self()->syntax->getGroupInfo("highlighting","context");
01597   uint i=buildContext0Offset;
01598   if (data)
01599   {
01600     while (KateHlManager::self()->syntax->nextGroup(data))
01601     {
01602       kDebug(13010)<<"Found a context in file, building structure now";
01603       //BEGIN - Translation of the attribute parameter
01604       QString tmpAttr=KateHlManager::self()->syntax->groupData(data,QString("attribute")).simplified();
01605       int attr;
01606       if (QString("%1").arg(tmpAttr.toInt())==tmpAttr)
01607         attr=tmpAttr.toInt();
01608       else
01609         attr=lookupAttrName(tmpAttr,iDl);
01610       //END - Translation of the attribute parameter
01611 
01612       ctxName=buildPrefix+KateHlManager::self()->syntax->groupData(data,QString("lineEndContext")).simplified();
01613 
01614       QString tmpLineEndContext=KateHlManager::self()->syntax->groupData(data,QString("lineEndContext")).simplified();
01615       KateHlContextModification context;
01616 
01617       context=getContextModificationFromString(&ContextNameList, tmpLineEndContext,dummy);
01618 
01619       QString tmpNIBF = KateHlManager::self()->syntax->groupData(data, QString("noIndentationBasedFolding") );
01620       bool noIndentationBasedFolding=IS_TRUE(tmpNIBF);
01621 
01622       //BEGIN get fallthrough props
01623       bool ft = false;
01624       KateHlContextModification ftc = 0; // fallthrough context
01625       if ( i > 0 )  // fallthrough is not smart in context 0
01626       {
01627         QString tmpFt = KateHlManager::self()->syntax->groupData(data, QString("fallthrough") );
01628         if ( IS_TRUE(tmpFt) )
01629           ft = true;
01630         if ( ft )
01631         {
01632           QString tmpFtc = KateHlManager::self()->syntax->groupData( data, QString("fallthroughContext") );
01633 
01634           ftc=getContextModificationFromString(&ContextNameList, tmpFtc,dummy);
01635 
01636           // stay is not allowed, we need to #pop or push some context...
01637           if (ftc.type == KateHlContextModification::doNothing) ftc = 0;
01638 
01639           kDebug(13010)<<"Setting fall through context (context "<<i<<"): "<<ftc.newContext;
01640         }
01641       }
01642       //END falltrhough props
01643 
01644       bool dynamic = false;
01645       QString tmpDynamic = KateHlManager::self()->syntax->groupData(data, QString("dynamic") );
01646       if ( tmpDynamic.toLower() == "true" ||  tmpDynamic.toInt() == 1 )
01647         dynamic = true;
01648 
01649       KateHlContext *ctxNew = new KateHlContext (
01650         ident,
01651         attr,
01652         context,
01653         (KateHlManager::self()->syntax->groupData(data,QString("lineBeginContext"))).isEmpty()?-1:
01654         (KateHlManager::self()->syntax->groupData(data,QString("lineBeginContext"))).toInt(),
01655         ft, ftc, dynamic,noIndentationBasedFolding);
01656 
01657       m_contexts.push_back (ctxNew);
01658 
01659       kDebug(13010) << "INDEX: " << i << " LENGTH " << m_contexts.size()-1;
01660 
01661       //Let's create all items for the context
01662       while (KateHlManager::self()->syntax->nextItem(data))
01663       {
01664 //    kDebug(13010)<< "In make Contextlist: Item:";
01665 
01666       // KateHlIncludeRules : add a pointer to each item in that context
01667         // TODO add a attrib includeAttrib
01668       QString tag = KateHlManager::self()->syntax->groupItemData(data,QString(""));
01669       if ( tag == "IncludeRules" ) //if the new item is an Include rule, we have to take special care
01670       {
01671         QString incCtx = KateHlManager::self()->syntax->groupItemData( data, QString("context"));
01672         QString incAttrib = KateHlManager::self()->syntax->groupItemData( data, QString("includeAttrib"));
01673         bool includeAttrib = IS_TRUE( incAttrib );
01674 
01675         // only context refernces of type Name, ##Name, and Subname##Name are allowed
01676         if (incCtx.startsWith("##") || (!incCtx.startsWith('#')))
01677         {
01678            int incCtxi = incCtx.indexOf ("##");
01679            //#stay, #pop is not interesting here
01680            if (incCtxi >= 0)
01681            {
01682              QString incSet = incCtx.mid(incCtxi + 2);
01683              QString incCtxN = incSet + ':' + incCtx.left(incCtxi);
01684 
01685              //a cross highlighting reference
01686              kDebug(13010)<<"Cross highlight reference <IncludeRules>, context "<<incCtxN;
01687              KateHlIncludeRule *ir=new KateHlIncludeRule(i,m_contexts[i]->items.count(),incCtxN,includeAttrib);
01688 
01689              //use the same way to determine cross hl file references as other items do
01690              if (!embeddedHls.contains(incSet))
01691                embeddedHls.insert(incSet,KateEmbeddedHlInfo());
01692              else
01693                kDebug(13010)<<"Skipping embeddedHls.insert for "<<incCtxN;
01694 
01695             unresolvedContextReferences.insert(&(ir->incCtx), incCtxN);
01696 
01697             includeRules.append(ir);
01698           }
01699           else
01700           {
01701             // a local reference -> just initialize the include rule structure
01702             incCtx=buildPrefix+incCtx.simplified ();
01703             includeRules.append(new KateHlIncludeRule(i,m_contexts[i]->items.count(),incCtx, includeAttrib));
01704           }
01705         }
01706 
01707         continue;
01708       }
01709       // TODO -- can we remove the block below??
01710 #if 0
01711                 QString tag = KateHlManager::self()->syntax->groupKateExtendedAttribute(data,QString(""));
01712                 if ( tag == "IncludeRules" ) {
01713                   // attrib context: the index (jowenn, i think using names here
01714                   // would be a cool feat, goes for mentioning the context in
01715                   // any item. a map or dict?)
01716                   int ctxId = getIdFromString(&ContextNameList,
01717                                                KateHlManager::self()->syntax->groupKateExtendedAttribute( data, QString("context")),dummy); // the index is *required*
01718                   if ( ctxId > -1) { // we can even reuse rules of 0 if we want to:)
01719                     kDebug(13010)<<"makeContextList["<<i<<"]: including all items of context "<<ctxId;
01720                     if ( ctxId < (int) i ) { // must be defined
01721                       for ( c = m_contexts[ctxId]->items.first(); c; c = m_contexts[ctxId]->items.next() )
01722                         m_contexts[i]->items.append(c);
01723                     }
01724                     else
01725                       kDebug(13010)<<"Context "<<ctxId<<"not defined. You can not include the rules of an undefined context";
01726                   }
01727                   continue; // while nextItem
01728                 }
01729 #endif
01730       c=createKateHlItem(data,iDl,&RegionList,&ContextNameList);
01731       if (c)
01732       {
01733         m_contexts[i]->items.append(c);
01734 
01735         // Not supported completely atm and only one level. Subitems.(all have
01736         // to be matched to at once)
01737         datasub=KateHlManager::self()->syntax->getSubItems(data);
01738         for (bool tmpbool=KateHlManager::self()->syntax->nextItem(datasub);
01739              tmpbool;
01740              tmpbool=KateHlManager::self()->syntax->nextItem(datasub))
01741         {
01742           c->subItems.resize (c->subItems.size()+1);
01743           c->subItems[c->subItems.size()-1] = createKateHlItem(datasub,iDl,&RegionList,&ContextNameList);
01744         }
01745         KateHlManager::self()->syntax->freeGroupInfo(datasub);
01746       }
01747       }
01748       i++;
01749     }
01750   }
01751 
01752   KateHlManager::self()->syntax->freeGroupInfo(data);
01753 
01754   if (RegionList.count()!=1)
01755     folding=true;
01756 
01757   folding = folding || m_foldingIndentationSensitive;
01758 
01759   //BEGIN Resolve multiline region if possible
01760   if (!m_additionalData[ ident ]->multiLineRegion.isEmpty()) {
01761     long commentregionid=RegionList.indexOf( m_additionalData[ ident ]->multiLineRegion );
01762     if (-1==commentregionid) {
01763       errorsAndWarnings+=i18n(
01764           "<b>%1</b>: Specified multiline comment region (%2) could not be resolved<br />"
01765                              , buildIdentifier,  m_additionalData[ ident ]->multiLineRegion );
01766       m_additionalData[ ident ]->multiLineRegion.clear();
01767       kDebug(13010)<<"ERROR comment region attribute could not be resolved";
01768 
01769     } else {
01770       m_additionalData[ ident ]->multiLineRegion=QString::number(commentregionid+1);
01771       kDebug(13010)<<"comment region resolved to:"<<m_additionalData[ ident ]->multiLineRegion;
01772     }
01773   }
01774   //END Resolve multiline region if possible
01775   return i;
01776 }
01777 
01778 void KateHighlighting::clearAttributeArrays ()
01779 {
01780   QMutableHashIterator< QString, QList<KTextEditor::Attribute::Ptr> > it = m_attributeArrays;
01781   while (it.hasNext())
01782   {
01783     it.next();
01784 
01785     // k, schema correct, let create the data
01786     KateAttributeList defaultStyleList;
01787 
01788     KateHlManager::self()->getDefaults(it.key(), defaultStyleList);
01789 
01790     QList<KateExtendedAttribute::Ptr> itemDataList;
01791     getKateExtendedAttributeList(it.key(), itemDataList);
01792 
01793     uint nAttribs = itemDataList.count();
01794     QList<KTextEditor::Attribute::Ptr>& array = it.value();
01795     array.clear();
01796 
01797     for (uint z = 0; z < nAttribs; z++)
01798     {
01799       KateExtendedAttribute::Ptr itemData = itemDataList.at(z);
01800       KTextEditor::Attribute::Ptr newAttribute( new KTextEditor::Attribute(*defaultStyleList.at(itemData->defaultStyleIndex())) );
01801 
01802       if (itemData && itemData->hasAnyProperty())
01803         *newAttribute += *itemData;
01804 
01805       array.append(newAttribute);
01806     }
01807   }
01808 }
01809 
01810 QList<KTextEditor::Attribute::Ptr> KateHighlighting::attributes (const QString &schema)
01811 {
01812   // found it, already floating around
01813   if (m_attributeArrays.contains(schema))
01814     return m_attributeArrays[schema];
01815 
01816   // k, schema correct, let create the data
01817   QList<KTextEditor::Attribute::Ptr> array;
01818   KateAttributeList defaultStyleList;
01819 
01820   KateHlManager::self()->getDefaults(schema, defaultStyleList);
01821 
01822   QList<KateExtendedAttribute::Ptr> itemDataList;
01823   getKateExtendedAttributeList(schema, itemDataList);
01824 
01825   uint nAttribs = itemDataList.count();
01826   for (uint z = 0; z < nAttribs; z++)
01827   {
01828     KateExtendedAttribute::Ptr itemData = itemDataList.at(z);
01829     KTextEditor::Attribute::Ptr newAttribute( new KTextEditor::Attribute(*defaultStyleList.at(itemData->defaultStyleIndex())) );
01830 
01831     if (itemData && itemData->hasAnyProperty())
01832       *newAttribute += *itemData;
01833 
01834     array.append(newAttribute);
01835   }
01836 
01837   m_attributeArrays.insert(schema, array);
01838 
01839   return array;
01840 }
01841 
01842 //END
01843 
01844 // kate: space-indent on; indent-width 2; replace-tabs on;

Kate

Skip menu "Kate"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal