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