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.

1661 lines
43KB

  1. /* This file is part of the KDE libraries
  2. Copyright (c) 2000 Waldo Bastian <bastian@kde.org>
  3. Copyright (C) 2002-2004 Christoph Cullmann <cullmann@kde.org>
  4. This library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Library General Public
  6. License version 2 as published by the Free Software Foundation.
  7. This library is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. Library General Public License for more details.
  11. You should have received a copy of the GNU Library General Public License
  12. along with this library; see the file COPYING.LIB. If not, write to
  13. the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  14. Boston, MA 02110-1301, USA.
  15. */
  16. #include <sys/types.h>
  17. #include <sys/stat.h>
  18. #include <unistd.h>
  19. #include "katebuffer.h"
  20. #include "katebuffer.moc"
  21. #include "katedocument.h"
  22. #include "katehighlight.h"
  23. #include "kateconfig.h"
  24. #include "katefactory.h"
  25. #include "kateautoindent.h"
  26. #include <kdebug.h>
  27. #include <tdeglobal.h>
  28. #include <kcharsets.h>
  29. #include <tqpopupmenu.h>
  30. #include <tqfile.h>
  31. #include <tqtextstream.h>
  32. #include <tqtimer.h>
  33. #include <tqtextcodec.h>
  34. #include <tqcstring.h>
  35. #include <tqdatetime.h>
  36. /**
  37. * loader block size, load 256 kb at once per default
  38. * if file size is smaller, fall back to file size
  39. */
  40. static const TQ_ULONG KATE_FILE_LOADER_BS = 256 * 1024;
  41. /**
  42. * KATE_AVG_BLOCK_SIZE is in characters !
  43. * (internaly we calc with approx 80 chars per line !)
  44. * block will max contain around BLOCK_SIZE chars or
  45. * BLOCK_LINES lines (after load, later that won't be tracked)
  46. */
  47. static const TQ_ULONG KATE_AVG_BLOCK_SIZE = 2048 * 80;
  48. static const TQ_ULONG KATE_MAX_BLOCK_LINES = 2048;
  49. /**
  50. * hl will look at the next KATE_HL_LOOKAHEAD lines
  51. * or until the current block ends if a line is requested
  52. * will avoid to run doHighlight too often
  53. */
  54. static const uint KATE_HL_LOOKAHEAD = 64;
  55. /**
  56. * KATE_MAX_BLOCKS_LOADED should be at least 4, as some
  57. * methodes will cause heavy trashing, if not at least the
  58. * latest 2-3 used blocks are alive
  59. */
  60. uint KateBuffer::m_maxLoadedBlocks = 16;
  61. /**
  62. * Initial value for m_maxDynamicContexts
  63. */
  64. static const uint KATE_MAX_DYNAMIC_CONTEXTS = 512;
  65. void KateBuffer::setMaxLoadedBlocks (uint count)
  66. {
  67. m_maxLoadedBlocks = kMax (4U, count);
  68. }
  69. class KateFileLoader
  70. {
  71. public:
  72. KateFileLoader (const TQString &filename, TQTextCodec *codec, bool removeTrailingSpaces)
  73. : m_file (filename)
  74. , m_buffer (kMin ((TQ_ULONG)m_file.size(), KATE_FILE_LOADER_BS))
  75. , m_codec (codec)
  76. , m_decoder (m_codec->makeDecoder())
  77. , m_position (0)
  78. , m_lastLineStart (0)
  79. , m_eof (false) // default to not eof
  80. , lastWasEndOfLine (true) // at start of file, we had a virtual newline
  81. , lastWasR (false) // we have not found a \r as last char
  82. , m_eol (-1) // no eol type detected atm
  83. , m_twoByteEncoding (TQString(codec->name()) == "ISO-10646-UCS-2")
  84. , m_binary (false)
  85. , m_removeTrailingSpaces (removeTrailingSpaces)
  86. {
  87. kdDebug (13020) << "OPEN USES ENCODING: " << m_codec->name() << endl;
  88. }
  89. ~KateFileLoader ()
  90. {
  91. delete m_decoder;
  92. }
  93. /**
  94. * open file, read first chunk of data, detect eol
  95. */
  96. bool open ()
  97. {
  98. if (m_file.open (IO_ReadOnly))
  99. {
  100. int c = m_file.readBlock (m_buffer.data(), m_buffer.size());
  101. if (c > 0)
  102. {
  103. // fix utf16 LE, stolen from tdehtml ;)
  104. if ((c >= 2) && (m_codec->mibEnum() == 1000) && (m_buffer[1] == 0x00))
  105. {
  106. // utf16LE, we need to put the decoder in LE mode
  107. char reverseUtf16[3] = {0xFF, 0xFE, 0x00};
  108. m_decoder->toUnicode(reverseUtf16, 2);
  109. }
  110. processNull (c);
  111. m_text = m_decoder->toUnicode (m_buffer, c);
  112. }
  113. m_eof = (c == -1) || (c == 0) || (m_text.length() == 0) || m_file.atEnd();
  114. for (uint i=0; i < m_text.length(); i++)
  115. {
  116. if (m_text[i] == '\n')
  117. {
  118. m_eol = KateDocumentConfig::eolUnix;
  119. break;
  120. }
  121. else if ((m_text[i] == '\r'))
  122. {
  123. if (((i+1) < m_text.length()) && (m_text[i+1] == '\n'))
  124. {
  125. m_eol = KateDocumentConfig::eolDos;
  126. break;
  127. }
  128. else
  129. {
  130. m_eol = KateDocumentConfig::eolMac;
  131. break;
  132. }
  133. }
  134. }
  135. return true;
  136. }
  137. return false;
  138. }
  139. // no new lines around ?
  140. inline bool eof () const { return m_eof && !lastWasEndOfLine && (m_lastLineStart == m_text.length()); }
  141. // eol mode ? autodetected on open(), -1 for no eol found in the first block!
  142. inline int eol () const { return m_eol; }
  143. // binary ?
  144. inline bool binary () const { return m_binary; }
  145. // should spaces be ignored at end of line?
  146. inline bool removeTrailingSpaces () const { return m_removeTrailingSpaces; }
  147. // internal unicode data array
  148. inline const TQChar *unicode () const { return m_text.unicode(); }
  149. // read a line, return length + offset in unicode data
  150. void readLine (uint &offset, uint &length)
  151. {
  152. length = 0;
  153. offset = 0;
  154. while (m_position <= m_text.length())
  155. {
  156. if (m_position == m_text.length())
  157. {
  158. // try to load more text if something is around
  159. if (!m_eof)
  160. {
  161. int c = m_file.readBlock (m_buffer.data(), m_buffer.size());
  162. uint readString = 0;
  163. if (c > 0)
  164. {
  165. processNull (c);
  166. TQString str (m_decoder->toUnicode (m_buffer, c));
  167. readString = str.length();
  168. m_text = m_text.mid (m_lastLineStart, m_position-m_lastLineStart)
  169. + str;
  170. }
  171. else
  172. m_text = m_text.mid (m_lastLineStart, m_position-m_lastLineStart);
  173. // is file completly read ?
  174. m_eof = (c == -1) || (c == 0) || (readString == 0) || m_file.atEnd();
  175. // recalc current pos and last pos
  176. m_position -= m_lastLineStart;
  177. m_lastLineStart = 0;
  178. }
  179. // oh oh, end of file, escape !
  180. if (m_eof && (m_position == m_text.length()))
  181. {
  182. lastWasEndOfLine = false;
  183. // line data
  184. offset = m_lastLineStart;
  185. length = m_position-m_lastLineStart;
  186. m_lastLineStart = m_position;
  187. return;
  188. }
  189. }
  190. if (m_text[m_position] == '\n')
  191. {
  192. lastWasEndOfLine = true;
  193. if (lastWasR)
  194. {
  195. m_lastLineStart++;
  196. lastWasR = false;
  197. }
  198. else
  199. {
  200. // line data
  201. offset = m_lastLineStart;
  202. length = m_position-m_lastLineStart;
  203. m_lastLineStart = m_position+1;
  204. m_position++;
  205. return;
  206. }
  207. }
  208. else if (m_text[m_position] == '\r')
  209. {
  210. lastWasEndOfLine = true;
  211. lastWasR = true;
  212. // line data
  213. offset = m_lastLineStart;
  214. length = m_position-m_lastLineStart;
  215. m_lastLineStart = m_position+1;
  216. m_position++;
  217. return;
  218. }
  219. else
  220. {
  221. lastWasEndOfLine = false;
  222. lastWasR = false;
  223. }
  224. m_position++;
  225. }
  226. }
  227. // this nice methode will kill all 0 bytes (or double bytes)
  228. // and remember if this was a binary or not ;)
  229. void processNull (uint length)
  230. {
  231. if (m_twoByteEncoding)
  232. {
  233. for (uint i=1; i < length; i+=2)
  234. {
  235. if ((m_buffer[i] == 0) && (m_buffer[i-1] == 0))
  236. {
  237. m_binary = true;
  238. m_buffer[i] = ' ';
  239. }
  240. }
  241. }
  242. else
  243. {
  244. for (uint i=0; i < length; i++)
  245. {
  246. if (m_buffer[i] == 0)
  247. {
  248. m_binary = true;
  249. m_buffer[i] = ' ';
  250. }
  251. }
  252. }
  253. }
  254. private:
  255. TQFile m_file;
  256. TQByteArray m_buffer;
  257. TQTextCodec *m_codec;
  258. TQTextDecoder *m_decoder;
  259. TQString m_text;
  260. uint m_position;
  261. uint m_lastLineStart;
  262. bool m_eof;
  263. bool lastWasEndOfLine;
  264. bool lastWasR;
  265. int m_eol;
  266. bool m_twoByteEncoding;
  267. bool m_binary;
  268. bool m_removeTrailingSpaces;
  269. };
  270. /**
  271. * Create an empty buffer. (with one block with one empty line)
  272. */
  273. KateBuffer::KateBuffer(KateDocument *doc)
  274. : TQObject (doc),
  275. editSessionNumber (0),
  276. editIsRunning (false),
  277. editTagLineStart (0xffffffff),
  278. editTagLineEnd (0),
  279. editTagLineFrom (false),
  280. editChangesDone (false),
  281. m_doc (doc),
  282. m_lines (0),
  283. m_lastInSyncBlock (0),
  284. m_lastFoundBlock (0),
  285. m_cacheReadError(false),
  286. m_cacheWriteError(false),
  287. m_loadingBorked (false),
  288. m_binary (false),
  289. m_highlight (0),
  290. m_regionTree (this),
  291. m_tabWidth (8),
  292. m_lineHighlightedMax (0),
  293. m_lineHighlighted (0),
  294. m_maxDynamicContexts (KATE_MAX_DYNAMIC_CONTEXTS)
  295. {
  296. clear();
  297. }
  298. /**
  299. * Cleanup on destruction
  300. */
  301. KateBuffer::~KateBuffer()
  302. {
  303. // DELETE ALL BLOCKS, will free mem
  304. for (uint i=0; i < m_blocks.size(); i++)
  305. delete m_blocks[i];
  306. // release HL
  307. if (m_highlight)
  308. m_highlight->release();
  309. }
  310. void KateBuffer::editStart ()
  311. {
  312. editSessionNumber++;
  313. if (editSessionNumber > 1)
  314. return;
  315. editIsRunning = true;
  316. editTagLineStart = 0xffffffff;
  317. editTagLineEnd = 0;
  318. editTagLineFrom = false;
  319. editChangesDone = false;
  320. }
  321. void KateBuffer::editEnd ()
  322. {
  323. if (editSessionNumber == 0)
  324. return;
  325. editSessionNumber--;
  326. if (editSessionNumber > 0)
  327. return;
  328. if (editChangesDone)
  329. {
  330. // hl update !!!
  331. if ( m_highlight && !m_highlight->noHighlighting()
  332. && (editTagLineStart <= editTagLineEnd)
  333. && (editTagLineEnd <= m_lineHighlighted))
  334. {
  335. // look one line too far, needed for linecontinue stuff
  336. editTagLineEnd++;
  337. // look one line before, needed nearly 100% only for indentation based folding !
  338. if (editTagLineStart > 0)
  339. editTagLineStart--;
  340. KateBufBlock *buf2 = 0;
  341. bool needContinue = false;
  342. while ((buf2 = findBlock(editTagLineStart)))
  343. {
  344. needContinue = doHighlight (buf2,
  345. (editTagLineStart > buf2->startLine()) ? editTagLineStart : buf2->startLine(),
  346. (editTagLineEnd > buf2->endLine()) ? buf2->endLine() : editTagLineEnd,
  347. true);
  348. editTagLineStart = (editTagLineEnd > buf2->endLine()) ? buf2->endLine() : editTagLineEnd;
  349. if ((editTagLineStart >= m_lines) || (editTagLineStart >= editTagLineEnd))
  350. break;
  351. }
  352. if (needContinue)
  353. m_lineHighlighted = editTagLineStart;
  354. if (editTagLineStart > m_lineHighlightedMax)
  355. m_lineHighlightedMax = editTagLineStart;
  356. }
  357. else if (editTagLineStart < m_lineHighlightedMax)
  358. m_lineHighlightedMax = editTagLineStart;
  359. }
  360. editIsRunning = false;
  361. }
  362. void KateBuffer::clear()
  363. {
  364. m_regionTree.clear();
  365. // cleanup the blocks
  366. for (uint i=0; i < m_blocks.size(); i++)
  367. delete m_blocks[i];
  368. m_blocks.clear ();
  369. // create a bufblock with one line, we need that, only in openFile we won't have that
  370. KateBufBlock *block = new KateBufBlock(this, 0, 0);
  371. m_blocks.append (block);
  372. // reset the state
  373. m_lines = block->lines();
  374. m_lastInSyncBlock = 0;
  375. m_lastFoundBlock = 0;
  376. m_cacheWriteError = false;
  377. m_cacheReadError = false;
  378. m_loadingBorked = false;
  379. m_binary = false;
  380. m_lineHighlightedMax = 0;
  381. m_lineHighlighted = 0;
  382. }
  383. bool KateBuffer::openFile (const TQString &m_file)
  384. {
  385. KateFileLoader file (m_file, m_doc->config()->codec(), m_doc->configFlags() & KateDocument::cfRemoveSpaces);
  386. bool ok = false;
  387. struct stat sbuf;
  388. if (stat(TQFile::encodeName(m_file), &sbuf) == 0)
  389. {
  390. if (S_ISREG(sbuf.st_mode) && file.open())
  391. ok = true;
  392. }
  393. if (!ok)
  394. {
  395. clear();
  396. return false; // Error
  397. }
  398. // set eol mode, if a eol char was found in the first 256kb block and we allow this at all!
  399. if (m_doc->config()->allowEolDetection() && (file.eol() != -1))
  400. m_doc->config()->setEol (file.eol());
  401. // flush current content
  402. clear ();
  403. // cleanup the blocks
  404. for (uint i=0; i < m_blocks.size(); i++)
  405. delete m_blocks[i];
  406. m_blocks.clear ();
  407. // do the real work
  408. KateBufBlock *block = 0;
  409. m_lines = 0;
  410. while (!file.eof() && !m_cacheWriteError)
  411. {
  412. block = new KateBufBlock (this, block, 0, &file);
  413. m_lines = block->endLine ();
  414. if (m_cacheWriteError || (block->lines() == 0))
  415. {
  416. delete block;
  417. break;
  418. }
  419. else
  420. m_blocks.append (block);
  421. }
  422. // we had a cache write error, this load is really borked !
  423. if (m_cacheWriteError)
  424. m_loadingBorked = true;
  425. if (m_blocks.isEmpty() || (m_lines == 0))
  426. {
  427. // file was really empty, clean the buffers + emit the line changed
  428. // loadingBorked will be false for such files, not matter what happened
  429. // before
  430. clear ();
  431. }
  432. else
  433. {
  434. // fix region tree
  435. m_regionTree.fixRoot (m_lines);
  436. }
  437. // if we have no hl or the "None" hl activated, whole file is correct highlighted
  438. // after loading, which wonder ;)
  439. if (!m_highlight || m_highlight->noHighlighting())
  440. {
  441. m_lineHighlighted = m_lines;
  442. m_lineHighlightedMax = m_lines;
  443. }
  444. // binary?
  445. m_binary = file.binary ();
  446. kdDebug (13020) << "LOADING DONE" << endl;
  447. return !m_loadingBorked;
  448. }
  449. bool KateBuffer::canEncode ()
  450. {
  451. TQTextCodec *codec = m_doc->config()->codec();
  452. kdDebug(13020) << "ENC NAME: " << codec->name() << endl;
  453. // hardcode some unicode encodings which can encode all chars
  454. if ((TQString(codec->name()) == "UTF-8") || (TQString(codec->name()) == "ISO-10646-UCS-2"))
  455. return true;
  456. for (uint i=0; i < m_lines; i++)
  457. {
  458. if (!codec->canEncode (plainLine(i)->string()))
  459. {
  460. kdDebug(13020) << "STRING LINE: " << plainLine(i)->string() << endl;
  461. kdDebug(13020) << "ENC WORKING: FALSE" << endl;
  462. return false;
  463. }
  464. }
  465. return true;
  466. }
  467. bool KateBuffer::saveFile (const TQString &m_file)
  468. {
  469. TQFile file (m_file);
  470. TQTextStream stream (&file);
  471. if ( !file.open( IO_WriteOnly ) )
  472. {
  473. return false; // Error
  474. }
  475. TQTextCodec *codec = m_doc->config()->codec();
  476. // disable Unicode headers
  477. stream.setEncoding(TQTextStream::RawUnicode);
  478. // this line sets the mapper to the correct codec
  479. stream.setCodec(codec);
  480. // our loved eol string ;)
  481. TQString eol = m_doc->config()->eolString ();
  482. // should we strip spaces?
  483. bool removeTrailingSpaces = m_doc->configFlags() & KateDocument::cfRemoveSpaces;
  484. // just dump the lines out ;)
  485. for (uint i=0; i < m_lines; i++)
  486. {
  487. KateTextLine::Ptr textline = plainLine(i);
  488. // strip spaces
  489. if (removeTrailingSpaces)
  490. {
  491. int lastChar = textline->lastChar();
  492. if (lastChar > -1)
  493. {
  494. stream << TQConstString (textline->text(), lastChar+1).string();
  495. }
  496. }
  497. else // simple, dump the line
  498. stream << textline->string();
  499. if ((i+1) < m_lines)
  500. stream << eol;
  501. }
  502. file.close ();
  503. m_loadingBorked = false;
  504. return (file.status() == IO_Ok);
  505. }
  506. KateTextLine::Ptr KateBuffer::line_internal (KateBufBlock *buf, uint i)
  507. {
  508. // update hl until this line + max KATE_HL_LOOKAHEAD
  509. KateBufBlock *buf2 = 0;
  510. while ((i >= m_lineHighlighted) && (buf2 = findBlock(m_lineHighlighted)))
  511. {
  512. uint end = kMin(i + KATE_HL_LOOKAHEAD, buf2->endLine());
  513. doHighlight ( buf2,
  514. kMax(m_lineHighlighted, buf2->startLine()),
  515. end,
  516. false );
  517. m_lineHighlighted = end;
  518. }
  519. // update hl max
  520. if (m_lineHighlighted > m_lineHighlightedMax)
  521. m_lineHighlightedMax = m_lineHighlighted;
  522. return buf->line (i - buf->startLine());
  523. }
  524. KateBufBlock *KateBuffer::findBlock_internal (uint i, uint *index)
  525. {
  526. uint lastLine = m_blocks[m_lastInSyncBlock]->endLine ();
  527. if (lastLine > i) // we are in a allready known area !
  528. {
  529. while (true)
  530. {
  531. KateBufBlock *buf = m_blocks[m_lastFoundBlock];
  532. if ( (buf->startLine() <= i)
  533. && (buf->endLine() > i) )
  534. {
  535. if (index)
  536. (*index) = m_lastFoundBlock;
  537. return m_blocks[m_lastFoundBlock];
  538. }
  539. if (i < buf->startLine())
  540. m_lastFoundBlock--;
  541. else
  542. m_lastFoundBlock++;
  543. }
  544. }
  545. else // we need first to resync the startLines !
  546. {
  547. if ((m_lastInSyncBlock+1) < m_blocks.size())
  548. m_lastInSyncBlock++;
  549. else
  550. return 0;
  551. for (; m_lastInSyncBlock < m_blocks.size(); m_lastInSyncBlock++)
  552. {
  553. // get next block
  554. KateBufBlock *buf = m_blocks[m_lastInSyncBlock];
  555. // sync startLine !
  556. buf->setStartLine (lastLine);
  557. // is it allready the searched block ?
  558. if ((i >= lastLine) && (i < buf->endLine()))
  559. {
  560. // remember this block as last found !
  561. m_lastFoundBlock = m_lastInSyncBlock;
  562. if (index)
  563. (*index) = m_lastFoundBlock;
  564. return buf;
  565. }
  566. // increase lastLine with blocklinecount
  567. lastLine += buf->lines ();
  568. }
  569. }
  570. // no block found !
  571. // index will not be set to any useful value in this case !
  572. return 0;
  573. }
  574. void KateBuffer::changeLine(uint i)
  575. {
  576. KateBufBlock *buf = findBlock(i);
  577. if (!buf)
  578. return;
  579. // mark this block dirty
  580. buf->markDirty ();
  581. // mark buffer changed
  582. editChangesDone = true;
  583. // tag this line as changed
  584. if (i < editTagLineStart)
  585. editTagLineStart = i;
  586. if (i > editTagLineEnd)
  587. editTagLineEnd = i;
  588. }
  589. void KateBuffer::insertLine(uint i, KateTextLine::Ptr line)
  590. {
  591. uint index = 0;
  592. KateBufBlock *buf;
  593. if (i == m_lines)
  594. buf = findBlock(i-1, &index);
  595. else
  596. buf = findBlock(i, &index);
  597. if (!buf)
  598. return;
  599. buf->insertLine(i - buf->startLine(), line);
  600. if (m_lineHighlightedMax > i)
  601. m_lineHighlightedMax++;
  602. if (m_lineHighlighted > i)
  603. m_lineHighlighted++;
  604. m_lines++;
  605. // last sync block adjust
  606. if (m_lastInSyncBlock > index)
  607. m_lastInSyncBlock = index;
  608. // last found
  609. if (m_lastInSyncBlock < m_lastFoundBlock)
  610. m_lastFoundBlock = m_lastInSyncBlock;
  611. // mark buffer changed
  612. editChangesDone = true;
  613. // tag this line as inserted
  614. if (i < editTagLineStart)
  615. editTagLineStart = i;
  616. if (i <= editTagLineEnd)
  617. editTagLineEnd++;
  618. if (i > editTagLineEnd)
  619. editTagLineEnd = i;
  620. // line inserted
  621. editTagLineFrom = true;
  622. m_regionTree.lineHasBeenInserted (i);
  623. }
  624. void KateBuffer::removeLine(uint i)
  625. {
  626. uint index = 0;
  627. KateBufBlock *buf = findBlock(i, &index);
  628. if (!buf)
  629. return;
  630. buf->removeLine(i - buf->startLine());
  631. if (m_lineHighlightedMax > i)
  632. m_lineHighlightedMax--;
  633. if (m_lineHighlighted > i)
  634. m_lineHighlighted--;
  635. m_lines--;
  636. // trash away a empty block
  637. if (buf->lines() == 0)
  638. {
  639. // we need to change which block is last in sync
  640. if (m_lastInSyncBlock >= index)
  641. {
  642. m_lastInSyncBlock = index;
  643. if (buf->next())
  644. {
  645. if (buf->prev())
  646. buf->next()->setStartLine (buf->prev()->endLine());
  647. else
  648. buf->next()->setStartLine (0);
  649. }
  650. }
  651. // cu block !
  652. delete buf;
  653. m_blocks.erase (m_blocks.begin()+index);
  654. // make sure we don't keep a pointer to the deleted block
  655. if( m_lastInSyncBlock >= index )
  656. m_lastInSyncBlock = index - 1;
  657. }
  658. else
  659. {
  660. // last sync block adjust
  661. if (m_lastInSyncBlock > index)
  662. m_lastInSyncBlock = index;
  663. }
  664. // last found
  665. if (m_lastInSyncBlock < m_lastFoundBlock)
  666. m_lastFoundBlock = m_lastInSyncBlock;
  667. // mark buffer changed
  668. editChangesDone = true;
  669. // tag this line as removed
  670. if (i < editTagLineStart)
  671. editTagLineStart = i;
  672. if (i < editTagLineEnd)
  673. editTagLineEnd--;
  674. if (i > editTagLineEnd)
  675. editTagLineEnd = i;
  676. // line removed
  677. editTagLineFrom = true;
  678. m_regionTree.lineHasBeenRemoved (i);
  679. }
  680. void KateBuffer::setTabWidth (uint w)
  681. {
  682. if ((m_tabWidth != w) && (m_tabWidth > 0))
  683. {
  684. m_tabWidth = w;
  685. if (m_highlight && m_highlight->foldingIndentationSensitive())
  686. invalidateHighlighting();
  687. }
  688. }
  689. void KateBuffer::setHighlight(uint hlMode)
  690. {
  691. KateHighlighting *h = KateHlManager::self()->getHl(hlMode);
  692. // aha, hl will change
  693. if (h != m_highlight)
  694. {
  695. bool invalidate = !h->noHighlighting();
  696. if (m_highlight)
  697. {
  698. m_highlight->release();
  699. invalidate = true;
  700. }
  701. h->use();
  702. // Clear code folding tree (see bug #124102)
  703. m_regionTree.clear();
  704. m_regionTree.fixRoot(m_lines);
  705. // try to set indentation
  706. if (!h->indentation().isEmpty())
  707. m_doc->config()->setIndentationMode (KateAutoIndent::modeNumber(h->indentation()));
  708. m_highlight = h;
  709. if (invalidate)
  710. invalidateHighlighting();
  711. // inform the document that the hl was really changed
  712. // needed to update attributes and more ;)
  713. m_doc->bufferHlChanged ();
  714. }
  715. }
  716. void KateBuffer::invalidateHighlighting()
  717. {
  718. m_lineHighlightedMax = 0;
  719. m_lineHighlighted = 0;
  720. }
  721. void KateBuffer::updatePreviousNotEmptyLine(KateBufBlock *blk,uint current_line,bool addindent,uint deindent)
  722. {
  723. KateTextLine::Ptr textLine;
  724. do {
  725. if (current_line>0) current_line--;
  726. else
  727. {
  728. uint line=blk->startLine()+current_line;
  729. if (line==0) return;
  730. line--;
  731. blk=findBlock(line);
  732. if (!blk) {
  733. kdDebug(13020)<<"updatePreviousNotEmptyLine: block not found, this must not happen"<<endl;
  734. return;
  735. }
  736. current_line=line-blk->startLine();
  737. }
  738. textLine = blk->line(current_line);
  739. } while (textLine->firstChar()==-1);
  740. kdDebug(13020)<<"updatePreviousNotEmptyLine: updating line:"<<(blk->startLine()+current_line)<<endl;
  741. TQMemArray<uint> foldingList=textLine->foldingListArray();
  742. while ( (foldingList.size()>0) && ( abs(foldingList[foldingList.size()-2])==1)) {
  743. foldingList.resize(foldingList.size()-2,TQGArray::SpeedOptim);
  744. }
  745. addIndentBasedFoldingInformation(foldingList,addindent,deindent);
  746. textLine->setFoldingList(foldingList);
  747. bool retVal_folding = false;
  748. m_regionTree.updateLine (current_line + blk->startLine(), &foldingList, &retVal_folding, true,false);
  749. emit tagLines (blk->startLine()+current_line, blk->startLine()+current_line);
  750. }
  751. void KateBuffer::addIndentBasedFoldingInformation(TQMemArray<uint> &foldingList,bool addindent,uint deindent)
  752. {
  753. if (addindent) {
  754. //kdDebug(13020)<<"adding indent for line :"<<current_line + buf->startLine()<<" textLine->noIndentBasedFoldingAtStart"<<textLine->noIndentBasedFoldingAtStart()<<endl;
  755. kdDebug(13020)<<"adding ident"<<endl;
  756. foldingList.resize (foldingList.size() + 2, TQGArray::SpeedOptim);
  757. foldingList[foldingList.size()-2] = 1;
  758. foldingList[foldingList.size()-1] = 0;
  759. }
  760. kdDebug(13020)<<"DEINDENT: "<<deindent<<endl;
  761. if (deindent > 0)
  762. {
  763. foldingList.resize (foldingList.size() + (deindent*2), TQGArray::SpeedOptim);
  764. for (uint z= foldingList.size()-(deindent*2); z < foldingList.size(); z=z+2)
  765. {
  766. foldingList[z] = -1;
  767. foldingList[z+1] = 0;
  768. }
  769. }
  770. }
  771. bool KateBuffer::doHighlight (KateBufBlock *buf, uint startLine, uint endLine, bool invalidate)
  772. {
  773. // no hl around, no stuff to do
  774. if (!m_highlight)
  775. return false;
  776. /*if (m_highlight->foldingIndentationSensitive())
  777. {
  778. startLine=0;
  779. endLine=50;
  780. }*/
  781. // we tried to start in a line behind this buf block !
  782. if (startLine >= (buf->startLine()+buf->lines()))
  783. return false;
  784. //TQTime t;
  785. //t.start();
  786. //kdDebug (13020) << "HIGHLIGHTED START --- NEED HL, LINESTART: " << startLine << " LINEEND: " << endLine << endl;
  787. //kdDebug (13020) << "HL UNTIL LINE: " << m_lineHighlighted << " MAX: " << m_lineHighlightedMax << endl;
  788. //kdDebug (13020) << "HL DYN COUNT: " << KateHlManager::self()->countDynamicCtxs() << " MAX: " << m_maxDynamicContexts << endl;
  789. // see if there are too many dynamic contexts; if yes, invalidate HL of all documents
  790. if (KateHlManager::self()->countDynamicCtxs() >= m_maxDynamicContexts)
  791. {
  792. {
  793. if (KateHlManager::self()->resetDynamicCtxs())
  794. {
  795. kdDebug (13020) << "HL invalidated - too many dynamic contexts ( >= " << m_maxDynamicContexts << ")" << endl;
  796. // avoid recursive invalidation
  797. KateHlManager::self()->setForceNoDCReset(true);
  798. for (KateDocument *doc = KateFactory::self()->documents()->first(); doc; doc = KateFactory::self()->documents()->next())
  799. doc->makeAttribs();
  800. // doHighlight *shall* do his work. After invalidation, some highlight has
  801. // been recalculated, but *maybe not* until endLine ! So we shall force it manually...
  802. KateBufBlock *buf = 0;
  803. while ((endLine > m_lineHighlighted) && (buf = findBlock(m_lineHighlighted)))
  804. {
  805. uint end = kMin(endLine, buf->endLine());
  806. doHighlight ( buf,
  807. kMax(m_lineHighlighted, buf->startLine()),
  808. end,
  809. false );
  810. m_lineHighlighted = end;
  811. }
  812. KateHlManager::self()->setForceNoDCReset(false);
  813. return false;
  814. }
  815. else
  816. {
  817. m_maxDynamicContexts *= 2;
  818. kdDebug (13020) << "New dynamic contexts limit: " << m_maxDynamicContexts << endl;
  819. }
  820. }
  821. }
  822. // get the previous line, if we start at the beginning of this block
  823. // take the last line of the previous block
  824. KateTextLine::Ptr prevLine = 0;
  825. if ((startLine == buf->startLine()) && buf->prev() && (buf->prev()->lines() > 0))
  826. prevLine = buf->prev()->line (buf->prev()->lines() - 1);
  827. else if ((startLine > buf->startLine()) && (startLine <= buf->endLine()))
  828. prevLine = buf->line(startLine - buf->startLine() - 1);
  829. else
  830. prevLine = new KateTextLine ();
  831. // does we need to emit a signal for the folding changes ?
  832. bool codeFoldingUpdate = false;
  833. // here we are atm, start at start line in the block
  834. uint current_line = startLine - buf->startLine();
  835. // do we need to continue
  836. bool stillcontinue=false;
  837. bool indentContinueWhitespace=false;
  838. bool indentContinueNextWhitespace=false;
  839. // loop over the lines of the block, from startline to endline or end of block
  840. // if stillcontinue forces us to do so
  841. while ( (current_line < buf->lines())
  842. && (stillcontinue || ((current_line + buf->startLine()) <= endLine)) )
  843. {
  844. // current line
  845. KateTextLine::Ptr textLine = buf->line(current_line);
  846. TQMemArray<uint> foldingList;
  847. bool ctxChanged = false;
  848. m_highlight->doHighlight (prevLine, textLine, &foldingList, &ctxChanged);
  849. //
  850. // indentation sensitive folding
  851. //
  852. bool indentChanged = false;
  853. if (m_highlight->foldingIndentationSensitive())
  854. {
  855. // get the indentation array of the previous line to start with !
  856. TQMemArray<unsigned short> indentDepth;
  857. indentDepth.duplicate (prevLine->indentationDepthArray());
  858. // current indentation of this line
  859. uint iDepth = textLine->indentDepth(m_tabWidth);
  860. if ((current_line+buf->startLine())==0)
  861. {
  862. indentDepth.resize (1, TQGArray::SpeedOptim);
  863. indentDepth[0] = iDepth;
  864. }
  865. textLine->setNoIndentBasedFoldingAtStart(prevLine->noIndentBasedFolding());
  866. // this line is empty, beside spaces, or has indentaion based folding disabled, use indentation depth of the previous line !
  867. kdDebug(13020)<<"current_line:"<<current_line + buf->startLine()<<" textLine->noIndentBasedFoldingAtStart"<<textLine->noIndentBasedFoldingAtStart()<<endl;
  868. if ( (textLine->firstChar() == -1) || textLine->noIndentBasedFoldingAtStart())
  869. {
  870. // do this to get skipped empty lines indent right, which was given in the indenation array
  871. if (!prevLine->indentationDepthArray().isEmpty())
  872. {
  873. iDepth = (prevLine->indentationDepthArray())[prevLine->indentationDepthArray().size()-1];
  874. kdDebug(13020)<<"reusing old depth as current"<<endl;
  875. }
  876. else
  877. {
  878. iDepth = prevLine->indentDepth(m_tabWidth);
  879. kdDebug(13020)<<"creating indentdepth for previous line"<<endl;
  880. }
  881. }
  882. kdDebug(13020)<<"iDepth:"<<iDepth<<endl;
  883. // query the next line indentation, if we are at the end of the block
  884. // use the first line of the next buf block
  885. uint nextLineIndentation = 0;
  886. bool nextLineIndentationValid=true;
  887. indentContinueNextWhitespace=false;
  888. if ((current_line+1) < buf->lines())
  889. {
  890. if (buf->line(current_line+1)->firstChar() == -1)
  891. {
  892. nextLineIndentation = iDepth;
  893. indentContinueNextWhitespace=true;
  894. }
  895. else
  896. nextLineIndentation = buf->line(current_line+1)->indentDepth(m_tabWidth);
  897. }
  898. else
  899. {
  900. KateBufBlock *blk = buf->next();
  901. if (blk && (blk->lines() > 0))
  902. {
  903. if (blk->line (0)->firstChar() == -1)
  904. {
  905. nextLineIndentation = iDepth;
  906. indentContinueNextWhitespace=true;
  907. }
  908. else
  909. nextLineIndentation = blk->line (0)->indentDepth(m_tabWidth);
  910. }
  911. else nextLineIndentationValid=false;
  912. }
  913. if (!textLine->noIndentBasedFoldingAtStart()) {
  914. if ((iDepth > 0) && (indentDepth.isEmpty() || (indentDepth[indentDepth.size()-1] < iDepth)))
  915. {
  916. kdDebug(13020)<<"adding depth to \"stack\":"<<iDepth<<endl;
  917. indentDepth.resize (indentDepth.size()+1, TQGArray::SpeedOptim);
  918. indentDepth[indentDepth.size()-1] = iDepth;
  919. } else {
  920. if (!indentDepth.isEmpty())
  921. {
  922. for (int z=indentDepth.size()-1; z > -1; z--)
  923. if (indentDepth[z]>iDepth)
  924. indentDepth.resize(z, TQGArray::SpeedOptim);
  925. if ((iDepth > 0) && (indentDepth.isEmpty() || (indentDepth[indentDepth.size()-1] < iDepth)))
  926. {
  927. kdDebug(13020)<<"adding depth to \"stack\":"<<iDepth<<endl;
  928. indentDepth.resize (indentDepth.size()+1, TQGArray::SpeedOptim);
  929. indentDepth[indentDepth.size()-1] = iDepth;
  930. if (prevLine->firstChar()==-1) {
  931. }
  932. }
  933. }
  934. }
  935. }
  936. if (!textLine->noIndentBasedFolding())
  937. {
  938. if (nextLineIndentationValid)
  939. {
  940. //if (textLine->firstChar()!=-1)
  941. {
  942. kdDebug(13020)<<"nextLineIndentation:"<<nextLineIndentation<<endl;
  943. bool addindent=false;
  944. uint deindent=0;
  945. if (!indentDepth.isEmpty())
  946. kdDebug()<<"indentDepth[indentDepth.size()-1]:"<<indentDepth[indentDepth.size()-1]<<endl;
  947. if ((nextLineIndentation>0) && ( indentDepth.isEmpty() || (indentDepth[indentDepth.size()-1]<nextLineIndentation)))
  948. {
  949. kdDebug(13020)<<"addindent==true"<<endl;
  950. addindent=true;
  951. } else {
  952. if ((!indentDepth.isEmpty()) && (indentDepth[indentDepth.size()-1]>nextLineIndentation))
  953. {
  954. kdDebug(13020)<<"...."<<endl;
  955. for (int z=indentDepth.size()-1; z > -1; z--)
  956. {
  957. kdDebug(13020)<<indentDepth[z]<<" "<<nextLineIndentation<<endl;
  958. if (indentDepth[z]>nextLineIndentation)
  959. deindent++;
  960. }
  961. }
  962. }
  963. /* }
  964. if (textLine->noIndentBasedFolding()) kdDebug(13020)<<"=============================indentation based folding disabled======================"<<endl;
  965. if (!textLine->noIndentBasedFolding()) {*/
  966. if ((textLine->firstChar()==-1)) {
  967. updatePreviousNotEmptyLine(buf,current_line,addindent,deindent);
  968. codeFoldingUpdate=true;
  969. }
  970. else
  971. {
  972. addIndentBasedFoldingInformation(foldingList,addindent,deindent);
  973. }
  974. }
  975. }
  976. }
  977. indentChanged = !(indentDepth == textLine->indentationDepthArray());
  978. // assign the new array to the textline !
  979. if (indentChanged)
  980. textLine->setIndentationDepth (indentDepth);
  981. indentContinueWhitespace=textLine->firstChar()==-1;
  982. }
  983. bool foldingColChanged=false;
  984. bool foldingChanged = false; //!(foldingList == textLine->foldingListArray());
  985. if (foldingList.size()!=textLine->foldingListArray().size()) {
  986. foldingChanged=true;
  987. } else {
  988. TQMemArray<uint>::ConstIterator it=foldingList.begin();
  989. TQMemArray<uint>::ConstIterator it1=textLine->foldingListArray();
  990. bool markerType=true;
  991. for(;it!=foldingList.end();++it,++it1) {
  992. if (markerType) {
  993. if ( ((*it)!=(*it1))) {
  994. foldingChanged=true;
  995. foldingColChanged=false;
  996. break;
  997. }
  998. } else {
  999. if ((*it)!=(*it1)) {
  1000. foldingColChanged=true;
  1001. }
  1002. }
  1003. markerType=!markerType;
  1004. }
  1005. }
  1006. if (foldingChanged || foldingColChanged) {
  1007. textLine->setFoldingList(foldingList);
  1008. if (foldingChanged==false){
  1009. textLine->setFoldingColumnsOutdated(textLine->foldingColumnsOutdated() | foldingColChanged);
  1010. } else textLine->setFoldingColumnsOutdated(false);
  1011. }
  1012. bool retVal_folding = false;
  1013. //perhaps make en enums out of the change flags
  1014. m_regionTree.updateLine (current_line + buf->startLine(), &foldingList, &retVal_folding, foldingChanged,foldingColChanged);
  1015. codeFoldingUpdate = codeFoldingUpdate | retVal_folding;
  1016. // need we to continue ?
  1017. stillcontinue = ctxChanged || indentChanged || indentContinueWhitespace || indentContinueNextWhitespace;
  1018. // move around the lines
  1019. prevLine = textLine;
  1020. // increment line
  1021. current_line++;
  1022. }
  1023. buf->markDirty ();
  1024. // tag the changed lines !
  1025. if (invalidate)
  1026. emit tagLines (startLine, current_line + buf->startLine());
  1027. // emit that we have changed the folding
  1028. if (codeFoldingUpdate)
  1029. emit codeFoldingUpdated();
  1030. //kdDebug (13020) << "HIGHLIGHTED END --- NEED HL, LINESTART: " << startLine << " LINEEND: " << endLine << endl;
  1031. //kdDebug (13020) << "HL UNTIL LINE: " << m_lineHighlighted << " MAX: " << m_lineHighlightedMax << endl;
  1032. //kdDebug (13020) << "HL DYN COUNT: " << KateHlManager::self()->countDynamicCtxs() << " MAX: " << m_maxDynamicContexts << endl;
  1033. //kdDebug (13020) << "TIME TAKEN: " << t.elapsed() << endl;
  1034. // if we are at the last line of the block + we still need to continue
  1035. // return the need of that !
  1036. return stillcontinue && ((current_line+1) == buf->lines());
  1037. }
  1038. void KateBuffer::codeFoldingColumnUpdate(unsigned int lineNr) {
  1039. KateTextLine::Ptr line=plainLine(lineNr);
  1040. if (!line) return;
  1041. if (line->foldingColumnsOutdated()) {
  1042. line->setFoldingColumnsOutdated(false);
  1043. bool tmp;
  1044. TQMemArray<uint> folding=line->foldingListArray();
  1045. m_regionTree.updateLine(lineNr,&folding,&tmp,true,false);
  1046. }
  1047. }
  1048. //BEGIN KateBufBlock
  1049. KateBufBlock::KateBufBlock ( KateBuffer *parent, KateBufBlock *prev, KateBufBlock *next,
  1050. KateFileLoader *stream )
  1051. : m_state (KateBufBlock::stateDirty),
  1052. m_startLine (0),
  1053. m_lines (0),
  1054. m_vmblock (0),
  1055. m_vmblockSize (0),
  1056. m_parent (parent),
  1057. m_prev (prev),
  1058. m_next (next),
  1059. list (0),
  1060. listPrev (0),
  1061. listNext (0)
  1062. {
  1063. // init startline + the next pointers of the neighbour blocks
  1064. if (m_prev)
  1065. {
  1066. m_startLine = m_prev->endLine ();
  1067. m_prev->m_next = this;
  1068. }
  1069. if (m_next)
  1070. m_next->m_prev = this;
  1071. // we have a stream, use it to fill the block !
  1072. // this can lead to 0 line blocks which are invalid !
  1073. if (stream)
  1074. {
  1075. // this we lead to either dirty or swapped state
  1076. fillBlock (stream);
  1077. }
  1078. else // init the block if no stream given !
  1079. {
  1080. // fill in one empty line !
  1081. KateTextLine::Ptr textLine = new KateTextLine ();
  1082. m_stringList.push_back (textLine);
  1083. m_lines++;
  1084. // if we have allready enough blocks around, swap one
  1085. if (m_parent->m_loadedBlocks.count() >= KateBuffer::maxLoadedBlocks())
  1086. m_parent->m_loadedBlocks.first()->swapOut();
  1087. // we are a new nearly empty dirty block
  1088. m_state = KateBufBlock::stateDirty;
  1089. m_parent->m_loadedBlocks.append (this);
  1090. }
  1091. }
  1092. KateBufBlock::~KateBufBlock ()
  1093. {
  1094. // sync prev/next pointers
  1095. if (m_prev)
  1096. m_prev->m_next = m_next;
  1097. if (m_next)
  1098. m_next->m_prev = m_prev;
  1099. // if we have some swapped data allocated, free it now or never
  1100. if (m_vmblock)
  1101. KateFactory::self()->vm()->free(m_vmblock);
  1102. // remove me from the list I belong
  1103. KateBufBlockList::remove (this);
  1104. }
  1105. void KateBufBlock::fillBlock (KateFileLoader *stream)
  1106. {
  1107. // is allready too much stuff around in mem ?
  1108. bool swap = m_parent->m_loadedBlocks.count() >= KateBuffer::maxLoadedBlocks();
  1109. TQByteArray rawData;
  1110. // calcs the approx size for KATE_AVG_BLOCK_SIZE chars !
  1111. if (swap)
  1112. rawData.resize ((KATE_AVG_BLOCK_SIZE * sizeof(TQChar)) + ((KATE_AVG_BLOCK_SIZE/80) * 8));
  1113. char *buf = rawData.data ();
  1114. uint size = 0;
  1115. uint blockSize = 0;
  1116. while (!stream->eof() && (blockSize < KATE_AVG_BLOCK_SIZE) && (m_lines < KATE_MAX_BLOCK_LINES))
  1117. {
  1118. uint offset = 0, length = 0;
  1119. stream->readLine(offset, length);
  1120. const TQChar *unicodeData = stream->unicode () + offset;
  1121. // strip spaces at end of line
  1122. if ( stream->removeTrailingSpaces() )
  1123. {
  1124. while (length > 0)
  1125. {
  1126. if (unicodeData[length-1].isSpace())
  1127. --length;
  1128. else
  1129. break;
  1130. }
  1131. }
  1132. blockSize += length;
  1133. if (swap)
  1134. {
  1135. // create the swapped data on the fly, no need to waste time
  1136. // via going over the textline classes and dump them !
  1137. char attr = KateTextLine::flagNoOtherData;
  1138. uint pos = size;
  1139. // calc new size
  1140. size = size + 1 + sizeof(uint) + (sizeof(TQChar)*length);
  1141. if (size > rawData.size ())
  1142. {
  1143. rawData.resize (size);
  1144. buf = rawData.data ();
  1145. }
  1146. memcpy(buf+pos, (char *) &attr, 1);
  1147. pos += 1;
  1148. memcpy(buf+pos, (char *) &length, sizeof(uint));
  1149. pos += sizeof(uint);
  1150. memcpy(buf+pos, (char *) unicodeData, sizeof(TQChar)*length);
  1151. pos += sizeof(TQChar)*length;
  1152. }
  1153. else
  1154. {
  1155. KateTextLine::Ptr textLine = new KateTextLine ();
  1156. textLine->insertText (0, length, unicodeData);
  1157. m_stringList.push_back (textLine);
  1158. }
  1159. m_lines++;
  1160. }
  1161. if (swap)
  1162. {
  1163. m_vmblock = KateFactory::self()->vm()->allocate(size);
  1164. m_vmblockSize = size;
  1165. if (!rawData.isEmpty())
  1166. {
  1167. if (!KateFactory::self()->vm()->copyBlock(m_vmblock, rawData.data(), 0, size))
  1168. {
  1169. if (m_vmblock)
  1170. KateFactory::self()->vm()->free(m_vmblock);
  1171. m_vmblock = 0;
  1172. m_vmblockSize = 0;
  1173. m_parent->m_cacheWriteError = true;
  1174. }
  1175. }
  1176. // fine, we are swapped !
  1177. m_state = KateBufBlock::stateSwapped;
  1178. }
  1179. else
  1180. {
  1181. // we are a new dirty block without any swap data
  1182. m_state = KateBufBlock::stateDirty;
  1183. m_parent->m_loadedBlocks.append (this);
  1184. }
  1185. kdDebug (13020) << "A BLOCK LOADED WITH LINES: " << m_lines << endl;
  1186. }
  1187. KateTextLine::Ptr KateBufBlock::line(uint i)
  1188. {
  1189. // take care that the string list is around !!!
  1190. if (m_state == KateBufBlock::stateSwapped)
  1191. swapIn ();
  1192. // LRU
  1193. if (!m_parent->m_loadedBlocks.isLast(this))
  1194. m_parent->m_loadedBlocks.append (this);
  1195. return m_stringList[i];
  1196. }
  1197. void KateBufBlock::insertLine(uint i, KateTextLine::Ptr line)
  1198. {
  1199. // take care that the string list is around !!!
  1200. if (m_state == KateBufBlock::stateSwapped)
  1201. swapIn ();
  1202. m_stringList.insert (m_stringList.begin()+i, line);
  1203. m_lines++;
  1204. markDirty ();
  1205. }
  1206. void KateBufBlock::removeLine(uint i)
  1207. {
  1208. // take care that the string list is around !!!
  1209. if (m_state == KateBufBlock::stateSwapped)
  1210. swapIn ();
  1211. m_stringList.erase (m_stringList.begin()+i);
  1212. m_lines--;
  1213. markDirty ();
  1214. }
  1215. void KateBufBlock::markDirty ()
  1216. {
  1217. if (m_state != KateBufBlock::stateSwapped)
  1218. {
  1219. // LRU
  1220. if (!m_parent->m_loadedBlocks.isLast(this))
  1221. m_parent->m_loadedBlocks.append (this);
  1222. if (m_state == KateBufBlock::stateClean)
  1223. {
  1224. // if we have some swapped data allocated which is dirty, free it now
  1225. if (m_vmblock)
  1226. KateFactory::self()->vm()->free(m_vmblock);
  1227. m_vmblock = 0;
  1228. m_vmblockSize = 0;
  1229. // we are dirty
  1230. m_state = KateBufBlock::stateDirty;
  1231. }
  1232. }
  1233. }
  1234. void KateBufBlock::swapIn ()
  1235. {
  1236. if (m_state != KateBufBlock::stateSwapped)
  1237. return;
  1238. TQByteArray rawData (m_vmblockSize);
  1239. // what to do if that fails ?
  1240. if (!KateFactory::self()->vm()->copyBlock(rawData.data(), m_vmblock, 0, rawData.size()))
  1241. m_parent->m_cacheReadError = true;
  1242. // reserve mem, keep realloc away on push_back
  1243. m_stringList.reserve (m_lines);
  1244. char *buf = rawData.data();
  1245. for (uint i=0; i < m_lines; i++)
  1246. {
  1247. KateTextLine::Ptr textLine = new KateTextLine ();
  1248. buf = textLine->restore (buf);
  1249. m_stringList.push_back (textLine);
  1250. }
  1251. // if we have allready enough blocks around, swap one
  1252. if (m_parent->m_loadedBlocks.count() >= KateBuffer::maxLoadedBlocks())
  1253. m_parent->m_loadedBlocks.first()->swapOut();
  1254. // fine, we are now clean again, save state + append to clean list
  1255. m_state = KateBufBlock::stateClean;
  1256. m_parent->m_loadedBlocks.append (this);
  1257. }
  1258. void KateBufBlock::swapOut ()
  1259. {
  1260. if (m_state == KateBufBlock::stateSwapped)
  1261. return;
  1262. if (m_state == KateBufBlock::stateDirty)
  1263. {
  1264. bool haveHl = m_parent->m_highlight && !m_parent->m_highlight->noHighlighting();
  1265. // Calculate size.
  1266. uint size = 0;
  1267. for (uint i=0; i < m_lines; i++)
  1268. size += m_stringList[i]->dumpSize (haveHl);
  1269. TQByteArray rawData (size);
  1270. char *buf = rawData.data();
  1271. // Dump textlines
  1272. for (uint i=0; i < m_lines; i++)
  1273. buf = m_stringList[i]->dump (buf, haveHl);
  1274. m_vmblock = KateFactory::self()->vm()->allocate(rawData.size());
  1275. m_vmblockSize = rawData.size();
  1276. if (!rawData.isEmpty())
  1277. {
  1278. if (!KateFactory::self()->vm()->copyBlock(m_vmblock, rawData.data(), 0, rawData.size()))
  1279. {
  1280. if (m_vmblock)
  1281. KateFactory::self()->vm()->free(m_vmblock);
  1282. m_vmblock = 0;
  1283. m_vmblockSize = 0;
  1284. m_parent->m_cacheWriteError = true;
  1285. return;
  1286. }
  1287. }
  1288. }
  1289. m_stringList.clear();
  1290. // we are now swapped out, set state + remove us out of the lists !
  1291. m_state = KateBufBlock::stateSwapped;
  1292. KateBufBlockList::remove (this);
  1293. }
  1294. //END KateBufBlock
  1295. //BEGIN KateBufBlockList
  1296. KateBufBlockList::KateBufBlockList ()
  1297. : m_count (0),
  1298. m_first (0),
  1299. m_last (0)
  1300. {
  1301. }
  1302. void KateBufBlockList::append (KateBufBlock *buf)
  1303. {
  1304. if (buf->list)
  1305. buf->list->removeInternal (buf);
  1306. m_count++;
  1307. // append a element
  1308. if (m_last)
  1309. {
  1310. m_last->listNext = buf;
  1311. buf->listPrev = m_last;
  1312. buf->listNext = 0;
  1313. m_last = buf;
  1314. buf->list = this;
  1315. return;
  1316. }
  1317. // insert the first element
  1318. m_last = buf;
  1319. m_first = buf;
  1320. buf->listPrev = 0;
  1321. buf->listNext = 0;
  1322. buf->list = this;
  1323. }
  1324. void KateBufBlockList::removeInternal (KateBufBlock *buf)
  1325. {
  1326. if (buf->list != this)
  1327. return;
  1328. m_count--;
  1329. if ((buf == m_first) && (buf == m_last))
  1330. {
  1331. // last element removed !
  1332. m_first = 0;
  1333. m_last = 0;
  1334. }
  1335. else if (buf == m_first)
  1336. {
  1337. // first element removed
  1338. m_first = buf->listNext;
  1339. m_first->listPrev = 0;
  1340. }
  1341. else if (buf == m_last)
  1342. {
  1343. // last element removed
  1344. m_last = buf->listPrev;
  1345. m_last->listNext = 0;
  1346. }
  1347. else
  1348. {
  1349. buf->listPrev->listNext = buf->listNext;
  1350. buf->listNext->listPrev = buf->listPrev;
  1351. }
  1352. buf->listPrev = 0;
  1353. buf->listNext = 0;
  1354. buf->list = 0;
  1355. }
  1356. //END KateBufBlockList
  1357. // kate: space-indent on; indent-width 2; replace-tabs on;