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)
00125 m_codec = QTextCodec::codecForName(m_prober->encodingName());
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 const char* actualEncoding () const { return m_codec->name().constData(); }
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(QFile::encodeName(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 KateTextLine::Ptr KateBuffer::line (int line)
00763 {
00764
00765 if (line < 0 || line >= m_lines)
00766 return KateTextLine::Ptr();
00767
00768
00769 if (line < m_lineHighlighted)
00770 return plainLine (line);
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 return plainLine (line);
00784 }
00785
00786 void KateBuffer::changeLine(int i)
00787 {
00788 if (i < 0 || i >= m_lines)
00789 return;
00790
00791
00792 editChangesDone = true;
00793
00794
00795 if (i < editTagLineStart)
00796 editTagLineStart = i;
00797
00798 if (i > editTagLineEnd)
00799 editTagLineEnd = i;
00800 }
00801
00802 void KateBuffer::insertLine(int i, KateTextLine::Ptr line)
00803 {
00804 if (i < 0 || i > m_lines)
00805 return;
00806
00807
00808 int block = findBlock (i);
00809 if (block == -1)
00810 block = m_blocks.size() - 1;
00811
00812
00813 m_blocks[block]->lines.insert (i - m_blocks[block]->start, line);
00814 m_lines++;
00815 fixBlocksFrom (block);
00816
00817 if (m_lineHighlightedMax > i)
00818 m_lineHighlightedMax++;
00819
00820 if (m_lineHighlighted > i)
00821 m_lineHighlighted++;
00822
00823
00824 editChangesDone = true;
00825
00826
00827 if (i < editTagLineStart)
00828 editTagLineStart = i;
00829
00830 if (i <= editTagLineEnd)
00831 editTagLineEnd++;
00832
00833 if (i > editTagLineEnd)
00834 editTagLineEnd = i;
00835
00836
00837 editTagLineFrom = true;
00838
00839 m_regionTree.lineHasBeenInserted (i);
00840 }
00841
00842 void KateBuffer::removeLine(int i)
00843 {
00844 int block = findBlock (i);
00845
00846 if (block == -1)
00847 return;
00848
00849
00850 m_blocks[block]->lines.remove (i - m_blocks[block]->start);
00851 m_lines--;
00852 fixBlocksFrom (block);
00853
00854 if (m_lineHighlightedMax > i)
00855 m_lineHighlightedMax--;
00856
00857 if (m_lineHighlighted > i)
00858 m_lineHighlighted--;
00859
00860
00861 editChangesDone = true;
00862
00863
00864 if (i < editTagLineStart)
00865 editTagLineStart = i;
00866
00867 if (i < editTagLineEnd)
00868 editTagLineEnd--;
00869
00870 if (i > editTagLineEnd)
00871 editTagLineEnd = i;
00872
00873
00874
00875 if (editTagLineEnd >= m_lines)
00876 editTagLineEnd = m_lines - 1;
00877
00878 if (editTagLineStart > editTagLineEnd)
00879 editTagLineStart = editTagLineEnd;
00880
00881
00882 editTagLineFrom = true;
00883
00884 m_regionTree.lineHasBeenRemoved (i);
00885 }
00886
00887 void KateBuffer::setTabWidth (int w)
00888 {
00889 if ((m_tabWidth != w) && (m_tabWidth > 0))
00890 {
00891 m_tabWidth = w;
00892
00893 if (m_highlight && m_highlight->foldingIndentationSensitive())
00894 invalidateHighlighting();
00895 }
00896 }
00897
00898 void KateBuffer::setHighlight(int hlMode)
00899 {
00900 KateHighlighting *h = KateHlManager::self()->getHl(hlMode);
00901
00902
00903 if (h != m_highlight)
00904 {
00905 bool invalidate = !h->noHighlighting();
00906
00907 if (m_highlight)
00908 {
00909 m_highlight->release();
00910 invalidate = true;
00911 }
00912
00913 h->use();
00914
00915
00916 m_regionTree.clear();
00917 m_regionTree.fixRoot(m_lines);
00918
00919
00920 if (!h->indentation().isEmpty())
00921 m_doc->config()->setIndentationMode (h->indentation());
00922
00923 m_highlight = h;
00924
00925 if (invalidate)
00926 invalidateHighlighting();
00927
00928
00929
00930 m_doc->bufferHlChanged ();
00931 }
00932 }
00933
00934 void KateBuffer::invalidateHighlighting()
00935 {
00936 m_lineHighlightedMax = 0;
00937 m_lineHighlighted = 0;
00938 }
00939
00940
00941 void KateBuffer::updatePreviousNotEmptyLine(int current_line,bool addindent,int deindent)
00942 {
00943 KateTextLine::Ptr textLine;
00944 do {
00945 if (current_line == 0) return;
00946
00947 --current_line;
00948
00949 textLine = plainLine (current_line);
00950 } while (textLine->firstChar()==-1);
00951
00952 kDebug(13020)<<"updatePreviousNotEmptyLine: updating line:"<<current_line;
00953 QVector<int> foldingList=textLine->foldingListArray();
00954 while ( (foldingList.size()>0) && ( abs(foldingList[foldingList.size()-2])==1)) {
00955 foldingList.resize(foldingList.size()-2);
00956 }
00957 addIndentBasedFoldingInformation(foldingList,textLine->length(),addindent,deindent);
00958 textLine->setFoldingList(foldingList);
00959
00960 bool retVal_folding = false;
00961 m_regionTree.updateLine (current_line, &foldingList, &retVal_folding, true,false);
00962
00963
00964 }
00965
00966 void KateBuffer::addIndentBasedFoldingInformation(QVector<int> &foldingList,int linelength,bool addindent,int deindent)
00967 {
00968 if (addindent) {
00969
00970 kDebug(13020)<<"adding ident";
00971 foldingList.resize (foldingList.size() + 2);
00972 foldingList[foldingList.size()-2] = 1;
00973 foldingList[foldingList.size()-1] = 0;
00974 }
00975 kDebug(13020)<<"DEINDENT: "<<deindent;
00976 if (deindent > 0)
00977 {
00978
00979
00980
00981 for (int z=0;z<deindent;z++) {
00982
00983 foldingList.prepend(linelength+1);
00984 foldingList.prepend(-1);
00985 }
00986
00987
00988
00989
00990
00991
00992 }
00993 }
00994
00995
00996 bool KateBuffer::isEmptyLine(KateTextLine::Ptr textline)
00997 {
00998 QLinkedList<QRegExp> l;
00999 l=m_highlight->emptyLines(textline->attribute(0));
01000 kDebug(13020)<<"trying to find empty line data";
01001 if (l.isEmpty()) return false;
01002 QString txt=textline->string();
01003 kDebug(13020)<<"checking empty line regexp";
01004 foreach(const QRegExp &re,l) {
01005 if (re.exactMatch(txt)) return true;
01006 }
01007 kDebug(13020)<<"no matches";
01008 return false;
01009 }
01010
01011 bool KateBuffer::doHighlight (int startLine, int endLine, bool invalidate)
01012 {
01013
01014 if (!m_highlight)
01015 return false;
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030 if (KateHlManager::self()->countDynamicCtxs() >= m_maxDynamicContexts)
01031 {
01032 {
01033 if (KateHlManager::self()->resetDynamicCtxs())
01034 {
01035 kDebug (13020) << "HL invalidated - too many dynamic contexts ( >= " << m_maxDynamicContexts << ")";
01036
01037
01038 KateHlManager::self()->setForceNoDCReset(true);
01039
01040 for (int i=0; i < KateGlobal::self()->kateDocuments().size(); ++i)
01041 (KateGlobal::self()->kateDocuments())[i]->makeAttribs();
01042
01043
01044
01045 doHighlight ( m_lineHighlighted, endLine, false );
01046 m_lineHighlighted = endLine;
01047
01048 KateHlManager::self()->setForceNoDCReset(false);
01049
01050 return false;
01051 }
01052 else
01053 {
01054 m_maxDynamicContexts *= 2;
01055 kDebug (13020) << "New dynamic contexts limit: " << m_maxDynamicContexts;
01056 }
01057 }
01058 }
01059
01060
01061 KateTextLine::Ptr prevLine;
01062
01063 if (startLine >= 1)
01064 prevLine = plainLine (startLine-1);
01065 else
01066 prevLine = new KateTextLine ();
01067
01068
01069 bool codeFoldingUpdate = false;
01070
01071
01072 int current_line = startLine;
01073
01074
01075 bool stillcontinue=false;
01076 bool indentContinueWhitespace=false;
01077 bool indentContinueNextWhitespace=false;
01078
01079
01080 while ( (current_line < m_lines) && (stillcontinue || (current_line <= endLine)) )
01081 {
01082
01083 KateTextLine::Ptr textLine = plainLine (current_line);
01084
01085 QVector<int> foldingList;
01086 bool ctxChanged = false;
01087
01088 m_highlight->doHighlight (prevLine.data(), textLine.data(), foldingList, ctxChanged);
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102
01103
01104 bool indentChanged = false;
01105 if (m_highlight->foldingIndentationSensitive())
01106 {
01107
01108 QVector<unsigned short> indentDepth (prevLine->indentationDepthArray());
01109
01110
01111 int iDepth = textLine->indentDepth(m_tabWidth);
01112 if (current_line==0)
01113 {
01114 indentDepth.resize (1);
01115 indentDepth[0] = iDepth;
01116 }
01117
01118 textLine->setNoIndentBasedFoldingAtStart(prevLine->noIndentBasedFolding());
01119
01120 kDebug(13020)<<"current_line:"<<current_line<<" textLine->noIndentBasedFoldingAtStart"<<textLine->noIndentBasedFoldingAtStart();
01121 if ( (textLine->firstChar() == -1) || textLine->noIndentBasedFoldingAtStart() || isEmptyLine(textLine) )
01122 {
01123
01124 if (!prevLine->indentationDepthArray().isEmpty())
01125 {
01126 iDepth = (prevLine->indentationDepthArray())[prevLine->indentationDepthArray().size()-1];
01127 kDebug(13020)<<"reusing old depth as current";
01128 }
01129 else
01130 {
01131 iDepth = prevLine->indentDepth(m_tabWidth);
01132 kDebug(13020)<<"creating indentdepth for previous line";
01133 }
01134 }
01135
01136 kDebug(13020)<<"iDepth:"<<iDepth;
01137
01138
01139
01140 int nextLineIndentation = 0;
01141 bool nextLineIndentationValid=true;
01142 indentContinueNextWhitespace=false;
01143 if ((current_line+1) < m_lines)
01144 {
01145 if ( (plainLine (current_line+1)->firstChar() == -1) || isEmptyLine(plainLine (current_line+1)) )
01146 {
01147 nextLineIndentation = iDepth;
01148 indentContinueNextWhitespace=true;
01149 }
01150 else
01151 nextLineIndentation = plainLine (current_line+1)->indentDepth(m_tabWidth);
01152 }
01153 else
01154 {
01155 nextLineIndentationValid=false;
01156 }
01157
01158 if (!textLine->noIndentBasedFoldingAtStart()) {
01159
01160 if ((iDepth > 0) && (indentDepth.isEmpty() || (indentDepth[indentDepth.size()-1] < iDepth)))
01161 {
01162 kDebug(13020)<<"adding depth to \"stack\":"<<iDepth;
01163 indentDepth.append (iDepth);
01164 } else {
01165 if (!indentDepth.isEmpty())
01166 {
01167 for (int z=indentDepth.size()-1; z > -1; z--)
01168 if (indentDepth[z]>iDepth)
01169 indentDepth.resize(z);
01170 if ((iDepth > 0) && (indentDepth.isEmpty() || (indentDepth[indentDepth.size()-1] < iDepth)))
01171 {
01172 kDebug(13020)<<"adding depth to \"stack\":"<<iDepth;
01173 indentDepth.append (iDepth);
01174 if (prevLine->firstChar()==-1) {
01175
01176 }
01177 }
01178 }
01179 }
01180 }
01181
01182 if (!textLine->noIndentBasedFolding())
01183 {
01184 if (nextLineIndentationValid)
01185 {
01186
01187 {
01188 kDebug(13020)<<"nextLineIndentation:"<<nextLineIndentation;
01189 bool addindent=false;
01190 int deindent=0;
01191 if (!indentDepth.isEmpty())
01192 kDebug(13020)<<"indentDepth[indentDepth.size()-1]:"<<indentDepth[indentDepth.size()-1];
01193 if ((nextLineIndentation>0) && ( indentDepth.isEmpty() || (indentDepth[indentDepth.size()-1]<nextLineIndentation)))
01194 {
01195 kDebug(13020)<<"addindent==true";
01196 addindent=true;
01197 } else {
01198 if ((!indentDepth.isEmpty()) && (indentDepth[indentDepth.size()-1]>nextLineIndentation))
01199 {
01200 kDebug(13020)<<"....";
01201 for (int z=indentDepth.size()-1; z > -1; z--)
01202 {
01203 kDebug(13020)<<indentDepth[z]<<" "<<nextLineIndentation;
01204 if (indentDepth[z]>nextLineIndentation)
01205 deindent++;
01206 }
01207 }
01208 }
01209
01210
01211
01212 if ((textLine->firstChar()==-1)) {
01213 updatePreviousNotEmptyLine(current_line,addindent,deindent);
01214 codeFoldingUpdate=true;
01215 }
01216 else
01217 {
01218 addIndentBasedFoldingInformation(foldingList,textLine->length(),addindent,deindent);
01219 }
01220 }
01221 }
01222 }
01223 indentChanged = !(indentDepth == textLine->indentationDepthArray());
01224
01225
01226 if (indentChanged)
01227 textLine->setIndentationDepth (indentDepth);
01228
01229 indentContinueWhitespace=textLine->firstChar()==-1;
01230 }
01231 bool foldingColChanged=false;
01232 bool foldingChanged = false;
01233 if (foldingList.size()!=textLine->foldingListArray().size()) {
01234 foldingChanged=true;
01235 } else {
01236 QVector<int>::ConstIterator it=foldingList.begin();
01237 QVector<int>::ConstIterator it1=textLine->foldingListArray().begin();
01238 bool markerType=true;
01239 for(;it!=foldingList.end();++it,++it1) {
01240 if (markerType) {
01241 if ( ((*it)!=(*it1))) {
01242 foldingChanged=true;
01243 foldingColChanged=false;
01244 break;
01245 }
01246 } else {
01247 if ((*it)!=(*it1)) {
01248 foldingColChanged=true;
01249 }
01250 }
01251 markerType=!markerType;
01252 }
01253 }
01254
01255 if (foldingChanged || foldingColChanged) {
01256 textLine->setFoldingList(foldingList);
01257 if (foldingChanged==false){
01258 textLine->setFoldingColumnsOutdated(textLine->foldingColumnsOutdated() | foldingColChanged);
01259 } else textLine->setFoldingColumnsOutdated(false);
01260 }
01261 bool retVal_folding = false;
01262
01263 m_regionTree.updateLine (current_line, &foldingList, &retVal_folding, foldingChanged,foldingColChanged);
01264
01265 codeFoldingUpdate = codeFoldingUpdate | retVal_folding;
01266
01267
01268 stillcontinue = ctxChanged || indentChanged || indentContinueWhitespace || indentContinueNextWhitespace;
01269
01270
01271 prevLine = textLine;
01272
01273
01274 current_line++;
01275 }
01276
01277
01278 if (invalidate)
01279 emit tagLines (startLine, current_line);
01280
01281
01282 if (codeFoldingUpdate)
01283 emit codeFoldingUpdated();
01284
01285 kDebug (13020) << "HIGHLIGHTED END --- NEED HL, LINESTART: " << startLine << " LINEEND: " << endLine;
01286 kDebug (13020) << "HL UNTIL LINE: " << m_lineHighlighted << " MAX: " << m_lineHighlightedMax;
01287 kDebug (13020) << "HL DYN COUNT: " << KateHlManager::self()->countDynamicCtxs() <<