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