00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "katebuffer.h"
00021 #include "katebuffer.moc"
00022
00023 #include "katedocument.h"
00024 #include "katehighlight.h"
00025 #include "kateconfig.h"
00026 #include "katecodefoldinghelpers.h"
00027
00028 #include <kvmallocator.h>
00029 #include <kdebug.h>
00030 #include <kglobal.h>
00031 #include <kcharsets.h>
00032
00033 #include <qfile.h>
00034 #include <qtextstream.h>
00035 #include <qtimer.h>
00036 #include <qtextcodec.h>
00037
00038 #include <assert.h>
00039
00040
00041 #define AVG_BLOCK_SIZE 32000
00042
00046 class KateBufFileLoader
00047 {
00048 public:
00049 KateBufFileLoader (const QString &m_file) :
00050 file (m_file), stream (&file), codec (0), prev (0), lastCharEOL (false)
00051 {
00052 }
00053
00054 ~KateBufFileLoader ()
00055 {
00056 }
00057
00058 public:
00059 QFile file;
00060 QTextStream stream;
00061 QTextCodec *codec;
00062 KateBufBlock *prev;
00063 bool lastCharEOL;
00064 };
00065
00070 class KateBufBlock
00071 {
00072 friend class KateBuffer;
00073
00074 public:
00075
00076
00077
00078 KateBufBlock (KateBuffer *parent, KateBufBlock *prev, KVMAllocator *vm);
00079
00080 ~KateBufBlock ();
00081
00088 bool fillBlock (QTextStream *stream, bool lastCharEOL);
00089
00094 void buildStringList();
00095
00100 void flushStringList();
00101
00106 void disposeStringList();
00107
00112 void disposeRawData();
00113
00117 bool swapOut ();
00118
00123 bool swapIn ();
00124
00129 void disposeSwap ();
00130
00135 TextLine::Ptr line(uint i);
00136
00140 void insertLine(uint i, TextLine::Ptr line);
00141
00145 void removeLine(uint i);
00146
00150 inline uint startLine () { return m_startLine; };
00151
00152 inline void setStartLine (uint line)
00153 {
00154 m_startLine = line;
00155 }
00156
00160 inline uint endLine () { return m_startLine + m_lines; }
00161
00165 inline uint lines () { return m_lines; }
00166
00167 inline uint firstLineIndentation () { return m_firstLineIndentation; }
00168 inline bool firstLineOnlySpaces () { return m_firstLineOnlySpaces; }
00169
00170 inline TextLine::Ptr lastLine () { return m_lastLine; }
00171
00172 private:
00173
00174 uint m_startLine;
00175 uint m_lines;
00176
00177
00178 uint m_firstLineIndentation;
00179 bool m_firstLineOnlySpaces;
00180 TextLine::Ptr m_lastLine;
00181
00182
00183 KVMAllocator *m_vm;
00184 KVMAllocator::Block *m_vmblock;
00185 uint m_vmblockSize;
00186 bool b_vmDataValid;
00187
00192 QByteArray m_rawData;
00193 bool b_rawDataValid;
00194
00198 TextLine::List m_stringList;
00199 bool b_stringListValid;
00200
00201
00202 bool b_needHighlight;
00203
00204
00205 KateBuffer* m_parent;
00206 };
00207
00211 KateBuffer::KateBuffer(KateDocument *doc)
00212 : QObject (doc),
00213 m_hlUpdate (true),
00214 m_lines (0),
00215 m_highlightedTo (0),
00216 m_highlightedRequested (0),
00217 m_lastInSyncBlock (0),
00218 m_highlight (0),
00219 m_doc (doc),
00220 m_loader (0),
00221 m_vm (0),
00222 m_regionTree (0),
00223 m_highlightedTill (0),
00224 m_highlightedEnd (0),
00225 m_highlightedSteps (0),
00226 m_cacheReadError(false),
00227 m_cacheWriteError(false),
00228 m_loadingBorked (false),
00229 m_tabWidth (0)
00230 {
00231 m_blocks.setAutoDelete(true);
00232
00233 connect( &m_highlightTimer, SIGNAL(timeout()), this, SLOT(pleaseHighlight()));
00234
00235 clear();
00236 }
00237
00241 KateBuffer::~KateBuffer()
00242 {
00243 m_blocks.clear ();
00244
00245 delete m_vm;
00246 delete m_loader;
00247 }
00248
00249 void KateBuffer::setTabWidth (uint w)
00250 {
00251 if (m_tabWidth != w)
00252 {
00253 m_tabWidth = w;
00254
00255 if (m_highlight && m_highlight->foldingIndentationSensitive())
00256 invalidateHighlighting();
00257 }
00258 }
00259
00263 void KateBuffer::checkLoadedMax ()
00264 {
00265 if (m_loadedBlocks.count() > 40)
00266 {
00267 KateBufBlock *buf2 = m_loadedBlocks.take(2);
00268 bool ok = buf2->swapOut ();
00269 if (!ok)
00270 {
00271 m_cacheWriteError = true;
00272 m_loadedBlocks.append(buf2);
00273 }
00274 }
00275 }
00276
00280 void KateBuffer::checkCleanMax ()
00281 {
00282 if (m_cleanBlocks.count() > 10)
00283 {
00284 checkLoadedMax ();
00285
00286 KateBufBlock *buf2 = m_cleanBlocks.take(2);
00287 buf2->disposeStringList();
00288 m_loadedBlocks.append(buf2);
00289 }
00290 }
00291
00295 void KateBuffer::checkDirtyMax ()
00296 {
00297 if (m_dirtyBlocks.count() > 10)
00298 {
00299 checkLoadedMax ();
00300
00301 KateBufBlock *buf2 = m_dirtyBlocks.take(2);
00302 buf2->flushStringList();
00303 buf2->disposeStringList();
00304 m_loadedBlocks.append(buf2);
00305 }
00306 }
00307
00308 uint KateBuffer::countVisible ()
00309 {
00310 return m_lines - m_regionTree->getHiddenLinesCount(m_lines);
00311 }
00312
00313 uint KateBuffer::lineNumber (uint visibleLine)
00314 {
00315 return m_regionTree->getRealLine (visibleLine);
00316 }
00317
00318 uint KateBuffer::lineVisibleNumber (uint line)
00319 {
00320 return m_regionTree->getVirtualLine (line);
00321 }
00322
00323 void KateBuffer::lineInfo (KateLineInfo *info, unsigned int line)
00324 {
00325 m_regionTree->getLineInfo(info,line);
00326 }
00327
00328 KateCodeFoldingTree *KateBuffer::foldingTree ()
00329 {
00330 return m_regionTree;
00331 }
00332
00336 void KateBuffer::loadBlock(KateBufBlock *buf)
00337 {
00338 if (m_loadedBlocks.findRef (buf) > -1)
00339 return;
00340
00341
00342 checkLoadedMax ();
00343
00344
00345 if (!buf->swapIn ())
00346 {
00347 m_cacheReadError = true;
00348 return;
00349 }
00350
00351 m_loadedBlocks.append(buf);
00352 }
00353
00357 void KateBuffer::parseBlock(KateBufBlock *buf)
00358 {
00359 if (m_cleanBlocks.findRef (buf) > -1)
00360 return;
00361
00362
00363 if (!buf->b_rawDataValid)
00364 loadBlock(buf);
00365
00366
00367 checkCleanMax ();
00368
00369
00370 buf->buildStringList();
00371
00372 m_loadedBlocks.removeRef(buf);
00373 m_cleanBlocks.append(buf);
00374 }
00375
00379 void KateBuffer::dirtyBlock(KateBufBlock *buf)
00380 {
00381 if (m_dirtyBlocks.findRef (buf) > -1)
00382 return;
00383
00384
00385 checkDirtyMax ();
00386
00387
00388 buf->disposeRawData();
00389
00390
00391 if (buf->b_vmDataValid)
00392 buf->disposeSwap();
00393
00394 m_cleanBlocks.removeRef(buf);
00395 m_dirtyBlocks.append(buf);
00396 }
00397
00401 KateBufBlock *KateBuffer::findBlock(uint i)
00402 {
00403 if ((i >= m_lines))
00404 return 0;
00405
00406 KateBufBlock *buf = 0;
00407
00408 if (m_blocks.current() && (int(m_lastInSyncBlock) >= m_blocks.at()))
00409 {
00410 buf = m_blocks.current();
00411 }
00412 else
00413 {
00414 buf = m_blocks.at (m_lastInSyncBlock);
00415 }
00416
00417 int lastLine = 0;
00418 while (buf != 0)
00419 {
00420 lastLine = buf->endLine ();
00421
00422 if (i < buf->startLine())
00423 {
00424
00425 buf = m_blocks.prev ();
00426 }
00427 else if (i >= buf->endLine())
00428 {
00429
00430 buf = m_blocks.next();
00431 }
00432 else
00433 {
00434
00435 return buf;
00436 }
00437
00438 if (buf && (m_blocks.at () > int(m_lastInSyncBlock)) && (int(buf->startLine()) != lastLine))
00439 {
00440 buf->setStartLine (lastLine);
00441 m_lastInSyncBlock = m_blocks.at ();
00442 }
00443 }
00444
00445 return 0;
00446 }
00447
00448 void KateBuffer::clear()
00449 {
00450
00451
00452
00453 if (m_regionTree) m_regionTree->clear();
00454 else
00455 {
00456 m_regionTree=new KateCodeFoldingTree(this);
00457 connect(m_regionTree,SIGNAL(setLineVisible(unsigned int, bool)), this,SLOT(setLineVisible(unsigned int,bool)));
00458 }
00459
00460
00461 m_cleanBlocks.clear();
00462 m_dirtyBlocks.clear();
00463 m_loadedBlocks.clear();
00464 m_blocks.clear();
00465 delete m_vm;
00466 m_vm = new KVMAllocator;
00467 m_highlight = 0;
00468
00469
00470 KateBufBlock *block = new KateBufBlock(this, 0, m_vm);
00471 block->b_rawDataValid = true;
00472 block->m_rawData.resize (sizeof(uint) + 1);
00473 char* buf = block->m_rawData.data ();
00474 uint length = 0;
00475 memcpy(buf, (char *) &length, sizeof(uint));
00476 char attr = TextLine::flagNoOtherData;
00477 memcpy(buf+sizeof(uint), (char *) &attr, 1);
00478 block->m_lines++;
00479
00480 m_blocks.append (block);
00481 m_loadedBlocks.append (block);
00482
00483 m_lines = block->m_lines;
00484
00485 m_highlightedTo = 0;
00486 m_highlightedRequested = 0;
00487 m_lastInSyncBlock = 0;
00488
00489 emit linesChanged(m_lines);
00490 }
00491
00492 void KateBuffer::setHighlight(Highlight *highlight)
00493 {
00494 m_highlight = highlight;
00495 invalidateHighlighting();
00496 }
00497
00501 bool KateBuffer::openFile (const QString &m_file)
00502 {
00503 clear();
00504
00505
00506 KateBufFileLoader loader (m_file);
00507
00508 if ( !loader.file.open( IO_ReadOnly ) || !loader.file.isDirectAccess() )
00509 {
00510 clear();
00511 return false;
00512 }
00513
00514
00515 while (true)
00516 {
00517 int ch = loader.file.getch();
00518
00519 if (ch == -1)
00520 break;
00521
00522 if ((ch == '\r'))
00523 {
00524 ch = loader.file.getch ();
00525
00526 if (ch == '\n')
00527 {
00528 m_doc->config()->setEol (KateDocumentConfig::eolDos);
00529 break;
00530 }
00531 else
00532 {
00533 m_doc->config()->setEol (KateDocumentConfig::eolMac);
00534 break;
00535 }
00536 }
00537 else if (ch == '\n')
00538 {
00539 m_doc->config()->setEol (KateDocumentConfig::eolUnix);
00540 break;
00541 }
00542 }
00543
00544 if (loader.file.size () > 0)
00545 {
00546 loader.file.at (loader.file.size () - 1);
00547
00548 int ch = loader.file.getch();
00549
00550 if ((ch == '\n') || (ch == '\r'))
00551 loader.lastCharEOL = true;
00552 }
00553
00554 loader.file.reset ();
00555
00556 QTextCodec *codec = m_doc->config()->codec();
00557 loader.stream.setEncoding(QTextStream::RawUnicode);
00558 loader.stream.setCodec(codec);
00559 loader.codec = codec;
00560 loader.prev = 0;
00561
00562
00563 m_loadedBlocks.clear();
00564 m_blocks.clear();
00565 m_lines = 0;
00566
00567
00568 m_loadingBorked = false;
00569
00570
00571
00572 bool eof = false;
00573 while (true)
00574 {
00575 if (loader.stream.atEnd())
00576 eof = true;
00577
00578 if (eof)
00579 break;
00580
00581 checkLoadedMax ();
00582 if (m_cacheWriteError)
00583 break;
00584
00585 KateBufBlock *block = new KateBufBlock(this, loader.prev, m_vm);
00586 eof = block->fillBlock (&loader.stream, loader.lastCharEOL);
00587
00588 m_blocks.append (block);
00589 m_loadedBlocks.append (block);
00590
00591 loader.prev = block;
00592 m_lines = block->endLine ();
00593 }
00594
00595 if (m_cacheWriteError)
00596 {
00597 m_loadingBorked = true;
00598 }
00599
00600 if (m_cacheWriteError)
00601 kdDebug(13020)<<"Loading failed, no room for temp-file.\n";
00602 else
00603 kdDebug(13020)<<"Loading finished.\n";
00604
00605
00606
00607 if (m_blocks.isEmpty() || (count () == 0))
00608 clear ();
00609 else
00610 m_regionTree->fixRoot (m_lines);
00611
00612 emit linesChanged(m_lines);
00613 emit loadingFinished ();
00614
00615 return !m_loadingBorked;
00616 }
00617
00618 bool KateBuffer::canEncode ()
00619 {
00620 QTextCodec *codec = m_doc->config()->codec();
00621
00622 kdDebug(13020) << "ENC NAME: " << codec->name() << endl;
00623
00624
00625 if ((QString(codec->name()) == "UTF-8") || (QString(codec->name()) == "ISO-10646-UCS-2"))
00626 return true;
00627
00628 for (uint i=0; i < m_lines; i++)
00629 {
00630 if (!codec->canEncode (plainLine(i)->string()))
00631 {
00632 kdDebug(13020) << "STRING LINE: " << plainLine(i)->string() << endl;
00633 kdDebug(13020) << "ENC WORKING: FALSE" << endl;
00634
00635 return false;
00636 }
00637 }
00638
00639 return true;
00640 }
00641
00642 bool KateBuffer::saveFile (const QString &m_file)
00643 {
00644 QFile file (m_file);
00645 QTextStream stream (&file);
00646
00647 if ( !file.open( IO_WriteOnly ) )
00648 {
00649 return false;
00650 }
00651
00652 QTextCodec *codec = m_doc->config()->codec();
00653
00654
00655 stream.setEncoding(QTextStream::RawUnicode);
00656
00657
00658 stream.setCodec(codec);
00659
00660 QString eol = m_doc->config()->eolString ();
00661
00662 QString tabs;
00663 if (m_doc->configFlags() & KateDocument::cfReplaceTabs)
00664 tabs.fill (QChar(' '), m_doc->config()->tabWidth());
00665
00666 for (uint i=0; i < m_lines; i++)
00667 {
00668
00669 if (m_doc->configFlags() & KateDocument::cfReplaceTabs)
00670 stream << textLine (i, m_doc->configFlags() & KateDocument::cfRemoveSpaces).replace (QChar('\t'), tabs);
00671 else
00672 stream << textLine (i, m_doc->configFlags() & KateDocument::cfRemoveSpaces);
00673
00674 if (i < (m_lines-1))
00675 stream << eol;
00676 }
00677
00678 file.close ();
00679
00680 m_loadingBorked = false;
00681
00682 return (file.status() == IO_Ok);
00683 }
00684
00688 TextLine::Ptr KateBuffer::line(uint i)
00689 {
00690 KateBufBlock *buf = findBlock(i);
00691
00692 if (!buf)
00693 return 0;
00694
00695 if (!buf->b_stringListValid)
00696 parseBlock(buf);
00697
00698 if (buf->b_needHighlight)
00699 {
00700 buf->b_needHighlight = false;
00701
00702 if (m_highlightedTo > buf->startLine())
00703 {
00704 needHighlight (buf, buf->startLine(), buf->endLine());
00705 }
00706 }
00707
00708 if ((m_highlightedRequested <= i) && (m_highlightedTo <= i))
00709 {
00710 m_highlightedRequested = buf->endLine();
00711
00712 pleaseHighlight (m_highlightedTo, buf->endLine());
00713
00714
00715 if (!buf->b_stringListValid)
00716 parseBlock(buf);
00717 }
00718
00719 return buf->line (i - buf->m_startLine);
00720 }
00721
00722 bool KateBuffer::needHighlight(KateBufBlock *buf, uint startLine, uint endLine)
00723 {
00724
00725 if (!m_highlight)
00726 return false;
00727
00728
00729 if (!m_hlUpdate)
00730 return false;
00731
00732
00733 if (startLine >= (buf->startLine()+buf->lines()))
00734 return false;
00735
00736
00737 if (!buf->b_stringListValid)
00738 parseBlock(buf);
00739
00740
00741
00742 TextLine::Ptr prevLine = 0;
00743
00744 if (startLine == buf->startLine())
00745 {
00746 int pos = m_blocks.findRef (buf);
00747 if (pos > 0)
00748 {
00749 KateBufBlock *blk = m_blocks.at (pos-1);
00750
00751 if (blk->b_stringListValid && (blk->lines() > 0))
00752 prevLine = blk->line (blk->lines() - 1);
00753 else
00754 prevLine = blk->lastLine();
00755 }
00756 }
00757 else if ((startLine > buf->startLine()) && (startLine <= buf->endLine()))
00758 {
00759 prevLine = buf->line(startLine - buf->startLine() - 1);
00760 }
00761
00762 if (!prevLine)
00763 prevLine = new TextLine ();
00764
00765 bool line_continue = prevLine->hlLineContinue();
00766
00767 QMemArray<short> ctxNum, endCtx;
00768 ctxNum.duplicate (prevLine->ctxArray ());
00769
00770
00771 bool codeFoldingUpdate = false;
00772
00773
00774 uint current_line = startLine - buf->startLine();
00775
00776
00777 bool stillcontinue=false;
00778
00779
00780
00781 while ( (current_line < buf->lines())
00782 && (stillcontinue || ((current_line + buf->startLine()) <= endLine)) )
00783 {
00784
00785 TextLine::Ptr textLine = buf->line(current_line);
00786
00787 endCtx.duplicate (textLine->ctxArray ());
00788
00789 QMemArray<signed char> foldingList;
00790 m_highlight->doHighlight(ctxNum, textLine, line_continue, &foldingList);
00791
00792
00793
00794
00795 bool indentChanged = false;
00796 if (m_highlight->foldingIndentationSensitive())
00797 {
00798
00799 QMemArray<unsigned short> indentDepth;
00800 indentDepth.duplicate (prevLine->indentationDepthArray());
00801
00802
00803 uint iDepth = textLine->indentDepth(m_tabWidth);
00804
00805
00806 if (textLine->firstChar() == -1)
00807 {
00808
00809 if (!prevLine->indentationDepthArray().isEmpty())
00810 iDepth = (prevLine->indentationDepthArray())[prevLine->indentationDepthArray().size()-1];
00811 else
00812 iDepth = prevLine->indentDepth(m_tabWidth);
00813
00814
00815 indentChanged = true;
00816 }
00817
00818
00819
00820 uint nextLineIndentation = 0;
00821
00822 if ((current_line+1) < buf->lines())
00823 {
00824 if (buf->line(current_line+1)->firstChar() == -1)
00825 nextLineIndentation = iDepth;
00826 else
00827 nextLineIndentation = buf->line(current_line+1)->indentDepth(m_tabWidth);
00828 }
00829 else
00830 {
00831 int pos = m_blocks.findRef (buf);
00832 if (uint(pos + 1) < m_blocks.count())
00833 {
00834 KateBufBlock *blk = m_blocks.at (pos+1);
00835
00836 if (blk->b_stringListValid && (blk->lines() > 0))
00837 {
00838 if (blk->line (0)->firstChar() == -1)
00839 nextLineIndentation = iDepth;
00840 else
00841 nextLineIndentation = blk->line (0)->indentDepth(m_tabWidth);
00842 }
00843 else
00844 {
00845 if (blk->firstLineOnlySpaces())
00846 nextLineIndentation = iDepth;
00847 else
00848 nextLineIndentation = blk->firstLineIndentation();
00849 }
00850 }
00851 }
00852
00853
00854
00855 bool newIn = false;
00856 if ((iDepth > 0) && (indentDepth.isEmpty() || (indentDepth[indentDepth.size()-1] < iDepth)))
00857 {
00858 indentDepth.resize (indentDepth.size()+1);
00859 indentDepth[indentDepth.size()-1] = iDepth;
00860 newIn = true;
00861 }
00862 else
00863 {
00864 for (int z=indentDepth.size()-1; z > -1; z--)
00865 {
00866 if (indentDepth[z] > iDepth)
00867 indentDepth.resize (z);
00868 else if (indentDepth[z] == iDepth)
00869 break;
00870 else if (indentDepth[z] < iDepth)
00871 {
00872 indentDepth.resize (indentDepth.size()+1);
00873 indentDepth[indentDepth.size()-1] = iDepth;
00874 newIn = true;
00875 break;
00876 }
00877 }
00878 }
00879
00880
00881 indentChanged = indentChanged || (indentDepth.size() != textLine->indentationDepthArray().size())
00882 || (indentDepth != textLine->indentationDepthArray());
00883
00884
00885 textLine->setIndentationDepth (indentDepth);
00886
00887
00888 if (newIn)
00889 {
00890 foldingList.resize (foldingList.size() + 1);
00891 foldingList[foldingList.size()-1] = 1;
00892 }
00893
00894
00895
00896 uint remIn = 0;
00897
00898 for (int z=indentDepth.size()-1; z > -1; z--)
00899 {
00900 if (indentDepth[z] > nextLineIndentation)
00901 remIn++;
00902 else
00903 break;
00904 }
00905
00906 if (remIn > 0)
00907 {
00908 foldingList.resize (foldingList.size() + remIn);
00909
00910 for (uint z= foldingList.size()-remIn; z < foldingList.size(); z++)
00911 foldingList[z] = -1;
00912 }
00913 }
00914
00915 bool foldingChanged = (foldingList.size() != textLine->foldingListArray().size())
00916 || (foldingList != textLine->foldingListArray());
00917
00918 if (foldingChanged)
00919 textLine->setFoldingList(foldingList);
00920
00921 bool retVal_folding = false;
00922 m_regionTree->updateLine(current_line + buf->startLine(), &foldingList, &retVal_folding, foldingChanged);
00923
00924 codeFoldingUpdate = codeFoldingUpdate | retVal_folding;
00925
00926 line_continue=textLine->hlLineContinue();
00927
00928 ctxNum.duplicate (textLine->ctxArray());
00929
00930 if ( indentChanged || (endCtx.size() != ctxNum.size()) )
00931 {
00932 stillcontinue = true;
00933 }
00934 else
00935 {
00936 stillcontinue = false;
00937
00938 if ((ctxNum != endCtx))
00939 stillcontinue = true;
00940 }
00941
00942
00943 prevLine = textLine;
00944
00945
00946 current_line++;
00947 }
00948
00949
00950 emit tagLines (startLine, current_line + buf->startLine());
00951
00952
00953 if (codeFoldingUpdate)
00954 emit codeFoldingUpdated();
00955
00956
00957
00958 return stillcontinue && ((current_line+1) == buf->lines());
00959 }
00960
00961 void KateBuffer::updateHighlighting(uint from, uint to, bool invalidate)
00962 {
00963
00964 if (!m_hlUpdate)
00965 return;
00966
00967
00968
00969 if (from > m_highlightedTo )
00970 from = m_highlightedTo;
00971
00972 uint done = 0;
00973 bool endStateChanged = true;
00974
00975 while (done < to)
00976 {
00977 KateBufBlock *buf = findBlock(from);
00978 if (!buf)
00979 return;
00980
00981 if (!buf->b_stringListValid)
00982 {
00983 parseBlock(buf);
00984 }
00985
00986 if (buf->b_needHighlight || invalidate || m_highlightedTo < buf->endLine())
00987 {
00988 uint fromLine = buf->startLine();
00989 uint tillLine = buf->endLine();
00990
00991 if (!buf->b_needHighlight && invalidate)
00992 {
00993 if (to < tillLine)
00994 tillLine = to;
00995
00996 if (from > fromLine)
00997 {
00998 if (m_highlightedTo > from)
00999 fromLine = from;
01000 else if (m_highlightedTo > fromLine)
01001 fromLine = m_highlightedTo;
01002 }
01003 }
01004
01005 buf->b_needHighlight = false;
01006
01007
01008 endStateChanged = needHighlight (buf, fromLine, tillLine);
01009
01010 if (buf->b_rawDataValid)
01011 {
01012 dirtyBlock(buf);
01013 }
01014 }
01015
01016 done = buf->endLine();
01017 from = done;
01018 }
01019 if (invalidate)
01020 {
01021 if (endStateChanged)
01022 m_highlightedTo = done;
01023 m_highlightedRequested = done;
01024 }
01025 else
01026 {
01027 if (done > m_highlightedTo)
01028 m_highlightedTo = done;
01029 }
01030 }
01031
01032 void KateBuffer::invalidateHighlighting()
01033 {
01034 m_highlightedTo = 0;
01035 m_highlightedRequested = 0;
01036 }
01037
01038 void KateBuffer::pleaseHighlight(uint from, uint to)
01039 {
01040 if (to > m_highlightedEnd)
01041 m_highlightedEnd = to;
01042
01043 if (m_highlightedEnd < from)
01044 return;
01045
01046
01047
01048
01049 m_highlightedSteps = ((m_highlightedEnd-from) / 5) + 1;
01050 if (m_highlightedSteps < 100)
01051 m_highlightedSteps = 100;
01052 else if (m_highlightedSteps > 2000)
01053 m_highlightedSteps = 2000;
01054
01055 uint till = from + m_highlightedSteps;
01056 if (till > m_highlightedEnd)
01057 till = m_highlightedEnd;
01058
01059 updateHighlighting(from, till, false);
01060
01061 m_highlightedTill = till;
01062 if (m_highlightedTill >= m_highlightedEnd)
01063 {
01064 m_highlightedTill = 0;
01065 m_highlightedEnd = 0;
01066 m_highlightTimer.stop();
01067 }
01068 else
01069 {
01070 m_highlightTimer.start(100, true);
01071 }
01072 }
01073
01074 void KateBuffer::pleaseHighlight()
01075 {
01076 uint till = m_highlightedTill + m_highlightedSteps;
01077
01078 if (m_highlightedSteps == 0)
01079 till += 100;
01080
01081 if (m_highlightedEnd > m_lines)
01082 m_highlightedEnd = m_lines;
01083
01084 if (till > m_highlightedEnd)
01085 till = m_highlightedEnd;
01086
01087 updateHighlighting(m_highlightedTill, till, false);
01088
01089 m_highlightedTill = till;
01090 if (m_highlightedTill >= m_highlightedEnd)
01091 {
01092 m_highlightedTill = 0;
01093 m_highlightedEnd = 0;
01094 m_highlightedSteps = 0;
01095 m_highlightTimer.stop();
01096 }
01097 else
01098 {
01099 m_highlightTimer.start(100, true);
01100 }
01101 }
01102
01106 TextLine::Ptr KateBuffer::plainLine(uint i)
01107 {
01108 KateBufBlock *buf = findBlock(i);
01109 if (!buf)
01110 return 0;
01111
01112 if (!buf->b_stringListValid)
01113 {
01114 parseBlock(buf);
01115 }
01116
01117 return buf->line(i - buf->m_startLine);
01118 }
01119
01123 QString KateBuffer::textLine(uint i, bool withoutTrailingSpaces)
01124 {
01125 KateBufBlock *buf = findBlock(i);
01126 if (!buf)
01127 return QString();
01128
01129 if (!buf->b_stringListValid)
01130 {
01131 parseBlock(buf);
01132 }
01133
01134 if (withoutTrailingSpaces)
01135 return buf->line(i - buf->startLine())->withoutTrailingSpaces();
01136
01137 return buf->line(i - buf->startLine())->string();
01138 }
01139
01140 void KateBuffer::insertLine(uint i, TextLine::Ptr line)
01141 {
01142
01143
01144
01145 KateBufBlock *buf;
01146 if (i == m_lines)
01147 buf = findBlock(i-1);
01148 else
01149 buf = findBlock(i);
01150
01151 if (!buf)
01152 return;
01153
01154 if (!buf->b_stringListValid)
01155 parseBlock(buf);
01156
01157 if (buf->b_rawDataValid)
01158 dirtyBlock(buf);
01159
01160 buf->insertLine(i - buf->startLine(), line);
01161
01162 if (m_highlightedTo > i)
01163 m_highlightedTo++;
01164 m_lines++;
01165
01166 if (int(m_lastInSyncBlock) > m_blocks.findRef (buf))
01167 m_lastInSyncBlock = m_blocks.findRef (buf);
01168
01169 m_regionTree->lineHasBeenInserted (i);
01170 }
01171
01172 void
01173 KateBuffer::removeLine(uint i)
01174 {
01175 KateBufBlock *buf = findBlock(i);
01176 assert(buf);
01177 if (!buf->b_stringListValid)
01178 {
01179 parseBlock(buf);
01180 }
01181 if (buf->b_rawDataValid)
01182 {
01183 dirtyBlock(buf);
01184 }
01185
01186 buf->removeLine(i - buf->startLine());
01187
01188 if (m_highlightedTo > i)
01189 m_highlightedTo--;
01190
01191 m_lines--;
01192
01193
01194 if (buf->lines() == 0)
01195 {
01196 if ((m_lastInSyncBlock > 0) && (int(m_lastInSyncBlock) >= m_blocks.findRef (buf)))
01197 m_lastInSyncBlock = m_blocks.findRef (buf) -1;
01198
01199 m_cleanBlocks.removeRef(buf);
01200 m_dirtyBlocks.removeRef(buf);
01201 m_loadedBlocks.removeRef(buf);
01202 m_blocks.removeRef(buf);
01203 }
01204 else
01205 {
01206 if (int(m_lastInSyncBlock) > m_blocks.findRef (buf))
01207 m_lastInSyncBlock = m_blocks.findRef (buf);
01208 }
01209
01210 m_regionTree->lineHasBeenRemoved (i);
01211 }
01212
01213 void KateBuffer::changeLine(uint i)
01214 {
01216 KateBufBlock *buf = findBlock(i);
01217 assert(buf);
01218 assert(buf->b_stringListValid);
01219
01220 if (buf->b_rawDataValid)
01221 {
01222 dirtyBlock(buf);
01223 }
01224 }
01225
01226 void KateBuffer::setLineVisible(unsigned int lineNr, bool visible)
01227 {
01228 kdDebug(13000)<<"void KateBuffer::setLineVisible(unsigned int lineNr, bool visible)"<<endl;
01229 TextLine::Ptr l=plainLine(lineNr);
01230 if (l)
01231 {
01232 l->setVisible(visible);
01233 changeLine (lineNr);
01234 }
01235 else
01236 kdDebug(13000)<<QString("Invalid line %1").arg(lineNr)<<endl;
01237 }
01238
01239 uint KateBuffer::length ()
01240 {
01241 uint l = 0;
01242
01243 for (uint i = 0; i < count(); i++)
01244 {
01245 l += plainLine(i)->length();
01246 }
01247
01248 return l;
01249 }
01250
01251 int KateBuffer::lineLength ( uint i )
01252 {
01253 TextLine::Ptr l = plainLine(i);
01254 Q_ASSERT(l);
01255 if (!l) return 0;
01256 return l->length();
01257 }
01258
01259 QString KateBuffer::text()
01260 {
01261 QString s;
01262
01263 for (uint i = 0; i < count(); i++)
01264 {
01265 s.append (textLine(i));
01266 if ( (i < (count()-1)) )
01267 s.append('\n');
01268 }
01269
01270 return s;
01271 }
01272
01273 QString KateBuffer::text ( uint startLine, uint startCol, uint endLine, uint endCol, bool blockwise )
01274 {
01275 if ( blockwise && (startCol > endCol) )
01276 return QString ();
01277
01278 QString s;
01279
01280 if (startLine == endLine)
01281 {
01282 if (startCol > endCol)
01283 return QString ();
01284
01285 TextLine::Ptr textLine = plainLine(startLine);
01286
01287 if ( !textLine )
01288 return QString ();
01289
01290 return textLine->string(startCol, endCol-startCol);
01291 }
01292 else
01293 {
01294 for (uint i = startLine; (i <= endLine) && (i < count()); i++)
01295 {
01296 TextLine::Ptr textLine = plainLine(i);
01297
01298 if ( !blockwise )
01299 {
01300 if (i == startLine)
01301 s.append (textLine->string(startCol, textLine->length()-startCol));
01302 else if (i == endLine)
01303 s.append (textLine->string(0, endCol));
01304 else
01305 s.append (textLine->string());
01306 }
01307 else
01308 {
01309 s.append (textLine->string (startCol, endCol - startCol));
01310 }
01311
01312 if ( i < endLine )
01313 s.append('\n');
01314 }
01315 }
01316
01317 return s;
01318 }
01319
01320 void KateBuffer::dumpRegionTree()
01321 {
01322 m_regionTree->debugDump();
01323 }
01324
01325
01326
01335 KateBufBlock::KateBufBlock(KateBuffer *parent, KateBufBlock *prev, KVMAllocator *vm)
01336 : m_firstLineIndentation (0),
01337 m_firstLineOnlySpaces (true),
01338 m_lastLine (0),
01339 m_vm (vm),
01340 m_vmblock (0),
01341 m_vmblockSize (0),
01342 b_vmDataValid (false),
01343 b_rawDataValid (false),
01344 b_stringListValid (false),
01345 b_needHighlight (true),
01346 m_parent (parent)
01347 {
01348 if (prev)
01349 m_startLine = prev->endLine ();
01350 else
01351 m_startLine = 0;
01352
01353 m_lines = 0;
01354 }
01355
01359 KateBufBlock::~KateBufBlock ()
01360 {
01361 if (b_vmDataValid)
01362 disposeSwap ();
01363 }
01364
01368 bool KateBufBlock::fillBlock (QTextStream *stream, bool lastCharEOL)
01369 {
01370 bool eof = false;
01371 uint lines = 0;
01372
01373 m_rawData.resize (AVG_BLOCK_SIZE);
01374 char *buf = m_rawData.data ();
01375 uint pos = 0;
01376 char attr = TextLine::flagNoOtherData;
01377
01378 uint size = 0;
01379 while (size < AVG_BLOCK_SIZE)
01380 {
01381 QString line = stream->readLine();
01382
01383 if (!(!lastCharEOL && stream->atEnd() && line.isNull()))
01384 {
01385 uint length = line.length ();
01386 size = pos + sizeof(uint) + (sizeof(QChar)*length) + 1;
01387
01388 if (size > m_rawData.size ())
01389 {
01390 m_rawData.resize (size);
01391 buf = m_rawData.data ();
01392 }
01393
01394 memcpy(buf+pos, (char *) &length, sizeof(uint));
01395 pos += sizeof(uint);
01396
01397 if (!line.isNull())
01398 {
01399 memcpy(buf+pos, (char *) line.unicode(), sizeof(QChar)*length);
01400 pos += sizeof(QChar)*length;
01401 }
01402
01403 memcpy(buf+pos, (char *) &attr, 1);
01404 pos += 1;
01405
01406 lines++;
01407 }
01408
01409 if (stream->atEnd() && line.isNull())
01410 {
01411 eof = true;
01412 break;
01413 }
01414 }
01415
01416 if (pos < m_rawData.size())
01417 {
01418 m_rawData.resize (size);
01419 }
01420
01421 m_lines = lines;
01422 b_rawDataValid = true;
01423
01424 return eof;
01425 }
01426
01432 bool KateBufBlock::swapOut ()
01433 {
01434
01435 assert(b_rawDataValid);
01436
01437 if (!b_vmDataValid)
01438 {
01439 m_vmblock = m_vm->allocate(m_rawData.count());
01440 m_vmblockSize = m_rawData.count();
01441
01442 if (!m_rawData.isEmpty())
01443 {
01444 bool ok = m_vm->copyBlock(m_vmblock, m_rawData.data(), 0, m_rawData.count());
01445 if (!ok)
01446 return false;
01447 }
01448
01449 b_vmDataValid = true;
01450 }
01451 disposeRawData();
01452 return true;
01453 }
01454
01459 bool KateBufBlock::swapIn ()
01460 {
01461
01462 assert(b_vmDataValid);
01463 assert(!b_rawDataValid);
01464 assert(m_vmblock);
01465 m_rawData.resize(m_vmblockSize);
01466 bool ok = m_vm->copyBlock(m_rawData.data(), m_vmblock, 0, m_vmblockSize);
01467 if (!ok)
01468 return false;
01469 b_rawDataValid = true;
01470 return true;
01471 }
01472
01476 void KateBufBlock::buildStringList()
01477 {
01478
01479 assert(m_stringList.empty());
01480
01481 char *buf = m_rawData.data();
01482 char *end = buf + m_rawData.count();
01483
01484 while(buf < end)
01485 {
01486 TextLine::Ptr textLine = new TextLine ();
01487 buf = textLine->restore (buf);
01488 m_stringList.push_back (textLine);
01489 }
01490
01491
01492
01493 if (m_lines > 0)
01494 {
01495 m_lastLine = m_stringList[m_lines - 1];
01496 }
01497 else
01498 {
01499 m_lastLine = 0;
01500 }
01501
01502 m_firstLineIndentation = 0;
01503 m_firstLineOnlySpaces = true;
01504
01505 assert(m_stringList.size() == m_lines);
01506 b_stringListValid = true;
01507
01508 }
01509
01514 void KateBufBlock::flushStringList()
01515 {
01516
01517 assert(b_stringListValid);
01518 assert(!b_rawDataValid);
01519
01520
01521 uint size = 0;
01522 for(TextLine::List::const_iterator it = m_stringList.begin(); it != m_stringList.end(); ++it)
01523 size += (*it)->dumpSize ();
01524
01525 m_rawData.resize (size);
01526 char *buf = m_rawData.data();
01527
01528
01529 for(TextLine::List::iterator it = m_stringList.begin(); it != m_stringList.end(); ++it)
01530 buf = (*it)->dump (buf);
01531
01532 assert(buf-m_rawData.data() == (int)size);
01533 b_rawDataValid = true;
01534 }
01535
01539 void KateBufBlock::disposeStringList()
01540 {
01541
01542 assert(b_rawDataValid || b_vmDataValid);
01543
01544 if (m_lines > 0)
01545 {
01546 m_firstLineIndentation = m_stringList[0]->indentDepth (m_parent->tabWidth());
01547 m_firstLineOnlySpaces = (m_stringList[0]->firstChar() == -1);
01548 m_lastLine = m_stringList[m_lines - 1];
01549 }
01550 else
01551 {
01552 m_firstLineIndentation = 0;
01553 m_firstLineOnlySpaces = true;
01554 m_lastLine = 0;
01555 }
01556
01557 m_stringList.clear();
01558 b_stringListValid = false;
01559 }
01560
01564 void KateBufBlock::disposeRawData()
01565 {
01566
01567 assert(b_stringListValid || b_vmDataValid);
01568 b_rawDataValid = false;
01569 m_rawData.resize (0);
01570 }
01571
01575 void KateBufBlock::disposeSwap()
01576 {
01577 if (m_vmblock)
01578 m_vm->free(m_vmblock);
01579
01580 m_vmblock = 0;
01581 m_vmblockSize = 0;
01582 b_vmDataValid = false;
01583 }
01584
01589 TextLine::Ptr KateBufBlock::line(uint i)
01590 {
01591 assert(b_stringListValid);
01592 assert(i < m_stringList.size());
01593
01594 return m_stringList[i];
01595 }
01596
01597 void KateBufBlock::insertLine(uint i, TextLine::Ptr line)
01598 {
01599 assert(b_stringListValid);
01600 assert(i <= m_stringList.size());
01601
01602 m_stringList.insert (m_stringList.begin()+i, line);
01603 m_lines++;
01604 }
01605
01606 void KateBufBlock::removeLine(uint i)
01607 {
01608 assert(b_stringListValid);
01609 assert(i < m_stringList.size());
01610
01611 m_stringList.erase (m_stringList.begin()+i);
01612 m_lines--;
01613 }
01614
01615