00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <sys/types.h>
00021 #include <sys/stat.h>
00022 #include <unistd.h>
00023
00024 #include "katebuffer.h"
00025 #include "katebuffer.moc"
00026
00027 #include "katedocument.h"
00028 #include "katehighlight.h"
00029 #include "kateconfig.h"
00030 #include "katefactory.h"
00031 #include "kateautoindent.h"
00032
00033 #include <kdebug.h>
00034 #include <kglobal.h>
00035 #include <kcharsets.h>
00036
00037 #include <qpopupmenu.h>
00038 #include <qfile.h>
00039 #include <qtextstream.h>
00040 #include <qtimer.h>
00041 #include <qtextcodec.h>
00042 #include <qcstring.h>
00043 #include <qdatetime.h>
00044
00049 static const Q_ULONG KATE_FILE_LOADER_BS = 256 * 1024;
00050
00057 static const Q_ULONG KATE_AVG_BLOCK_SIZE = 2048 * 80;
00058 static const Q_ULONG KATE_MAX_BLOCK_LINES = 2048;
00059
00065 static const uint KATE_HL_LOOKAHEAD = 64;
00066
00072 uint KateBuffer::m_maxLoadedBlocks = 16;
00073
00077 static const uint KATE_MAX_DYNAMIC_CONTEXTS = 512;
00078
00079 void KateBuffer::setMaxLoadedBlocks (uint count)
00080 {
00081 m_maxLoadedBlocks = KMAX ((uint)4, count);
00082 }
00083
00084 class KateFileLoader
00085 {
00086 public:
00087 KateFileLoader (const QString &filename, QTextCodec *codec)
00088 : m_file (filename)
00089 , m_buffer (KMIN (m_file.size(), KATE_FILE_LOADER_BS))
00090 , m_codec (codec)
00091 , m_decoder (m_codec->makeDecoder())
00092 , m_position (0)
00093 , m_lastLineStart (0)
00094 , m_eof (false)
00095 , lastWasEndOfLine (true)
00096 , lastWasR (false)
00097 , m_eol (-1)
00098 , m_twoByteEncoding (QString(codec->name()) == "ISO-10646-UCS-2")
00099 , m_binary (false)
00100 {
00101 }
00102
00103 ~KateFileLoader ()
00104 {
00105 delete m_decoder;
00106 }
00107
00111 bool open ()
00112 {
00113 if (m_file.open (IO_ReadOnly))
00114 {
00115 int c = m_file.readBlock (m_buffer.data(), m_buffer.size());
00116
00117 if (c > 0)
00118 {
00119
00120 if ((c >= 2) && (m_codec->mibEnum() == 1000) && (m_buffer[1] == 0x00))
00121 {
00122
00123 char reverseUtf16[3] = {0xFF, 0xFE, 0x00};
00124 m_decoder->toUnicode(reverseUtf16, 2);
00125 }
00126
00127 processNull (c);
00128 m_text = m_decoder->toUnicode (m_buffer, c);
00129 }
00130
00131 m_eof = (c == -1) || (c == 0) || (m_text.length() == 0) || m_file.atEnd();
00132
00133 for (uint i=0; i < m_text.length(); i++)
00134 {
00135 if (m_text[i] == '\n')
00136 {
00137 m_eol = KateDocumentConfig::eolUnix;
00138 break;
00139 }
00140 else if ((m_text[i] == '\r'))
00141 {
00142 if (((i+1) < m_text.length()) && (m_text[i+1] == '\n'))
00143 {
00144 m_eol = KateDocumentConfig::eolDos;
00145 break;
00146 }
00147 else
00148 {
00149 m_eol = KateDocumentConfig::eolMac;
00150 break;
00151 }
00152 }
00153 }
00154
00155 return true;
00156 }
00157
00158 return false;
00159 }
00160
00161
00162 inline bool eof () const { return m_eof && !lastWasEndOfLine && (m_lastLineStart == m_text.length()); }
00163
00164
00165 inline int eol () const { return m_eol; }
00166
00167
00168 inline bool binary () const { return m_binary; }
00169
00170
00171 inline const QChar *unicode () const { return m_text.unicode(); }
00172
00173
00174 void readLine (uint &offset, uint &length)
00175 {
00176 length = 0;
00177 offset = 0;
00178
00179 while (m_position <= m_text.length())
00180 {
00181 if (m_position == m_text.length())
00182 {
00183
00184 if (!m_eof)
00185 {
00186 int c = m_file.readBlock (m_buffer.data(), m_buffer.size());
00187
00188 uint readString = 0;
00189 if (c > 0)
00190 {
00191 processNull (c);
00192
00193 QString str (m_decoder->toUnicode (m_buffer, c));
00194 readString = str.length();
00195
00196 m_text = m_text.mid (m_lastLineStart, m_position-m_lastLineStart)
00197 + str;
00198 }
00199 else
00200 m_text = m_text.mid (m_lastLineStart, m_position-m_lastLineStart);
00201
00202
00203 m_eof = (c == -1) || (c == 0) || (readString == 0) || m_file.atEnd();
00204
00205
00206 m_position -= m_lastLineStart;
00207 m_lastLineStart = 0;
00208 }
00209
00210
00211 if (m_eof && (m_position == m_text.length()))
00212 {
00213 lastWasEndOfLine = false;
00214
00215
00216 offset = m_lastLineStart;
00217 length = m_position-m_lastLineStart;
00218
00219 m_lastLineStart = m_position;
00220
00221 return;
00222 }
00223 }
00224
00225 if (m_text[m_position] == '\n')
00226 {
00227 lastWasEndOfLine = true;
00228
00229 if (lastWasR)
00230 {
00231 m_lastLineStart++;
00232 lastWasR = false;
00233 }
00234 else
00235 {
00236
00237 offset = m_lastLineStart;
00238 length = m_position-m_lastLineStart;
00239
00240 m_lastLineStart = m_position+1;
00241 m_position++;
00242
00243 return;
00244 }
00245 }
00246 else if (m_text[m_position] == '\r')
00247 {
00248 lastWasEndOfLine = true;
00249 lastWasR = true;
00250
00251
00252 offset = m_lastLineStart;
00253 length = m_position-m_lastLineStart;
00254
00255 m_lastLineStart = m_position+1;
00256 m_position++;
00257
00258 return;
00259 }
00260 else
00261 {
00262 lastWasEndOfLine = false;
00263 lastWasR = false;
00264 }
00265
00266 m_position++;
00267 }
00268 }
00269
00270
00271
00272 void processNull (uint length)
00273 {
00274 if (m_twoByteEncoding)
00275 {
00276 for (uint i=1; i < length; i+=2)
00277 {
00278 if ((m_buffer[i] == 0) && (m_buffer[i-1] == 0))
00279 {
00280 m_binary = true;
00281 m_buffer[i] = ' ';
00282 }
00283 }
00284 }
00285 else
00286 {
00287 for (uint i=0; i < length; i++)
00288 {
00289 if (m_buffer[i] == 0)
00290 {
00291 m_binary = true;
00292 m_buffer[i] = ' ';
00293 }
00294 }
00295 }
00296 }
00297
00298 private:
00299 QFile m_file;
00300 QByteArray m_buffer;
00301 QTextCodec *m_codec;
00302 QTextDecoder *m_decoder;
00303 QString m_text;
00304 uint m_position;
00305 uint m_lastLineStart;
00306 bool m_eof;
00307 bool lastWasEndOfLine;
00308 bool lastWasR;
00309 int m_eol;
00310 bool m_twoByteEncoding;
00311 bool m_binary;
00312 };
00313
00317 KateBuffer::KateBuffer(KateDocument *doc)
00318 : QObject (doc),
00319 editSessionNumber (0),
00320 editIsRunning (false),
00321 editTagLineStart (0xffffffff),
00322 editTagLineEnd (0),
00323 m_doc (doc),
00324 m_lines (0),
00325 m_lastInSyncBlock (0),
00326 m_lastFoundBlock (0),
00327 m_cacheReadError(false),
00328 m_cacheWriteError(false),
00329 m_loadingBorked (false),
00330 m_binary (false),
00331 m_highlight (0),
00332 m_regionTree (this),
00333 m_tabWidth (8),
00334 m_lineHighlightedMax (0),
00335 m_lineHighlighted (0),
00336 m_maxDynamicContexts (KATE_MAX_DYNAMIC_CONTEXTS)
00337 {
00338 clear();
00339 }
00340
00344 KateBuffer::~KateBuffer()
00345 {
00346
00347 for (uint i=0; i < m_blocks.size(); i++)
00348 delete m_blocks[i];
00349
00350
00351 if (m_highlight)
00352 m_highlight->release();
00353 }
00354
00355 void KateBuffer::editStart ()
00356 {
00357 editSessionNumber++;
00358
00359 if (editSessionNumber > 1)
00360 return;
00361
00362 editIsRunning = true;
00363
00364 editTagLineStart = 0xffffffff;
00365 editTagLineEnd = 0;
00366 }
00367
00368 void KateBuffer::editEnd ()
00369 {
00370 if (editSessionNumber == 0)
00371 return;
00372
00373 editSessionNumber--;
00374
00375 if (editSessionNumber > 0)
00376 return;
00377
00378
00379 if ( m_highlight && !m_highlight->noHighlighting()
00380 && (editTagLineStart <= editTagLineEnd)
00381 && (editTagLineEnd <= m_lineHighlighted))
00382 {
00383
00384 editTagLineEnd++;
00385
00386
00387 if (editTagLineStart > 0)
00388 editTagLineStart--;
00389
00390 KateBufBlock *buf2 = 0;
00391 bool needContinue = false;
00392 while ((buf2 = findBlock(editTagLineStart)))
00393 {
00394 needContinue = doHighlight (buf2,
00395 (editTagLineStart > buf2->startLine()) ? editTagLineStart : buf2->startLine(),
00396 (editTagLineEnd > buf2->endLine()) ? buf2->endLine() : editTagLineEnd,
00397 true);
00398
00399 editTagLineStart = (editTagLineEnd > buf2->endLine()) ? buf2->endLine() : editTagLineEnd;
00400
00401 if ((editTagLineStart >= m_lines) || (editTagLineStart >= editTagLineEnd))
00402 break;
00403 }
00404
00405 if (needContinue)
00406 m_lineHighlighted = editTagLineStart;
00407
00408 if (editTagLineStart > m_lineHighlightedMax)
00409 m_lineHighlightedMax = editTagLineStart;
00410 }
00411 else if (editTagLineStart < m_lineHighlightedMax)
00412 m_lineHighlightedMax = editTagLineStart;
00413
00414 editIsRunning = false;
00415 }
00416
00417 void KateBuffer::editTagLine (uint line)
00418 {
00419 if (line < editTagLineStart)
00420 editTagLineStart = line;
00421
00422 if (line > editTagLineEnd)
00423 editTagLineEnd = line;
00424 }
00425
00426 void KateBuffer::editInsertTagLine (uint line)
00427 {
00428 if (line < editTagLineStart)
00429 editTagLineStart = line;
00430
00431 if (line <= editTagLineEnd)
00432 editTagLineEnd++;
00433
00434 if (line > editTagLineEnd)
00435 editTagLineEnd = line;
00436 }
00437
00438 void KateBuffer::editRemoveTagLine (uint line)
00439 {
00440 if (line < editTagLineStart)
00441 editTagLineStart = line;
00442
00443 if (line < editTagLineEnd)
00444 editTagLineEnd--;
00445
00446 if (line > editTagLineEnd)
00447 editTagLineEnd = line;
00448 }
00449
00450 void KateBuffer::clear()
00451 {
00452 m_regionTree.clear();
00453
00454
00455 for (uint i=0; i < m_blocks.size(); i++)
00456 delete m_blocks[i];
00457
00458 m_blocks.clear ();
00459
00460
00461 KateBufBlock *block = new KateBufBlock(this, 0, 0);
00462 m_blocks.append (block);
00463
00464
00465 m_lines = block->lines();
00466 m_lastInSyncBlock = 0;
00467 m_lastFoundBlock = 0;
00468 m_cacheWriteError = false;
00469 m_cacheReadError = false;
00470 m_loadingBorked = false;
00471 m_binary = false;
00472
00473 m_lineHighlightedMax = 0;
00474 m_lineHighlighted = 0;
00475 }
00476
00477 bool KateBuffer::openFile (const QString &m_file)
00478 {
00479 KateFileLoader file (m_file, m_doc->config()->codec());
00480
00481 bool ok = false;
00482 struct stat sbuf;
00483 if (stat(QFile::encodeName(m_file), &sbuf) == 0)
00484 {
00485 if (S_ISREG(sbuf.st_mode) && file.open())
00486 ok = true;
00487 }
00488
00489 if (!ok)
00490 {
00491 clear();
00492 return false;
00493 }
00494
00495
00496 if (file.eol() != -1)
00497 m_doc->config()->setEol (file.eol());
00498
00499
00500 clear ();
00501
00502
00503 for (uint i=0; i < m_blocks.size(); i++)
00504 delete m_blocks[i];
00505
00506 m_blocks.clear ();
00507
00508
00509 KateBufBlock *block = 0;
00510 m_lines = 0;
00511 while (!file.eof() && !m_cacheWriteError)
00512 {
00513 block = new KateBufBlock (this, block, 0, &file);
00514
00515 m_lines = block->endLine ();
00516
00517 if (m_cacheWriteError || (block->lines() == 0))
00518 {
00519 delete block;
00520 break;
00521 }
00522 else
00523 m_blocks.append (block);
00524 }
00525
00526
00527 if (m_cacheWriteError)
00528 m_loadingBorked = true;
00529
00530 if (m_blocks.isEmpty() || (m_lines == 0))
00531 {
00532
00533
00534
00535 clear ();
00536 }
00537 else
00538 {
00539
00540 m_regionTree.fixRoot (m_lines);
00541 }
00542
00543
00544
00545 if (!m_highlight || m_highlight->noHighlighting())
00546 {
00547 m_lineHighlighted = m_lines;
00548 m_lineHighlightedMax = m_lines;
00549 }
00550
00551
00552 m_binary = file.binary ();
00553
00554 kdDebug (13020) << "LOADING DONE" << endl;
00555
00556 return !m_loadingBorked;
00557 }
00558
00559 bool KateBuffer::canEncode ()
00560 {
00561 QTextCodec *codec = m_doc->config()->codec();
00562
00563 kdDebug(13020) << "ENC NAME: " << codec->name() << endl;
00564
00565
00566 if ((QString(codec->name()) == "UTF-8") || (QString(codec->name()) == "ISO-10646-UCS-2"))
00567 return true;
00568
00569 for (uint i=0; i < m_lines; i++)
00570 {
00571 if (!codec->canEncode (plainLine(i)->string()))
00572 {
00573 kdDebug(13020) << "STRING LINE: " << plainLine(i)->string() << endl;
00574 kdDebug(13020) << "ENC WORKING: FALSE" << endl;
00575
00576 return false;
00577 }
00578 }
00579
00580 return true;
00581 }
00582
00583 bool KateBuffer::saveFile (const QString &m_file)
00584 {
00585 QFile file (m_file);
00586 QTextStream stream (&file);
00587
00588 if ( !file.open( IO_WriteOnly ) )
00589 {
00590 return false;
00591 }
00592
00593 QTextCodec *codec = m_doc->config()->codec();
00594
00595
00596 stream.setEncoding(QTextStream::RawUnicode);
00597
00598
00599 stream.setCodec(codec);
00600
00601 QString eol = m_doc->config()->eolString ();
00602
00603
00604 uint pos, found, ml, l;
00605 QChar onespace(' ');
00606 QString onetab("\t");
00607 uint tw = m_doc->config()->tabWidth();
00608
00609
00610 if ( m_doc->configFlags() & KateDocument::cfReplaceTabs ||
00611 m_doc->configFlags() & KateDocument::cfRemoveSpaces )
00612 m_doc->editStart();
00613
00614 for (uint i=0; i < m_lines; i++)
00615 {
00616 KateTextLine::Ptr textLine = plainLine(i);
00617
00618 if (textLine)
00619 {
00620
00621 if ( m_doc->configFlags() & KateDocument::cfReplaceTabs )
00622 {
00623 pos = 0;
00624 while ( textLine->searchText( pos, onetab, &found, &ml ) )
00625 {
00626 l = tw - ( found%tw );
00627 if ( l )
00628 {
00629 QString t;
00630 m_doc->editRemoveText( i, found, 1 );
00631 m_doc->editInsertText( i, found, t.fill(onespace, l) );
00632 pos += l-1;
00633 }
00634 }
00635 }
00636
00637
00638 if ( (m_doc->configFlags() & KateDocument::cfRemoveSpaces) && textLine->length() )
00639 {
00640 pos = textLine->length() - 1;
00641 uint lns = textLine->lastChar();
00642 if ( lns != pos )
00643 m_doc->editRemoveText( i, lns + 1, pos - lns );
00644 }
00645
00646 stream << textLine->string();
00647
00648 if ((i+1) < m_lines)
00649 stream << eol;
00650 }
00651 }
00652
00653 if ( m_doc->configFlags() & KateDocument::cfReplaceTabs ||
00654 m_doc->configFlags() & KateDocument::cfRemoveSpaces )
00655 m_doc->editEnd();
00656
00657 file.close ();
00658
00659 m_loadingBorked = false;
00660
00661 return (file.status() == IO_Ok);
00662 }
00663
00664 KateTextLine::Ptr KateBuffer::line_internal (KateBufBlock *buf, uint i)
00665 {
00666
00667 KateBufBlock *buf2 = 0;
00668 while ((i >= m_lineHighlighted) && (buf2 = findBlock(m_lineHighlighted)))
00669 {
00670 uint end = kMin(i + KATE_HL_LOOKAHEAD, buf2->endLine());
00671
00672 doHighlight ( buf2,
00673 kMax(m_lineHighlighted, buf2->startLine()),
00674 end,
00675 false );
00676
00677 m_lineHighlighted = end;
00678 }
00679
00680
00681 if (m_lineHighlighted > m_lineHighlightedMax)
00682 m_lineHighlightedMax = m_lineHighlighted;
00683
00684 return buf->line (i - buf->startLine());
00685 }
00686
00687 KateBufBlock *KateBuffer::findBlock_internal (uint i, uint *index)
00688 {
00689 uint lastLine = m_blocks[m_lastInSyncBlock]->endLine ();
00690
00691 if (lastLine > i)
00692 {
00693 while (true)
00694 {
00695 KateBufBlock *buf = m_blocks[m_lastFoundBlock];
00696
00697 if ( (buf->startLine() <= i)
00698 && (buf->endLine() > i) )
00699 {
00700 if (index)
00701 (*index) = m_lastFoundBlock;
00702
00703 return m_blocks[m_lastFoundBlock];
00704 }
00705
00706 if (i < buf->startLine())
00707 m_lastFoundBlock--;
00708 else
00709 m_lastFoundBlock++;
00710 }
00711 }
00712 else
00713 {
00714 if ((m_lastInSyncBlock+1) < m_blocks.size())
00715 m_lastInSyncBlock++;
00716 else
00717 return 0;
00718
00719 for (; m_lastInSyncBlock < m_blocks.size(); m_lastInSyncBlock++)
00720 {
00721
00722 KateBufBlock *buf = m_blocks[m_lastInSyncBlock];
00723
00724
00725 buf->setStartLine (lastLine);
00726
00727
00728 if ((i >= lastLine) && (i < buf->endLine()))
00729 {
00730
00731 m_lastFoundBlock = m_lastInSyncBlock;
00732
00733 if (index)
00734 (*index) = m_lastFoundBlock;
00735
00736 return buf;
00737 }
00738
00739
00740 lastLine += buf->lines ();
00741 }
00742 }
00743
00744
00745
00746 return 0;
00747 }
00748
00749 void KateBuffer::changeLine(uint i)
00750 {
00751 KateBufBlock *buf = findBlock(i);
00752
00753 editTagLine (i);
00754
00755 if (buf)
00756 buf->markDirty ();
00757 }
00758
00759 void KateBuffer::insertLine(uint i, KateTextLine::Ptr line)
00760 {
00761 uint index = 0;
00762 KateBufBlock *buf;
00763 if (i == m_lines)
00764 buf = findBlock(i-1, &index);
00765 else
00766 buf = findBlock(i, &index);
00767
00768 if (!buf)
00769 return;
00770
00771 buf->insertLine(i - buf->startLine(), line);
00772
00773 if (m_lineHighlightedMax > i)
00774 m_lineHighlightedMax++;
00775
00776 if (m_lineHighlighted > i)
00777 m_lineHighlighted++;
00778
00779 m_lines++;
00780
00781
00782 if (m_lastInSyncBlock > index)
00783 m_lastInSyncBlock = index;
00784
00785
00786 if (m_lastInSyncBlock < m_lastFoundBlock)
00787 m_lastFoundBlock = m_lastInSyncBlock;
00788
00789 editInsertTagLine (i);
00790
00791 m_regionTree.lineHasBeenInserted (i);
00792 }
00793
00794 void KateBuffer::removeLine(uint i)
00795 {
00796 uint index = 0;
00797 KateBufBlock *buf = findBlock(i, &index);
00798
00799 if (!buf)
00800 return;
00801
00802 buf->removeLine(i - buf->startLine());
00803
00804 if (m_lineHighlightedMax > i)
00805 m_lineHighlightedMax--;
00806
00807 if (m_lineHighlighted > i)
00808 m_lineHighlighted--;
00809
00810 m_lines--;
00811
00812
00813 if (buf->lines() == 0)
00814 {
00815
00816 if (m_lastInSyncBlock >= index)
00817 {
00818 m_lastInSyncBlock = index;
00819
00820 if (buf->next())
00821 {
00822 if (buf->prev())
00823 buf->next()->setStartLine (buf->prev()->endLine());
00824 else
00825 buf->next()->setStartLine (0);
00826 }
00827 }
00828
00829
00830 delete buf;
00831 m_blocks.erase (m_blocks.begin()+index);
00832 }
00833 else
00834 {
00835
00836 if (m_lastInSyncBlock > index)
00837 m_lastInSyncBlock = index;
00838 }
00839
00840
00841 if (m_lastInSyncBlock < m_lastFoundBlock)
00842 m_lastFoundBlock = m_lastInSyncBlock;
00843
00844 editRemoveTagLine (i);
00845
00846 m_regionTree.lineHasBeenRemoved (i);
00847 }
00848
00849 void KateBuffer::setTabWidth (uint w)
00850 {
00851 if ((m_tabWidth != w) && (m_tabWidth > 0))
00852 {
00853 m_tabWidth = w;
00854
00855 if (m_highlight && m_highlight->foldingIndentationSensitive())
00856 invalidateHighlighting();
00857 }
00858 }
00859
00860 void KateBuffer::setHighlight(uint hlMode)
00861 {
00862 KateHighlighting *h = KateHlManager::self()->getHl(hlMode);
00863
00864
00865 if (h != m_highlight)
00866 {
00867 bool invalidate = !h->noHighlighting();
00868
00869 if (m_highlight)
00870 {
00871 m_highlight->release();
00872 invalidate = true;
00873 }
00874
00875 h->use();
00876
00877
00878 if (!h->indentation().isEmpty())
00879 m_doc->config()->setIndentationMode (KateAutoIndent::modeNumber(h->indentation()));
00880
00881 m_highlight = h;
00882
00883 if (invalidate)
00884 invalidateHighlighting();
00885
00886
00887
00888 m_doc->bufferHlChanged ();
00889 }
00890 }
00891
00892 void KateBuffer::invalidateHighlighting()
00893 {
00894 m_lineHighlightedMax = 0;
00895 m_lineHighlighted = 0;
00896 }
00897
00898 bool KateBuffer::doHighlight (KateBufBlock *buf, uint startLine, uint endLine, bool invalidate)
00899 {
00900
00901 if (!m_highlight)
00902 return false;
00903
00904
00905 if (startLine >= (buf->startLine()+buf->lines()))
00906 return false;
00907
00908 QTime t;
00909 t.start();
00910 kdDebug (13020) << "HIGHLIGHTED START --- NEED HL, LINESTART: " << startLine << " LINEEND: " << endLine << endl;
00911 kdDebug (13020) << "HL UNTIL LINE: " << m_lineHighlighted << " MAX: " << m_lineHighlightedMax << endl;
00912 kdDebug (13020) << "HL DYN COUNT: " << KateHlManager::self()->countDynamicCtxs() << " MAX: " << m_maxDynamicContexts << endl;
00913
00914
00915 if (KateHlManager::self()->countDynamicCtxs() >= m_maxDynamicContexts)
00916 {
00917 {
00918 if (KateHlManager::self()->resetDynamicCtxs())
00919 {
00920 kdDebug (13020) << "HL invalidated - too many dynamic contexts ( >= " << m_maxDynamicContexts << ")" << endl;
00921
00922
00923 KateHlManager::self()->setForceNoDCReset(true);
00924
00925 for (KateDocument *doc = KateFactory::self()->documents()->first(); doc; doc = KateFactory::self()->documents()->next())
00926 doc->makeAttribs();
00927
00928
00929
00930 KateBufBlock *buf = 0;
00931 while ((endLine > m_lineHighlighted) && (buf = findBlock(m_lineHighlighted)))
00932 {
00933 uint end = kMin(endLine, buf->endLine());
00934
00935 doHighlight ( buf,
00936 kMax(m_lineHighlighted, buf->startLine()),
00937 end,
00938 false );
00939
00940 m_lineHighlighted = end;
00941 }
00942
00943 KateHlManager::self()->setForceNoDCReset(false);
00944
00945 return false;
00946 }
00947 else
00948 {
00949 m_maxDynamicContexts *= 2;
00950 kdDebug (13020) << "New dynamic contexts limit: " << m_maxDynamicContexts << endl;
00951 }
00952 }
00953 }
00954
00955
00956
00957 KateTextLine::Ptr prevLine = 0;
00958
00959 if ((startLine == buf->startLine()) && buf->prev() && (buf->prev()->lines() > 0))
00960 prevLine = buf->prev()->line (buf->prev()->lines() - 1);
00961 else if ((startLine > buf->startLine()) && (startLine <= buf->endLine()))
00962 prevLine = buf->line(startLine - buf->startLine() - 1);
00963 else
00964 prevLine = new KateTextLine ();
00965
00966
00967 bool codeFoldingUpdate = false;
00968
00969
00970 uint current_line = startLine - buf->startLine();
00971
00972
00973 bool stillcontinue=false;
00974
00975
00976
00977 while ( (current_line < buf->lines())
00978 && (stillcontinue || ((current_line + buf->startLine()) <= endLine)) )
00979 {
00980
00981 KateTextLine::Ptr textLine = buf->line(current_line);
00982
00983 QMemArray<uint> foldingList;
00984 bool ctxChanged = false;
00985
00986 m_highlight->doHighlight (prevLine, textLine, &foldingList, &ctxChanged);
00987
00988
00989
00990
00991 bool indentChanged = false;
00992 if (m_highlight->foldingIndentationSensitive())
00993 {
00994
00995 QMemArray<unsigned short> indentDepth;
00996 indentDepth.duplicate (prevLine->indentationDepthArray());
00997
00998
00999 uint iDepth = textLine->indentDepth(m_tabWidth);
01000
01001
01002 if (textLine->firstChar() == -1)
01003 {
01004
01005 if (!prevLine->indentationDepthArray().isEmpty())
01006 iDepth = (prevLine->indentationDepthArray())[prevLine->indentationDepthArray().size()-1];
01007 else
01008 iDepth = prevLine->indentDepth(m_tabWidth);
01009 }
01010
01011
01012
01013 uint nextLineIndentation = 0;
01014
01015 if ((current_line+1) < buf->lines())
01016 {
01017 if (buf->line(current_line+1)->firstChar() == -1)
01018 nextLineIndentation = iDepth;
01019 else
01020 nextLineIndentation = buf->line(current_line+1)->indentDepth(m_tabWidth);
01021 }
01022 else
01023 {
01024 KateBufBlock *blk = buf->next();
01025
01026 if (blk && (blk->lines() > 0))
01027 {
01028 if (blk->line (0)->firstChar() == -1)
01029 nextLineIndentation = iDepth;
01030 else
01031 nextLineIndentation = blk->line (0)->indentDepth(m_tabWidth);
01032 }
01033 }
01034
01035
01036
01037 bool newIn = false;
01038 if ((iDepth > 0) && (indentDepth.isEmpty() || (indentDepth[indentDepth.size()-1] < iDepth)))
01039 {
01040 indentDepth.resize (indentDepth.size()+1, QGArray::SpeedOptim);
01041 indentDepth[indentDepth.size()-1] = iDepth;
01042 newIn = true;
01043 }
01044 else
01045 {
01046 for (int z=indentDepth.size()-1; z > -1; z--)
01047 {
01048 if (indentDepth[z] > iDepth)
01049 indentDepth.resize (z, QGArray::SpeedOptim);
01050 else if (indentDepth[z] == iDepth)
01051 break;
01052 else if (indentDepth[z] < iDepth)
01053 {
01054 indentDepth.resize (indentDepth.size()+1, QGArray::SpeedOptim);
01055 indentDepth[indentDepth.size()-1] = iDepth;
01056 newIn = true;
01057 break;
01058 }
01059 }
01060 }
01061
01062
01063 indentChanged = !(indentDepth == textLine->indentationDepthArray());
01064
01065
01066 if (indentChanged)
01067 textLine->setIndentationDepth (indentDepth);
01068
01069
01070 if (newIn)
01071 {
01072 foldingList.resize (foldingList.size() + 2, QGArray::SpeedOptim);
01073 foldingList[foldingList.size()-2] = 1;
01074 foldingList[foldingList.size()-1] = 0;
01075 }
01076
01077
01078
01079 uint remIn = 0;
01080
01081 for (int z=indentDepth.size()-1; z > -1; z--)
01082 {
01083 if (indentDepth[z] > nextLineIndentation)
01084 remIn++;
01085 else
01086 break;
01087 }
01088
01089 if (remIn > 0)
01090 {
01091 foldingList.resize (foldingList.size() + (remIn*2), QGArray::SpeedOptim);
01092
01093 for (uint z= foldingList.size()-(remIn*2); z < foldingList.size(); z=z+2)
01094 {
01095 foldingList[z] = -1;
01096 foldingList[z+1] = 0;
01097 }
01098 }
01099 }
01100 bool foldingColChanged=false;
01101 bool foldingChanged = false;
01102 if (foldingList.size()!=textLine->foldingListArray().size()) {
01103 foldingChanged=true;
01104 } else {
01105 QMemArray<uint>::ConstIterator it=foldingList.begin();
01106 QMemArray<uint>::ConstIterator it1=textLine->foldingListArray();
01107 bool markerType=true;
01108 for(;it!=foldingList.end();++it,++it1) {
01109 if (markerType) {
01110 if ( ((*it)!=(*it1))) {
01111 foldingChanged=true;
01112 foldingColChanged=false;
01113 break;
01114 }
01115 } else {
01116 if ((*it)!=(*it1)) {
01117 foldingColChanged=true;
01118 }
01119 }
01120 markerType=!markerType;
01121 }
01122 }
01123
01124 if (foldingChanged || foldingColChanged) {
01125 textLine->setFoldingList(foldingList);
01126 if (foldingChanged==false){
01127 textLine->setFoldingColumnsOutdated(textLine->foldingColumnsOutdated() | foldingColChanged);
01128 } else textLine->setFoldingColumnsOutdated(false);
01129 }
01130 bool retVal_folding = false;
01131
01132 m_regionTree.updateLine (current_line + buf->startLine(), &foldingList, &retVal_folding, foldingChanged,foldingColChanged);
01133
01134 codeFoldingUpdate = codeFoldingUpdate | retVal_folding;
01135
01136
01137 stillcontinue = ctxChanged || indentChanged;
01138
01139
01140 prevLine = textLine;
01141
01142
01143 current_line++;
01144 }
01145
01146 buf->markDirty ();
01147
01148
01149 if (invalidate)
01150 emit tagLines (startLine, current_line + buf->startLine());
01151
01152
01153 if (codeFoldingUpdate)
01154 emit codeFoldingUpdated();
01155
01156 kdDebug (13020) << "HIGHLIGHTED END --- NEED HL, LINESTART: " << startLine << " LINEEND: " << endLine << endl;
01157 kdDebug (13020) << "HL UNTIL LINE: " << m_lineHighlighted << " MAX: " << m_lineHighlightedMax << endl;
01158 kdDebug (13020) << "HL DYN COUNT: " << KateHlManager::self()->countDynamicCtxs() << " MAX: " << m_maxDynamicContexts << endl;
01159 kdDebug (13020) << "TIME TAKEN: " << t.elapsed() << endl;
01160
01161
01162
01163 return stillcontinue && ((current_line+1) == buf->lines());
01164 }
01165
01166 void KateBuffer::codeFoldingColumnUpdate(unsigned int lineNr) {
01167 KateTextLine::Ptr line=plainLine(lineNr);
01168 if (!line) return;
01169 if (line->foldingColumnsOutdated()) {
01170 line->setFoldingColumnsOutdated(false);
01171 bool tmp;
01172 QMemArray<uint> folding=line->foldingListArray();
01173 m_regionTree.updateLine(lineNr,&folding,&tmp,true,false);
01174 }
01175 }
01176
01177
01178
01179 KateBufBlock::KateBufBlock ( KateBuffer *parent, KateBufBlock *prev, KateBufBlock *next,
01180 KateFileLoader *stream )
01181 : m_state (KateBufBlock::stateDirty),
01182 m_startLine (0),
01183 m_lines (0),
01184 m_vmblock (0),
01185 m_vmblockSize (0),
01186 m_parent (parent),
01187 m_prev (prev),
01188 m_next (next),
01189 list (0),
01190 listPrev (0),
01191 listNext (0)
01192 {
01193
01194 if (m_prev)
01195 {
01196 m_startLine = m_prev->endLine ();
01197 m_prev->m_next = this;
01198 }
01199
01200 if (m_next)
01201 m_next->m_prev = this;
01202
01203
01204
01205 if (stream)
01206 {
01207
01208 fillBlock (stream);
01209 }
01210 else
01211 {
01212
01213 KateTextLine::Ptr textLine = new KateTextLine ();
01214 m_stringList.push_back (textLine);
01215 m_lines++;
01216
01217
01218 if (m_parent->m_loadedBlocks.count() >= KateBuffer::maxLoadedBlocks())
01219 m_parent->m_loadedBlocks.first()->swapOut();
01220
01221
01222 m_state = KateBufBlock::stateDirty;
01223 m_parent->m_loadedBlocks.append (this);
01224 }
01225 }
01226
01227 KateBufBlock::~KateBufBlock ()
01228 {
01229
01230 if (m_prev)
01231 m_prev->m_next = m_next;
01232
01233 if (m_next)
01234 m_next->m_prev = m_prev;
01235
01236
01237 if (m_vmblock)
01238 KateFactory::self()->vm()->free(m_vmblock);
01239
01240
01241 KateBufBlockList::remove (this);
01242 }
01243
01244 void KateBufBlock::fillBlock (KateFileLoader *stream)
01245 {
01246
01247 bool swap = m_parent->m_loadedBlocks.count() >= KateBuffer::maxLoadedBlocks();
01248
01249 QByteArray rawData;
01250
01251
01252 if (swap)
01253 rawData.resize ((KATE_AVG_BLOCK_SIZE * sizeof(QChar)) + ((KATE_AVG_BLOCK_SIZE/80) * 8));
01254
01255 char *buf = rawData.data ();
01256 uint size = 0;
01257 uint blockSize = 0;
01258 while (!stream->eof() && (blockSize < KATE_AVG_BLOCK_SIZE) && (m_lines < KATE_MAX_BLOCK_LINES))
01259 {
01260 uint offset = 0, length = 0;
01261 stream->readLine(offset, length);
01262 const QChar *unicodeData = stream->unicode () + offset;
01263
01264 blockSize += length;
01265
01266 if (swap)
01267 {
01268
01269
01270 char attr = KateTextLine::flagNoOtherData;
01271 uint pos = size;
01272
01273
01274 size = size + 1 + sizeof(uint) + (sizeof(QChar)*length);
01275
01276 if (size > rawData.size ())
01277 {
01278 rawData.resize (size);
01279 buf = rawData.data ();
01280 }
01281
01282 memcpy(buf+pos, (char *) &attr, 1);
01283 pos += 1;
01284
01285 memcpy(buf+pos, (char *) &length, sizeof(uint));
01286 pos += sizeof(uint);
01287
01288 memcpy(buf+pos, (char *) unicodeData, sizeof(QChar)*length);
01289 pos += sizeof(QChar)*length;
01290 }
01291 else
01292 {
01293 KateTextLine::Ptr textLine = new KateTextLine ();
01294 textLine->insertText (0, length, unicodeData);
01295 m_stringList.push_back (textLine);
01296 }
01297
01298 m_lines++;
01299 }
01300
01301 if (swap)
01302 {
01303 m_vmblock = KateFactory::self()->vm()->allocate(size);
01304 m_vmblockSize = size;
01305
01306 if (!rawData.isEmpty())
01307 {
01308 if (!KateFactory::self()->vm()->copyBlock(m_vmblock, rawData.data(), 0, size))
01309 {
01310 if (m_vmblock)
01311 KateFactory::self()->vm()->free(m_vmblock);
01312
01313 m_vmblock = 0;
01314 m_vmblockSize = 0;
01315
01316 m_parent->m_cacheWriteError = true;
01317 }
01318 }
01319
01320
01321 m_state = KateBufBlock::stateSwapped;
01322 }
01323 else
01324 {
01325
01326 m_state = KateBufBlock::stateDirty;
01327 m_parent->m_loadedBlocks.append (this);
01328 }
01329
01330 kdDebug (13020) << "A BLOCK LOADED WITH LINES: " << m_lines << endl;
01331 }
01332
01333 KateTextLine::Ptr KateBufBlock::line(uint i)
01334 {
01335
01336 if (m_state == KateBufBlock::stateSwapped)
01337 swapIn ();
01338
01339
01340 if (!m_parent->m_loadedBlocks.isLast(this))
01341 m_parent->m_loadedBlocks.append (this);
01342
01343 return m_stringList[i];
01344 }
01345
01346 void KateBufBlock::insertLine(uint i, KateTextLine::Ptr line)
01347 {
01348
01349 if (m_state == KateBufBlock::stateSwapped)
01350 swapIn ();
01351
01352 m_stringList.insert (m_stringList.begin()+i, line);
01353 m_lines++;
01354
01355 markDirty ();
01356 }
01357
01358 void KateBufBlock::removeLine(uint i)
01359 {
01360
01361 if (m_state == KateBufBlock::stateSwapped)
01362 swapIn ();
01363
01364 m_stringList.erase (m_stringList.begin()+i);
01365 m_lines--;
01366
01367 markDirty ();
01368 }
01369
01370 void KateBufBlock::markDirty ()
01371 {
01372 if (m_state != KateBufBlock::stateSwapped)
01373 {
01374
01375 if (!m_parent->m_loadedBlocks.isLast(this))
01376 m_parent->m_loadedBlocks.append (this);
01377
01378 if (m_state == KateBufBlock::stateClean)
01379 {
01380
01381 if (m_vmblock)
01382 KateFactory::self()->vm()->free(m_vmblock);
01383
01384 m_vmblock = 0;
01385 m_vmblockSize = 0;
01386
01387
01388 m_state = KateBufBlock::stateDirty;
01389 }
01390 }
01391 }
01392
01393 void KateBufBlock::swapIn ()
01394 {
01395 if (m_state != KateBufBlock::stateSwapped)
01396 return;
01397
01398 QByteArray rawData (m_vmblockSize);
01399
01400
01401 if (!KateFactory::self()->vm()->copyBlock(rawData.data(), m_vmblock, 0, rawData.size()))
01402 m_parent->m_cacheReadError = true;
01403
01404
01405 m_stringList.reserve (m_lines);
01406
01407 char *buf = rawData.data();
01408 for (uint i=0; i < m_lines; i++)
01409 {
01410 KateTextLine::Ptr textLine = new KateTextLine ();
01411 buf = textLine->restore (buf);
01412 m_stringList.push_back (textLine);
01413 }
01414
01415
01416 if (m_parent->m_loadedBlocks.count() >= KateBuffer::maxLoadedBlocks())
01417 m_parent->m_loadedBlocks.first()->swapOut();
01418
01419
01420 m_state = KateBufBlock::stateClean;
01421 m_parent->m_loadedBlocks.append (this);
01422 }
01423
01424 void KateBufBlock::swapOut ()
01425 {
01426 if (m_state == KateBufBlock::stateSwapped)
01427 return;
01428
01429 if (m_state == KateBufBlock::stateDirty)
01430 {
01431 bool haveHl = m_parent->m_highlight && !m_parent->m_highlight->noHighlighting();
01432
01433
01434 uint size = 0;
01435 for (uint i=0; i < m_lines; i++)
01436 size += m_stringList[i]->dumpSize (haveHl);
01437
01438 QByteArray rawData (size);
01439 char *buf = rawData.data();
01440
01441
01442 for (uint i=0; i < m_lines; i++)
01443 buf = m_stringList[i]->dump (buf, haveHl);
01444
01445 m_vmblock = KateFactory::self()->vm()->allocate(rawData.size());
01446 m_vmblockSize = rawData.size();
01447
01448 if (!rawData.isEmpty())
01449 {
01450 if (!KateFactory::self()->vm()->copyBlock(m_vmblock, rawData.data(), 0, rawData.size()))
01451 {
01452 if (m_vmblock)
01453 KateFactory::self()->vm()->free(m_vmblock);
01454
01455 m_vmblock = 0;
01456 m_vmblockSize = 0;
01457
01458 m_parent->m_cacheWriteError = true;
01459
01460 return;
01461 }
01462 }
01463 }
01464
01465 m_stringList.clear();
01466
01467
01468 m_state = KateBufBlock::stateSwapped;
01469 KateBufBlockList::remove (this);
01470 }
01471
01472
01473
01474
01475
01476 KateBufBlockList::KateBufBlockList ()
01477 : m_count (0),
01478 m_first (0),
01479 m_last (0)
01480 {
01481 }
01482
01483 void KateBufBlockList::append (KateBufBlock *buf)
01484 {
01485 if (buf->list)
01486 buf->list->removeInternal (buf);
01487
01488 m_count++;
01489
01490
01491 if (m_last)
01492 {
01493 m_last->listNext = buf;
01494
01495 buf->listPrev = m_last;
01496 buf->listNext = 0;
01497
01498 m_last = buf;
01499
01500 buf->list = this;
01501
01502 return;
01503 }
01504
01505
01506 m_last = buf;
01507 m_first = buf;
01508
01509 buf->listPrev = 0;
01510 buf->listNext = 0;
01511
01512 buf->list = this;
01513 }
01514
01515 void KateBufBlockList::removeInternal (KateBufBlock *buf)
01516 {
01517 if (buf->list != this)
01518 return;
01519
01520 m_count--;
01521
01522 if ((buf == m_first) && (buf == m_last))
01523 {
01524
01525 m_first = 0;
01526 m_last = 0;
01527 }
01528 else if (buf == m_first)
01529 {
01530
01531 m_first = buf->listNext;
01532 m_first->listPrev = 0;
01533 }
01534 else if (buf == m_last)
01535 {
01536
01537 m_last = buf->listPrev;
01538 m_last->listNext = 0;
01539 }
01540 else
01541 {
01542 buf->listPrev->listNext = buf->listNext;
01543 buf->listNext->listPrev = buf->listPrev;
01544 }
01545
01546 buf->listPrev = 0;
01547 buf->listNext = 0;
01548
01549 buf->list = 0;
01550 }
01551
01552
01553
01554