TDE core libraries
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3473 lines
100 KiB

9 years ago
  1. /* This file is part of the KDE libraries
  2. Copyright (C) 2003, 2004 Anders Lund <anders@alweb.dk>
  3. Copyright (C) 2003 Hamish Rodda <rodda@kde.org>
  4. Copyright (C) 2001,2002 Joseph Wenninger <jowenn@kde.org>
  5. Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org>
  6. Copyright (C) 1999 Jochen Wilhelmy <digisnap@cs.tu-berlin.de>
  7. This library is free software; you can redistribute it and/or
  8. modify it under the terms of the GNU Library General Public
  9. License version 2 as published by the Free Software Foundation.
  10. This library is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. Library General Public License for more details.
  14. You should have received a copy of the GNU Library General Public License
  15. along with this library; see the file COPYING.LIB. If not, write to
  16. the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  17. Boston, MA 02110-1301, USA.
  18. */
  19. //BEGIN INCLUDES
  20. #include "katehighlight.h"
  21. #include "katehighlight.moc"
  22. #include "katetextline.h"
  23. #include "katedocument.h"
  24. #include "katesyntaxdocument.h"
  25. #include "katerenderer.h"
  26. #include "katefactory.h"
  27. #include "kateschema.h"
  28. #include "kateconfig.h"
  29. #include <tdeconfig.h>
  30. #include <tdeglobal.h>
  31. #include <kinstance.h>
  32. #include <kmimetype.h>
  33. #include <tdelocale.h>
  34. #include <kregexp.h>
  35. #include <tdepopupmenu.h>
  36. #include <tdeglobalsettings.h>
  37. #include <kdebug.h>
  38. #include <kstandarddirs.h>
  39. #include <tdemessagebox.h>
  40. #include <kstaticdeleter.h>
  41. #include <tdeapplication.h>
  42. #include <tqstringlist.h>
  43. #include <tqtextstream.h>
  44. //END
  45. //BEGIN defines
  46. // same as in kmimemagic, no need to feed more data
  47. #define KATE_HL_HOWMANY 1024
  48. // min. x seconds between two dynamic contexts reset
  49. static const int KATE_DYNAMIC_CONTEXTS_RESET_DELAY = 30 * 1000;
  50. // x is a TQString. if x is "true" or "1" this expression returns "true"
  51. #define IS_TRUE(x) x.lower() == TQString("true") || x.toInt() == 1
  52. //END defines
  53. //BEGIN Prviate HL classes
  54. inline bool kateInsideString (const TQString &str, TQChar ch)
  55. {
  56. const TQChar *unicode = str.unicode();
  57. const uint len = str.length();
  58. for (uint i=0; i < len; i++)
  59. if (unicode[i] == ch)
  60. return true;
  61. return false;
  62. }
  63. class KateHlItem
  64. {
  65. public:
  66. KateHlItem(int attribute, int context,signed char regionId, signed char regionId2);
  67. virtual ~KateHlItem();
  68. public:
  69. // caller must keep in mind: LEN > 0 is a must !!!!!!!!!!!!!!!!!!!!!1
  70. // Now, the function returns the offset detected, or 0 if no match is found.
  71. // bool linestart isn't needed, this is equivalent to offset == 0.
  72. virtual int checkHgl(const TQString& text, int offset, int len) = 0;
  73. virtual bool lineContinue(){return false;}
  74. virtual TQStringList *capturedTexts() {return 0;}
  75. virtual KateHlItem *clone(const TQStringList *) {return this;}
  76. static void dynamicSubstitute(TQString& str, const TQStringList *args);
  77. TQMemArray<KateHlItem*> subItems;
  78. int attr;
  79. int ctx;
  80. signed char region;
  81. signed char region2;
  82. bool lookAhead;
  83. bool dynamic;
  84. bool dynamicChild;
  85. bool firstNonSpace;
  86. bool onlyConsume;
  87. int column;
  88. // start enable flags, nicer than the virtual methodes
  89. // saves function calls
  90. bool alwaysStartEnable;
  91. bool customStartEnable;
  92. };
  93. class KateHlContext
  94. {
  95. public:
  96. KateHlContext(const TQString &_hlId, int attribute, int lineEndContext,int _lineBeginContext,
  97. bool _fallthrough, int _fallthroughContext, bool _dynamic,bool _noIndentationBasedFolding);
  98. virtual ~KateHlContext();
  99. KateHlContext *clone(const TQStringList *args);
  100. TQValueVector<KateHlItem*> items;
  101. TQString hlId; ///< A unique highlight identifier. Used to look up correct properties.
  102. int attr;
  103. int ctx;
  104. int lineBeginContext;
  105. /** @internal anders: possible escape if no rules matches.
  106. false unless 'fallthrough="1|true"' (insensitive)
  107. if true, go to ftcxt w/o eating of string.
  108. ftctx is "fallthroughContext" in xml files, valid values are int or #pop[..]
  109. see in KateHighlighting::doHighlight */
  110. bool fallthrough;
  111. int ftctx; // where to go after no rules matched
  112. bool dynamic;
  113. bool dynamicChild;
  114. bool noIndentationBasedFolding;
  115. };
  116. class KateEmbeddedHlInfo
  117. {
  118. public:
  119. KateEmbeddedHlInfo() {loaded=false;context0=-1;}
  120. KateEmbeddedHlInfo(bool l, int ctx0) {loaded=l;context0=ctx0;}
  121. public:
  122. bool loaded;
  123. int context0;
  124. };
  125. class KateHlIncludeRule
  126. {
  127. public:
  128. KateHlIncludeRule(int ctx_=0, uint pos_=0, const TQString &incCtxN_="", bool incAttrib=false)
  129. : ctx(ctx_)
  130. , pos( pos_)
  131. , incCtxN( incCtxN_ )
  132. , includeAttrib( incAttrib )
  133. {
  134. incCtx=-1;
  135. }
  136. //KateHlIncludeRule(int ctx_, uint pos_, bool incAttrib) {ctx=ctx_;pos=pos_;incCtx=-1;incCtxN="";includeAttrib=incAttrib}
  137. public:
  138. int ctx;
  139. uint pos;
  140. int incCtx;
  141. TQString incCtxN;
  142. bool includeAttrib;
  143. };
  144. class KateHlCharDetect : public KateHlItem
  145. {
  146. public:
  147. KateHlCharDetect(int attribute, int context,signed char regionId,signed char regionId2, TQChar);
  148. virtual int checkHgl(const TQString& text, int offset, int len);
  149. virtual KateHlItem *clone(const TQStringList *args);
  150. private:
  151. TQChar sChar;
  152. };
  153. class KateHl2CharDetect : public KateHlItem
  154. {
  155. public:
  156. KateHl2CharDetect(int attribute, int context, signed char regionId,signed char regionId2, TQChar ch1, TQChar ch2);
  157. KateHl2CharDetect(int attribute, int context,signed char regionId,signed char regionId2, const TQChar *ch);
  158. virtual int checkHgl(const TQString& text, int offset, int len);
  159. virtual KateHlItem *clone(const TQStringList *args);
  160. private:
  161. TQChar sChar1;
  162. TQChar sChar2;
  163. };
  164. class KateHlStringDetect : public KateHlItem
  165. {
  166. public:
  167. KateHlStringDetect(int attribute, int context, signed char regionId,signed char regionId2, const TQString &, bool inSensitive=false);
  168. virtual int checkHgl(const TQString& text, int offset, int len);
  169. virtual KateHlItem *clone(const TQStringList *args);
  170. private:
  171. const TQString str;
  172. const int strLen;
  173. const bool _inSensitive;
  174. };
  175. class KateHlRangeDetect : public KateHlItem
  176. {
  177. public:
  178. KateHlRangeDetect(int attribute, int context, signed char regionId,signed char regionId2, TQChar ch1, TQChar ch2);
  179. virtual int checkHgl(const TQString& text, int offset, int len);
  180. private:
  181. TQChar sChar1;
  182. TQChar sChar2;
  183. };
  184. class KateHlKeyword : public KateHlItem
  185. {
  186. public:
  187. KateHlKeyword(int attribute, int context,signed char regionId,signed char regionId2, bool insensitive, const TQString& delims);
  188. virtual ~KateHlKeyword ();
  189. void addList(const TQStringList &);
  190. virtual int checkHgl(const TQString& text, int offset, int len);
  191. private:
  192. TQMemArray< TQDict<bool>* > dict;
  193. bool _insensitive;
  194. const TQString& deliminators;
  195. int minLen;
  196. int maxLen;
  197. };
  198. class KateHlInt : public KateHlItem
  199. {
  200. public:
  201. KateHlInt(int attribute, int context, signed char regionId,signed char regionId2);
  202. virtual int checkHgl(const TQString& text, int offset, int len);
  203. };
  204. class KateHlFloat : public KateHlItem
  205. {
  206. public:
  207. KateHlFloat(int attribute, int context, signed char regionId,signed char regionId2);
  208. virtual ~KateHlFloat () {}
  209. virtual int checkHgl(const TQString& text, int offset, int len);
  210. };
  211. class KateHlCFloat : public KateHlFloat
  212. {
  213. public:
  214. KateHlCFloat(int attribute, int context, signed char regionId,signed char regionId2);
  215. virtual int checkHgl(const TQString& text, int offset, int len);
  216. int checkIntHgl(const TQString& text, int offset, int len);
  217. };
  218. class KateHlCOct : public KateHlItem
  219. {
  220. public:
  221. KateHlCOct(int attribute, int context, signed char regionId,signed char regionId2);
  222. virtual int checkHgl(const TQString& text, int offset, int len);
  223. };
  224. class KateHlCHex : public KateHlItem
  225. {
  226. public:
  227. KateHlCHex(int attribute, int context, signed char regionId,signed char regionId2);
  228. virtual int checkHgl(const TQString& text, int offset, int len);
  229. };
  230. class KateHlLineContinue : public KateHlItem
  231. {
  232. public:
  233. KateHlLineContinue(int attribute, int context, signed char regionId,signed char regionId2);
  234. virtual bool endEnable(TQChar c) {return c == '\0';}
  235. virtual int checkHgl(const TQString& text, int offset, int len);
  236. virtual bool lineContinue(){return true;}
  237. };
  238. class KateHlCStringChar : public KateHlItem
  239. {
  240. public:
  241. KateHlCStringChar(int attribute, int context, signed char regionId,signed char regionId2);
  242. virtual int checkHgl(const TQString& text, int offset, int len);
  243. };
  244. class KateHlCChar : public KateHlItem
  245. {
  246. public:
  247. KateHlCChar(int attribute, int context,signed char regionId,signed char regionId2);
  248. virtual int checkHgl(const TQString& text, int offset, int len);
  249. };
  250. class KateHlAnyChar : public KateHlItem
  251. {
  252. public:
  253. KateHlAnyChar(int attribute, int context, signed char regionId,signed char regionId2, const TQString& charList);
  254. virtual int checkHgl(const TQString& text, int offset, int len);
  255. private:
  256. const TQString _charList;
  257. };
  258. class KateHlRegExpr : public KateHlItem
  259. {
  260. public:
  261. KateHlRegExpr(int attribute, int context,signed char regionId,signed char regionId2 ,TQString expr, bool insensitive, bool minimal);
  262. ~KateHlRegExpr() { delete Expr; };
  263. virtual int checkHgl(const TQString& text, int offset, int len);
  264. virtual TQStringList *capturedTexts();
  265. virtual KateHlItem *clone(const TQStringList *args);
  266. private:
  267. TQRegExp *Expr;
  268. bool handlesLinestart;
  269. TQString _regexp;
  270. bool _insensitive;
  271. bool _minimal;
  272. };
  273. class KateHlDetectSpaces : public KateHlItem
  274. {
  275. public:
  276. KateHlDetectSpaces (int attribute, int context,signed char regionId,signed char regionId2)
  277. : KateHlItem(attribute,context,regionId,regionId2) {}
  278. virtual int checkHgl(const TQString& text, int offset, int len)
  279. {
  280. int len2 = offset + len;
  281. while ((offset < len2) && text[offset].isSpace()) offset++;
  282. return offset;
  283. }
  284. };
  285. class KateHlDetectIdentifier : public KateHlItem
  286. {
  287. public:
  288. KateHlDetectIdentifier (int attribute, int context,signed char regionId,signed char regionId2)
  289. : KateHlItem(attribute,context,regionId,regionId2) { alwaysStartEnable = false; }
  290. virtual int checkHgl(const TQString& text, int offset, int len)
  291. {
  292. // first char should be a letter or underscore
  293. if ( text[offset].isLetter() || text[offset] == TQChar ('_') )
  294. {
  295. // memorize length
  296. int len2 = offset+len;
  297. // one char seen
  298. offset++;
  299. // now loop for all other thingies
  300. while (
  301. (offset < len2)
  302. && (text[offset].isLetterOrNumber() || (text[offset] == TQChar ('_')))
  303. )
  304. offset++;
  305. return offset;
  306. }
  307. return 0;
  308. }
  309. };
  310. //END
  311. //BEGIN STATICS
  312. KateHlManager *KateHlManager::s_self = 0;
  313. static const bool trueBool = true;
  314. static const TQString stdDeliminator = TQString (" \t.():!+,-<=>%&*/;?[]^{|}~\\");
  315. //END
  316. //BEGIN NON MEMBER FUNCTIONS
  317. static KateHlItemData::ItemStyles getDefStyleNum(TQString name)
  318. {
  319. if (name=="dsNormal") return KateHlItemData::dsNormal;
  320. else if (name=="dsKeyword") return KateHlItemData::dsKeyword;
  321. else if (name=="dsDataType") return KateHlItemData::dsDataType;
  322. else if (name=="dsDecVal") return KateHlItemData::dsDecVal;
  323. else if (name=="dsBaseN") return KateHlItemData::dsBaseN;
  324. else if (name=="dsFloat") return KateHlItemData::dsFloat;
  325. else if (name=="dsChar") return KateHlItemData::dsChar;
  326. else if (name=="dsString") return KateHlItemData::dsString;
  327. else if (name=="dsComment") return KateHlItemData::dsComment;
  328. else if (name=="dsOthers") return KateHlItemData::dsOthers;
  329. else if (name=="dsAlert") return KateHlItemData::dsAlert;
  330. else if (name=="dsFunction") return KateHlItemData::dsFunction;
  331. else if (name=="dsRegionMarker") return KateHlItemData::dsRegionMarker;
  332. else if (name=="dsError") return KateHlItemData::dsError;
  333. return KateHlItemData::dsNormal;
  334. }
  335. //END
  336. //BEGIN KateHlItem
  337. KateHlItem::KateHlItem(int attribute, int context,signed char regionId,signed char regionId2)
  338. : attr(attribute),
  339. ctx(context),
  340. region(regionId),
  341. region2(regionId2),
  342. lookAhead(false),
  343. dynamic(false),
  344. dynamicChild(false),
  345. firstNonSpace(false),
  346. onlyConsume(false),
  347. column (-1),
  348. alwaysStartEnable (true),
  349. customStartEnable (false)
  350. {
  351. }
  352. KateHlItem::~KateHlItem()
  353. {
  354. //kdDebug(13010)<<"In hlItem::~KateHlItem()"<<endl;
  355. for (uint i=0; i < subItems.size(); i++)
  356. delete subItems[i];
  357. }
  358. void KateHlItem::dynamicSubstitute(TQString &str, const TQStringList *args)
  359. {
  360. for (uint i = 0; i < str.length() - 1; ++i)
  361. {
  362. if (str[i] == '%')
  363. {
  364. char c = str[i + 1].latin1();
  365. if (c == '%')
  366. str.replace(i, 1, "");
  367. else if (c >= '0' && c <= '9')
  368. {
  369. if ((uint)(c - '0') < args->size())
  370. {
  371. str.replace(i, 2, (*args)[c - '0']);
  372. i += ((*args)[c - '0']).length() - 1;
  373. }
  374. else
  375. {
  376. str.replace(i, 2, "");
  377. --i;
  378. }
  379. }
  380. }
  381. }
  382. }
  383. //END
  384. //BEGIN KateHlCharDetect
  385. KateHlCharDetect::KateHlCharDetect(int attribute, int context, signed char regionId,signed char regionId2, TQChar c)
  386. : KateHlItem(attribute,context,regionId,regionId2)
  387. , sChar(c)
  388. {
  389. }
  390. int KateHlCharDetect::checkHgl(const TQString& text, int offset, int /*len*/)
  391. {
  392. if (text[offset] == sChar)
  393. return offset + 1;
  394. return 0;
  395. }
  396. KateHlItem *KateHlCharDetect::clone(const TQStringList *args)
  397. {
  398. char c = sChar.latin1();
  399. if (c < '0' || c > '9' || (unsigned)(c - '0') >= args->size())
  400. return this;
  401. KateHlCharDetect *ret = new KateHlCharDetect(attr, ctx, region, region2, (*args)[c - '0'][0]);
  402. ret->dynamicChild = true;
  403. return ret;
  404. }
  405. //END
  406. //BEGIN KateHl2CharDetect
  407. KateHl2CharDetect::KateHl2CharDetect(int attribute, int context, signed char regionId,signed char regionId2, TQChar ch1, TQChar ch2)
  408. : KateHlItem(attribute,context,regionId,regionId2)
  409. , sChar1 (ch1)
  410. , sChar2 (ch2)
  411. {
  412. }
  413. int KateHl2CharDetect::checkHgl(const TQString& text, int offset, int len)
  414. {
  415. if ((len >= 2) && text[offset++] == sChar1 && text[offset++] == sChar2)
  416. return offset;
  417. return 0;
  418. }
  419. KateHlItem *KateHl2CharDetect::clone(const TQStringList *args)
  420. {
  421. char c1 = sChar1.latin1();
  422. char c2 = sChar2.latin1();
  423. if (c1 < '0' || c1 > '9' || (unsigned)(c1 - '0') >= args->size())
  424. return this;
  425. if (c2 < '0' || c2 > '9' || (unsigned)(c2 - '0') >= args->size())
  426. return this;
  427. KateHl2CharDetect *ret = new KateHl2CharDetect(attr, ctx, region, region2, (*args)[c1 - '0'][0], (*args)[c2 - '0'][0]);
  428. ret->dynamicChild = true;
  429. return ret;
  430. }
  431. //END
  432. //BEGIN KateHlStringDetect
  433. KateHlStringDetect::KateHlStringDetect(int attribute, int context, signed char regionId,signed char regionId2,const TQString &s, bool inSensitive)
  434. : KateHlItem(attribute, context,regionId,regionId2)
  435. , str(inSensitive ? s.upper() : s)
  436. , strLen (str.length())
  437. , _inSensitive(inSensitive)
  438. {
  439. }
  440. int KateHlStringDetect::checkHgl(const TQString& text, int offset, int len)
  441. {
  442. if (len < strLen)
  443. return 0;
  444. if (_inSensitive)
  445. {
  446. for (int i=0; i < strLen; i++)
  447. if (text[offset++].upper() != str[i])
  448. return 0;
  449. return offset;
  450. }
  451. else
  452. {
  453. for (int i=0; i < strLen; i++)
  454. if (text[offset++] != str[i])
  455. return 0;
  456. return offset;
  457. }
  458. return 0;
  459. }
  460. KateHlItem *KateHlStringDetect::clone(const TQStringList *args)
  461. {
  462. TQString newstr = str;
  463. dynamicSubstitute(newstr, args);
  464. if (newstr == str)
  465. return this;
  466. KateHlStringDetect *ret = new KateHlStringDetect(attr, ctx, region, region2, newstr, _inSensitive);
  467. ret->dynamicChild = true;
  468. return ret;
  469. }
  470. //END
  471. //BEGIN KateHlRangeDetect
  472. KateHlRangeDetect::KateHlRangeDetect(int attribute, int context, signed char regionId,signed char regionId2, TQChar ch1, TQChar ch2)
  473. : KateHlItem(attribute,context,regionId,regionId2)
  474. , sChar1 (ch1)
  475. , sChar2 (ch2)
  476. {
  477. }
  478. int KateHlRangeDetect::checkHgl(const TQString& text, int offset, int len)
  479. {
  480. if (text[offset] == sChar1)
  481. {
  482. do
  483. {
  484. offset++;
  485. len--;
  486. if (len < 1) return 0;
  487. }
  488. while (text[offset] != sChar2);
  489. return offset + 1;
  490. }
  491. return 0;
  492. }
  493. //END
  494. //BEGIN KateHlKeyword
  495. KateHlKeyword::KateHlKeyword (int attribute, int context, signed char regionId,signed char regionId2, bool insensitive, const TQString& delims)
  496. : KateHlItem(attribute,context,regionId,regionId2)
  497. , _insensitive(insensitive)
  498. , deliminators(delims)
  499. , minLen (0xFFFFFF)
  500. , maxLen (0)
  501. {
  502. alwaysStartEnable = false;
  503. customStartEnable = true;
  504. }
  505. KateHlKeyword::~KateHlKeyword ()
  506. {
  507. for (uint i=0; i < dict.size(); ++i)
  508. delete dict[i];
  509. }
  510. void KateHlKeyword::addList(const TQStringList& list)
  511. {
  512. for(uint i=0; i < list.count(); ++i)
  513. {
  514. int len = list[i].length();
  515. if (minLen > len)
  516. minLen = len;
  517. if (maxLen < len)
  518. maxLen = len;
  519. if ((uint)len >= dict.size())
  520. {
  521. uint oldSize = dict.size();
  522. dict.resize (len+1);
  523. for (uint m=oldSize; m < dict.size(); ++m)
  524. dict[m] = 0;
  525. }
  526. if (!dict[len])
  527. dict[len] = new TQDict<bool> (17, !_insensitive);
  528. dict[len]->insert(list[i], &trueBool);
  529. }
  530. }
  531. int KateHlKeyword::checkHgl(const TQString& text, int offset, int len)
  532. {
  533. int offset2 = offset;
  534. int wordLen = 0;
  535. while ((len > wordLen) && !kateInsideString (deliminators, text[offset2]))
  536. {
  537. offset2++;
  538. wordLen++;
  539. if (wordLen > maxLen) return 0;
  540. }
  541. if (wordLen < minLen) return 0;
  542. if ( dict[wordLen] && dict[wordLen]->find(TQConstString(text.unicode() + offset, wordLen).string()) )
  543. return offset2;
  544. return 0;
  545. }
  546. //END
  547. //BEGIN KateHlInt
  548. KateHlInt::KateHlInt(int attribute, int context, signed char regionId,signed char regionId2)
  549. : KateHlItem(attribute,context,regionId,regionId2)
  550. {
  551. alwaysStartEnable = false;
  552. }
  553. int KateHlInt::checkHgl(const TQString& text, int offset, int len)
  554. {
  555. int offset2 = offset;
  556. while ((len > 0) && text[offset2].isDigit())
  557. {
  558. offset2++;
  559. len--;
  560. }
  561. if (offset2 > offset)
  562. {
  563. if (len > 0)
  564. {
  565. for (uint i=0; i < subItems.size(); i++)
  566. {
  567. if ( (offset = subItems[i]->checkHgl(text, offset2, len)) )
  568. return offset;
  569. }
  570. }
  571. return offset2;
  572. }
  573. return 0;
  574. }
  575. //END
  576. //BEGIN KateHlFloat
  577. KateHlFloat::KateHlFloat(int attribute, int context, signed char regionId,signed char regionId2)
  578. : KateHlItem(attribute,context, regionId,regionId2)
  579. {
  580. alwaysStartEnable = false;
  581. }
  582. int KateHlFloat::checkHgl(const TQString& text, int offset, int len)
  583. {
  584. bool b = false;
  585. bool p = false;
  586. while ((len > 0) && text[offset].isDigit())
  587. {
  588. offset++;
  589. len--;
  590. b = true;
  591. }
  592. if ((len > 0) && (p = (text[offset] == '.')))
  593. {
  594. offset++;
  595. len--;
  596. while ((len > 0) && text[offset].isDigit())
  597. {
  598. offset++;
  599. len--;
  600. b = true;
  601. }
  602. }
  603. if (!b)
  604. return 0;
  605. if ((len > 0) && ((text[offset] & 0xdf) == 'E'))
  606. {
  607. offset++;
  608. len--;
  609. }
  610. else
  611. {
  612. if (!p)
  613. return 0;
  614. else
  615. {
  616. if (len > 0)
  617. {
  618. for (uint i=0; i < subItems.size(); i++)
  619. {
  620. int offset2 = subItems[i]->checkHgl(text, offset, len);
  621. if (offset2)
  622. return offset2;
  623. }
  624. }
  625. return offset;
  626. }
  627. }
  628. if ((len > 0) && (text[offset] == '-' || text[offset] =='+'))
  629. {
  630. offset++;
  631. len--;
  632. }
  633. b = false;
  634. while ((len > 0) && text[offset].isDigit())
  635. {
  636. offset++;
  637. len--;
  638. b = true;
  639. }
  640. if (b)
  641. {
  642. if (len > 0)
  643. {
  644. for (uint i=0; i < subItems.size(); i++)
  645. {
  646. int offset2 = subItems[i]->checkHgl(text, offset, len);
  647. if (offset2)
  648. return offset2;
  649. }
  650. }
  651. return offset;
  652. }
  653. return 0;
  654. }
  655. //END
  656. //BEGIN KateHlCOct
  657. KateHlCOct::KateHlCOct(int attribute, int context, signed char regionId,signed char regionId2)
  658. : KateHlItem(attribute,context,regionId,regionId2)
  659. {
  660. alwaysStartEnable = false;
  661. }
  662. int KateHlCOct::checkHgl(const TQString& text, int offset, int len)
  663. {
  664. if (text[offset] == '0')
  665. {
  666. offset++;
  667. len--;
  668. int offset2 = offset;
  669. while ((len > 0) && (text.at(offset2) >= TQChar('0') && text.at(offset2) <= TQChar('7')))
  670. {
  671. offset2++;
  672. len--;
  673. }
  674. if (offset2 > offset)
  675. {
  676. if ((len > 0) && ((text[offset2] & 0xdf) == 'L' || (text[offset] & 0xdf) == 'U' ))
  677. offset2++;
  678. return offset2;
  679. }
  680. }
  681. return 0;
  682. }
  683. //END
  684. //BEGIN KateHlCHex
  685. KateHlCHex::KateHlCHex(int attribute, int context,signed char regionId,signed char regionId2)
  686. : KateHlItem(attribute,context,regionId,regionId2)
  687. {
  688. alwaysStartEnable = false;
  689. }
  690. int KateHlCHex::checkHgl(const TQString& text, int offset, int len)
  691. {
  692. if ((len > 1) && (text[offset++] == '0') && ((text[offset++] & 0xdf) == 'X' ))
  693. {
  694. len -= 2;
  695. int offset2 = offset;
  696. while ((len > 0) && (text[offset2].isDigit() || ((text[offset2] & 0xdf) >= 'A' && (text[offset2] & 0xdf) <= 'F')))
  697. {
  698. offset2++;
  699. len--;
  700. }
  701. if (offset2 > offset)
  702. {
  703. if ((len > 0) && ((text[offset2] & 0xdf) == 'L' || (text[offset2] & 0xdf) == 'U' ))
  704. offset2++;
  705. return offset2;
  706. }
  707. }
  708. return 0;
  709. }
  710. //END
  711. //BEGIN KateHlCFloat
  712. KateHlCFloat::KateHlCFloat(int attribute, int context, signed char regionId,signed char regionId2)
  713. : KateHlFloat(attribute,context,regionId,regionId2)
  714. {
  715. alwaysStartEnable = false;
  716. }
  717. int KateHlCFloat::checkIntHgl(const TQString& text, int offset, int len)
  718. {
  719. int offset2 = offset;
  720. while ((len > 0) && text[offset].isDigit()) {
  721. offset2++;
  722. len--;
  723. }
  724. if (offset2 > offset)
  725. return offset2;
  726. return 0;
  727. }
  728. int KateHlCFloat::checkHgl(const TQString& text, int offset, int len)
  729. {
  730. int offset2 = KateHlFloat::checkHgl(text, offset, len);
  731. if (offset2)
  732. {
  733. if ((text[offset2] & 0xdf) == 'F' )
  734. offset2++;
  735. return offset2;
  736. }
  737. else
  738. {
  739. offset2 = checkIntHgl(text, offset, len);
  740. if (offset2 && ((text[offset2] & 0xdf) == 'F' ))
  741. return ++offset2;
  742. else
  743. return 0;
  744. }
  745. }
  746. //END
  747. //BEGIN KateHlAnyChar
  748. KateHlAnyChar::KateHlAnyChar(int attribute, int context, signed char regionId,signed char regionId2, const TQString& charList)
  749. : KateHlItem(attribute, context,regionId,regionId2)
  750. , _charList(charList)
  751. {
  752. }
  753. int KateHlAnyChar::checkHgl(const TQString& text, int offset, int)
  754. {
  755. if (kateInsideString (_charList, text[offset]))
  756. return ++offset;
  757. return 0;
  758. }
  759. //END
  760. //BEGIN KateHlRegExpr
  761. KateHlRegExpr::KateHlRegExpr( int attribute, int context, signed char regionId,signed char regionId2, TQString regexp, bool insensitive, bool minimal)
  762. : KateHlItem(attribute, context, regionId,regionId2)
  763. , handlesLinestart (regexp.startsWith("^"))
  764. , _regexp(regexp)
  765. , _insensitive(insensitive)
  766. , _minimal(minimal)
  767. {
  768. if (!handlesLinestart)
  769. regexp.prepend("^");
  770. Expr = new TQRegExp(regexp, !_insensitive);
  771. Expr->setMinimal(_minimal);
  772. }
  773. int KateHlRegExpr::checkHgl(const TQString& text, int offset, int /*len*/)
  774. {
  775. if (offset && handlesLinestart)
  776. return 0;
  777. int offset2 = Expr->search( text, offset, TQRegExp::CaretAtOffset );
  778. if (offset2 == -1) return 0;
  779. return (offset + Expr->matchedLength());
  780. }
  781. TQStringList *KateHlRegExpr::capturedTexts()
  782. {
  783. return new TQStringList(Expr->capturedTexts());
  784. }
  785. KateHlItem *KateHlRegExpr::clone(const TQStringList *args)
  786. {
  787. TQString regexp = _regexp;
  788. TQStringList escArgs = *args;
  789. for (TQStringList::Iterator it = escArgs.begin(); it != escArgs.end(); ++it)
  790. {
  791. (*it).replace(TQRegExp("(\\W)"), "\\\\1");
  792. }
  793. dynamicSubstitute(regexp, &escArgs);
  794. if (regexp == _regexp)
  795. return this;
  796. // kdDebug (13010) << "clone regexp: " << regexp << endl;
  797. KateHlRegExpr *ret = new KateHlRegExpr(attr, ctx, region, region2, regexp, _insensitive, _minimal);
  798. ret->dynamicChild = true;
  799. return ret;
  800. }
  801. //END
  802. //BEGIN KateHlLineContinue
  803. KateHlLineContinue::KateHlLineContinue(int attribute, int context, signed char regionId,signed char regionId2)
  804. : KateHlItem(attribute,context,regionId,regionId2) {
  805. }
  806. int KateHlLineContinue::checkHgl(const TQString& text, int offset, int len)
  807. {
  808. if ((len == 1) && (text[offset] == '\\'))
  809. return ++offset;
  810. return 0;
  811. }
  812. //END
  813. //BEGIN KateHlCStringChar
  814. KateHlCStringChar::KateHlCStringChar(int attribute, int context,signed char regionId,signed char regionId2)
  815. : KateHlItem(attribute,context,regionId,regionId2) {
  816. }
  817. // checks for C escaped chars \n and escaped hex/octal chars
  818. static int checkEscapedChar(const TQString& text, int offset, int& len)
  819. {
  820. int i;
  821. if (text[offset] == '\\' && len > 1)
  822. {
  823. offset++;
  824. len--;
  825. switch(text[offset])
  826. {
  827. case 'a': // checks for control chars
  828. case 'b': // we want to fall through
  829. case 'e':
  830. case 'f':
  831. case 'n':
  832. case 'r':
  833. case 't':
  834. case 'v':
  835. case '\'':
  836. case '\"':
  837. case '?' : // added ? ANSI C classifies this as an escaped char
  838. case '\\':
  839. offset++;
  840. len--;
  841. break;
  842. case 'x': // if it's like \xff
  843. offset++; // eat the x
  844. len--;
  845. // these for loops can probably be
  846. // replaced with something else but
  847. // for right now they work
  848. // check for hexdigits
  849. for (i = 0; (len > 0) && (i < 2) && (static_cast<const char>(text.at(offset)) >= '0' && static_cast<const char>(text.at(offset)) <= '9' || (text[offset] & 0xdf) >= 'A' && (text[offset] & 0xdf) <= 'F'); i++)
  850. {
  851. offset++;
  852. len--;
  853. }
  854. if (i == 0)
  855. return 0; // takes care of case '\x'
  856. break;
  857. case '0': case '1': case '2': case '3' :
  858. case '4': case '5': case '6': case '7' :
  859. for (i = 0; (len > 0) && (i < 3) && (static_cast<const char>(text.at(offset)) >= '0' && static_cast<const char>(text.at(offset)) <= '7'); i++)
  860. {
  861. offset++;
  862. len--;
  863. }
  864. break;
  865. default:
  866. return 0;
  867. }
  868. return offset;
  869. }
  870. return 0;
  871. }
  872. int KateHlCStringChar::checkHgl(const TQString& text, int offset, int len)
  873. {
  874. return checkEscapedChar(text, offset, len);
  875. }
  876. //END
  877. //BEGIN KateHlCChar
  878. KateHlCChar::KateHlCChar(int attribute, int context,signed char regionId,signed char regionId2)
  879. : KateHlItem(attribute,context,regionId,regionId2) {
  880. }
  881. int KateHlCChar::checkHgl(const TQString& text, int offset, int len)
  882. {
  883. if ((len > 1) && (text[offset] == '\'') && (text[offset+1] != '\''))
  884. {
  885. int oldl;
  886. oldl = len;
  887. len--;
  888. int offset2 = checkEscapedChar(text, offset + 1, len);
  889. if (!offset2)
  890. {
  891. if (oldl > 2)
  892. {
  893. offset2 = offset + 2;
  894. len = oldl - 2;
  895. }
  896. else
  897. {
  898. return 0;
  899. }
  900. }
  901. if ((len > 0) && (text[offset2] == '\''))
  902. return ++offset2;
  903. }
  904. return 0;
  905. }
  906. //END
  907. //BEGIN KateHl2CharDetect
  908. KateHl2CharDetect::KateHl2CharDetect(int attribute, int context, signed char regionId,signed char regionId2, const TQChar *s)
  909. : KateHlItem(attribute,context,regionId,regionId2) {
  910. sChar1 = s[0];
  911. sChar2 = s[1];
  912. }
  913. //END KateHl2CharDetect
  914. KateHlItemData::KateHlItemData(const TQString name, int defStyleNum)
  915. : name(name), defStyleNum(defStyleNum) {
  916. }
  917. KateHlData::KateHlData(const TQString &wildcards, const TQString &mimetypes, const TQString &identifier, int priority)
  918. : wildcards(wildcards), mimetypes(mimetypes), identifier(identifier), priority(priority)
  919. {
  920. }
  921. //BEGIN KateHlContext
  922. KateHlContext::KateHlContext (const TQString &_hlId, int attribute, int lineEndContext, int _lineBeginContext, bool _fallthrough,
  923. int _fallthroughContext, bool _dynamic, bool _noIndentationBasedFolding)
  924. {
  925. hlId = _hlId;
  926. attr = attribute;
  927. ctx = lineEndContext;
  928. lineBeginContext = _lineBeginContext;
  929. fallthrough = _fallthrough;
  930. ftctx = _fallthroughContext;
  931. dynamic = _dynamic;
  932. dynamicChild = false;
  933. noIndentationBasedFolding=_noIndentationBasedFolding;
  934. if (_noIndentationBasedFolding) kdDebug(13010)<<TQString("**********************_noIndentationBasedFolding is TRUE*****************")<<endl;
  935. }
  936. KateHlContext *KateHlContext::clone(const TQStringList *args)
  937. {
  938. KateHlContext *ret = new KateHlContext(hlId, attr, ctx, lineBeginContext, fallthrough, ftctx, false,noIndentationBasedFolding);
  939. for (uint n=0; n < items.size(); ++n)
  940. {
  941. KateHlItem *item = items[n];
  942. KateHlItem *i = (item->dynamic ? item->clone(args) : item);
  943. ret->items.append(i);
  944. }
  945. ret->dynamicChild = true;
  946. return ret;
  947. }
  948. KateHlContext::~KateHlContext()
  949. {
  950. if (dynamicChild)
  951. {
  952. for (uint n=0; n < items.size(); ++n)
  953. {
  954. if (items[n]->dynamicChild)
  955. delete items[n];
  956. }
  957. }
  958. }
  959. //END
  960. //BEGIN KateHighlighting
  961. KateHighlighting::KateHighlighting(const KateSyntaxModeListItem *def) : refCount(0)
  962. {
  963. m_attributeArrays.setAutoDelete (true);
  964. errorsAndWarnings = "";
  965. building=false;
  966. noHl = false;
  967. m_foldingIndentationSensitive = false;
  968. folding=false;
  969. internalIDList.setAutoDelete(true);
  970. if (def == 0)
  971. {
  972. noHl = true;
  973. iName = "None"; // not translated internal name (for config and more)
  974. iNameTranslated = i18n("None"); // user visible name
  975. iSection = "";
  976. m_priority = 0;
  977. iHidden = false;
  978. m_additionalData.insert( "none", new HighlightPropertyBag );
  979. m_additionalData["none"]->deliminator = stdDeliminator;
  980. m_additionalData["none"]->wordWrapDeliminator = stdDeliminator;
  981. m_hlIndex[0] = "none";
  982. }
  983. else
  984. {
  985. iName = def->name;
  986. iNameTranslated = def->nameTranslated;
  987. iSection = def->section;
  988. iHidden = def->hidden;
  989. iWildcards = def->extension;
  990. iMimetypes = def->mimetype;
  991. identifier = def->identifier;
  992. iVersion=def->version;
  993. iAuthor=def->author;
  994. iLicense=def->license;
  995. m_priority=def->priority.toInt();
  996. }
  997. deliminator = stdDeliminator;
  998. }
  999. KateHighlighting::~KateHighlighting()
  1000. {
  1001. // cu contexts
  1002. for (uint i=0; i < m_contexts.size(); ++i)
  1003. delete m_contexts[i];
  1004. m_contexts.clear ();
  1005. }
  1006. void KateHighlighting::generateContextStack(int *ctxNum, int ctx, TQMemArray<short>* ctxs, int *prevLine)
  1007. {
  1008. //kdDebug(13010)<<TQString("Entering generateContextStack with %1").arg(ctx)<<endl;
  1009. while (true)
  1010. {
  1011. if (ctx >= 0)
  1012. {
  1013. (*ctxNum) = ctx;
  1014. ctxs->resize (ctxs->size()+1, TQGArray::SpeedOptim);
  1015. (*ctxs)[ctxs->size()-1]=(*ctxNum);
  1016. return;
  1017. }
  1018. else
  1019. {
  1020. if (ctx == -1)
  1021. {
  1022. (*ctxNum)=( (ctxs->isEmpty() ) ? 0 : (*ctxs)[ctxs->size()-1]);
  1023. }
  1024. else
  1025. {
  1026. int size = ctxs->size() + ctx + 1;
  1027. if (size > 0)
  1028. {
  1029. ctxs->resize (size, TQGArray::SpeedOptim);
  1030. (*ctxNum)=(*ctxs)[size-1];
  1031. }
  1032. else
  1033. {
  1034. ctxs->resize (0, TQGArray::SpeedOptim);
  1035. (*ctxNum)=0;
  1036. }
  1037. ctx = 0;
  1038. if ((*prevLine) >= (int)(ctxs->size()-1))
  1039. {
  1040. *prevLine=ctxs->size()-1;
  1041. if ( ctxs->isEmpty() )
  1042. return;
  1043. KateHlContext *c = contextNum((*ctxs)[ctxs->size()-1]);
  1044. if (c && (c->ctx != -1))
  1045. {
  1046. //kdDebug(13010)<<"PrevLine > size()-1 and ctx!=-1)"<<endl;
  1047. ctx = c->ctx;
  1048. continue;
  1049. }
  1050. }
  1051. }
  1052. return;
  1053. }
  1054. }
  1055. }
  1056. /**
  1057. * Creates a new dynamic context or reuse an old one if it has already been created.
  1058. */
  1059. int KateHighlighting::makeDynamicContext(KateHlContext *model, const TQStringList *args)
  1060. {
  1061. QPair<KateHlContext *, TQString> key(model, args->front());
  1062. short value;
  1063. if (dynamicCtxs.contains(key))
  1064. value = dynamicCtxs[key];
  1065. else
  1066. {
  1067. kdDebug(13010) << "new stuff: " << startctx << endl;
  1068. KateHlContext *newctx = model->clone(args);
  1069. m_contexts.push_back (newctx);
  1070. value = startctx++;
  1071. dynamicCtxs[key] = value;
  1072. KateHlManager::self()->incDynamicCtxs();
  1073. }
  1074. // kdDebug(13010) << "Dynamic context: using context #" << value << " (for model " << model << " with args " << *args << ")" << endl;
  1075. return value;
  1076. }
  1077. /**
  1078. * Drop all dynamic contexts. Shall be called with extreme care, and shall be immediatly
  1079. * followed by a full HL invalidation.
  1080. */
  1081. void KateHighlighting::dropDynamicContexts()
  1082. {
  1083. for (uint i=base_startctx; i < m_contexts.size(); ++i)
  1084. delete m_contexts[i];
  1085. m_contexts.resize (base_startctx);
  1086. dynamicCtxs.clear();
  1087. startctx = base_startctx;
  1088. }
  1089. /**
  1090. * Parse the text and fill in the context array and folding list array
  1091. *
  1092. * @param prevLine The previous line, the context array is picked up from that if present.
  1093. * @param textLine The text line to parse
  1094. * @param foldingList will be filled
  1095. * @param ctxChanged will be set to reflect if the context changed
  1096. */
  1097. void KateHighlighting::doHighlight ( KateTextLine *prevLine,
  1098. KateTextLine *textLine,
  1099. TQMemArray<uint>* foldingList,
  1100. bool *ctxChanged )
  1101. {
  1102. if (!textLine)
  1103. return;
  1104. if (noHl)
  1105. {
  1106. if (textLine->length() > 0)
  1107. memset (textLine->attributes(), 0, textLine->length());
  1108. return;
  1109. }
  1110. // duplicate the ctx stack, only once !
  1111. TQMemArray<short> ctx;
  1112. ctx.duplicate (prevLine->ctxArray());
  1113. int ctxNum = 0;
  1114. int previousLine = -1;
  1115. KateHlContext *context;
  1116. if (ctx.isEmpty())
  1117. {
  1118. // If the stack is empty, we assume to be in Context 0 (Normal)
  1119. context = contextNum(ctxNum);
  1120. }
  1121. else
  1122. {
  1123. // There does an old context stack exist -> find the context at the line start
  1124. ctxNum = ctx[ctx.size()-1]; //context ID of the last character in the previous line
  1125. //kdDebug(13010) << "\t\tctxNum = " << ctxNum << " contextList[ctxNum] = " << contextList[ctxNum] << endl; // ellis
  1126. //if (lineContinue) kdDebug(13010)<<TQString("The old context should be %1").arg((int)ctxNum)<<endl;
  1127. if (!(context = contextNum(ctxNum)))
  1128. context = contextNum(0);
  1129. //kdDebug(13010)<<"test1-2-1-text2"<<endl;
  1130. previousLine=ctx.size()-1; //position of the last context ID of th previous line within the stack
  1131. // hl continue set or not ???
  1132. if (prevLine->hlLineContinue())
  1133. {
  1134. prevLine--;
  1135. }
  1136. else
  1137. {
  1138. generateContextStack(&ctxNum, context->ctx, &ctx, &previousLine); //get stack ID to use
  1139. if (!(context = contextNum(ctxNum)))
  1140. context = contextNum(0);
  1141. }
  1142. //kdDebug(13010)<<"test1-2-1-text4"<<endl;
  1143. //if (lineContinue) kdDebug(13010)<<TQString("The new context is %1").arg((int)ctxNum)<<endl;
  1144. }
  1145. // text, for programming convenience :)
  1146. TQChar lastChar = ' ';
  1147. const TQString& text = textLine->string();
  1148. const int len = textLine->length();
  1149. // calc at which char the first char occurs, set it to length of line if never
  1150. const int firstChar = textLine->firstChar();
  1151. const int startNonSpace = (firstChar == -1) ? len : firstChar;
  1152. // last found item
  1153. KateHlItem *item = 0;
  1154. // loop over the line, offset gives current offset
  1155. int offset = 0;
  1156. while (offset < len)
  1157. {
  1158. bool anItemMatched = false;
  1159. bool standardStartEnableDetermined = false;
  1160. bool customStartEnableDetermined = false;
  1161. uint index = 0;
  1162. for (item = context->items.empty() ? 0 : context->items[0]; item; item = (++index < context->items.size()) ? context->items[index] : 0 )
  1163. {
  1164. // does we only match if we are firstNonSpace?
  1165. if (item->firstNonSpace && (offset > startNonSpace))