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