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;
KDE 4.6 API Reference