00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "katehighlighthelpers.h"
00025
00026 #include "katetextline.h"
00027 #include "katedocument.h"
00028 #include "katesyntaxdocument.h"
00029 #include "katerenderer.h"
00030 #include "kateglobal.h"
00031 #include "kateschema.h"
00032 #include "kateconfig.h"
00033 #include "kateextendedattribute.h"
00034
00035 #include <QtCore/QSet>
00036
00037
00038
00039 KateHlItem::KateHlItem(int attribute, KateHlContextModification context,signed char regionId,signed char regionId2)
00040 : attr(attribute),
00041 ctx(context),
00042 region(regionId),
00043 region2(regionId2),
00044 lookAhead(false),
00045 dynamic(false),
00046 dynamicChild(false),
00047 firstNonSpace(false),
00048 onlyConsume(false),
00049 column (-1),
00050 alwaysStartEnable (true),
00051 customStartEnable (false)
00052 {
00053 }
00054
00055 KateHlItem::~KateHlItem()
00056 {
00057
00058 for (int i=0; i < subItems.size(); i++)
00059 delete subItems[i];
00060 }
00061
00062 void KateHlItem::dynamicSubstitute(QString &str, const QStringList *args)
00063 {
00064 for (int i = 0; i < str.length() - 1; ++i)
00065 {
00066 if (str[i] == '%')
00067 {
00068 char c = str[i + 1].toLatin1();
00069 if (c == '%')
00070 str.remove(i, 1);
00071 else if (c >= '0' && c <= '9')
00072 {
00073 if ((int)(c - '0') < args->size())
00074 {
00075 str.replace(i, 2, (*args)[c - '0']);
00076 i += ((*args)[c - '0']).length() - 1;
00077 }
00078 else
00079 {
00080 str.remove(i, 2);
00081 --i;
00082 }
00083 }
00084 }
00085 }
00086 }
00087
00088
00089
00090 KateHlCharDetect::KateHlCharDetect(int attribute, KateHlContextModification context, signed char regionId,signed char regionId2, QChar c)
00091 : KateHlItem(attribute,context,regionId,regionId2)
00092 , sChar(c)
00093 {
00094 }
00095
00096 int KateHlCharDetect::checkHgl(const QString& text, int offset, int )
00097 {
00098 if (text[offset] == sChar)
00099 return offset + 1;
00100
00101 return 0;
00102 }
00103
00104 KateHlItem *KateHlCharDetect::clone(const QStringList *args)
00105 {
00106 char c = sChar.toLatin1();
00107
00108 if (c < '0' || c > '9' || (c - '0') >= args->size())
00109 return this;
00110
00111 KateHlCharDetect *ret = new KateHlCharDetect(attr, ctx, region, region2, (*args)[c - '0'][0]);
00112 ret->dynamicChild = true;
00113 return ret;
00114 }
00115
00116
00117
00118 KateHl2CharDetect::KateHl2CharDetect(int attribute, KateHlContextModification context, signed char regionId,signed char regionId2, QChar ch1, QChar ch2)
00119 : KateHlItem(attribute,context,regionId,regionId2)
00120 , sChar1 (ch1)
00121 , sChar2 (ch2)
00122 {
00123 }
00124
00125 int KateHl2CharDetect::checkHgl(const QString& text, int offset, int len)
00126 {
00127 if ((len >= 2) && text[offset++] == sChar1 && text[offset++] == sChar2)
00128 return offset;
00129
00130 return 0;
00131 }
00132
00133 KateHlItem *KateHl2CharDetect::clone(const QStringList *args)
00134 {
00135 char c1 = sChar1.toLatin1();
00136 char c2 = sChar2.toLatin1();
00137
00138 if (c1 < '0' || c1 > '9' || (c1 - '0') >= args->size())
00139 return this;
00140
00141 if (c2 < '0' || c2 > '9' || (c2 - '0') >= args->size())
00142 return this;
00143
00144 KateHl2CharDetect *ret = new KateHl2CharDetect(attr, ctx, region, region2, (*args)[c1 - '0'][0], (*args)[c2 - '0'][0]);
00145 ret->dynamicChild = true;
00146 return ret;
00147 }
00148
00149
00150
00151 KateHlStringDetect::KateHlStringDetect(int attribute, KateHlContextModification context, signed char regionId,signed char regionId2,const QString &s, bool inSensitive)
00152 : KateHlItem(attribute, context,regionId,regionId2)
00153 , str(inSensitive ? s.toUpper() : s)
00154 , strLen (str.length())
00155 , _inSensitive(inSensitive)
00156 {
00157 }
00158
00159 int KateHlStringDetect::checkHgl(const QString& text, int offset, int len)
00160 {
00161 if (len < strLen)
00162 return 0;
00163
00164 if (_inSensitive)
00165 {
00166 for (int i=0; i < strLen; i++)
00167 if (text[offset++].toUpper() != str[i])
00168 return 0;
00169
00170 return offset;
00171 }
00172 else
00173 {
00174 for (int i=0; i < strLen; i++)
00175 if (text[offset++] != str[i])
00176 return 0;
00177
00178 return offset;
00179 }
00180
00181 return 0;
00182 }
00183
00184 KateHlItem *KateHlStringDetect::clone(const QStringList *args)
00185 {
00186 QString newstr = str;
00187
00188 dynamicSubstitute(newstr, args);
00189
00190 if (newstr == str)
00191 return this;
00192
00193 KateHlStringDetect *ret = new KateHlStringDetect(attr, ctx, region, region2, newstr, _inSensitive);
00194 ret->dynamicChild = true;
00195 return ret;
00196 }
00197
00198
00199
00200 KateHlRangeDetect::KateHlRangeDetect(int attribute, KateHlContextModification context, signed char regionId,signed char regionId2, QChar ch1, QChar ch2)
00201 : KateHlItem(attribute,context,regionId,regionId2)
00202 , sChar1 (ch1)
00203 , sChar2 (ch2)
00204 {
00205 }
00206
00207 int KateHlRangeDetect::checkHgl(const QString& text, int offset, int len)
00208 {
00209 if (text[offset] == sChar1)
00210 {
00211 do
00212 {
00213 offset++;
00214 len--;
00215 if (len < 1) return 0;
00216 }
00217 while (text[offset] != sChar2);
00218
00219 return offset + 1;
00220 }
00221 return 0;
00222 }
00223
00224
00225
00226 KateHlKeyword::KateHlKeyword (int attribute, KateHlContextModification context, signed char regionId,signed char regionId2, bool insensitive, const QString& delims)
00227 : KateHlItem(attribute,context,regionId,regionId2)
00228 , _insensitive(insensitive)
00229 , deliminators(delims)
00230 , minLen (0xFFFFFF)
00231 , maxLen (0)
00232 {
00233 alwaysStartEnable = false;
00234 customStartEnable = true;
00235 }
00236
00237 KateHlKeyword::~KateHlKeyword ()
00238 {
00239 for (int i=0; i < dict.size(); ++i)
00240 delete dict[i];
00241 }
00242
00243 void KateHlKeyword::addList(const QStringList& list)
00244 {
00245 for(int i=0; i < list.count(); ++i)
00246 {
00247 int len = list[i].length();
00248
00249 if (minLen > len)
00250 minLen = len;
00251
00252 if (maxLen < len)
00253 maxLen = len;
00254
00255 if (len >= dict.size())
00256 {
00257 uint oldSize = dict.size();
00258 dict.resize (len+1);
00259
00260 for (int m=oldSize; m < dict.size(); ++m)
00261 dict[m] = 0;
00262 }
00263
00264 if (!dict[len])
00265 dict[len] = new QSet<QString> ();
00266
00267 if (!_insensitive)
00268 dict[len]->insert(list[i]);
00269 else
00270 dict[len]->insert(list[i].toLower());
00271 }
00272 }
00273
00274 int KateHlKeyword::checkHgl(const QString& text, int offset, int len)
00275 {
00276 int offset2 = offset;
00277 int wordLen = 0;
00278
00279 while ((len > wordLen) && !deliminators.contains(text[offset2]))
00280 {
00281 offset2++;
00282 wordLen++;
00283
00284 if (wordLen > maxLen) return 0;
00285 }
00286
00287 if (wordLen < minLen || !dict[wordLen]) return 0;
00288
00289 if (!_insensitive)
00290 {
00291 if (dict[wordLen]->contains(QString::fromRawData(text.unicode() + offset, wordLen)) )
00292 return offset2;
00293 }
00294 else
00295 {
00296 if (dict[wordLen]->contains(QString::fromRawData(text.unicode() + offset, wordLen).toLower()) )
00297 return offset2;
00298 }
00299
00300 return 0;
00301 }
00302
00303
00304
00305 KateHlInt::KateHlInt(int attribute, KateHlContextModification context, signed char regionId,signed char regionId2)
00306 : KateHlItem(attribute,context,regionId,regionId2)
00307 {
00308 alwaysStartEnable = false;
00309 }
00310
00311 int KateHlInt::checkHgl(const QString& text, int offset, int len)
00312 {
00313 int offset2 = offset;
00314
00315 while ((len > 0) && text[offset2].isDigit())
00316 {
00317 offset2++;
00318 len--;
00319 }
00320
00321 if (offset2 > offset)
00322 {
00323 if (len > 0)
00324 {
00325 for (int i=0; i < subItems.size(); i++)
00326 {
00327 if ( (offset = subItems[i]->checkHgl(text, offset2, len)) )
00328 return offset;
00329 }
00330 }
00331
00332 return offset2;
00333 }
00334
00335 return 0;
00336 }
00337
00338
00339
00340 KateHlFloat::KateHlFloat(int attribute, KateHlContextModification context, signed char regionId,signed char regionId2)
00341 : KateHlItem(attribute,context, regionId,regionId2)
00342 {
00343 alwaysStartEnable = false;
00344 }
00345
00346 int KateHlFloat::checkHgl(const QString& text, int offset, int len)
00347 {
00348 bool b = false;
00349 bool p = false;
00350
00351 while ((len > 0) && text[offset].isDigit())
00352 {
00353 offset++;
00354 len--;
00355 b = true;
00356 }
00357
00358 if ((len > 0) && (p = (text[offset] == '.')))
00359 {
00360 offset++;
00361 len--;
00362
00363 while ((len > 0) && text[offset].isDigit())
00364 {
00365 offset++;
00366 len--;
00367 b = true;
00368 }
00369 }
00370
00371 if (!b)
00372 return 0;
00373
00374 if ((len > 0) && ((text[offset].toAscii() & 0xdf) == 'E'))
00375 {
00376 offset++;
00377 len--;
00378 }
00379 else
00380 {
00381 if (!p)
00382 return 0;
00383 else
00384 {
00385 if (len > 0)
00386 {
00387 for (int i=0; i < subItems.size(); ++i)
00388 {
00389 int offset2 = subItems[i]->checkHgl(text, offset, len);
00390
00391 if (offset2)
00392 return offset2;
00393 }
00394 }
00395
00396 return offset;
00397 }
00398 }
00399
00400 if ((len > 0) && (text[offset] == '-' || text[offset] =='+'))
00401 {
00402 offset++;
00403 len--;
00404 }
00405
00406 b = false;
00407
00408 while ((len > 0) && text[offset].isDigit())
00409 {
00410 offset++;
00411 len--;
00412 b = true;
00413 }
00414
00415 if (b)
00416 {
00417 if (len > 0)
00418 {
00419 for (int i=0; i < subItems.size(); ++i)
00420 {
00421 int offset2 = subItems[i]->checkHgl(text, offset, len);
00422
00423 if (offset2)
00424 return offset2;
00425 }
00426 }
00427
00428 return offset;
00429 }
00430
00431 return 0;
00432 }
00433
00434
00435
00436 KateHlCOct::KateHlCOct(int attribute, KateHlContextModification context, signed char regionId,signed char regionId2)
00437 : KateHlItem(attribute,context,regionId,regionId2)
00438 {
00439 alwaysStartEnable = false;
00440 }
00441
00442 int KateHlCOct::checkHgl(const QString& text, int offset, int len)
00443 {
00444 if (text[offset].toAscii() == '0')
00445 {
00446 offset++;
00447 len--;
00448
00449 int offset2 = offset;
00450
00451 while ((len > 0) && (text[offset2].toAscii() >= '0' && text[offset2].toAscii() <= '7'))
00452 {
00453 offset2++;
00454 len--;
00455 }
00456
00457 if (offset2 > offset)
00458 {
00459 if ((len > 0) && ((text[offset2].toAscii() & 0xdf) == 'L' || (text[offset].toAscii() & 0xdf) == 'U' ))
00460 offset2++;
00461
00462 return offset2;
00463 }
00464 }
00465
00466 return 0;
00467 }
00468
00469
00470
00471 KateHlCHex::KateHlCHex(int attribute, KateHlContextModification context,signed char regionId,signed char regionId2)
00472 : KateHlItem(attribute,context,regionId,regionId2)
00473 {
00474 alwaysStartEnable = false;
00475 }
00476
00477 int KateHlCHex::checkHgl(const QString& text, int offset, int len)
00478 {
00479 if ((len > 1) && (text[offset++].toAscii() == '0') && ((text[offset++].toAscii() & 0xdf) == 'X' ))
00480 {
00481 len -= 2;
00482
00483 int offset2 = offset;
00484
00485 while ((len > 0) && (text[offset2].isDigit() || ((text[offset2].toAscii() & 0xdf) >= 'A' && (text[offset2].toAscii() & 0xdf) <= 'F')))
00486 {
00487 offset2++;
00488 len--;
00489 }
00490
00491 if (offset2 > offset)
00492 {
00493 if ((len > 0) && ((text[offset2].toAscii() & 0xdf) == 'L' || (text[offset2].toAscii() & 0xdf) == 'U' ))
00494 offset2++;
00495
00496 return offset2;
00497 }
00498 }
00499
00500 return 0;
00501 }
00502
00503
00504
00505 KateHlCFloat::KateHlCFloat(int attribute, KateHlContextModification context, signed char regionId,signed char regionId2)
00506 : KateHlFloat(attribute,context,regionId,regionId2)
00507 {
00508 alwaysStartEnable = false;
00509 }
00510
00511 int KateHlCFloat::checkIntHgl(const QString& text, int offset, int len)
00512 {
00513 int offset2 = offset;
00514
00515 while ((len > 0) && text[offset].isDigit()) {
00516 offset2++;
00517 len--;
00518 }
00519
00520 if (offset2 > offset)
00521 return offset2;
00522
00523 return 0;
00524 }
00525
00526 int KateHlCFloat::checkHgl(const QString& text, int offset, int len)
00527 {
00528 int offset2 = KateHlFloat::checkHgl(text, offset, len);
00529
00530 if (offset2)
00531 {
00532 if ((text[offset2].toAscii() & 0xdf) == 'F' )
00533 offset2++;
00534
00535 return offset2;
00536 }
00537 else
00538 {
00539 offset2 = checkIntHgl(text, offset, len);
00540
00541 if (offset2 && ((text[offset2].toAscii() & 0xdf) == 'F' ))
00542 return ++offset2;
00543 else
00544 return 0;
00545 }
00546 }
00547
00548
00549
00550 KateHlAnyChar::KateHlAnyChar(int attribute, KateHlContextModification context, signed char regionId,signed char regionId2, const QString& charList)
00551 : KateHlItem(attribute, context,regionId,regionId2)
00552 , _charList(charList)
00553 {
00554 }
00555
00556 int KateHlAnyChar::checkHgl(const QString& text, int offset, int)
00557 {
00558 if (_charList.contains(text[offset]))
00559 return ++offset;
00560
00561 return 0;
00562 }
00563
00564
00565
00566 KateHlRegExpr::KateHlRegExpr( int attribute, KateHlContextModification context, signed char regionId,signed char regionId2, const QString ®exp, bool insensitive, bool minimal)
00567 : KateHlItem(attribute, context, regionId,regionId2)
00568 , handlesLinestart (regexp.startsWith('^'))
00569 , _regexp(regexp)
00570 , _insensitive(insensitive)
00571 , _minimal(minimal)
00572 {
00573 Expr = new QRegExp(handlesLinestart ? regexp : '^' + regexp, _insensitive ? Qt::CaseInsensitive : Qt::CaseSensitive );
00574 Expr->setMinimal(_minimal);
00575 }
00576
00577 int KateHlRegExpr::checkHgl(const QString& text, int offset, int )
00578 {
00579 if (offset && handlesLinestart)
00580 return 0;
00581
00582 int offset2 = Expr->indexIn( text, offset, QRegExp::CaretAtOffset );
00583
00584 if (offset2 == -1) return 0;
00585
00586 return (offset + Expr->matchedLength());
00587 }
00588
00589 QStringList *KateHlRegExpr::capturedTexts()
00590 {
00591 return new QStringList(Expr->capturedTexts());
00592 }
00593
00594 KateHlItem *KateHlRegExpr::clone(const QStringList *args)
00595 {
00596 QString regexp = _regexp;
00597 QStringList escArgs = *args;
00598
00599 for (QStringList::Iterator it = escArgs.begin(); it != escArgs.end(); ++it)
00600 {
00601 (*it).replace(QRegExp("(\\W)"), "\\\\1");
00602 }
00603
00604 dynamicSubstitute(regexp, &escArgs);
00605
00606 if (regexp == _regexp)
00607 return this;
00608
00609
00610
00611 KateHlRegExpr *ret = new KateHlRegExpr(attr, ctx, region, region2, regexp, _insensitive, _minimal);
00612 ret->dynamicChild = true;
00613 return ret;
00614 }
00615
00616
00617
00618 KateHlLineContinue::KateHlLineContinue(int attribute, KateHlContextModification context, signed char regionId,signed char regionId2)
00619 : KateHlItem(attribute,context,regionId,regionId2) {
00620 }
00621
00622 int KateHlLineContinue::checkHgl(const QString& text, int offset, int len)
00623 {
00624 if ((len == 1) && (text[offset] == '\\'))
00625 return ++offset;
00626
00627 return 0;
00628 }
00629
00630
00631
00632 KateHlCStringChar::KateHlCStringChar(int attribute, KateHlContextModification context,signed char regionId,signed char regionId2)
00633 : KateHlItem(attribute,context,regionId,regionId2) {
00634 }
00635
00636
00637 static int checkEscapedChar(const QString& text, int offset, int& len)
00638 {
00639 int i;
00640 if (text[offset] == '\\' && len > 1)
00641 {
00642 offset++;
00643 len--;
00644
00645 switch(text[offset].toAscii())
00646 {
00647 case 'a':
00648 case 'b':
00649 case 'e':
00650 case 'f':
00651
00652 case 'n':
00653 case 'r':
00654 case 't':
00655 case 'v':
00656 case '\'':
00657 case '\"':
00658 case '?' :
00659 case '\\':
00660 offset++;
00661 len--;
00662 break;
00663
00664 case 'x':
00665 offset++;
00666 len--;
00667
00668
00669
00670
00671 for (i = 0; (len > 0) && (i < 2); i++)
00672 {
00673 const char ch = text[offset].toAscii();
00674 if (((ch >= '0') && (ch <= '9')) || (((ch & 0xdf) >= 'A') && ((ch & 0xdf) <= 'F'))) {
00675 offset++;
00676 len--;
00677 } else {
00678 break;
00679 }
00680 }
00681
00682 if (i == 0)
00683 return 0;
00684
00685 break;
00686
00687 case '0': case '1': case '2': case '3' :
00688 case '4': case '5': case '6': case '7' :
00689 for (i = 0; (len > 0) && (i < 3) && (text[offset] >='0'&& text[offset] <='7'); i++)
00690 {
00691 offset++;
00692 len--;
00693 }
00694 break;
00695
00696 default:
00697 return 0;
00698 }
00699
00700 return offset;
00701 }
00702
00703 return 0;
00704 }
00705
00706 int KateHlCStringChar::checkHgl(const QString& text, int offset, int len)
00707 {
00708 return checkEscapedChar(text, offset, len);
00709 }
00710
00711
00712
00713 KateHlCChar::KateHlCChar(int attribute, KateHlContextModification context,signed char regionId,signed char regionId2)
00714 : KateHlItem(attribute,context,regionId,regionId2) {
00715 }
00716
00717 int KateHlCChar::checkHgl(const QString& text, int offset, int len)
00718 {
00719 if ((len > 1) && (text[offset] == '\'') && (text[offset+1] != '\''))
00720 {
00721 int oldl;
00722 oldl = len;
00723
00724 len--;
00725
00726 int offset2 = checkEscapedChar(text, offset + 1, len);
00727
00728 if (!offset2)
00729 {
00730 if (oldl > 2)
00731 {
00732 offset2 = offset + 2;
00733 len = oldl - 2;
00734 }
00735 else
00736 {
00737 return 0;
00738 }
00739 }
00740
00741 if ((len > 0) && (text[offset2] == '\''))
00742 return ++offset2;
00743 }
00744
00745 return 0;
00746 }
00747
00748
00749
00750 KateHl2CharDetect::KateHl2CharDetect(int attribute, KateHlContextModification context, signed char regionId,signed char regionId2, const QChar *s)
00751 : KateHlItem(attribute,context,regionId,regionId2) {
00752 sChar1 = s[0];
00753 sChar2 = s[1];
00754 }
00755
00756
00757
00758 KateHlContext::KateHlContext (const QString &_hlId, int attribute, KateHlContextModification _lineEndContext, KateHlContextModification _lineBeginContext, bool _fallthrough,
00759 KateHlContextModification _fallthroughContext, bool _dynamic, bool _noIndentationBasedFolding)
00760 {
00761 hlId = _hlId;
00762 attr = attribute;
00763 lineEndContext = _lineEndContext;
00764 lineBeginContext = _lineBeginContext;
00765 fallthrough = _fallthrough;
00766 ftctx = _fallthroughContext;
00767 dynamic = _dynamic;
00768 dynamicChild = false;
00769 noIndentationBasedFolding=_noIndentationBasedFolding;
00770 if (_noIndentationBasedFolding) kDebug(13010)<<QString("**********************_noIndentationBasedFolding is TRUE*****************");
00771
00772 }
00773
00774 KateHlContext *KateHlContext::clone(const QStringList *args)
00775 {
00776 KateHlContext *ret = new KateHlContext(hlId, attr, lineEndContext, lineBeginContext, fallthrough, ftctx, false,noIndentationBasedFolding);
00777
00778 for (int n=0; n < items.size(); ++n)
00779 {
00780 KateHlItem *item = items[n];
00781 KateHlItem *i = (item->dynamic ? item->clone(args) : item);
00782 ret->items.append(i);
00783 }
00784
00785 ret->dynamicChild = true;
00786
00787 return ret;
00788 }
00789
00790 KateHlContext::~KateHlContext()
00791 {
00792 if (dynamicChild)
00793 {
00794 for (int n=0; n < items.size(); ++n)
00795 {
00796 if (items[n]->dynamicChild)
00797 delete items[n];
00798 }
00799 }
00800 }
00801
00802
00803