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