00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <sys/types.h>
00021 #include <sys/stat.h>
00022 #include <unistd.h>
00023
00024 #include "katebuffer.h"
00025 #include "katebuffer.moc"
00026
00027 #include "katedocument.h"
00028 #include "katehighlight.h"
00029 #include "kateconfig.h"
00030 #include "katefactory.h"
00031 #include "kateautoindent.h"
00032
00033 #include <kdebug.h>
00034 #include <kglobal.h>
00035 #include <kcharsets.h>
00036
00037 #include <qpopupmenu.h>
00038 #include <qfile.h>
00039 #include <qtextstream.h>
00040 #include <qtimer.h>
00041 #include <qtextcodec.h>
00042 #include <qcstring.h>
00043 #include <qdatetime.h>
00044
00049 static const Q_ULONG KATE_FILE_LOADER_BS = 256 * 1024;
00050
00057 static const Q_ULONG KATE_AVG_BLOCK_SIZE = 2048 * 80;
00058 static const Q_ULONG KATE_MAX_BLOCK_LINES = 2048;
00059
00065 static const uint KATE_HL_LOOKAHEAD = 64;
00066
00072 uint KateBuffer::m_maxLoadedBlocks = 16;
00073
00077 static const uint KATE_MAX_DYNAMIC_CONTEXTS = 512;
00078
00079 void KateBuffer::setMaxLoadedBlocks (uint count)
00080 {
00081 m_maxLoadedBlocks = KMAX ((uint)4, count);
00082 }
00083
00084 class KateFileLoader
00085 {
00086 public:
00087 KateFileLoader (const QString &filename, QTextCodec *codec, 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 else
00812 {
00813
00814 if (m_lastInSyncBlock > index)
00815 m_lastInSyncBlock = index;
00816 }
00817
00818
00819 if (m_lastInSyncBlock < m_lastFoundBlock)
00820 m_lastFoundBlock = m_lastInSyncBlock;
00821
00822
00823 editChangesDone = true;
00824
00825
00826 if (i < editTagLineStart)
00827 editTagLineStart = i;
00828
00829 if (i < editTagLineEnd)
00830 editTagLineEnd--;
00831
00832 if (i > editTagLineEnd)
00833 editTagLineEnd = i;
00834
00835
00836 editTagLineFrom = true;
00837
00838 m_regionTree.lineHasBeenRemoved (i);
00839 }
00840
00841 void KateBuffer::setTabWidth (uint w)
00842 {
00843 if ((m_tabWidth != w) && (m_tabWidth > 0))
00844 {
00845 m_tabWidth = w;
00846
00847 if (m_highlight && m_highlight->foldingIndentationSensitive())
00848 invalidateHighlighting();
00849 }
00850 }
00851
00852 void KateBuffer::setHighlight(uint hlMode)
00853 {
00854 KateHighlighting *h = KateHlManager::self()->getHl(hlMode);
00855
00856
00857 if (h != m_highlight)
00858 {
00859 bool invalidate = !h->noHighlighting();
00860
00861 if (m_highlight)
00862 {
00863 m_highlight->release();
00864 invalidate = true;
00865 }
00866
00867 h->use();
00868
00869
00870 if (!h->indentation().isEmpty())
00871 m_doc->config()->setIndentationMode (KateAutoIndent::modeNumber(h->indentation()));
00872
00873 m_highlight = h;
00874
00875 if (invalidate)
00876 invalidateHighlighting();
00877
00878
00879
00880 m_doc->bufferHlChanged ();
00881 }
00882 }
00883
00884 void KateBuffer::invalidateHighlighting()
00885 {
00886 m_lineHighlightedMax = 0;
00887 m_lineHighlighted = 0;
00888 }
00889
00890
00891 void KateBuffer::updatePreviousNotEmptyLine(KateBufBlock *blk,uint current_line,bool addindent,uint deindent)
00892 {
00893 KateTextLine::Ptr textLine;
00894 do {
00895 if (current_line>0) current_line--;
00896 else
00897 {
00898 uint line=blk->startLine()+current_line;
00899 if (line==0) return;
00900 line--;
00901 blk=findBlock(line);
00902 if (!blk) {
00903 kdDebug(13020)<<"updatePreviousNotEmptyLine: block not found, this must not happen"<<endl;
00904 return;
00905 }
00906 current_line=line-blk->startLine();
00907 }
00908 textLine = blk->line(current_line);
00909 } while (textLine->firstChar()==-1);
00910 kdDebug(13020)<<"updatePreviousNotEmptyLine: updating line:"<<(blk->startLine()+current_line)<<endl;
00911 QMemArray<uint> foldingList=textLine->foldingListArray();
00912 while ( (foldingList.size()>0) && ( abs(foldingList[foldingList.size()-2])==1)) {
00913 foldingList.resize(foldingList.size()-2,QGArray::SpeedOptim);
00914 }
00915 addIndentBasedFoldingInformation(foldingList,addindent,deindent);
00916 textLine->setFoldingList(foldingList);
00917 bool retVal_folding = false;
00918 m_regionTree.updateLine (current_line + blk->startLine(), &foldingList, &retVal_folding, true,false);
00919 emit tagLines (blk->startLine()+current_line, blk->startLine()+current_line);
00920 }
00921
00922 void KateBuffer::addIndentBasedFoldingInformation(QMemArray<uint> &foldingList,bool addindent,uint deindent)
00923 {
00924 if (addindent) {
00925
00926 kdDebug(13020)<<"adding ident"<<endl;
00927 foldingList.resize (foldingList.size() + 2, QGArray::SpeedOptim);
00928 foldingList[foldingList.size()-2] = 1;
00929 foldingList[foldingList.size()-1] = 0;
00930 }
00931 kdDebug(13020)<<"DEINDENT: "<<deindent<<endl;
00932 if (deindent > 0)
00933 {
00934 foldingList.resize (foldingList.size() + (deindent*2), QGArray::SpeedOptim);
00935
00936 for (uint z= foldingList.size()-(deindent*2); z < foldingList.size(); z=z+2)
00937 {
00938 foldingList[z] = -1;
00939 foldingList[z+1] = 0;
00940 }
00941 }
00942 }
00943
00944 bool KateBuffer::doHighlight (KateBufBlock *buf, uint startLine, uint endLine, bool invalidate)
00945 {
00946
00947 if (!m_highlight)
00948 return false;
00949
00950
00951
00952
00953
00954
00955
00956
00957 if (startLine >= (buf->startLine()+buf->lines()))
00958 return false;
00959
00960
00961
00962
00963
00964
00965
00966
00967 if (KateHlManager::self()->countDynamicCtxs() >= m_maxDynamicContexts)
00968 {
00969 {
00970 if (KateHlManager::self()->resetDynamicCtxs())
00971 {
00972 kdDebug (13020) << "HL invalidated - too many dynamic contexts ( >= " << m_maxDynamicContexts << ")" << endl;
00973
00974
00975 KateHlManager::self()->setForceNoDCReset(true);
00976
00977 for (KateDocument *doc = KateFactory::self()->documents()->first(); doc; doc = KateFactory::self()->documents()->next())
00978 doc->makeAttribs();
00979
00980
00981
00982 KateBufBlock *buf = 0;
00983 while ((endLine > m_lineHighlighted) && (buf = findBlock(m_lineHighlighted)))
00984 {
00985 uint end = kMin(endLine, buf->endLine());
00986
00987 doHighlight ( buf,
00988 kMax(m_lineHighlighted, buf->startLine()),
00989 end,
00990 false );
00991
00992 m_lineHighlighted = end;
00993 }
00994
00995 KateHlManager::self()->setForceNoDCReset(false);
00996
00997 return false;
00998 }
00999 else
01000 {
01001 m_maxDynamicContexts *= 2;
01002 kdDebug (13020) << "New dynamic contexts limit: " << m_maxDynamicContexts << endl;
01003 }
01004 }
01005 }
01006
01007
01008
01009 KateTextLine::Ptr prevLine = 0;
01010
01011 if ((startLine == buf->startLine()) && buf->prev() && (buf->prev()->lines() > 0))
01012 prevLine = buf->prev()->line (buf->prev()->lines() - 1);
01013 else if ((startLine > buf->startLine()) && (startLine <= buf->endLine()))
01014 prevLine = buf->line(startLine - buf->startLine() - 1);
01015 else
01016 prevLine = new KateTextLine ();
01017
01018
01019 bool codeFoldingUpdate = false;
01020
01021
01022 uint current_line = startLine - buf->startLine();
01023
01024
01025 bool stillcontinue=false;
01026 bool indentContinueWhitespace=false;
01027 bool indentContinueNextWhitespace=false;
01028
01029
01030 while ( (current_line < buf->lines())
01031 && (stillcontinue || ((current_line + buf->startLine()) <= endLine)) )
01032 {
01033
01034 KateTextLine::Ptr textLine = buf->line(current_line);
01035
01036 QMemArray<uint> foldingList;
01037 bool ctxChanged = false;
01038
01039 m_highlight->doHighlight (prevLine, textLine, &foldingList, &ctxChanged);
01040
01041
01042
01043
01044 bool indentChanged = false;
01045 if (m_highlight->foldingIndentationSensitive())
01046 {
01047
01048 QMemArray<unsigned short> indentDepth;
01049 indentDepth.duplicate (prevLine->indentationDepthArray());
01050
01051
01052 uint iDepth = textLine->indentDepth(m_tabWidth);
01053 if ((current_line+buf->startLine())==0)
01054 {
01055 indentDepth.resize (1, QGArray::SpeedOptim);
01056 indentDepth[0] = iDepth;
01057 }
01058
01059 textLine->setNoIndentBasedFoldingAtStart(prevLine->noIndentBasedFolding());
01060
01061 kdDebug(13020)<<"current_line:"<<current_line + buf->startLine()<<" textLine->noIndentBasedFoldingAtStart"<<textLine->noIndentBasedFoldingAtStart()<<endl;
01062 if ( (textLine->firstChar() == -1) || textLine->noIndentBasedFoldingAtStart())
01063 {
01064
01065 if (!prevLine->indentationDepthArray().isEmpty())
01066 {
01067 iDepth = (prevLine->indentationDepthArray())[prevLine->indentationDepthArray().size()-1];
01068 kdDebug(13020)<<"reusing old depth as current"<<endl;
01069 }
01070 else
01071 {
01072 iDepth = prevLine->indentDepth(m_tabWidth);
01073 kdDebug(13020)<<"creating indentdepth for previous line"<<endl;
01074 }
01075 }
01076
01077 kdDebug(13020)<<"iDepth:"<<iDepth<<endl;
01078
01079
01080
01081 uint nextLineIndentation = 0;
01082 bool nextLineIndentationValid=true;
01083 indentContinueNextWhitespace=false;
01084 if ((current_line+1) < buf->lines())
01085 {
01086 if (buf->line(current_line+1)->firstChar() == -1)
01087 {
01088 nextLineIndentation = iDepth;
01089 indentContinueNextWhitespace=true;
01090 }
01091 else
01092 nextLineIndentation = buf->line(current_line+1)->indentDepth(m_tabWidth);
01093 }
01094 else
01095 {
01096 KateBufBlock *blk = buf->next();
01097
01098 if (blk && (blk->lines() > 0))
01099 {
01100 if (blk->line (0)->firstChar() == -1)
01101 {
01102 nextLineIndentation = iDepth;
01103 indentContinueNextWhitespace=true;
01104 }
01105 else
01106 nextLineIndentation = blk->line (0)->indentDepth(m_tabWidth);
01107 }
01108 else nextLineIndentationValid=false;
01109 }
01110
01111 if (!textLine->noIndentBasedFoldingAtStart()) {
01112
01113 if ((iDepth > 0) && (indentDepth.isEmpty() || (indentDepth[indentDepth.size()-1] < iDepth)))
01114 {
01115 kdDebug(13020)<<"adding depth to \"stack\":"<<iDepth<<endl;
01116 indentDepth.resize (indentDepth.size()+1, QGArray::SpeedOptim);
01117 indentDepth[indentDepth.size()-1] = iDepth;
01118 } else {
01119 if (!indentDepth.isEmpty())
01120 {
01121 for (int z=indentDepth.size()-1; z > -1; z--)
01122 if (indentDepth[z]>iDepth)
01123 indentDepth.resize(z, QGArray::SpeedOptim);
01124 if ((iDepth > 0) && (indentDepth.isEmpty() || (indentDepth[indentDepth.size()-1] < iDepth)))
01125 {
01126 kdDebug(13020)<<"adding depth to \"stack\":"<<iDepth<<endl;
01127 indentDepth.resize (indentDepth.size()+1, QGArray::SpeedOptim);
01128 indentDepth[indentDepth.size()-1] = iDepth;
01129 if (prevLine->firstChar()==-1) {
01130
01131 }
01132 }
01133 }
01134 }
01135 }
01136
01137 if (!textLine->noIndentBasedFolding())
01138 {
01139 if (nextLineIndentationValid)
01140 {
01141
01142 {
01143 kdDebug(13020)<<"nextLineIndentation:"<<nextLineIndentation<<endl;
01144 bool addindent=false;
01145 uint deindent=0;
01146 if (!indentDepth.isEmpty())
01147 kdDebug()<<"indentDepth[indentDepth.size()-1]:"<<indentDepth[indentDepth.size()-1]<<endl;
01148 if ((nextLineIndentation>0) && ( indentDepth.isEmpty() || (indentDepth[indentDepth.size()-1]<nextLineIndentation)))
01149 {
01150 kdDebug(13020)<<"addindent==true"<<endl;
01151 addindent=true;
01152 } else {
01153 if ((!indentDepth.isEmpty()) && (indentDepth[indentDepth.size()-1]>nextLineIndentation))
01154 {
01155 kdDebug(13020)<<"...."<<endl;
01156 for (int z=indentDepth.size()-1; z > -1; z--)
01157 {
01158 kdDebug(13020)<<indentDepth[z]<<" "<<nextLineIndentation<<endl;
01159 if (indentDepth[z]>nextLineIndentation)
01160 deindent++;
01161 }
01162 }
01163 }
01164
01165
01166
01167 if ((textLine->firstChar()==-1)) {
01168 updatePreviousNotEmptyLine(buf,current_line,addindent,deindent);
01169 codeFoldingUpdate=true;
01170 }
01171 else
01172 {
01173 addIndentBasedFoldingInformation(foldingList,addindent,deindent);
01174 }
01175 }
01176 }
01177 }
01178 indentChanged = !(indentDepth == textLine->indentationDepthArray());
01179
01180
01181 if (indentChanged)
01182 textLine->setIndentationDepth (indentDepth);
01183
01184 indentContinueWhitespace=textLine->firstChar()==-1;
01185 }
01186 bool foldingColChanged=false;
01187 bool foldingChanged = false;
01188 if (foldingList.size()!=textLine->foldingListArray().size()) {
01189 foldingChanged=true;
01190 } else {
01191 QMemArray<uint>::ConstIterator it=foldingList.begin();
01192 QMemArray<uint>::ConstIterator it1=textLine->foldingListArray();
01193 bool markerType=true;
01194 for(;it!=foldingList.end();++it,++it1) {
01195 if (markerType) {
01196 if ( ((*it)!=(*it1))) {
01197 foldingChanged=true;
01198 foldingColChanged=false;
01199 break;
01200 }
01201 } else {
01202 if ((*it)!=(*it1)) {
01203 foldingColChanged=true;
01204 }
01205 }
01206 markerType=!markerType;
01207 }
01208 }
01209
01210 if (foldingChanged || foldingColChanged) {
01211 textLine->setFoldingList(foldingList);
01212 if (foldingChanged==false){
01213 textLine->setFoldingColumnsOutdated(textLine->foldingColumnsOutdated() | foldingColChanged);
01214 } else textLine->setFoldingColumnsOutdated(false);
01215 }
01216 bool retVal_folding = false;
01217
01218 m_regionTree.updateLine (current_line + buf->startLine(), &foldingList, &retVal_folding, foldingChanged,foldingColChanged);
01219
01220 codeFoldingUpdate = codeFoldingUpdate | retVal_folding;
01221
01222
01223 stillcontinue = ctxChanged || indentChanged || indentContinueWhitespace || indentContinueNextWhitespace;
01224
01225
01226 prevLine = textLine;
01227
01228
01229 current_line++;
01230 }
01231
01232 buf->markDirty ();
01233
01234
01235 if (invalidate)
01236 emit tagLines (startLine, current_line + buf->startLine());
01237
01238
01239 if (codeFoldingUpdate)
01240 emit codeFoldingUpdated();
01241
01242
01243
01244
01245
01246
01247
01248
01249 return stillcontinue && ((current_line+1) == buf->lines());
01250 }
01251
01252 void KateBuffer::codeFoldingColumnUpdate(unsigned int lineNr) {
01253 KateTextLine::Ptr line=plainLine(lineNr);
01254 if (!line) return;
01255 if (line->foldingColumnsOutdated()) {
01256 line->setFoldingColumnsOutdated(false);
01257 bool tmp;
01258 QMemArray<uint> folding=line->foldingListArray();
01259 m_regionTree.updateLine(lineNr,&folding,&tmp,true,false);
01260 }
01261 }
01262
01263
01264
01265 KateBufBlock::KateBufBlock ( KateBuffer *parent, KateBufBlock *prev, KateBufBlock *next,
01266 KateFileLoader *stream )
01267 : m_state (KateBufBlock::stateDirty),
01268 m_startLine (0),
01269 m_lines (0),
01270 m_vmblock (0),
01271 m_vmblockSize (0),
01272 m_parent (parent),
01273 m_prev (prev),
01274 m_next (next),
01275 list (0),
01276 listPrev (0),
01277 listNext (0)
01278 {
01279
01280 if (m_prev)
01281 {
01282 m_startLine = m_prev->endLine ();
01283 m_prev->m_next = this;
01284 }
01285
01286 if (m_next)
01287 m_next->m_prev = this;
01288
01289
01290
01291 if (stream)
01292 {
01293
01294 fillBlock (stream);
01295 }
01296 else
01297 {
01298
01299 KateTextLine::Ptr textLine = new KateTextLine ();
01300 m_stringList.push_back (textLine);
01301 m_lines++;
01302
01303
01304 if (m_parent->m_loadedBlocks.count() >= KateBuffer::maxLoadedBlocks())
01305 m_parent->m_loadedBlocks.first()->swapOut();
01306
01307
01308 m_state = KateBufBlock::stateDirty;
01309 m_parent->m_loadedBlocks.append (this);
01310 }
01311 }
01312
01313 KateBufBlock::~KateBufBlock ()
01314 {
01315
01316 if (m_prev)
01317 m_prev->m_next = m_next;
01318
01319 if (m_next)
01320 m_next->m_prev = m_prev;
01321
01322
01323 if (m_vmblock)
01324 KateFactory::self()->vm()->free(m_vmblock);
01325
01326
01327 KateBufBlockList::remove (this);
01328 }
01329
01330 void KateBufBlock::fillBlock (KateFileLoader *stream)
01331 {
01332
01333 bool swap = m_parent->m_loadedBlocks.count() >= KateBuffer::maxLoadedBlocks();
01334
01335 QByteArray rawData;
01336
01337
01338 if (swap)
01339 rawData.resize ((KATE_AVG_BLOCK_SIZE * sizeof(QChar)) + ((KATE_AVG_BLOCK_SIZE/80) * 8));
01340
01341 char *buf = rawData.data ();
01342 uint size = 0;
01343 uint blockSize = 0;
01344 while (!stream->eof() && (blockSize < KATE_AVG_BLOCK_SIZE) && (m_lines < KATE_MAX_BLOCK_LINES))
01345 {
01346 uint offset = 0, length = 0;
01347 stream->readLine(offset, length);
01348 const QChar *unicodeData = stream->unicode () + offset;
01349
01350
01351 if ( stream->removeTrailingSpaces() )
01352 {
01353 while (length > 0)
01354 {
01355 if (unicodeData[length-1].isSpace())
01356 --length;
01357 else
01358 break;
01359 }
01360 }
01361
01362 blockSize += length;
01363
01364 if (swap)
01365 {
01366
01367
01368 char attr = KateTextLine::flagNoOtherData;
01369 uint pos = size;
01370
01371
01372 size = size + 1 + sizeof(uint) + (sizeof(QChar)*length);
01373
01374 if (size > rawData.size ())
01375 {
01376 rawData.resize (size);
01377 buf = rawData.data ();
01378 }
01379
01380 memcpy(buf+pos, (char *) &attr, 1);
01381 pos += 1;
01382
01383 memcpy(buf+pos, (char *) &length, sizeof(uint));
01384 pos += sizeof(uint);
01385
01386 memcpy(buf+pos, (char *) unicodeData, sizeof(QChar)*length);
01387 pos += sizeof(QChar)*length;
01388 }
01389 else
01390 {
01391 KateTextLine::Ptr textLine = new KateTextLine ();
01392 textLine->insertText (0, length, unicodeData);
01393 m_stringList.push_back (textLine);
01394 }
01395
01396 m_lines++;
01397 }
01398
01399 if (swap)
01400 {
01401 m_vmblock = KateFactory::self()->vm()->allocate(size);
01402 m_vmblockSize = size;
01403
01404 if (!rawData.isEmpty())
01405 {
01406 if (!KateFactory::self()->vm()->copyBlock(m_vmblock, rawData.data(), 0, size))
01407 {
01408 if (m_vmblock)
01409 KateFactory::self()->vm()->free(m_vmblock);
01410
01411 m_vmblock = 0;
01412 m_vmblockSize = 0;
01413
01414 m_parent->m_cacheWriteError = true;
01415 }
01416 }
01417
01418
01419 m_state = KateBufBlock::stateSwapped;
01420 }
01421 else
01422 {
01423
01424 m_state = KateBufBlock::stateDirty;
01425 m_parent->m_loadedBlocks.append (this);
01426 }
01427
01428 kdDebug (13020) << "A BLOCK LOADED WITH LINES: " << m_lines << endl;
01429 }
01430
01431 KateTextLine::Ptr KateBufBlock::line(uint i)
01432 {
01433
01434 if (m_state == KateBufBlock::stateSwapped)
01435 swapIn ();
01436
01437
01438 if (!m_parent->m_loadedBlocks.isLast(this))
01439 m_parent->m_loadedBlocks.append (this);
01440
01441 return m_stringList[i];
01442 }
01443
01444 void KateBufBlock::insertLine(uint i, KateTextLine::Ptr line)
01445 {
01446
01447 if (m_state == KateBufBlock::stateSwapped)
01448 swapIn ();
01449
01450 m_stringList.insert (m_stringList.begin()+i, line);
01451 m_lines++;
01452
01453 markDirty ();
01454 }
01455
01456 void KateBufBlock::removeLine(uint i)
01457 {
01458
01459 if (m_state == KateBufBlock::stateSwapped)
01460 swapIn ();
01461
01462 m_stringList.erase (m_stringList.begin()+i);
01463 m_lines--;
01464
01465 markDirty ();
01466 }
01467
01468 void KateBufBlock::markDirty ()
01469 {
01470 if (m_state != KateBufBlock::stateSwapped)
01471 {
01472
01473 if (!m_parent->m_loadedBlocks.isLast(this))
01474 m_parent->m_loadedBlocks.append (this);
01475
01476 if (m_state == KateBufBlock::stateClean)
01477 {
01478
01479 if (m_vmblock)
01480 KateFactory::self()->vm()->free(m_vmblock);
01481
01482 m_vmblock = 0;
01483 m_vmblockSize = 0;
01484
01485
01486 m_state = KateBufBlock::stateDirty;
01487 }
01488 }
01489 }
01490
01491 void KateBufBlock::swapIn ()
01492 {
01493 if (m_state != KateBufBlock::stateSwapped)
01494 return;
01495
01496 QByteArray rawData (m_vmblockSize);
01497
01498
01499 if (!KateFactory::self()->vm()->copyBlock(rawData.data(), m_vmblock, 0, rawData.size()))
01500 m_parent->m_cacheReadError = true;
01501
01502
01503 m_stringList.reserve (m_lines);
01504
01505 char *buf = rawData.data();
01506 for (uint i=0; i < m_lines; i++)
01507 {
01508 KateTextLine::Ptr textLine = new KateTextLine ();
01509 buf = textLine->restore (buf);
01510 m_stringList.push_back (textLine);
01511 }
01512
01513
01514 if (m_parent->m_loadedBlocks.count() >= KateBuffer::maxLoadedBlocks())
01515 m_parent->m_loadedBlocks.first()->swapOut();
01516
01517
01518 m_state = KateBufBlock::stateClean;
01519 m_parent->m_loadedBlocks.append (this);
01520 }
01521
01522 void KateBufBlock::swapOut ()
01523 {
01524 if (m_state == KateBufBlock::stateSwapped)
01525 return;
01526
01527 if (m_state == KateBufBlock::stateDirty)
01528 {
01529 bool haveHl = m_parent->m_highlight && !m_parent->m_highlight->noHighlighting();
01530
01531
01532 uint size = 0;
01533 for (uint i=0; i < m_lines; i++)
01534 size += m_stringList[i]->dumpSize (haveHl);
01535
01536 QByteArray rawData (size);
01537 char *buf = rawData.data();
01538
01539
01540 for (uint i=0; i < m_lines; i++)
01541 buf = m_stringList[i]->dump (buf, haveHl);
01542
01543 m_vmblock = KateFactory::self()->vm()->allocate(rawData.size());
01544 m_vmblockSize = rawData.size();
01545
01546 if (!rawData.isEmpty())
01547 {
01548 if (!KateFactory::self()->vm()->copyBlock(m_vmblock, rawData.data(), 0, rawData.size()))
01549 {
01550 if (m_vmblock)
01551 KateFactory::self()->vm()->free(m_vmblock);
01552
01553 m_vmblock = 0;
01554 m_vmblockSize = 0;
01555
01556 m_parent->m_cacheWriteError = true;
01557
01558 return;
01559 }
01560 }
01561 }
01562
01563 m_stringList.clear();
01564
01565
01566 m_state = KateBufBlock::stateSwapped;
01567 KateBufBlockList::remove (this);
01568 }
01569
01570
01571
01572
01573
01574 KateBufBlockList::KateBufBlockList ()
01575 : m_count (0),
01576 m_first (0),
01577 m_last (0)
01578 {
01579 }
01580
01581 void KateBufBlockList::append (KateBufBlock *buf)
01582 {
01583 if (buf->list)
01584 buf->list->removeInternal (buf);
01585
01586 m_count++;
01587
01588
01589 if (m_last)
01590 {
01591 m_last->listNext = buf;
01592
01593 buf->listPrev = m_last;
01594 buf->listNext = 0;
01595
01596 m_last = buf;
01597
01598 buf->list = this;
01599
01600 return;
01601 }
01602
01603
01604 m_last = buf;
01605 m_first = buf;
01606
01607 buf->listPrev = 0;
01608 buf->listNext = 0;
01609
01610 buf->list = this;
01611 }
01612
01613 void KateBufBlockList::removeInternal (KateBufBlock *buf)
01614 {
01615 if (buf->list != this)
01616 return;
01617
01618 m_count--;
01619
01620 if ((buf == m_first) && (buf == m_last))
01621 {
01622
01623 m_first = 0;
01624 m_last = 0;
01625 }
01626 else if (buf == m_first)
01627 {
01628
01629 m_first = buf->listNext;
01630 m_first->listPrev = 0;
01631 }
01632 else if (buf == m_last)
01633 {
01634
01635 m_last = buf->listPrev;
01636 m_last->listNext = 0;
01637 }
01638 else
01639 {
01640 buf->listPrev->listNext = buf->listNext;
01641 buf->listNext->listPrev = buf->listPrev;
01642 }
01643
01644 buf->listPrev = 0;
01645 buf->listNext = 0;
01646
01647 buf->list = 0;
01648 }
01649
01650
01651
01652