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