00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "katebuffer.h"
00022 #include "katebuffer.moc"
00023
00024 #include <sys/types.h>
00025 #include <sys/stat.h>
00026 #include <unistd.h>
00027 #include <stdlib.h>
00028
00029 #include "katedocument.h"
00030 #include "katehighlight.h"
00031 #include "kateconfig.h"
00032 #include "kateglobal.h"
00033 #include "kateautoindent.h"
00034
00035 #include <kdebug.h>
00036 #include <kglobal.h>
00037 #include <kcharsets.h>
00038 #include <kencodingprober.h>
00039 #include <kde_file.h>
00040
00041 #include <QtCore/QFile>
00042 #include <QtCore/QTextStream>
00043 #include <QtCore/QTimer>
00044 #include <QtCore/QTextCodec>
00045 #include <QtCore/QDate>
00046
00047 #include <limits.h>
00048
00054 static const qint64 KATE_FILE_LOADER_BS = 256 * 1024;
00055
00061 static const int KATE_HL_LOOKAHEAD = 64;
00062
00066 static const int KATE_MAX_DYNAMIC_CONTEXTS = 512;
00067
00071 static const int KATE_AVERAGE_LINES_PER_BLOCK = 4 * 1024;
00072
00073 class KateFileLoader
00074 {
00075 enum MIB
00076 {
00077 MibLatin1 = 4,
00078 Mib8859_8 = 85,
00079 MibUtf8 = 106,
00080 MibUcs2 = 1000,
00081 MibUtf16 = 1015,
00082 MibUtf16BE = 1013,
00083 MibUtf16LE = 1014
00084 };
00085 public:
00086 KateFileLoader (const QString &filename, QTextCodec *codec, bool removeTrailingSpaces, KEncodingProber::ProberType proberType)
00087 : m_codec(codec)
00088 , m_prober(new KEncodingProber(proberType))
00089 , m_multiByte(0)
00090 , m_eof (false)
00091 , m_lastWasEndOfLine (true)
00092 , m_lastWasR (false)
00093 , m_binary (false)
00094 , m_removeTrailingSpaces (removeTrailingSpaces)
00095 , m_utf8Borked (false)
00096 , m_position (0)
00097 , m_lastLineStart (0)
00098 , m_eol (-1)
00099 , m_file (filename)
00100 , m_buffer (qMin (m_file.size() == 0 ? KATE_FILE_LOADER_BS : m_file.size(), KATE_FILE_LOADER_BS), 0)
00101 {
00102 }
00103
00104 ~KateFileLoader ()
00105 {
00106
00107 }
00108
00112 bool open ()
00113 {
00114 if (m_file.open (QIODevice::ReadOnly))
00115 {
00116 int c = m_file.read (m_buffer.data(), m_buffer.size());
00117
00118 if (c > 0)
00119 {
00120
00121
00122 kDebug (13020) << "PROBER TYPE: " << KEncodingProber::nameForProberType(m_prober->proberType());
00123 m_prober->feed(m_buffer.data(), c);
00124 if (m_prober->confidence() > 0.5 && QTextCodec::codecForName(m_prober->encoding()))
00125 m_codec = QTextCodec::codecForName(m_prober->encoding());
00126 m_utf8Borked=errorsIfUtf8(m_buffer.data(), c);
00127 m_binary=processNull(m_buffer.data(), c);
00128 m_text = decoder()->toUnicode(m_buffer, c);
00129 kDebug (13020) << "OPEN USES ENCODING: " << m_codec->name();
00130 }
00131
00132 m_eof = (c == -1) || (c == 0);
00133
00134 for (int i=0; i < m_text.length(); i++)
00135 {
00136 if (m_text[i] == '\n')
00137 {
00138 m_eol = KateDocumentConfig::eolUnix;
00139 break;
00140 }
00141 else if ((m_text[i] == '\r'))
00142 {
00143 if (((i+1) < m_text.length()) && (m_text[i+1] == '\n'))
00144 {
00145 m_eol = KateDocumentConfig::eolDos;
00146 break;
00147 }
00148 else
00149 {
00150 m_eol = KateDocumentConfig::eolMac;
00151 break;
00152 }
00153 }
00154 }
00155
00156 return true;
00157 }
00158
00159 return false;
00160 }
00161
00162 inline QByteArray actualEncoding () const { return m_codec->name(); }
00163
00164
00165 inline bool eof () const { return m_eof && !m_lastWasEndOfLine && (m_lastLineStart == m_text.length()); }
00166
00167
00168 inline int eol () const { return m_eol; }
00169
00170
00171 inline bool binary () const { return m_binary; }
00172
00173
00174 inline bool brokenUTF8 () const { return m_utf8Borked; }
00175
00176 inline QTextDecoder* decoder() const { return m_codec->makeDecoder(); }
00177
00178 bool errorsIfUtf8 (const char* data, int length)
00179 {
00180 if (m_codec->mibEnum()!=MibUtf8)
00181 return false;
00182
00183
00184
00185
00186
00187 static const unsigned char highest1Bits = 0x80;
00188 static const unsigned char highest2Bits = 0xC0;
00189 static const unsigned char highest3Bits = 0xE0;
00190 static const unsigned char highest4Bits = 0xF0;
00191 static const unsigned char highest5Bits = 0xF8;
00192
00193 for (int i=0; i<length; ++i)
00194 {
00195 unsigned char c = data[i];
00196
00197 if (m_multiByte>0)
00198 {
00199 if ((c & highest2Bits) == 0x80)
00200 {
00201 --(m_multiByte);
00202 continue;
00203 }
00204 return true;
00205 }
00206
00207
00208 if ((c & highest1Bits) == 0x00)
00209 continue;
00210
00211
00212 if ((c & highest3Bits) == 0xC0)
00213 {
00214 m_multiByte = 1;
00215 continue;
00216 }
00217
00218
00219 if ((c & highest4Bits) == 0xE0)
00220 {
00221 m_multiByte = 2;
00222 continue;
00223 }
00224
00225
00226 if ((c & highest5Bits) == 0xF0)
00227 {
00228 m_multiByte = 3;
00229 continue;
00230 }
00231 return true;
00232 }
00233 return false;
00234 }
00235
00236 bool processNull(char *data, int len)
00237 {
00238 bool bin=false;
00239 if(is16Bit(m_codec))
00240 {
00241 for (int i=1; i < len; i+=2)
00242 {
00243 if ((data[i]=='\0') && (data[i-1]=='\0'))
00244 {
00245 bin=true;
00246 data[i]=' ';
00247 }
00248 }
00249 return bin;
00250 }
00251
00252 int i = len-1;
00253 while(--i>=0)
00254 {
00255 if(data[i]==0)
00256 {
00257 bin=true;
00258 data[i]=' ';
00259 }
00260 }
00261 return bin;
00262 }
00263
00264
00265 inline bool removeTrailingSpaces () const { return m_removeTrailingSpaces; }
00266
00267
00268 inline const QChar *unicode () const { return m_text.unicode(); }
00269
00270
00271 void readLine (int &offset, int &length)
00272 {
00273 length = 0;
00274 offset = 0;
00275
00276 while (m_position <= m_text.length())
00277 {
00278 if (m_position == m_text.length())
00279 {
00280
00281 if (!m_eof)
00282 {
00283 int c = m_file.read (m_buffer.data(), m_buffer.size());
00284
00285
00286 m_text.remove (0, m_lastLineStart);
00287
00288
00289 if (c > 0)
00290 {
00291 m_binary=processNull(m_buffer.data(), c)||m_binary;
00292 m_utf8Borked=m_utf8Borked||errorsIfUtf8(m_buffer.data(), c);
00293 m_text.append (decoder()->toUnicode (m_buffer.data(), c));
00294 }
00295
00296
00297 m_eof = (c == -1) || (c == 0);
00298
00299
00300 m_position -= m_lastLineStart;
00301 m_lastLineStart = 0;
00302 }
00303
00304
00305 if (m_eof && (m_position == m_text.length()))
00306 {
00307 m_lastWasEndOfLine = false;
00308
00309
00310 offset = m_lastLineStart;
00311 length = m_position-m_lastLineStart;
00312
00313 m_lastLineStart = m_position;
00314
00315 return;
00316 }
00317 }
00318
00319 if (m_text[m_position] == '\n')
00320 {
00321 m_lastWasEndOfLine = true;
00322
00323 if (m_lastWasR)
00324 {
00325 m_lastLineStart++;
00326 m_lastWasR = false;
00327 }
00328 else
00329 {
00330
00331 offset = m_lastLineStart;
00332 length = m_position-m_lastLineStart;
00333
00334 m_lastLineStart = m_position+1;
00335 m_position++;
00336
00337 return;
00338 }
00339 }
00340 else if (m_text[m_position] == '\r')
00341 {
00342 m_lastWasEndOfLine = true;
00343 m_lastWasR = true;
00344
00345
00346 offset = m_lastLineStart;
00347 length = m_position-m_lastLineStart;
00348
00349 m_lastLineStart = m_position+1;
00350 m_position++;
00351
00352 return;
00353 }
00354 else
00355 {
00356 m_lastWasEndOfLine = false;
00357 m_lastWasR = false;
00358 }
00359
00360 m_position++;
00361 }
00362 }
00363
00364 bool is16Bit(QTextCodec* codec)
00365 {
00366 switch (codec->mibEnum())
00367 {
00368 case MibUtf16:
00369 case MibUtf16BE:
00370 case MibUtf16LE:
00371 case MibUcs2:
00372 return true;
00373 default:
00374 return false;
00375 }
00376 }
00377
00378 private:
00379 QTextCodec *m_codec;
00380 KEncodingProber *m_prober;
00381 int m_multiByte;
00382 bool m_eof;
00383 bool m_lastWasEndOfLine;
00384 bool m_lastWasR;
00385 bool m_binary;
00386 bool m_removeTrailingSpaces;
00387 bool m_utf8Borked;
00388 int m_position;
00389 int m_lastLineStart;
00390 int m_eol;
00391 QFile m_file;
00392 QByteArray m_buffer;
00393 QString m_text;
00394 };
00395
00399 KateBuffer::KateBuffer(KateDocument *doc)
00400 : QObject (doc),
00401 editSessionNumber (0),
00402 editIsRunning (false),
00403 editTagLineStart (0xffffffff),
00404 editTagLineEnd (0),
00405 editTagLineFrom (false),
00406 editChangesDone (false),
00407 m_doc (doc),
00408 m_lastUsedBlock (0),
00409 m_lines (0),
00410 m_binary (false),
00411 m_brokenUTF8 (false),
00412 m_highlight (0),
00413 m_regionTree (this),
00414 m_tabWidth (8),
00415 m_lineHighlightedMax (0),
00416 m_lineHighlighted (0),
00417 m_maxDynamicContexts (KATE_MAX_DYNAMIC_CONTEXTS)
00418 {
00419 clear();
00420 }
00421
00425 KateBuffer::~KateBuffer()
00426 {
00427
00428 if (m_highlight)
00429 m_highlight->release();
00430
00431
00432 qDeleteAll (m_blocks);
00433 }
00434
00435 void KateBuffer::editStart ()
00436 {
00437 editSessionNumber++;
00438
00439 if (editSessionNumber > 1)
00440 return;
00441
00442 editIsRunning = true;
00443
00444 editTagLineStart = INT_MAX;
00445 editTagLineEnd = 0;
00446 editTagLineFrom = false;
00447
00448 editChangesDone = false;
00449 }
00450
00451 void KateBuffer::editEnd ()
00452 {
00453 if (editSessionNumber == 0)
00454 return;
00455
00456 editSessionNumber--;
00457
00458 if (editSessionNumber > 0)
00459 return;
00460
00461 if (editChangesDone)
00462 {
00463
00464 if (m_highlight && editTagLineStart <= editTagLineEnd && editTagLineEnd <= m_lineHighlighted)
00465 {
00466
00467 ++editTagLineEnd;
00468
00469
00470 if (editTagLineStart > 0)
00471 --editTagLineStart;
00472
00473 bool needContinue = doHighlight (
00474 editTagLineStart,
00475 editTagLineEnd,
00476 true);
00477
00478 editTagLineStart = editTagLineEnd;
00479
00480 if (needContinue)
00481 m_lineHighlighted = editTagLineStart;
00482
00483 if (editTagLineStart > m_lineHighlightedMax)
00484 m_lineHighlightedMax = editTagLineStart;
00485 }
00486 else if (editTagLineStart < m_lineHighlightedMax)
00487 m_lineHighlightedMax = editTagLineStart;
00488 }
00489
00490 editIsRunning = false;
00491 }
00492
00493 void KateBuffer::clear()
00494 {
00495 m_regionTree.clear();
00496
00497
00498 qDeleteAll (m_blocks);
00499 m_lastUsedBlock = 0;
00500 m_blocks.clear ();
00501
00502
00503 m_blocks.append (new KateBufferBlock(0));
00504
00505
00506 KateTextLine::Ptr textLine (new KateTextLine ());
00507 m_blocks[0]->lines.append (textLine);
00508 m_lines = 1;
00509
00510
00511 m_binary = false;
00512 m_brokenUTF8 = false;
00513
00514 m_lineHighlightedMax = 0;
00515 m_lineHighlighted = 0;
00516 }
00517
00518 bool KateBuffer::openFile (const QString &m_file)
00519 {
00520 QTime t;
00521 t.start();
00522
00523 KateFileLoader file (m_file, m_doc->config()->codec(), m_doc->config()->configFlags() & KateDocumentConfig::cfRemoveSpaces, m_doc->proberTypeForEncodingAutoDetection());
00524
00525 bool ok = false;
00526 KDE_struct_stat sbuf;
00527 if (KDE::stat(m_file, &sbuf) == 0)
00528 {
00529 if (S_ISREG(sbuf.st_mode) && file.open())
00530 ok = true;
00531 }
00532
00533 if (!ok)
00534 {
00535 clear();
00536 return false;
00537 }
00538
00539 m_doc->config()->setEncoding(file.actualEncoding());
00540
00541
00542 if (m_doc->config()->allowEolDetection() && (file.eol() != -1))
00543 m_doc->config()->setEol (file.eol());
00544
00545
00546 clear ();
00547
00548
00549 m_blocks[0]->lines.clear ();
00550 m_lines = 0;
00551
00552
00553 while ( !file.eof() )
00554 {
00555 int offset = 0, length = 0;
00556 file.readLine(offset, length);
00557 const QChar *unicodeData = file.unicode () + offset;
00558
00559
00560 if ( file.removeTrailingSpaces() )
00561 {
00562 while (length > 0)
00563 {
00564 if (unicodeData[length-1].isSpace())
00565 --length;
00566 else
00567 break;
00568 }
00569 }
00570
00571 KateTextLine::Ptr textLine (new KateTextLine (unicodeData, length));
00572
00573 if (m_blocks.last()->lines.size() >= KATE_AVERAGE_LINES_PER_BLOCK)
00574 m_blocks.append (new KateBufferBlock (m_lines));
00575
00576 m_blocks.last()->lines.append (textLine);
00577 m_lines++;
00578 }
00579
00580
00581 if (m_lines == 0)
00582 {
00583 KateTextLine::Ptr textLine (new KateTextLine ());
00584 m_blocks[0]->lines.append (textLine);
00585 m_lines = 1;
00586 }
00587
00588
00589 m_regionTree.fixRoot (m_lines);
00590
00591
00592 m_binary = file.binary ();
00593
00594
00595 m_brokenUTF8 = file.brokenUTF8();
00596
00597 kDebug (13020) << "Broken UTF-8: " << m_brokenUTF8;
00598
00599 kDebug (13020) << "LOADING DONE " << t.elapsed();
00600
00601 return true;
00602 }
00603
00604 bool KateBuffer::canEncode ()
00605 {
00606 QTextCodec *codec = m_doc->config()->codec();
00607
00608 kDebug(13020) << "ENC NAME: " << codec->name();
00609
00610
00611 if ((QString(codec->name()) == "UTF-8") || (QString(codec->name()) == "ISO-10646-UCS-2"))
00612 return true;
00613
00614 for (int i=0; i < m_lines; i++)
00615 {
00616 if (!codec->canEncode (plainLine(i)->string()))
00617 {
00618 kDebug(13020) << "STRING LINE: " << plainLine(i)->string();
00619 kDebug(13020) << "ENC WORKING: FALSE";
00620
00621 return false;
00622 }
00623 }
00624
00625 return true;
00626 }
00627
00628 bool KateBuffer::saveFile (const QString &m_file)
00629 {
00630 QFile file (m_file);
00631 QTextStream stream (&file);
00632
00633 if ( !file.open( QIODevice::WriteOnly ) )
00634 {
00635 return false;
00636 }
00637
00638 QTextCodec *codec = m_doc->config()->codec();
00639
00640
00641 stream.setCodec(QTextCodec::codecForName("UTF-16"));
00642
00643
00644 stream.setCodec(codec);
00645
00646
00647 QString eol = m_doc->config()->eolString ();
00648
00649
00650 bool removeTrailingSpaces = m_doc->config()->configFlags() & KateDocumentConfig::cfRemoveSpaces;
00651
00652
00653 for (int i=0; i < m_lines; i++)
00654 {
00655 KateTextLine::Ptr textline = plainLine(i);
00656
00657
00658 if (removeTrailingSpaces)
00659 {
00660 int lastChar = textline->lastChar();
00661
00662 if (lastChar > -1)
00663 {
00664 stream << textline->string().left(lastChar+1);
00665 }
00666 }
00667 else
00668 stream << textline->string();
00669
00670 if ((i+1) < m_lines)
00671 stream << eol;
00672 }
00673
00674 file.close ();
00675
00676 return (file.error() == QFile::NoError);
00677 }
00678
00679 int KateBuffer::findBlock (int line)
00680 {
00681
00682 if (line < 0 || line >= m_lines)
00683 return -1;
00684
00685
00686 if (m_lastUsedBlock < 0 || m_lastUsedBlock >= m_blocks.size())
00687 m_lastUsedBlock = 0;
00688
00689 forever
00690 {
00691 int start = m_blocks[m_lastUsedBlock]->start;
00692 int lines = m_blocks[m_lastUsedBlock]->lines.size ();
00693
00694 if (start <= line && line < (start + lines))
00695 return m_lastUsedBlock;
00696
00697 if (line < start)
00698 m_lastUsedBlock--;
00699 else
00700 m_lastUsedBlock++;
00701 }
00702
00703 return -1;
00704 }
00705
00706 void KateBuffer::fixBlocksFrom (int lastValidBlock)
00707 {
00712
00713 KateBufferBlock *block = m_blocks[lastValidBlock];
00714
00715
00716 int blockLines = block->lines.size();
00717
00718
00719 int lastLine = block->start + blockLines;
00720
00721
00722 if (blockLines == 0 && m_blocks.size() > 0)
00723 {
00724 delete block;
00725 m_blocks.remove (lastValidBlock);
00726
00727
00728 lastValidBlock--;
00729
00730
00731 m_lastUsedBlock--;
00732 }
00733 else if (blockLines > (2*KATE_AVERAGE_LINES_PER_BLOCK))
00734 {
00735 int linesToStay = blockLines - KATE_AVERAGE_LINES_PER_BLOCK;
00736
00737
00738 KateBufferBlock *newBlock = new KateBufferBlock (lastLine - KATE_AVERAGE_LINES_PER_BLOCK);
00739 m_blocks.insert (lastValidBlock+1, newBlock);
00740
00741
00742 newBlock->lines.resize (KATE_AVERAGE_LINES_PER_BLOCK);
00743 for (int i = 0; i < KATE_AVERAGE_LINES_PER_BLOCK; ++i)
00744 newBlock->lines[i] = block->lines[linesToStay + i];
00745
00746
00747 block->lines.resize (linesToStay);
00748
00749
00750 block = newBlock;
00751 lastValidBlock++;
00752 }
00753
00754
00755 for (int i = lastValidBlock + 1; i < m_blocks.size(); ++i)
00756 {
00757 m_blocks[i]->start = lastLine;
00758 lastLine += m_blocks[i]->lines.size();
00759 }
00760 }
00761
00762 void KateBuffer::ensureHighlighted (int line)
00763 {
00764
00765 if (line < 0 || line >= m_lines)
00766 return;
00767
00768
00769 if (line < m_lineHighlighted)
00770 return;
00771
00772
00773 int end = qMin(line + KATE_HL_LOOKAHEAD, m_lines-1);
00774
00775 doHighlight ( m_lineHighlighted, end, false );
00776
00777 m_lineHighlighted = end;
00778
00779
00780 if (m_lineHighlighted > m_lineHighlightedMax)
00781 m_lineHighlightedMax = m_lineHighlighted;
00782 }
00783
00784 void KateBuffer::changeLine(int i)
00785 {
00786 if (i < 0 || i >= m_lines)
00787 return;
00788
00789
00790 editChangesDone = true;
00791
00792
00793 if (i < editTagLineStart)
00794 editTagLineStart = i;
00795
00796 if (i > editTagLineEnd)
00797 editTagLineEnd = i;
00798 }
00799
00800 void KateBuffer::insertLine(int i, KateTextLine::Ptr line)
00801 {
00802 if (i < 0 || i > m_lines)
00803 return;
00804
00805
00806 int block = findBlock (i);
00807 if (block == -1)
00808 block = m_blocks.size() - 1;
00809
00810
00811 m_blocks[block]->lines.insert (i - m_blocks[block]->start, line);
00812 m_lines++;
00813 fixBlocksFrom (block);
00814
00815 if (m_lineHighlightedMax > i)
00816 m_lineHighlightedMax++;
00817
00818 if (m_lineHighlighted > i)
00819 m_lineHighlighted++;
00820
00821
00822 editChangesDone = true;
00823
00824
00825 if (i < editTagLineStart)
00826 editTagLineStart = i;
00827
00828 if (i <= editTagLineEnd)
00829 editTagLineEnd++;
00830
00831 if (i > editTagLineEnd)
00832 editTagLineEnd = i;
00833
00834
00835 editTagLineFrom = true;
00836
00837 m_regionTree.lineHasBeenInserted (i);
00838 }
00839
00840 void KateBuffer::removeLine(int i)
00841 {
00842 int block = findBlock (i);
00843
00844 if (block == -1)
00845 return;
00846
00847
00848 m_blocks[block]->lines.remove (i - m_blocks[block]->start);
00849 m_lines--;
00850 fixBlocksFrom (block);
00851
00852 if (m_lineHighlightedMax > i)
00853 m_lineHighlightedMax--;
00854
00855 if (m_lineHighlighted > i)
00856 m_lineHighlighted--;
00857
00858
00859 editChangesDone = true;
00860
00861
00862 if (i < editTagLineStart)
00863 editTagLineStart = i;
00864
00865 if (i < editTagLineEnd)
00866 editTagLineEnd--;
00867
00868 if (i > editTagLineEnd)
00869 editTagLineEnd = i;
00870
00871
00872
00873 if (editTagLineEnd >= m_lines)
00874 editTagLineEnd = m_lines - 1;
00875
00876 if (editTagLineStart > editTagLineEnd)
00877 editTagLineStart = editTagLineEnd;
00878
00879
00880 editTagLineFrom = true;
00881
00882 m_regionTree.lineHasBeenRemoved (i);
00883 }
00884
00885 void KateBuffer::setTabWidth (int w)
00886 {
00887 if ((m_tabWidth != w) && (m_tabWidth > 0))
00888 {
00889 m_tabWidth = w;
00890
00891 if (m_highlight && m_highlight->foldingIndentationSensitive())
00892 invalidateHighlighting();
00893 }
00894 }
00895
00896 void KateBuffer::setHighlight(int hlMode)
00897 {
00898 KateHighlighting *h = KateHlManager::self()->getHl(hlMode);
00899
00900
00901 if (h != m_highlight)
00902 {
00903 bool invalidate = !h->noHighlighting();
00904
00905 if (m_highlight)
00906 {
00907 m_highlight->release();
00908 invalidate = true;
00909 }
00910
00911 h->use();
00912
00913
00914 m_regionTree.clear();
00915 m_regionTree.fixRoot(m_lines);
00916
00917 m_highlight = h;
00918
00919 if (invalidate)
00920 invalidateHighlighting();
00921
00922
00923
00924 m_doc->bufferHlChanged ();
00925
00926
00927 if (!h->indentation().isEmpty())
00928 m_doc->config()->setIndentationMode (h->indentation());
00929 }
00930 }
00931
00932 void KateBuffer::invalidateHighlighting()
00933 {
00934 m_lineHighlightedMax = 0;
00935 m_lineHighlighted = 0;
00936 }
00937
00938
00939 void KateBuffer::updatePreviousNotEmptyLine(int current_line,bool addindent,int deindent)
00940 {
00941 KateTextLine::Ptr textLine;
00942 do {
00943 if (current_line == 0) return;
00944
00945 --current_line;
00946
00947 textLine = plainLine (current_line);
00948 } while (textLine->firstChar()==-1);
00949
00950 kDebug(13020)<<"updatePreviousNotEmptyLine: updating line:"<<current_line;
00951 QVector<int> foldingList=textLine->foldingListArray();
00952 while ( (foldingList.size()>0) && ( abs(foldingList[foldingList.size()-2])==1)) {
00953 foldingList.resize(foldingList.size()-2);
00954 }
00955 addIndentBasedFoldingInformation(foldingList,textLine->length(),addindent,deindent);
00956 textLine->setFoldingList(foldingList);
00957
00958 bool retVal_folding = false;
00959 m_regionTree.updateLine (current_line, &foldingList, &retVal_folding, true,false);
00960
00961
00962 }
00963
00964 void KateBuffer::addIndentBasedFoldingInformation(QVector<int> &foldingList,int linelength,bool addindent,int deindent)
00965 {
00966 if (addindent) {
00967
00968 kDebug(13020)<<"adding ident";
00969 foldingList.resize (foldingList.size() + 2);
00970 foldingList[foldingList.size()-2] = 1;
00971 foldingList[foldingList.size()-1] = 0;
00972 }
00973 kDebug(13020)<<"DEINDENT: "<<deindent;
00974 if (deindent > 0)
00975 {
00976
00977
00978
00979 for (int z=0;z<deindent;z++) {
00980
00981 foldingList.prepend(linelength+1);
00982 foldingList.prepend(-1);
00983 }
00984
00985
00986
00987
00988
00989
00990 }
00991 }
00992
00993
00994 bool KateBuffer::isEmptyLine(KateTextLine::Ptr textline)
00995 {
00996 QLinkedList<QRegExp> l;
00997 l=m_highlight->emptyLines(textline->attribute(0));
00998 kDebug(13020)<<"trying to find empty line data";
00999 if (l.isEmpty()) return false;
01000 QString txt=textline->string();
01001 kDebug(13020)<<"checking empty line regexp";
01002 foreach(const QRegExp &re,l) {
01003 if (re.exactMatch(txt)) return true;
01004 }
01005 kDebug(13020)<<"no matches";
01006 return false;
01007 }
01008
01009 bool KateBuffer::doHighlight (int startLine, int endLine, bool invalidate)
01010 {
01011
01012 if (!m_highlight)
01013 return false;
01014
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028 if (KateHlManager::self()->countDynamicCtxs() >= m_maxDynamicContexts)
01029 {
01030 {
01031 if (KateHlManager::self()->resetDynamicCtxs())
01032 {
01033 kDebug (13020) << "HL invalidated - too many dynamic contexts ( >= " << m_maxDynamicContexts << ")";
01034
01035
01036 KateHlManager::self()->setForceNoDCReset(true);
01037
01038 for (int i=0; i < KateGlobal::self()->kateDocuments().size(); ++i)
01039 (KateGlobal::self()->kateDocuments())[i]->makeAttribs();
01040
01041
01042
01043 doHighlight ( m_lineHighlighted, endLine, false );
01044 m_lineHighlighted = endLine;
01045
01046 KateHlManager::self()->setForceNoDCReset(false);
01047
01048 return false;
01049 }
01050 else
01051 {
01052 m_maxDynamicContexts *= 2;
01053 kDebug (13020) << "New dynamic contexts limit: " << m_maxDynamicContexts;
01054 }
01055 }
01056 }
01057
01058
01059 KateTextLine::Ptr prevLine;
01060
01061 if (startLine >= 1)
01062 prevLine = plainLine (startLine-1);
01063 else
01064 prevLine = new KateTextLine ();
01065
01066
01067 bool codeFoldingUpdate = false;
01068
01069
01070 int current_line = startLine;
01071
01072
01073 bool stillcontinue=false;
01074 bool indentContinueWhitespace=false;
01075 bool indentContinueNextWhitespace=false;
01076
01077
01078 while ( (current_line < m_lines) && (stillcontinue || (current_line <= endLine)) )
01079 {
01080
01081 KateTextLine::Ptr textLine = plainLine (current_line);
01082
01083 QVector<int> foldingList;
01084 bool ctxChanged = false;
01085
01086 m_highlight->doHighlight (prevLine.data(), textLine.data(), foldingList, ctxChanged);
01087
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102 bool indentChanged = false;
01103 if (m_highlight->foldingIndentationSensitive())
01104 {
01105
01106 QVector<unsigned short> indentDepth (prevLine->indentationDepthArray());
01107
01108
01109 int iDepth = textLine->indentDepth(m_tabWidth);
01110 if (current_line==0)
01111 {
01112 indentDepth.resize (1);
01113 indentDepth[0] = iDepth;
01114 }
01115
01116 textLine->setNoIndentBasedFoldingAtStart(prevLine->noIndentBasedFolding());
01117
01118 kDebug(13020)<<"current_line:"<<current_line<<" textLine->noIndentBasedFoldingAtStart"<<textLine->noIndentBasedFoldingAtStart();
01119 if ( (textLine->firstChar() == -1) || textLine->noIndentBasedFoldingAtStart() || isEmptyLine(textLine) )
01120 {
01121
01122 if (!prevLine->indentationDepthArray().isEmpty())
01123 {
01124 iDepth = (prevLine->indentationDepthArray())[prevLine->indentationDepthArray().size()-1];
01125 kDebug(13020)<<"reusing old depth as current";
01126 }
01127 else
01128 {
01129 iDepth = prevLine->indentDepth(m_tabWidth);
01130 kDebug(13020)<<"creating indentdepth for previous line";
01131 }
01132 }
01133
01134 kDebug(13020)<<"iDepth:"<<iDepth;
01135
01136
01137
01138 int nextLineIndentation = 0;
01139 bool nextLineIndentationValid=true;
01140 indentContinueNextWhitespace=false;
01141 if ((current_line+1) < m_lines)
01142 {
01143 if ( (plainLine (current_line+1)->firstChar() == -1) || isEmptyLine(plainLine (current_line+1)) )
01144 {
01145 nextLineIndentation = iDepth;
01146 indentContinueNextWhitespace=true;
01147 }
01148 else
01149 nextLineIndentation = plainLine (current_line+1)->indentDepth(m_tabWidth);
01150 }
01151 else
01152 {
01153 nextLineIndentationValid=false;
01154 }
01155
01156 if (!textLine->noIndentBasedFoldingAtStart()) {
01157
01158 if ((iDepth > 0) && (indentDepth.isEmpty() || (indentDepth[indentDepth.size()-1] < iDepth)))
01159 {
01160 kDebug(13020)<<"adding depth to \"stack\":"<<iDepth;
01161 indentDepth.append (iDepth);
01162 } else {
01163 if (!indentDepth.isEmpty())
01164 {
01165 for (int z=indentDepth.size()-1; z > -1; z--)
01166 if (indentDepth[z]>iDepth)
01167 indentDepth.resize(z);
01168 if ((iDepth > 0) && (indentDepth.isEmpty() || (indentDepth[indentDepth.size()-1] < iDepth)))
01169 {
01170 kDebug(13020)<<"adding depth to \"stack\":"<<iDepth;
01171 indentDepth.append (iDepth);
01172 if (prevLine->firstChar()==-1) {
01173
01174 }
01175 }
01176 }
01177 }
01178 }
01179
01180 if (!textLine->noIndentBasedFolding())
01181 {
01182 if (nextLineIndentationValid)
01183 {
01184
01185 {
01186 kDebug(13020)<<"nextLineIndentation:"<<nextLineIndentation;
01187 bool addindent=false;
01188 int deindent=0;
01189 if (!indentDepth.isEmpty())
01190 kDebug(13020)<<"indentDepth[indentDepth.size()-1]:"<<indentDepth[indentDepth.size()-1];
01191 if ((nextLineIndentation>0) && ( indentDepth.isEmpty() || (indentDepth[indentDepth.size()-1]<nextLineIndentation)))
01192 {
01193 kDebug(13020)<<"addindent==true";
01194 addindent=true;
01195 } else {
01196 if ((!indentDepth.isEmpty()) && (indentDepth[indentDepth.size()-1]>nextLineIndentation))
01197 {
01198 kDebug(13020)<<"....";
01199 for (int z=indentDepth.size()-1; z > -1; z--)
01200 {
01201 kDebug(13020)<<indentDepth[z]<<" "<<nextLineIndentation;
01202 if (indentDepth[z]>nextLineIndentation)
01203 deindent++;
01204 }
01205 }
01206 }
01207
01208
01209
01210 if ((textLine->firstChar()==-1)) {
01211 updatePreviousNotEmptyLine(current_line,addindent,deindent);
01212 codeFoldingUpdate=true;
01213 }
01214 else
01215 {
01216 addIndentBasedFoldingInformation(foldingList,textLine->length(),addindent,deindent);
01217 }
01218 }
01219 }
01220 }
01221 indentChanged = !(indentDepth == textLine->indentationDepthArray());
01222
01223
01224 if (indentChanged)
01225 textLine->setIndentationDepth (indentDepth);
01226
01227 indentContinueWhitespace=textLine->firstChar()==-1;
01228 }
01229 bool foldingColChanged=false;
01230 bool foldingChanged = false;
01231 if (foldingList.size()!=textLine->foldingListArray().size()) {
01232 foldingChanged=true;
01233 } else {
01234 QVector<int>::ConstIterator it=foldingList.constBegin();
01235 QVector<int>::ConstIterator it1=textLine->foldingListArray().constBegin();
01236 bool markerType=true;
01237 for(;it!=foldingList.constEnd();++it,++it1) {
01238 if (markerType) {
01239 if ( ((*it)!=(*it1))) {
01240 foldingChanged=true;
01241 foldingColChanged=false;
01242 break;
01243 }
01244 } else {
01245 if ((*it)!=(*it1)) {
01246 foldingColChanged=true;
01247 }
01248 }
01249 markerType=!markerType;
01250 }
01251 }
01252
01253 if (foldingChanged || foldingColChanged) {
01254 textLine->setFoldingList(foldingList);
01255 if (foldingChanged==false){
01256 textLine->setFoldingColumnsOutdated(textLine->foldingColumnsOutdated() | foldingColChanged);
01257 } else textLine->setFoldingColumnsOutdated(false);
01258 }
01259 bool retVal_folding = false;
01260
01261 m_regionTree.updateLine (current_line, &foldingList, &retVal_folding, foldingChanged,foldingColChanged);
01262
01263 codeFoldingUpdate = codeFoldingUpdate | retVal_folding;
01264
01265
01266 stillcontinue = ctxChanged || indentChanged || indentContinueWhitespace || indentContinueNextWhitespace;
01267
01268
01269 prevLine = textLine;
01270
01271
01272 current_line++;
01273 }
01274
01275
01276 if (invalidate)
01277 emit tagLines (startLine, current_line);
01278
01279
01280 if (codeFoldingUpdate)
01281 emit codeFoldingUpdated();
01282
01283 kDebug (13020) << "HIGHLIGHTED END --- NEED HL, LINESTART: " << startLine << " LINEEND: " << endLine;
01284 kDebug (13020) << "HL UNTIL LINE: " << m_lineHighlighted << " MAX: " << m_lineHighlightedMax;
01285 kDebug (13020) << "HL DYN COUNT: " << KateHlManager::self()->countDynamicCtxs() << " MAX: " << m_maxDynamicContexts;
01286
01287
01288
01289
01290 return stillcontinue;
01291 }
01292
01293 void KateBuffer::codeFoldingColumnUpdate(int lineNr) {
01294 KateTextLine::Ptr line=plainLine(lineNr);
01295 if (!line) return;
01296 if (line->foldingColumnsOutdated()) {
01297 line->setFoldingColumnsOutdated(false);
01298 bool tmp;
01299 QVector<int> folding=line->foldingListArray();
01300 m_regionTree.updateLine(lineNr,&folding,&tmp,true,false);
01301 }
01302 }
01303
01304