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