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