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