• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

Kate

katebuffer.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002    Copyright (c) 2000 Waldo Bastian <bastian@kde.org>
00003    Copyright (C) 2002-2004 Christoph Cullmann <cullmann@kde.org>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License version 2 as published by the Free Software Foundation.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017    Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include <sys/types.h>
00021 #include <sys/stat.h>
00022 #include <unistd.h>
00023 
00024 #include "katebuffer.h"
00025 #include "katebuffer.moc"
00026 
00027 #include "katedocument.h"
00028 #include "katehighlight.h"
00029 #include "kateconfig.h"
00030 #include "katefactory.h"
00031 #include "kateautoindent.h"
00032 
00033 #include <kdebug.h>
00034 #include <kglobal.h>
00035 #include <kcharsets.h>
00036 
00037 #include <qpopupmenu.h>
00038 #include <qfile.h>
00039 #include <qtextstream.h>
00040 #include <qtimer.h>
00041 #include <qtextcodec.h>
00042 #include <qcstring.h>
00043 #include <qdatetime.h>
00044 
00049 static const Q_ULONG KATE_FILE_LOADER_BS  = 256 * 1024;
00050 
00057 static const Q_ULONG KATE_AVG_BLOCK_SIZE  = 2048 * 80;
00058 static const Q_ULONG KATE_MAX_BLOCK_LINES = 2048;
00059 
00065 static const uint KATE_HL_LOOKAHEAD = 64;
00066 
00072 uint KateBuffer::m_maxLoadedBlocks = 16;
00073 
00077 static const uint KATE_MAX_DYNAMIC_CONTEXTS = 512;
00078 
00079 void KateBuffer::setMaxLoadedBlocks (uint count)
00080 {
00081   m_maxLoadedBlocks = kMax (4U, count);
00082 }
00083 
00084 class KateFileLoader
00085 {
00086   public:
00087     KateFileLoader (const QString &filename, QTextCodec *codec, bool removeTrailingSpaces)
00088       : m_file (filename)
00089       , m_buffer (kMin (m_file.size(), KATE_FILE_LOADER_BS))
00090       , m_codec (codec)
00091       , m_decoder (m_codec->makeDecoder())
00092       , m_position (0)
00093       , m_lastLineStart (0)
00094       , m_eof (false) // default to not eof
00095       , lastWasEndOfLine (true) // at start of file, we had a virtual newline
00096       , lastWasR (false) // we have not found a \r as last char
00097       , m_eol (-1) // no eol type detected atm
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           // fix utf16 LE, stolen from khtml ;)
00122           if ((c >= 2) && (m_codec->mibEnum() == 1000) && (m_buffer[1] == 0x00))
00123           {
00124             // utf16LE, we need to put the decoder in LE mode
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     // no new lines around ?
00164     inline bool eof () const { return m_eof && !lastWasEndOfLine && (m_lastLineStart == m_text.length()); }
00165 
00166     // eol mode ? autodetected on open(), -1 for no eol found in the first block!
00167     inline int eol () const { return m_eol; }
00168 
00169     // binary ?
00170     inline bool binary () const { return m_binary; }
00171 
00172     // should spaces be ignored at end of line?
00173     inline bool removeTrailingSpaces () const { return m_removeTrailingSpaces; }
00174 
00175     // internal unicode data array
00176     inline const QChar *unicode () const { return m_text.unicode(); }
00177 
00178     // read a line, return length + offset in unicode data
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           // try to load more text if something is around
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             // is file completly read ?
00208             m_eof = (c == -1) || (c == 0) || (readString == 0) || m_file.atEnd();
00209 
00210             // recalc current pos and last pos
00211             m_position -= m_lastLineStart;
00212             m_lastLineStart = 0;
00213           }
00214 
00215           // oh oh, end of file, escape !
00216           if (m_eof && (m_position == m_text.length()))
00217           {
00218             lastWasEndOfLine = false;
00219 
00220             // line data
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             // line data
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           // line data
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     // this nice methode will kill all 0 bytes (or double bytes)
00276     // and remember if this was a binary or not ;)
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   // DELETE ALL BLOCKS, will free mem
00355   for (uint i=0; i < m_blocks.size(); i++)
00356     delete m_blocks[i];
00357 
00358   // release HL
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     // hl update !!!
00392     if ( m_highlight && !m_highlight->noHighlighting()
00393         && (editTagLineStart <= editTagLineEnd)
00394         && (editTagLineEnd <= m_lineHighlighted))
00395     {
00396       // look one line too far, needed for linecontinue stuff
00397       editTagLineEnd++;
00398 
00399       // look one line before, needed nearly 100% only for indentation based folding !
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   // cleanup the blocks
00436   for (uint i=0; i < m_blocks.size(); i++)
00437     delete m_blocks[i];
00438 
00439   m_blocks.clear ();
00440 
00441   // create a bufblock with one line, we need that, only in openFile we won't have that
00442   KateBufBlock *block = new KateBufBlock(this, 0, 0);
00443   m_blocks.append (block);
00444 
00445   // reset the state
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; // Error
00474   }
00475 
00476   // set eol mode, if a eol char was found in the first 256kb block and we allow this at all!
00477   if (m_doc->config()->allowEolDetection() && (file.eol() != -1))
00478     m_doc->config()->setEol (file.eol());
00479 
00480   // flush current content
00481   clear ();
00482 
00483   // cleanup the blocks
00484   for (uint i=0; i < m_blocks.size(); i++)
00485     delete m_blocks[i];
00486 
00487   m_blocks.clear ();
00488 
00489   // do the real work
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   // we had a cache write error, this load is really borked !
00508   if (m_cacheWriteError)
00509     m_loadingBorked = true;
00510 
00511   if (m_blocks.isEmpty() || (m_lines == 0))
00512   {
00513     // file was really empty, clean the buffers + emit the line changed
00514     // loadingBorked will be false for such files, not matter what happened
00515     // before
00516     clear ();
00517   }
00518   else
00519   {
00520     // fix region tree
00521     m_regionTree.fixRoot (m_lines);
00522   }
00523 
00524   // if we have no hl or the "None" hl activated, whole file is correct highlighted
00525   // after loading, which wonder ;)
00526   if (!m_highlight || m_highlight->noHighlighting())
00527   {
00528     m_lineHighlighted = m_lines;
00529     m_lineHighlightedMax = m_lines;
00530   }
00531 
00532   // binary?
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   // hardcode some unicode encodings which can encode all chars
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; // Error
00572   }
00573 
00574   QTextCodec *codec = m_doc->config()->codec();
00575 
00576   // disable Unicode headers
00577   stream.setEncoding(QTextStream::RawUnicode);
00578 
00579   // this line sets the mapper to the correct codec
00580   stream.setCodec(codec);
00581 
00582   // our loved eol string ;)
00583   QString eol = m_doc->config()->eolString ();
00584 
00585   // should we strip spaces?
00586   bool removeTrailingSpaces = m_doc->configFlags() & KateDocument::cfRemoveSpaces;
00587 
00588   // just dump the lines out ;)
00589   for (uint i=0; i < m_lines; i++)
00590   {
00591     KateTextLine::Ptr textline = plainLine(i);
00592 
00593     // strip spaces
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 // simple, dump the line
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   // update hl until this line + max KATE_HL_LOOKAHEAD
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   // update hl max
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) // we are in a allready known area !
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 // we need first to resync the startLines !
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       // get next block
00675       KateBufBlock *buf = m_blocks[m_lastInSyncBlock];
00676 
00677       // sync startLine !
00678       buf->setStartLine (lastLine);
00679 
00680       // is it allready the searched block ?
00681       if ((i >= lastLine) && (i < buf->endLine()))
00682       {
00683         // remember this block as last found !
00684         m_lastFoundBlock = m_lastInSyncBlock;
00685 
00686         if (index)
00687           (*index) = m_lastFoundBlock;
00688 
00689         return buf;
00690       }
00691 
00692       // increase lastLine with blocklinecount
00693       lastLine += buf->lines ();
00694     }
00695   }
00696 
00697   // no block found !
00698   // index will not be set to any useful value in this case !
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   // mark this block dirty
00710   buf->markDirty ();
00711 
00712   // mark buffer changed
00713   editChangesDone = true;
00714 
00715   // tag this line as changed
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   // last sync block adjust
00746   if (m_lastInSyncBlock > index)
00747     m_lastInSyncBlock = index;
00748 
00749   // last found
00750   if (m_lastInSyncBlock < m_lastFoundBlock)
00751     m_lastFoundBlock = m_lastInSyncBlock;
00752 
00753   // mark buffer changed
00754   editChangesDone = true;
00755 
00756   // tag this line as inserted
00757   if (i < editTagLineStart)
00758     editTagLineStart = i;
00759 
00760   if (i <= editTagLineEnd)
00761     editTagLineEnd++;
00762 
00763   if (i > editTagLineEnd)
00764     editTagLineEnd = i;
00765 
00766   // line inserted
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   // trash away a empty block
00791   if (buf->lines() == 0)
00792   {
00793     // we need to change which block is last in sync
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     // cu block !
00808     delete buf;
00809     m_blocks.erase (m_blocks.begin()+index);
00810 
00811     // make sure we don't keep a pointer to the deleted block
00812     if( m_lastInSyncBlock >= index )
00813       m_lastInSyncBlock = index - 1;
00814   }
00815   else
00816   {
00817     // last sync block adjust
00818     if (m_lastInSyncBlock > index)
00819       m_lastInSyncBlock = index;
00820   }
00821 
00822   // last found
00823   if (m_lastInSyncBlock < m_lastFoundBlock)
00824     m_lastFoundBlock = m_lastInSyncBlock;
00825 
00826   // mark buffer changed
00827   editChangesDone = true;
00828 
00829   // tag this line as removed
00830    if (i < editTagLineStart)
00831     editTagLineStart = i;
00832 
00833   if (i < editTagLineEnd)
00834     editTagLineEnd--;
00835 
00836   if (i > editTagLineEnd)
00837     editTagLineEnd = i;
00838 
00839   // line removed
00840   editTagLineFrom = true;
00841 
00842   m_regionTree.lineHasBeenRemoved (i);
00843 }
00844 
00845 void KateBuffer::setTabWidth (uint w)
00846 {
00847   if ((m_tabWidth != w) && (m_tabWidth > 0))
00848   {
00849     m_tabWidth = w;
00850 
00851     if (m_highlight && m_highlight->foldingIndentationSensitive())
00852       invalidateHighlighting();
00853   }
00854 }
00855 
00856 void KateBuffer::setHighlight(uint hlMode)
00857 {
00858   KateHighlighting *h = KateHlManager::self()->getHl(hlMode);
00859 
00860    // aha, hl will change
00861   if (h != m_highlight)
00862   {
00863     bool invalidate = !h->noHighlighting();
00864 
00865     if (m_highlight)
00866     {
00867       m_highlight->release();
00868       invalidate = true;
00869     }
00870 
00871     h->use();
00872 
00873     // Clear code folding tree (see bug #124102)
00874     m_regionTree.clear();
00875     m_regionTree.fixRoot(m_lines);
00876 
00877     // try to set indentation
00878     if (!h->indentation().isEmpty())
00879       m_doc->config()->setIndentationMode (KateAutoIndent::modeNumber(h->indentation()));
00880 
00881     m_highlight = h;
00882 
00883     if (invalidate)
00884       invalidateHighlighting();
00885 
00886     // inform the document that the hl was really changed
00887     // needed to update attributes and more ;)
00888     m_doc->bufferHlChanged ();
00889   }
00890 }
00891 
00892 void KateBuffer::invalidateHighlighting()
00893 {
00894   m_lineHighlightedMax = 0;
00895   m_lineHighlighted = 0;
00896 }
00897 
00898 
00899 void KateBuffer::updatePreviousNotEmptyLine(KateBufBlock *blk,uint current_line,bool addindent,uint deindent)
00900 {
00901   KateTextLine::Ptr textLine;
00902   do {
00903     if (current_line>0) current_line--;
00904     else
00905     {
00906       uint line=blk->startLine()+current_line;
00907       if (line==0) return;
00908       line--;
00909       blk=findBlock(line);
00910       if (!blk) {
00911         kdDebug(13020)<<"updatePreviousNotEmptyLine: block not found, this must not happen"<<endl;
00912         return;
00913       }
00914       current_line=line-blk->startLine();
00915     }
00916     textLine = blk->line(current_line);
00917   } while (textLine->firstChar()==-1);
00918   kdDebug(13020)<<"updatePreviousNotEmptyLine: updating line:"<<(blk->startLine()+current_line)<<endl;
00919   QMemArray<uint> foldingList=textLine->foldingListArray();
00920   while ( (foldingList.size()>0)  && ( abs(foldingList[foldingList.size()-2])==1)) {
00921     foldingList.resize(foldingList.size()-2,QGArray::SpeedOptim);
00922   }
00923   addIndentBasedFoldingInformation(foldingList,addindent,deindent);
00924   textLine->setFoldingList(foldingList);
00925   bool retVal_folding = false;
00926   m_regionTree.updateLine (current_line + blk->startLine(), &foldingList, &retVal_folding, true,false);
00927   emit tagLines (blk->startLine()+current_line, blk->startLine()+current_line);
00928 }
00929 
00930 void KateBuffer::addIndentBasedFoldingInformation(QMemArray<uint> &foldingList,bool addindent,uint deindent)
00931 {
00932   if (addindent) {
00933     //kdDebug(13020)<<"adding indent for line :"<<current_line + buf->startLine()<<"  textLine->noIndentBasedFoldingAtStart"<<textLine->noIndentBasedFoldingAtStart()<<endl;
00934     kdDebug(13020)<<"adding ident"<<endl;
00935     foldingList.resize (foldingList.size() + 2, QGArray::SpeedOptim);
00936     foldingList[foldingList.size()-2] = 1;
00937     foldingList[foldingList.size()-1] = 0;
00938   }
00939   kdDebug(13020)<<"DEINDENT: "<<deindent<<endl;
00940   if (deindent > 0)
00941   {
00942     foldingList.resize (foldingList.size() + (deindent*2), QGArray::SpeedOptim);
00943 
00944     for (uint z= foldingList.size()-(deindent*2); z < foldingList.size(); z=z+2)
00945     {
00946       foldingList[z] = -1;
00947       foldingList[z+1] = 0;
00948     }
00949   }
00950 }
00951 
00952 bool KateBuffer::doHighlight (KateBufBlock *buf, uint startLine, uint endLine, bool invalidate)
00953 {
00954   // no hl around, no stuff to do
00955   if (!m_highlight)
00956     return false;
00957 
00958   /*if (m_highlight->foldingIndentationSensitive())
00959   {
00960     startLine=0;
00961     endLine=50;
00962   }*/
00963 
00964   // we tried to start in a line behind this buf block !
00965   if (startLine >= (buf->startLine()+buf->lines()))
00966     return false;
00967 
00968   //QTime t;
00969   //t.start();
00970   //kdDebug (13020) << "HIGHLIGHTED START --- NEED HL, LINESTART: " << startLine << " LINEEND: " << endLine << endl;
00971   //kdDebug (13020) << "HL UNTIL LINE: " << m_lineHighlighted << " MAX: " << m_lineHighlightedMax << endl;
00972   //kdDebug (13020) << "HL DYN COUNT: " << KateHlManager::self()->countDynamicCtxs() << " MAX: " << m_maxDynamicContexts << endl;
00973 
00974   // see if there are too many dynamic contexts; if yes, invalidate HL of all documents
00975   if (KateHlManager::self()->countDynamicCtxs() >= m_maxDynamicContexts)
00976   {
00977     {
00978       if (KateHlManager::self()->resetDynamicCtxs())
00979       {
00980         kdDebug (13020) << "HL invalidated - too many dynamic contexts ( >= " << m_maxDynamicContexts << ")" << endl;
00981 
00982         // avoid recursive invalidation
00983         KateHlManager::self()->setForceNoDCReset(true);
00984 
00985         for (KateDocument *doc = KateFactory::self()->documents()->first(); doc; doc = KateFactory::self()->documents()->next())
00986           doc->makeAttribs();
00987 
00988         // doHighlight *shall* do his work. After invalidation, some highlight has
00989         // been recalculated, but *maybe not* until endLine ! So we shall force it manually...
00990         KateBufBlock *buf = 0;
00991         while ((endLine > m_lineHighlighted) && (buf = findBlock(m_lineHighlighted)))
00992         {
00993           uint end = kMin(endLine, buf->endLine());
00994 
00995           doHighlight ( buf,
00996                         kMax(m_lineHighlighted, buf->startLine()),
00997                         end,
00998                         false );
00999 
01000           m_lineHighlighted = end;
01001         }
01002 
01003         KateHlManager::self()->setForceNoDCReset(false);
01004 
01005         return false;
01006       }
01007       else
01008       {
01009         m_maxDynamicContexts *= 2;
01010         kdDebug (13020) << "New dynamic contexts limit: " << m_maxDynamicContexts << endl;
01011       }
01012     }
01013   }
01014 
01015   // get the previous line, if we start at the beginning of this block
01016   // take the last line of the previous block
01017   KateTextLine::Ptr prevLine = 0;
01018 
01019   if ((startLine == buf->startLine()) && buf->prev() && (buf->prev()->lines() > 0))
01020     prevLine = buf->prev()->line (buf->prev()->lines() - 1);
01021   else if ((startLine > buf->startLine()) && (startLine <= buf->endLine()))
01022     prevLine = buf->line(startLine - buf->startLine() - 1);
01023   else
01024     prevLine = new KateTextLine ();
01025 
01026   // does we need to emit a signal for the folding changes ?
01027   bool codeFoldingUpdate = false;
01028 
01029   // here we are atm, start at start line in the block
01030   uint current_line = startLine - buf->startLine();
01031 
01032   // do we need to continue
01033   bool stillcontinue=false;
01034   bool indentContinueWhitespace=false;
01035   bool indentContinueNextWhitespace=false;
01036   // loop over the lines of the block, from startline to endline or end of block
01037   // if stillcontinue forces us to do so
01038   while ( (current_line < buf->lines())
01039           && (stillcontinue || ((current_line + buf->startLine()) <= endLine)) )
01040   {
01041     // current line
01042     KateTextLine::Ptr textLine = buf->line(current_line);
01043 
01044     QMemArray<uint> foldingList;
01045     bool ctxChanged = false;
01046 
01047     m_highlight->doHighlight (prevLine, textLine, &foldingList, &ctxChanged);
01048 
01049     //
01050     // indentation sensitive folding
01051     //
01052     bool indentChanged = false;
01053     if (m_highlight->foldingIndentationSensitive())
01054     {
01055       // get the indentation array of the previous line to start with !
01056       QMemArray<unsigned short> indentDepth;
01057       indentDepth.duplicate (prevLine->indentationDepthArray());
01058 
01059       // current indentation of this line
01060       uint iDepth = textLine->indentDepth(m_tabWidth);
01061       if ((current_line+buf->startLine())==0)
01062       {
01063           indentDepth.resize (1, QGArray::SpeedOptim);
01064           indentDepth[0] = iDepth;
01065       }
01066 
01067       textLine->setNoIndentBasedFoldingAtStart(prevLine->noIndentBasedFolding());
01068       // this line is empty, beside spaces, or has indentaion based folding disabled, use indentation depth of the previous line !
01069       kdDebug(13020)<<"current_line:"<<current_line + buf->startLine()<<" textLine->noIndentBasedFoldingAtStart"<<textLine->noIndentBasedFoldingAtStart()<<endl;
01070       if ( (textLine->firstChar() == -1) || textLine->noIndentBasedFoldingAtStart())
01071       {
01072         // do this to get skipped empty lines indent right, which was given in the indenation array
01073         if (!prevLine->indentationDepthArray().isEmpty())
01074         {
01075           iDepth = (prevLine->indentationDepthArray())[prevLine->indentationDepthArray().size()-1];
01076           kdDebug(13020)<<"reusing old depth as current"<<endl;
01077         }
01078         else
01079         {
01080           iDepth = prevLine->indentDepth(m_tabWidth);
01081           kdDebug(13020)<<"creating indentdepth for previous line"<<endl;
01082         }
01083       }
01084 
01085       kdDebug(13020)<<"iDepth:"<<iDepth<<endl;
01086 
01087       // query the next line indentation, if we are at the end of the block
01088       // use the first line of the next buf block
01089       uint nextLineIndentation = 0;
01090       bool nextLineIndentationValid=true;
01091       indentContinueNextWhitespace=false;
01092       if ((current_line+1) < buf->lines())
01093       {
01094         if (buf->line(current_line+1)->firstChar() == -1)
01095         {
01096           nextLineIndentation = iDepth;
01097           indentContinueNextWhitespace=true;
01098         }
01099         else
01100           nextLineIndentation = buf->line(current_line+1)->indentDepth(m_tabWidth);
01101       }
01102       else
01103       {
01104         KateBufBlock *blk = buf->next();
01105 
01106         if (blk && (blk->lines() > 0))
01107         {
01108           if (blk->line (0)->firstChar() == -1)
01109           {
01110             nextLineIndentation = iDepth;
01111             indentContinueNextWhitespace=true;
01112           }
01113           else
01114             nextLineIndentation = blk->line (0)->indentDepth(m_tabWidth);
01115         }
01116         else nextLineIndentationValid=false;
01117       }
01118 
01119       if  (!textLine->noIndentBasedFoldingAtStart()) {
01120 
01121         if ((iDepth > 0) && (indentDepth.isEmpty() || (indentDepth[indentDepth.size()-1] < iDepth)))
01122         {
01123           kdDebug(13020)<<"adding depth to \"stack\":"<<iDepth<<endl;
01124           indentDepth.resize (indentDepth.size()+1, QGArray::SpeedOptim);
01125           indentDepth[indentDepth.size()-1] = iDepth;
01126         } else {
01127           if (!indentDepth.isEmpty())
01128           {
01129             for (int z=indentDepth.size()-1; z > -1; z--)
01130               if (indentDepth[z]>iDepth)
01131                 indentDepth.resize(z, QGArray::SpeedOptim);
01132             if ((iDepth > 0) && (indentDepth.isEmpty() || (indentDepth[indentDepth.size()-1] < iDepth)))
01133             {
01134               kdDebug(13020)<<"adding depth to \"stack\":"<<iDepth<<endl;
01135               indentDepth.resize (indentDepth.size()+1, QGArray::SpeedOptim);
01136               indentDepth[indentDepth.size()-1] = iDepth;
01137               if (prevLine->firstChar()==-1) {
01138 
01139               }
01140             }
01141           }
01142         }
01143       }
01144 
01145       if (!textLine->noIndentBasedFolding())
01146       {
01147         if (nextLineIndentationValid)
01148         {
01149           //if (textLine->firstChar()!=-1)
01150           {
01151             kdDebug(13020)<<"nextLineIndentation:"<<nextLineIndentation<<endl;
01152             bool addindent=false;
01153             uint deindent=0;
01154             if (!indentDepth.isEmpty())
01155               kdDebug()<<"indentDepth[indentDepth.size()-1]:"<<indentDepth[indentDepth.size()-1]<<endl;
01156             if ((nextLineIndentation>0) && ( indentDepth.isEmpty() || (indentDepth[indentDepth.size()-1]<nextLineIndentation)))
01157             {
01158               kdDebug(13020)<<"addindent==true"<<endl;
01159               addindent=true;
01160             } else {
01161             if ((!indentDepth.isEmpty()) && (indentDepth[indentDepth.size()-1]>nextLineIndentation))
01162               {
01163                 kdDebug(13020)<<"...."<<endl;
01164                 for (int z=indentDepth.size()-1; z > -1; z--)
01165                 {
01166                   kdDebug(13020)<<indentDepth[z]<<"  "<<nextLineIndentation<<endl;
01167                   if (indentDepth[z]>nextLineIndentation)
01168                     deindent++;
01169                 }
01170               }
01171             }
01172 /*        }
01173         if (textLine->noIndentBasedFolding()) kdDebug(13020)<<"=============================indentation based folding disabled======================"<<endl;
01174         if (!textLine->noIndentBasedFolding()) {*/
01175             if ((textLine->firstChar()==-1)) {
01176               updatePreviousNotEmptyLine(buf,current_line,addindent,deindent);
01177               codeFoldingUpdate=true;
01178             }
01179             else
01180             {
01181               addIndentBasedFoldingInformation(foldingList,addindent,deindent);
01182             }
01183           }
01184         }
01185       }
01186       indentChanged = !(indentDepth == textLine->indentationDepthArray());
01187 
01188       // assign the new array to the textline !
01189       if (indentChanged)
01190         textLine->setIndentationDepth (indentDepth);
01191 
01192       indentContinueWhitespace=textLine->firstChar()==-1;
01193     }
01194     bool foldingColChanged=false;
01195     bool foldingChanged = false; 
01196     if (foldingList.size()!=textLine->foldingListArray().size()) {
01197       foldingChanged=true;
01198     } else {
01199       QMemArray<uint>::ConstIterator it=foldingList.begin();
01200       QMemArray<uint>::ConstIterator it1=textLine->foldingListArray();
01201       bool markerType=true;
01202       for(;it!=foldingList.end();++it,++it1) {
01203         if  (markerType) {
01204           if ( ((*it)!=(*it1))) {
01205             foldingChanged=true;
01206             foldingColChanged=false;
01207             break;
01208           }
01209         } else {
01210             if ((*it)!=(*it1)) {
01211               foldingColChanged=true;
01212             }
01213         }
01214         markerType=!markerType;
01215       }
01216     }
01217 
01218     if (foldingChanged || foldingColChanged) {
01219       textLine->setFoldingList(foldingList);
01220       if (foldingChanged==false){
01221         textLine->setFoldingColumnsOutdated(textLine->foldingColumnsOutdated() | foldingColChanged);
01222       } else textLine->setFoldingColumnsOutdated(false);
01223     }
01224     bool retVal_folding = false;
01225     //perhaps make en enums out of the change flags
01226     m_regionTree.updateLine (current_line + buf->startLine(), &foldingList, &retVal_folding, foldingChanged,foldingColChanged);
01227 
01228     codeFoldingUpdate = codeFoldingUpdate | retVal_folding;
01229 
01230     // need we to continue ?
01231     stillcontinue = ctxChanged || indentChanged || indentContinueWhitespace || indentContinueNextWhitespace;
01232 
01233     // move around the lines
01234     prevLine = textLine;
01235 
01236     // increment line
01237     current_line++;
01238   }
01239 
01240   buf->markDirty ();
01241 
01242   // tag the changed lines !
01243   if (invalidate)
01244     emit tagLines (startLine, current_line + buf->startLine());
01245 
01246   // emit that we have changed the folding
01247   if (codeFoldingUpdate)
01248     emit codeFoldingUpdated();
01249 
01250   //kdDebug (13020) << "HIGHLIGHTED END --- NEED HL, LINESTART: " << startLine << " LINEEND: " << endLine << endl;
01251   //kdDebug (13020) << "HL UNTIL LINE: " << m_lineHighlighted << " MAX: " << m_lineHighlightedMax << endl;
01252   //kdDebug (13020) << "HL DYN COUNT: " << KateHlManager::self()->countDynamicCtxs() << " MAX: " << m_maxDynamicContexts << endl;
01253   //kdDebug (13020) << "TIME TAKEN: " << t.elapsed() << endl;
01254 
01255   // if we are at the last line of the block + we still need to continue
01256   // return the need of that !
01257   return stillcontinue && ((current_line+1) == buf->lines());
01258 }
01259 
01260 void KateBuffer::codeFoldingColumnUpdate(unsigned int lineNr) {
01261   KateTextLine::Ptr line=plainLine(lineNr);
01262   if (!line) return;
01263   if (line->foldingColumnsOutdated()) {
01264     line->setFoldingColumnsOutdated(false);
01265     bool tmp;
01266     QMemArray<uint> folding=line->foldingListArray();
01267     m_regionTree.updateLine(lineNr,&folding,&tmp,true,false);
01268   }
01269 }
01270 
01271 //BEGIN KateBufBlock
01272 
01273 KateBufBlock::KateBufBlock ( KateBuffer *parent, KateBufBlock *prev, KateBufBlock *next,
01274                              KateFileLoader *stream )
01275 : m_state (KateBufBlock::stateDirty),
01276   m_startLine (0),
01277   m_lines (0),
01278   m_vmblock (0),
01279   m_vmblockSize (0),
01280   m_parent (parent),
01281   m_prev (prev),
01282   m_next (next),
01283   list (0),
01284   listPrev (0),
01285   listNext (0)
01286 {
01287   // init startline + the next pointers of the neighbour blocks
01288   if (m_prev)
01289   {
01290     m_startLine = m_prev->endLine ();
01291     m_prev->m_next = this;
01292   }
01293 
01294   if (m_next)
01295     m_next->m_prev = this;
01296 
01297   // we have a stream, use it to fill the block !
01298   // this can lead to 0 line blocks which are invalid !
01299   if (stream)
01300   {
01301     // this we lead to either dirty or swapped state
01302     fillBlock (stream);
01303   }
01304   else // init the block if no stream given !
01305   {
01306     // fill in one empty line !
01307     KateTextLine::Ptr textLine = new KateTextLine ();
01308     m_stringList.push_back (textLine);
01309     m_lines++;
01310 
01311     // if we have allready enough blocks around, swap one
01312     if (m_parent->m_loadedBlocks.count() >= KateBuffer::maxLoadedBlocks())
01313       m_parent->m_loadedBlocks.first()->swapOut();
01314 
01315     // we are a new nearly empty dirty block
01316     m_state = KateBufBlock::stateDirty;
01317     m_parent->m_loadedBlocks.append (this);
01318   }
01319 }
01320 
01321 KateBufBlock::~KateBufBlock ()
01322 {
01323   // sync prev/next pointers
01324   if (m_prev)
01325     m_prev->m_next = m_next;
01326 
01327   if (m_next)
01328     m_next->m_prev = m_prev;
01329 
01330   // if we have some swapped data allocated, free it now or never
01331   if (m_vmblock)
01332     KateFactory::self()->vm()->free(m_vmblock);
01333 
01334   // remove me from the list I belong
01335   KateBufBlockList::remove (this);
01336 }
01337 
01338 void KateBufBlock::fillBlock (KateFileLoader *stream)
01339 {
01340   // is allready too much stuff around in mem ?
01341   bool swap = m_parent->m_loadedBlocks.count() >= KateBuffer::maxLoadedBlocks();
01342 
01343   QByteArray rawData;
01344 
01345   // calcs the approx size for KATE_AVG_BLOCK_SIZE chars !
01346   if (swap)
01347     rawData.resize ((KATE_AVG_BLOCK_SIZE * sizeof(QChar)) + ((KATE_AVG_BLOCK_SIZE/80) * 8));
01348 
01349   char *buf = rawData.data ();
01350   uint size = 0;
01351   uint blockSize = 0;
01352   while (!stream->eof() && (blockSize < KATE_AVG_BLOCK_SIZE) && (m_lines < KATE_MAX_BLOCK_LINES))
01353   {
01354     uint offset = 0, length = 0;
01355     stream->readLine(offset, length);
01356     const QChar *unicodeData = stream->unicode () + offset;
01357 
01358     // strip spaces at end of line
01359     if ( stream->removeTrailingSpaces() )
01360     {
01361       while (length > 0)
01362       {
01363         if (unicodeData[length-1].isSpace())
01364           --length;
01365         else
01366           break;
01367       }
01368     }
01369 
01370     blockSize += length;
01371 
01372     if (swap)
01373     {
01374       // create the swapped data on the fly, no need to waste time
01375       // via going over the textline classes and dump them !
01376       char attr = KateTextLine::flagNoOtherData;
01377       uint pos = size;
01378 
01379       // calc new size
01380       size = size + 1 + sizeof(uint) + (sizeof(QChar)*length);
01381 
01382       if (size > rawData.size ())
01383       {
01384         rawData.resize (size);
01385         buf = rawData.data ();
01386       }
01387 
01388       memcpy(buf+pos, (char *) &attr, 1);
01389       pos += 1;
01390 
01391       memcpy(buf+pos, (char *) &length, sizeof(uint));
01392       pos += sizeof(uint);
01393 
01394       memcpy(buf+pos, (char *) unicodeData, sizeof(QChar)*length);
01395       pos += sizeof(QChar)*length;
01396     }
01397     else
01398     {
01399       KateTextLine::Ptr textLine = new KateTextLine ();
01400       textLine->insertText (0, length, unicodeData);
01401       m_stringList.push_back (textLine);
01402     }
01403 
01404     m_lines++;
01405   }
01406 
01407   if (swap)
01408   {
01409     m_vmblock = KateFactory::self()->vm()->allocate(size);
01410     m_vmblockSize = size;
01411 
01412     if (!rawData.isEmpty())
01413     {
01414       if (!KateFactory::self()->vm()->copyBlock(m_vmblock, rawData.data(), 0, size))
01415       {
01416         if (m_vmblock)
01417           KateFactory::self()->vm()->free(m_vmblock);
01418 
01419         m_vmblock = 0;
01420         m_vmblockSize = 0;
01421 
01422         m_parent->m_cacheWriteError = true;
01423       }
01424     }
01425 
01426     // fine, we are swapped !
01427     m_state = KateBufBlock::stateSwapped;
01428   }
01429   else
01430   {
01431     // we are a new dirty block without any swap data
01432     m_state = KateBufBlock::stateDirty;
01433     m_parent->m_loadedBlocks.append (this);
01434   }
01435 
01436   kdDebug (13020) << "A BLOCK LOADED WITH LINES: " << m_lines << endl;
01437 }
01438 
01439 KateTextLine::Ptr KateBufBlock::line(uint i)
01440 {
01441   // take care that the string list is around !!!
01442   if (m_state == KateBufBlock::stateSwapped)
01443     swapIn ();
01444 
01445   // LRU
01446   if (!m_parent->m_loadedBlocks.isLast(this))
01447     m_parent->m_loadedBlocks.append (this);
01448 
01449   return m_stringList[i];
01450 }
01451 
01452 void KateBufBlock::insertLine(uint i, KateTextLine::Ptr line)
01453 {
01454   // take care that the string list is around !!!
01455   if (m_state == KateBufBlock::stateSwapped)
01456     swapIn ();
01457 
01458   m_stringList.insert (m_stringList.begin()+i, line);
01459   m_lines++;
01460 
01461   markDirty ();
01462 }
01463 
01464 void KateBufBlock::removeLine(uint i)
01465 {
01466   // take care that the string list is around !!!
01467   if (m_state == KateBufBlock::stateSwapped)
01468     swapIn ();
01469 
01470   m_stringList.erase (m_stringList.begin()+i);
01471   m_lines--;
01472 
01473   markDirty ();
01474 }
01475 
01476 void KateBufBlock::markDirty ()
01477 {
01478   if (m_state != KateBufBlock::stateSwapped)
01479   {
01480     // LRU
01481     if (!m_parent->m_loadedBlocks.isLast(this))
01482       m_parent->m_loadedBlocks.append (this);
01483 
01484     if (m_state == KateBufBlock::stateClean)
01485     {
01486       // if we have some swapped data allocated which is dirty, free it now
01487       if (m_vmblock)
01488         KateFactory::self()->vm()->free(m_vmblock);
01489 
01490       m_vmblock = 0;
01491       m_vmblockSize = 0;
01492 
01493       // we are dirty
01494       m_state = KateBufBlock::stateDirty;
01495     }
01496   }
01497 }
01498 
01499 void KateBufBlock::swapIn ()
01500 {
01501   if (m_state != KateBufBlock::stateSwapped)
01502     return;
01503 
01504   QByteArray rawData (m_vmblockSize);
01505 
01506   // what to do if that fails ?
01507   if (!KateFactory::self()->vm()->copyBlock(rawData.data(), m_vmblock, 0, rawData.size()))
01508     m_parent->m_cacheReadError = true;
01509 
01510   // reserve mem, keep realloc away on push_back
01511   m_stringList.reserve (m_lines);
01512 
01513   char *buf = rawData.data();
01514   for (uint i=0; i < m_lines; i++)
01515   {
01516     KateTextLine::Ptr textLine = new KateTextLine ();
01517     buf = textLine->restore (buf);
01518     m_stringList.push_back (textLine);
01519   }
01520 
01521   // if we have allready enough blocks around, swap one
01522   if (m_parent->m_loadedBlocks.count() >= KateBuffer::maxLoadedBlocks())
01523     m_parent->m_loadedBlocks.first()->swapOut();
01524 
01525   // fine, we are now clean again, save state + append to clean list
01526   m_state = KateBufBlock::stateClean;
01527   m_parent->m_loadedBlocks.append (this);
01528 }
01529 
01530 void KateBufBlock::swapOut ()
01531 {
01532   if (m_state == KateBufBlock::stateSwapped)
01533     return;
01534 
01535   if (m_state == KateBufBlock::stateDirty)
01536   {
01537     bool haveHl = m_parent->m_highlight && !m_parent->m_highlight->noHighlighting();
01538 
01539     // Calculate size.
01540     uint size = 0;
01541     for (uint i=0; i < m_lines; i++)
01542       size += m_stringList[i]->dumpSize (haveHl);
01543 
01544     QByteArray rawData (size);
01545     char *buf = rawData.data();
01546 
01547     // Dump textlines
01548     for (uint i=0; i < m_lines; i++)
01549       buf = m_stringList[i]->dump (buf, haveHl);
01550 
01551     m_vmblock = KateFactory::self()->vm()->allocate(rawData.size());
01552     m_vmblockSize = rawData.size();
01553 
01554     if (!rawData.isEmpty())
01555     {
01556       if (!KateFactory::self()->vm()->copyBlock(m_vmblock, rawData.data(), 0, rawData.size()))
01557       {
01558         if (m_vmblock)
01559           KateFactory::self()->vm()->free(m_vmblock);
01560 
01561         m_vmblock = 0;
01562         m_vmblockSize = 0;
01563 
01564         m_parent->m_cacheWriteError = true;
01565 
01566         return;
01567       }
01568     }
01569   }
01570 
01571   m_stringList.clear();
01572 
01573   // we are now swapped out, set state + remove us out of the lists !
01574   m_state = KateBufBlock::stateSwapped;
01575   KateBufBlockList::remove (this);
01576 }
01577 
01578 //END KateBufBlock
01579 
01580 //BEGIN KateBufBlockList
01581 
01582 KateBufBlockList::KateBufBlockList ()
01583  : m_count (0),
01584    m_first (0),
01585    m_last (0)
01586 {
01587 }
01588 
01589 void KateBufBlockList::append (KateBufBlock *buf)
01590 {
01591   if (buf->list)
01592     buf->list->removeInternal (buf);
01593 
01594   m_count++;
01595 
01596   // append a element
01597   if (m_last)
01598   {
01599     m_last->listNext = buf;
01600 
01601     buf->listPrev = m_last;
01602     buf->listNext = 0;
01603 
01604     m_last = buf;
01605 
01606     buf->list = this;
01607 
01608     return;
01609   }
01610 
01611   // insert the first element
01612   m_last = buf;
01613   m_first = buf;
01614 
01615   buf->listPrev = 0;
01616   buf->listNext = 0;
01617 
01618   buf->list = this;
01619 }
01620 
01621 void KateBufBlockList::removeInternal (KateBufBlock *buf)
01622 {
01623   if (buf->list != this)
01624     return;
01625 
01626   m_count--;
01627 
01628   if ((buf == m_first) && (buf == m_last))
01629   {
01630     // last element removed !
01631     m_first = 0;
01632     m_last = 0;
01633   }
01634   else if (buf == m_first)
01635   {
01636     // first element removed
01637     m_first = buf->listNext;
01638     m_first->listPrev = 0;
01639   }
01640   else if (buf == m_last)
01641   {
01642     // last element removed
01643     m_last = buf->listPrev;
01644     m_last->listNext = 0;
01645   }
01646   else
01647   {
01648     buf->listPrev->listNext = buf->listNext;
01649     buf->listNext->listPrev = buf->listPrev;
01650   }
01651 
01652   buf->listPrev = 0;
01653   buf->listNext = 0;
01654 
01655   buf->list = 0;
01656 }
01657 
01658 //END KateBufBlockList
01659 
01660 // kate: space-indent on; indent-width 2; replace-tabs on;

Kate

Skip menu "Kate"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal