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