summaryrefslogtreecommitdiffstats
path: root/kate/part/katebuffer.cpp
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commitce4a32fe52ef09d8f5ff1dd22c001110902b60a2 (patch)
tree5ac38a06f3dde268dc7927dc155896926aaf7012 /kate/part/katebuffer.cpp
downloadtdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.tar.gz
tdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdelibs@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kate/part/katebuffer.cpp')
-rw-r--r--kate/part/katebuffer.cpp1660
1 files changed, 1660 insertions, 0 deletions
diff --git a/kate/part/katebuffer.cpp b/kate/part/katebuffer.cpp
new file mode 100644
index 000000000..06c919f96
--- /dev/null
+++ b/kate/part/katebuffer.cpp
@@ -0,0 +1,1660 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 2000 Waldo Bastian <bastian@kde.org>
+ Copyright (C) 2002-2004 Christoph Cullmann <cullmann@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "katebuffer.h"
+#include "katebuffer.moc"
+
+#include "katedocument.h"
+#include "katehighlight.h"
+#include "kateconfig.h"
+#include "katefactory.h"
+#include "kateautoindent.h"
+
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kcharsets.h>
+
+#include <qpopupmenu.h>
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qtimer.h>
+#include <qtextcodec.h>
+#include <qcstring.h>
+#include <qdatetime.h>
+
+/**
+ * loader block size, load 256 kb at once per default
+ * if file size is smaller, fall back to file size
+ */
+static const Q_ULONG KATE_FILE_LOADER_BS = 256 * 1024;
+
+/**
+ * KATE_AVG_BLOCK_SIZE is in characters !
+ * (internaly we calc with approx 80 chars per line !)
+ * block will max contain around BLOCK_SIZE chars or
+ * BLOCK_LINES lines (after load, later that won't be tracked)
+ */
+static const Q_ULONG KATE_AVG_BLOCK_SIZE = 2048 * 80;
+static const Q_ULONG KATE_MAX_BLOCK_LINES = 2048;
+
+/**
+ * hl will look at the next KATE_HL_LOOKAHEAD lines
+ * or until the current block ends if a line is requested
+ * will avoid to run doHighlight too often
+ */
+static const uint KATE_HL_LOOKAHEAD = 64;
+
+/**
+ * KATE_MAX_BLOCKS_LOADED should be at least 4, as some
+ * methodes will cause heavy trashing, if not at least the
+ * latest 2-3 used blocks are alive
+ */
+uint KateBuffer::m_maxLoadedBlocks = 16;
+
+/**
+ * Initial value for m_maxDynamicContexts
+ */
+static const uint KATE_MAX_DYNAMIC_CONTEXTS = 512;
+
+void KateBuffer::setMaxLoadedBlocks (uint count)
+{
+ m_maxLoadedBlocks = kMax (4U, count);
+}
+
+class KateFileLoader
+{
+ public:
+ KateFileLoader (const QString &filename, QTextCodec *codec, bool removeTrailingSpaces)
+ : m_file (filename)
+ , m_buffer (kMin (m_file.size(), KATE_FILE_LOADER_BS))
+ , m_codec (codec)
+ , m_decoder (m_codec->makeDecoder())
+ , m_position (0)
+ , m_lastLineStart (0)
+ , m_eof (false) // default to not eof
+ , lastWasEndOfLine (true) // at start of file, we had a virtual newline
+ , lastWasR (false) // we have not found a \r as last char
+ , m_eol (-1) // no eol type detected atm
+ , m_twoByteEncoding (QString(codec->name()) == "ISO-10646-UCS-2")
+ , m_binary (false)
+ , m_removeTrailingSpaces (removeTrailingSpaces)
+ {
+ kdDebug (13020) << "OPEN USES ENCODING: " << m_codec->name() << endl;
+ }
+
+ ~KateFileLoader ()
+ {
+ delete m_decoder;
+ }
+
+ /**
+ * open file, read first chunk of data, detect eol
+ */
+ bool open ()
+ {
+ if (m_file.open (IO_ReadOnly))
+ {
+ int c = m_file.readBlock (m_buffer.data(), m_buffer.size());
+
+ if (c > 0)
+ {
+ // fix utf16 LE, stolen from khtml ;)
+ if ((c >= 2) && (m_codec->mibEnum() == 1000) && (m_buffer[1] == 0x00))
+ {
+ // utf16LE, we need to put the decoder in LE mode
+ char reverseUtf16[3] = {0xFF, 0xFE, 0x00};
+ m_decoder->toUnicode(reverseUtf16, 2);
+ }
+
+ processNull (c);
+ m_text = m_decoder->toUnicode (m_buffer, c);
+ }
+
+ m_eof = (c == -1) || (c == 0) || (m_text.length() == 0) || m_file.atEnd();
+
+ for (uint i=0; i < m_text.length(); i++)
+ {
+ if (m_text[i] == '\n')
+ {
+ m_eol = KateDocumentConfig::eolUnix;
+ break;
+ }
+ else if ((m_text[i] == '\r'))
+ {
+ if (((i+1) < m_text.length()) && (m_text[i+1] == '\n'))
+ {
+ m_eol = KateDocumentConfig::eolDos;
+ break;
+ }
+ else
+ {
+ m_eol = KateDocumentConfig::eolMac;
+ break;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ // no new lines around ?
+ inline bool eof () const { return m_eof && !lastWasEndOfLine && (m_lastLineStart == m_text.length()); }
+
+ // eol mode ? autodetected on open(), -1 for no eol found in the first block!
+ inline int eol () const { return m_eol; }
+
+ // binary ?
+ inline bool binary () const { return m_binary; }
+
+ // should spaces be ignored at end of line?
+ inline bool removeTrailingSpaces () const { return m_removeTrailingSpaces; }
+
+ // internal unicode data array
+ inline const QChar *unicode () const { return m_text.unicode(); }
+
+ // read a line, return length + offset in unicode data
+ void readLine (uint &offset, uint &length)
+ {
+ length = 0;
+ offset = 0;
+
+ while (m_position <= m_text.length())
+ {
+ if (m_position == m_text.length())
+ {
+ // try to load more text if something is around
+ if (!m_eof)
+ {
+ int c = m_file.readBlock (m_buffer.data(), m_buffer.size());
+
+ uint readString = 0;
+ if (c > 0)
+ {
+ processNull (c);
+
+ QString str (m_decoder->toUnicode (m_buffer, c));
+ readString = str.length();
+
+ m_text = m_text.mid (m_lastLineStart, m_position-m_lastLineStart)
+ + str;
+ }
+ else
+ m_text = m_text.mid (m_lastLineStart, m_position-m_lastLineStart);
+
+ // is file completly read ?
+ m_eof = (c == -1) || (c == 0) || (readString == 0) || m_file.atEnd();
+
+ // recalc current pos and last pos
+ m_position -= m_lastLineStart;
+ m_lastLineStart = 0;
+ }
+
+ // oh oh, end of file, escape !
+ if (m_eof && (m_position == m_text.length()))
+ {
+ lastWasEndOfLine = false;
+
+ // line data
+ offset = m_lastLineStart;
+ length = m_position-m_lastLineStart;
+
+ m_lastLineStart = m_position;
+
+ return;
+ }
+ }
+
+ if (m_text[m_position] == '\n')
+ {
+ lastWasEndOfLine = true;
+
+ if (lastWasR)
+ {
+ m_lastLineStart++;
+ lastWasR = false;
+ }
+ else
+ {
+ // line data
+ offset = m_lastLineStart;
+ length = m_position-m_lastLineStart;
+
+ m_lastLineStart = m_position+1;
+ m_position++;
+
+ return;
+ }
+ }
+ else if (m_text[m_position] == '\r')
+ {
+ lastWasEndOfLine = true;
+ lastWasR = true;
+
+ // line data
+ offset = m_lastLineStart;
+ length = m_position-m_lastLineStart;
+
+ m_lastLineStart = m_position+1;
+ m_position++;
+
+ return;
+ }
+ else
+ {
+ lastWasEndOfLine = false;
+ lastWasR = false;
+ }
+
+ m_position++;
+ }
+ }
+
+ // this nice methode will kill all 0 bytes (or double bytes)
+ // and remember if this was a binary or not ;)
+ void processNull (uint length)
+ {
+ if (m_twoByteEncoding)
+ {
+ for (uint i=1; i < length; i+=2)
+ {
+ if ((m_buffer[i] == 0) && (m_buffer[i-1] == 0))
+ {
+ m_binary = true;
+ m_buffer[i] = ' ';
+ }
+ }
+ }
+ else
+ {
+ for (uint i=0; i < length; i++)
+ {
+ if (m_buffer[i] == 0)
+ {
+ m_binary = true;
+ m_buffer[i] = ' ';
+ }
+ }
+ }
+ }
+
+ private:
+ QFile m_file;
+ QByteArray m_buffer;
+ QTextCodec *m_codec;
+ QTextDecoder *m_decoder;
+ QString m_text;
+ uint m_position;
+ uint m_lastLineStart;
+ bool m_eof;
+ bool lastWasEndOfLine;
+ bool lastWasR;
+ int m_eol;
+ bool m_twoByteEncoding;
+ bool m_binary;
+ bool m_removeTrailingSpaces;
+};
+
+/**
+ * Create an empty buffer. (with one block with one empty line)
+ */
+KateBuffer::KateBuffer(KateDocument *doc)
+ : QObject (doc),
+ editSessionNumber (0),
+ editIsRunning (false),
+ editTagLineStart (0xffffffff),
+ editTagLineEnd (0),
+ editTagLineFrom (false),
+ editChangesDone (false),
+ m_doc (doc),
+ m_lines (0),
+ m_lastInSyncBlock (0),
+ m_lastFoundBlock (0),
+ m_cacheReadError(false),
+ m_cacheWriteError(false),
+ m_loadingBorked (false),
+ m_binary (false),
+ m_highlight (0),
+ m_regionTree (this),
+ m_tabWidth (8),
+ m_lineHighlightedMax (0),
+ m_lineHighlighted (0),
+ m_maxDynamicContexts (KATE_MAX_DYNAMIC_CONTEXTS)
+{
+ clear();
+}
+
+/**
+ * Cleanup on destruction
+ */
+KateBuffer::~KateBuffer()
+{
+ // DELETE ALL BLOCKS, will free mem
+ for (uint i=0; i < m_blocks.size(); i++)
+ delete m_blocks[i];
+
+ // release HL
+ if (m_highlight)
+ m_highlight->release();
+}
+
+void KateBuffer::editStart ()
+{
+ editSessionNumber++;
+
+ if (editSessionNumber > 1)
+ return;
+
+ editIsRunning = true;
+
+ editTagLineStart = 0xffffffff;
+ editTagLineEnd = 0;
+ editTagLineFrom = false;
+
+ editChangesDone = false;
+}
+
+void KateBuffer::editEnd ()
+{
+ if (editSessionNumber == 0)
+ return;
+
+ editSessionNumber--;
+
+ if (editSessionNumber > 0)
+ return;
+
+ if (editChangesDone)
+ {
+ // hl update !!!
+ if ( m_highlight && !m_highlight->noHighlighting()
+ && (editTagLineStart <= editTagLineEnd)
+ && (editTagLineEnd <= m_lineHighlighted))
+ {
+ // look one line too far, needed for linecontinue stuff
+ editTagLineEnd++;
+
+ // look one line before, needed nearly 100% only for indentation based folding !
+ if (editTagLineStart > 0)
+ editTagLineStart--;
+
+ KateBufBlock *buf2 = 0;
+ bool needContinue = false;
+ while ((buf2 = findBlock(editTagLineStart)))
+ {
+ needContinue = doHighlight (buf2,
+ (editTagLineStart > buf2->startLine()) ? editTagLineStart : buf2->startLine(),
+ (editTagLineEnd > buf2->endLine()) ? buf2->endLine() : editTagLineEnd,
+ true);
+
+ editTagLineStart = (editTagLineEnd > buf2->endLine()) ? buf2->endLine() : editTagLineEnd;
+
+ if ((editTagLineStart >= m_lines) || (editTagLineStart >= editTagLineEnd))
+ break;
+ }
+
+ if (needContinue)
+ m_lineHighlighted = editTagLineStart;
+
+ if (editTagLineStart > m_lineHighlightedMax)
+ m_lineHighlightedMax = editTagLineStart;
+ }
+ else if (editTagLineStart < m_lineHighlightedMax)
+ m_lineHighlightedMax = editTagLineStart;
+ }
+
+ editIsRunning = false;
+}
+
+void KateBuffer::clear()
+{
+ m_regionTree.clear();
+
+ // cleanup the blocks
+ for (uint i=0; i < m_blocks.size(); i++)
+ delete m_blocks[i];
+
+ m_blocks.clear ();
+
+ // create a bufblock with one line, we need that, only in openFile we won't have that
+ KateBufBlock *block = new KateBufBlock(this, 0, 0);
+ m_blocks.append (block);
+
+ // reset the state
+ m_lines = block->lines();
+ m_lastInSyncBlock = 0;
+ m_lastFoundBlock = 0;
+ m_cacheWriteError = false;
+ m_cacheReadError = false;
+ m_loadingBorked = false;
+ m_binary = false;
+
+ m_lineHighlightedMax = 0;
+ m_lineHighlighted = 0;
+}
+
+bool KateBuffer::openFile (const QString &m_file)
+{
+ KateFileLoader file (m_file, m_doc->config()->codec(), m_doc->configFlags() & KateDocument::cfRemoveSpaces);
+
+ bool ok = false;
+ struct stat sbuf;
+ if (stat(QFile::encodeName(m_file), &sbuf) == 0)
+ {
+ if (S_ISREG(sbuf.st_mode) && file.open())
+ ok = true;
+ }
+
+ if (!ok)
+ {
+ clear();
+ return false; // Error
+ }
+
+ // set eol mode, if a eol char was found in the first 256kb block and we allow this at all!
+ if (m_doc->config()->allowEolDetection() && (file.eol() != -1))
+ m_doc->config()->setEol (file.eol());
+
+ // flush current content
+ clear ();
+
+ // cleanup the blocks
+ for (uint i=0; i < m_blocks.size(); i++)
+ delete m_blocks[i];
+
+ m_blocks.clear ();
+
+ // do the real work
+ KateBufBlock *block = 0;
+ m_lines = 0;
+ while (!file.eof() && !m_cacheWriteError)
+ {
+ block = new KateBufBlock (this, block, 0, &file);
+
+ m_lines = block->endLine ();
+
+ if (m_cacheWriteError || (block->lines() == 0))
+ {
+ delete block;
+ break;
+ }
+ else
+ m_blocks.append (block);
+ }
+
+ // we had a cache write error, this load is really borked !
+ if (m_cacheWriteError)
+ m_loadingBorked = true;
+
+ if (m_blocks.isEmpty() || (m_lines == 0))
+ {
+ // file was really empty, clean the buffers + emit the line changed
+ // loadingBorked will be false for such files, not matter what happened
+ // before
+ clear ();
+ }
+ else
+ {
+ // fix region tree
+ m_regionTree.fixRoot (m_lines);
+ }
+
+ // if we have no hl or the "None" hl activated, whole file is correct highlighted
+ // after loading, which wonder ;)
+ if (!m_highlight || m_highlight->noHighlighting())
+ {
+ m_lineHighlighted = m_lines;
+ m_lineHighlightedMax = m_lines;
+ }
+
+ // binary?
+ m_binary = file.binary ();
+
+ kdDebug (13020) << "LOADING DONE" << endl;
+
+ return !m_loadingBorked;
+}
+
+bool KateBuffer::canEncode ()
+{
+ QTextCodec *codec = m_doc->config()->codec();
+
+ kdDebug(13020) << "ENC NAME: " << codec->name() << endl;
+
+ // hardcode some unicode encodings which can encode all chars
+ if ((QString(codec->name()) == "UTF-8") || (QString(codec->name()) == "ISO-10646-UCS-2"))
+ return true;
+
+ for (uint i=0; i < m_lines; i++)
+ {
+ if (!codec->canEncode (plainLine(i)->string()))
+ {
+ kdDebug(13020) << "STRING LINE: " << plainLine(i)->string() << endl;
+ kdDebug(13020) << "ENC WORKING: FALSE" << endl;
+
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool KateBuffer::saveFile (const QString &m_file)
+{
+ QFile file (m_file);
+ QTextStream stream (&file);
+
+ if ( !file.open( IO_WriteOnly ) )
+ {
+ return false; // Error
+ }
+
+ QTextCodec *codec = m_doc->config()->codec();
+
+ // disable Unicode headers
+ stream.setEncoding(QTextStream::RawUnicode);
+
+ // this line sets the mapper to the correct codec
+ stream.setCodec(codec);
+
+ // our loved eol string ;)
+ QString eol = m_doc->config()->eolString ();
+
+ // should we strip spaces?
+ bool removeTrailingSpaces = m_doc->configFlags() & KateDocument::cfRemoveSpaces;
+
+ // just dump the lines out ;)
+ for (uint i=0; i < m_lines; i++)
+ {
+ KateTextLine::Ptr textline = plainLine(i);
+
+ // strip spaces
+ if (removeTrailingSpaces)
+ {
+ int lastChar = textline->lastChar();
+
+ if (lastChar > -1)
+ {
+ stream << QConstString (textline->text(), lastChar+1).string();
+ }
+ }
+ else // simple, dump the line
+ stream << textline->string();
+
+ if ((i+1) < m_lines)
+ stream << eol;
+ }
+
+ file.close ();
+
+ m_loadingBorked = false;
+
+ return (file.status() == IO_Ok);
+}
+
+KateTextLine::Ptr KateBuffer::line_internal (KateBufBlock *buf, uint i)
+{
+ // update hl until this line + max KATE_HL_LOOKAHEAD
+ KateBufBlock *buf2 = 0;
+ while ((i >= m_lineHighlighted) && (buf2 = findBlock(m_lineHighlighted)))
+ {
+ uint end = kMin(i + KATE_HL_LOOKAHEAD, buf2->endLine());
+
+ doHighlight ( buf2,
+ kMax(m_lineHighlighted, buf2->startLine()),
+ end,
+ false );
+
+ m_lineHighlighted = end;
+ }
+
+ // update hl max
+ if (m_lineHighlighted > m_lineHighlightedMax)
+ m_lineHighlightedMax = m_lineHighlighted;
+
+ return buf->line (i - buf->startLine());
+}
+
+KateBufBlock *KateBuffer::findBlock_internal (uint i, uint *index)
+{
+ uint lastLine = m_blocks[m_lastInSyncBlock]->endLine ();
+
+ if (lastLine > i) // we are in a allready known area !
+ {
+ while (true)
+ {
+ KateBufBlock *buf = m_blocks[m_lastFoundBlock];
+
+ if ( (buf->startLine() <= i)
+ && (buf->endLine() > i) )
+ {
+ if (index)
+ (*index) = m_lastFoundBlock;
+
+ return m_blocks[m_lastFoundBlock];
+ }
+
+ if (i < buf->startLine())
+ m_lastFoundBlock--;
+ else
+ m_lastFoundBlock++;
+ }
+ }
+ else // we need first to resync the startLines !
+ {
+ if ((m_lastInSyncBlock+1) < m_blocks.size())
+ m_lastInSyncBlock++;
+ else
+ return 0;
+
+ for (; m_lastInSyncBlock < m_blocks.size(); m_lastInSyncBlock++)
+ {
+ // get next block
+ KateBufBlock *buf = m_blocks[m_lastInSyncBlock];
+
+ // sync startLine !
+ buf->setStartLine (lastLine);
+
+ // is it allready the searched block ?
+ if ((i >= lastLine) && (i < buf->endLine()))
+ {
+ // remember this block as last found !
+ m_lastFoundBlock = m_lastInSyncBlock;
+
+ if (index)
+ (*index) = m_lastFoundBlock;
+
+ return buf;
+ }
+
+ // increase lastLine with blocklinecount
+ lastLine += buf->lines ();
+ }
+ }
+
+ // no block found !
+ // index will not be set to any useful value in this case !
+ return 0;
+}
+
+void KateBuffer::changeLine(uint i)
+{
+ KateBufBlock *buf = findBlock(i);
+
+ if (!buf)
+ return;
+
+ // mark this block dirty
+ buf->markDirty ();
+
+ // mark buffer changed
+ editChangesDone = true;
+
+ // tag this line as changed
+ if (i < editTagLineStart)
+ editTagLineStart = i;
+
+ if (i > editTagLineEnd)
+ editTagLineEnd = i;
+}
+
+void KateBuffer::insertLine(uint i, KateTextLine::Ptr line)
+{
+ uint index = 0;
+ KateBufBlock *buf;
+ if (i == m_lines)
+ buf = findBlock(i-1, &index);
+ else
+ buf = findBlock(i, &index);
+
+ if (!buf)
+ return;
+
+ buf->insertLine(i - buf->startLine(), line);
+
+ if (m_lineHighlightedMax > i)
+ m_lineHighlightedMax++;
+
+ if (m_lineHighlighted > i)
+ m_lineHighlighted++;
+
+ m_lines++;
+
+ // last sync block adjust
+ if (m_lastInSyncBlock > index)
+ m_lastInSyncBlock = index;
+
+ // last found
+ if (m_lastInSyncBlock < m_lastFoundBlock)
+ m_lastFoundBlock = m_lastInSyncBlock;
+
+ // mark buffer changed
+ editChangesDone = true;
+
+ // tag this line as inserted
+ if (i < editTagLineStart)
+ editTagLineStart = i;
+
+ if (i <= editTagLineEnd)
+ editTagLineEnd++;
+
+ if (i > editTagLineEnd)
+ editTagLineEnd = i;
+
+ // line inserted
+ editTagLineFrom = true;
+
+ m_regionTree.lineHasBeenInserted (i);
+}
+
+void KateBuffer::removeLine(uint i)
+{
+ uint index = 0;
+ KateBufBlock *buf = findBlock(i, &index);
+
+ if (!buf)
+ return;
+
+ buf->removeLine(i - buf->startLine());
+
+ if (m_lineHighlightedMax > i)
+ m_lineHighlightedMax--;
+
+ if (m_lineHighlighted > i)
+ m_lineHighlighted--;
+
+ m_lines--;
+
+ // trash away a empty block
+ if (buf->lines() == 0)
+ {
+ // we need to change which block is last in sync
+ if (m_lastInSyncBlock >= index)
+ {
+ m_lastInSyncBlock = index;
+
+ if (buf->next())
+ {
+ if (buf->prev())
+ buf->next()->setStartLine (buf->prev()->endLine());
+ else
+ buf->next()->setStartLine (0);
+ }
+ }
+
+ // cu block !
+ delete buf;
+ m_blocks.erase (m_blocks.begin()+index);
+
+ // make sure we don't keep a pointer to the deleted block
+ if( m_lastInSyncBlock >= index )
+ m_lastInSyncBlock = index - 1;
+ }
+ else
+ {
+ // last sync block adjust
+ if (m_lastInSyncBlock > index)
+ m_lastInSyncBlock = index;
+ }
+
+ // last found
+ if (m_lastInSyncBlock < m_lastFoundBlock)
+ m_lastFoundBlock = m_lastInSyncBlock;
+
+ // mark buffer changed
+ editChangesDone = true;
+
+ // tag this line as removed
+ if (i < editTagLineStart)
+ editTagLineStart = i;
+
+ if (i < editTagLineEnd)
+ editTagLineEnd--;
+
+ if (i > editTagLineEnd)
+ editTagLineEnd = i;
+
+ // line removed
+ editTagLineFrom = true;
+
+ m_regionTree.lineHasBeenRemoved (i);
+}
+
+void KateBuffer::setTabWidth (uint w)
+{
+ if ((m_tabWidth != w) && (m_tabWidth > 0))
+ {
+ m_tabWidth = w;
+
+ if (m_highlight && m_highlight->foldingIndentationSensitive())
+ invalidateHighlighting();
+ }
+}
+
+void KateBuffer::setHighlight(uint hlMode)
+{
+ KateHighlighting *h = KateHlManager::self()->getHl(hlMode);
+
+ // aha, hl will change
+ if (h != m_highlight)
+ {
+ bool invalidate = !h->noHighlighting();
+
+ if (m_highlight)
+ {
+ m_highlight->release();
+ invalidate = true;
+ }
+
+ h->use();
+
+ // Clear code folding tree (see bug #124102)
+ m_regionTree.clear();
+ m_regionTree.fixRoot(m_lines);
+
+ // try to set indentation
+ if (!h->indentation().isEmpty())
+ m_doc->config()->setIndentationMode (KateAutoIndent::modeNumber(h->indentation()));
+
+ m_highlight = h;
+
+ if (invalidate)
+ invalidateHighlighting();
+
+ // inform the document that the hl was really changed
+ // needed to update attributes and more ;)
+ m_doc->bufferHlChanged ();
+ }
+}
+
+void KateBuffer::invalidateHighlighting()
+{
+ m_lineHighlightedMax = 0;
+ m_lineHighlighted = 0;
+}
+
+
+void KateBuffer::updatePreviousNotEmptyLine(KateBufBlock *blk,uint current_line,bool addindent,uint deindent)
+{
+ KateTextLine::Ptr textLine;
+ do {
+ if (current_line>0) current_line--;
+ else
+ {
+ uint line=blk->startLine()+current_line;
+ if (line==0) return;
+ line--;
+ blk=findBlock(line);
+ if (!blk) {
+ kdDebug(13020)<<"updatePreviousNotEmptyLine: block not found, this must not happen"<<endl;
+ return;
+ }
+ current_line=line-blk->startLine();
+ }
+ textLine = blk->line(current_line);
+ } while (textLine->firstChar()==-1);
+ kdDebug(13020)<<"updatePreviousNotEmptyLine: updating line:"<<(blk->startLine()+current_line)<<endl;
+ QMemArray<uint> foldingList=textLine->foldingListArray();
+ while ( (foldingList.size()>0) && ( abs(foldingList[foldingList.size()-2])==1)) {
+ foldingList.resize(foldingList.size()-2,QGArray::SpeedOptim);
+ }
+ addIndentBasedFoldingInformation(foldingList,addindent,deindent);
+ textLine->setFoldingList(foldingList);
+ bool retVal_folding = false;
+ m_regionTree.updateLine (current_line + blk->startLine(), &foldingList, &retVal_folding, true,false);
+ emit tagLines (blk->startLine()+current_line, blk->startLine()+current_line);
+}
+
+void KateBuffer::addIndentBasedFoldingInformation(QMemArray<uint> &foldingList,bool addindent,uint deindent)
+{
+ if (addindent) {
+ //kdDebug(13020)<<"adding indent for line :"<<current_line + buf->startLine()<<" textLine->noIndentBasedFoldingAtStart"<<textLine->noIndentBasedFoldingAtStart()<<endl;
+ kdDebug(13020)<<"adding ident"<<endl;
+ foldingList.resize (foldingList.size() + 2, QGArray::SpeedOptim);
+ foldingList[foldingList.size()-2] = 1;
+ foldingList[foldingList.size()-1] = 0;
+ }
+ kdDebug(13020)<<"DEINDENT: "<<deindent<<endl;
+ if (deindent > 0)
+ {
+ foldingList.resize (foldingList.size() + (deindent*2), QGArray::SpeedOptim);
+
+ for (uint z= foldingList.size()-(deindent*2); z < foldingList.size(); z=z+2)
+ {
+ foldingList[z] = -1;
+ foldingList[z+1] = 0;
+ }
+ }
+}
+
+bool KateBuffer::doHighlight (KateBufBlock *buf, uint startLine, uint endLine, bool invalidate)
+{
+ // no hl around, no stuff to do
+ if (!m_highlight)
+ return false;
+
+ /*if (m_highlight->foldingIndentationSensitive())
+ {
+ startLine=0;
+ endLine=50;
+ }*/
+
+ // we tried to start in a line behind this buf block !
+ if (startLine >= (buf->startLine()+buf->lines()))
+ return false;
+
+ //QTime t;
+ //t.start();
+ //kdDebug (13020) << "HIGHLIGHTED START --- NEED HL, LINESTART: " << startLine << " LINEEND: " << endLine << endl;
+ //kdDebug (13020) << "HL UNTIL LINE: " << m_lineHighlighted << " MAX: " << m_lineHighlightedMax << endl;
+ //kdDebug (13020) << "HL DYN COUNT: " << KateHlManager::self()->countDynamicCtxs() << " MAX: " << m_maxDynamicContexts << endl;
+
+ // see if there are too many dynamic contexts; if yes, invalidate HL of all documents
+ if (KateHlManager::self()->countDynamicCtxs() >= m_maxDynamicContexts)
+ {
+ {
+ if (KateHlManager::self()->resetDynamicCtxs())
+ {
+ kdDebug (13020) << "HL invalidated - too many dynamic contexts ( >= " << m_maxDynamicContexts << ")" << endl;
+
+ // avoid recursive invalidation
+ KateHlManager::self()->setForceNoDCReset(true);
+
+ for (KateDocument *doc = KateFactory::self()->documents()->first(); doc; doc = KateFactory::self()->documents()->next())
+ doc->makeAttribs();
+
+ // doHighlight *shall* do his work. After invalidation, some highlight has
+ // been recalculated, but *maybe not* until endLine ! So we shall force it manually...
+ KateBufBlock *buf = 0;
+ while ((endLine > m_lineHighlighted) && (buf = findBlock(m_lineHighlighted)))
+ {
+ uint end = kMin(endLine, buf->endLine());
+
+ doHighlight ( buf,
+ kMax(m_lineHighlighted, buf->startLine()),
+ end,
+ false );
+
+ m_lineHighlighted = end;
+ }
+
+ KateHlManager::self()->setForceNoDCReset(false);
+
+ return false;
+ }
+ else
+ {
+ m_maxDynamicContexts *= 2;
+ kdDebug (13020) << "New dynamic contexts limit: " << m_maxDynamicContexts << endl;
+ }
+ }
+ }
+
+ // get the previous line, if we start at the beginning of this block
+ // take the last line of the previous block
+ KateTextLine::Ptr prevLine = 0;
+
+ if ((startLine == buf->startLine()) && buf->prev() && (buf->prev()->lines() > 0))
+ prevLine = buf->prev()->line (buf->prev()->lines() - 1);
+ else if ((startLine > buf->startLine()) && (startLine <= buf->endLine()))
+ prevLine = buf->line(startLine - buf->startLine() - 1);
+ else
+ prevLine = new KateTextLine ();
+
+ // does we need to emit a signal for the folding changes ?
+ bool codeFoldingUpdate = false;
+
+ // here we are atm, start at start line in the block
+ uint current_line = startLine - buf->startLine();
+
+ // do we need to continue
+ bool stillcontinue=false;
+ bool indentContinueWhitespace=false;
+ bool indentContinueNextWhitespace=false;
+ // loop over the lines of the block, from startline to endline or end of block
+ // if stillcontinue forces us to do so
+ while ( (current_line < buf->lines())
+ && (stillcontinue || ((current_line + buf->startLine()) <= endLine)) )
+ {
+ // current line
+ KateTextLine::Ptr textLine = buf->line(current_line);
+
+ QMemArray<uint> foldingList;
+ bool ctxChanged = false;
+
+ m_highlight->doHighlight (prevLine, textLine, &foldingList, &ctxChanged);
+
+ //
+ // indentation sensitive folding
+ //
+ bool indentChanged = false;
+ if (m_highlight->foldingIndentationSensitive())
+ {
+ // get the indentation array of the previous line to start with !
+ QMemArray<unsigned short> indentDepth;
+ indentDepth.duplicate (prevLine->indentationDepthArray());
+
+ // current indentation of this line
+ uint iDepth = textLine->indentDepth(m_tabWidth);
+ if ((current_line+buf->startLine())==0)
+ {
+ indentDepth.resize (1, QGArray::SpeedOptim);
+ indentDepth[0] = iDepth;
+ }
+
+ textLine->setNoIndentBasedFoldingAtStart(prevLine->noIndentBasedFolding());
+ // this line is empty, beside spaces, or has indentaion based folding disabled, use indentation depth of the previous line !
+ kdDebug(13020)<<"current_line:"<<current_line + buf->startLine()<<" textLine->noIndentBasedFoldingAtStart"<<textLine->noIndentBasedFoldingAtStart()<<endl;
+ if ( (textLine->firstChar() == -1) || textLine->noIndentBasedFoldingAtStart())
+ {
+ // do this to get skipped empty lines indent right, which was given in the indenation array
+ if (!prevLine->indentationDepthArray().isEmpty())
+ {
+ iDepth = (prevLine->indentationDepthArray())[prevLine->indentationDepthArray().size()-1];
+ kdDebug(13020)<<"reusing old depth as current"<<endl;
+ }
+ else
+ {
+ iDepth = prevLine->indentDepth(m_tabWidth);
+ kdDebug(13020)<<"creating indentdepth for previous line"<<endl;
+ }
+ }
+
+ kdDebug(13020)<<"iDepth:"<<iDepth<<endl;
+
+ // query the next line indentation, if we are at the end of the block
+ // use the first line of the next buf block
+ uint nextLineIndentation = 0;
+ bool nextLineIndentationValid=true;
+ indentContinueNextWhitespace=false;
+ if ((current_line+1) < buf->lines())
+ {
+ if (buf->line(current_line+1)->firstChar() == -1)
+ {
+ nextLineIndentation = iDepth;
+ indentContinueNextWhitespace=true;
+ }
+ else
+ nextLineIndentation = buf->line(current_line+1)->indentDepth(m_tabWidth);
+ }
+ else
+ {
+ KateBufBlock *blk = buf->next();
+
+ if (blk && (blk->lines() > 0))
+ {
+ if (blk->line (0)->firstChar() == -1)
+ {
+ nextLineIndentation = iDepth;
+ indentContinueNextWhitespace=true;
+ }
+ else
+ nextLineIndentation = blk->line (0)->indentDepth(m_tabWidth);
+ }
+ else nextLineIndentationValid=false;
+ }
+
+ if (!textLine->noIndentBasedFoldingAtStart()) {
+
+ if ((iDepth > 0) && (indentDepth.isEmpty() || (indentDepth[indentDepth.size()-1] < iDepth)))
+ {
+ kdDebug(13020)<<"adding depth to \"stack\":"<<iDepth<<endl;
+ indentDepth.resize (indentDepth.size()+1, QGArray::SpeedOptim);
+ indentDepth[indentDepth.size()-1] = iDepth;
+ } else {
+ if (!indentDepth.isEmpty())
+ {
+ for (int z=indentDepth.size()-1; z > -1; z--)
+ if (indentDepth[z]>iDepth)
+ indentDepth.resize(z, QGArray::SpeedOptim);
+ if ((iDepth > 0) && (indentDepth.isEmpty() || (indentDepth[indentDepth.size()-1] < iDepth)))
+ {
+ kdDebug(13020)<<"adding depth to \"stack\":"<<iDepth<<endl;
+ indentDepth.resize (indentDepth.size()+1, QGArray::SpeedOptim);
+ indentDepth[indentDepth.size()-1] = iDepth;
+ if (prevLine->firstChar()==-1) {
+
+ }
+ }
+ }
+ }
+ }
+
+ if (!textLine->noIndentBasedFolding())
+ {
+ if (nextLineIndentationValid)
+ {
+ //if (textLine->firstChar()!=-1)
+ {
+ kdDebug(13020)<<"nextLineIndentation:"<<nextLineIndentation<<endl;
+ bool addindent=false;
+ uint deindent=0;
+ if (!indentDepth.isEmpty())
+ kdDebug()<<"indentDepth[indentDepth.size()-1]:"<<indentDepth[indentDepth.size()-1]<<endl;
+ if ((nextLineIndentation>0) && ( indentDepth.isEmpty() || (indentDepth[indentDepth.size()-1]<nextLineIndentation)))
+ {
+ kdDebug(13020)<<"addindent==true"<<endl;
+ addindent=true;
+ } else {
+ if ((!indentDepth.isEmpty()) && (indentDepth[indentDepth.size()-1]>nextLineIndentation))
+ {
+ kdDebug(13020)<<"...."<<endl;
+ for (int z=indentDepth.size()-1; z > -1; z--)
+ {
+ kdDebug(13020)<<indentDepth[z]<<" "<<nextLineIndentation<<endl;
+ if (indentDepth[z]>nextLineIndentation)
+ deindent++;
+ }
+ }
+ }
+/* }
+ if (textLine->noIndentBasedFolding()) kdDebug(13020)<<"=============================indentation based folding disabled======================"<<endl;
+ if (!textLine->noIndentBasedFolding()) {*/
+ if ((textLine->firstChar()==-1)) {
+ updatePreviousNotEmptyLine(buf,current_line,addindent,deindent);
+ codeFoldingUpdate=true;
+ }
+ else
+ {
+ addIndentBasedFoldingInformation(foldingList,addindent,deindent);
+ }
+ }
+ }
+ }
+ indentChanged = !(indentDepth == textLine->indentationDepthArray());
+
+ // assign the new array to the textline !
+ if (indentChanged)
+ textLine->setIndentationDepth (indentDepth);
+
+ indentContinueWhitespace=textLine->firstChar()==-1;
+ }
+ bool foldingColChanged=false;
+ bool foldingChanged = false; //!(foldingList == textLine->foldingListArray());
+ if (foldingList.size()!=textLine->foldingListArray().size()) {
+ foldingChanged=true;
+ } else {
+ QMemArray<uint>::ConstIterator it=foldingList.begin();
+ QMemArray<uint>::ConstIterator it1=textLine->foldingListArray();
+ bool markerType=true;
+ for(;it!=foldingList.end();++it,++it1) {
+ if (markerType) {
+ if ( ((*it)!=(*it1))) {
+ foldingChanged=true;
+ foldingColChanged=false;
+ break;
+ }
+ } else {
+ if ((*it)!=(*it1)) {
+ foldingColChanged=true;
+ }
+ }
+ markerType=!markerType;
+ }
+ }
+
+ if (foldingChanged || foldingColChanged) {
+ textLine->setFoldingList(foldingList);
+ if (foldingChanged==false){
+ textLine->setFoldingColumnsOutdated(textLine->foldingColumnsOutdated() | foldingColChanged);
+ } else textLine->setFoldingColumnsOutdated(false);
+ }
+ bool retVal_folding = false;
+ //perhaps make en enums out of the change flags
+ m_regionTree.updateLine (current_line + buf->startLine(), &foldingList, &retVal_folding, foldingChanged,foldingColChanged);
+
+ codeFoldingUpdate = codeFoldingUpdate | retVal_folding;
+
+ // need we to continue ?
+ stillcontinue = ctxChanged || indentChanged || indentContinueWhitespace || indentContinueNextWhitespace;
+
+ // move around the lines
+ prevLine = textLine;
+
+ // increment line
+ current_line++;
+ }
+
+ buf->markDirty ();
+
+ // tag the changed lines !
+ if (invalidate)
+ emit tagLines (startLine, current_line + buf->startLine());
+
+ // emit that we have changed the folding
+ if (codeFoldingUpdate)
+ emit codeFoldingUpdated();
+
+ //kdDebug (13020) << "HIGHLIGHTED END --- NEED HL, LINESTART: " << startLine << " LINEEND: " << endLine << endl;
+ //kdDebug (13020) << "HL UNTIL LINE: " << m_lineHighlighted << " MAX: " << m_lineHighlightedMax << endl;
+ //kdDebug (13020) << "HL DYN COUNT: " << KateHlManager::self()->countDynamicCtxs() << " MAX: " << m_maxDynamicContexts << endl;
+ //kdDebug (13020) << "TIME TAKEN: " << t.elapsed() << endl;
+
+ // if we are at the last line of the block + we still need to continue
+ // return the need of that !
+ return stillcontinue && ((current_line+1) == buf->lines());
+}
+
+void KateBuffer::codeFoldingColumnUpdate(unsigned int lineNr) {
+ KateTextLine::Ptr line=plainLine(lineNr);
+ if (!line) return;
+ if (line->foldingColumnsOutdated()) {
+ line->setFoldingColumnsOutdated(false);
+ bool tmp;
+ QMemArray<uint> folding=line->foldingListArray();
+ m_regionTree.updateLine(lineNr,&folding,&tmp,true,false);
+ }
+}
+
+//BEGIN KateBufBlock
+
+KateBufBlock::KateBufBlock ( KateBuffer *parent, KateBufBlock *prev, KateBufBlock *next,
+ KateFileLoader *stream )
+: m_state (KateBufBlock::stateDirty),
+ m_startLine (0),
+ m_lines (0),
+ m_vmblock (0),
+ m_vmblockSize (0),
+ m_parent (parent),
+ m_prev (prev),
+ m_next (next),
+ list (0),
+ listPrev (0),
+ listNext (0)
+{
+ // init startline + the next pointers of the neighbour blocks
+ if (m_prev)
+ {
+ m_startLine = m_prev->endLine ();
+ m_prev->m_next = this;
+ }
+
+ if (m_next)
+ m_next->m_prev = this;
+
+ // we have a stream, use it to fill the block !
+ // this can lead to 0 line blocks which are invalid !
+ if (stream)
+ {
+ // this we lead to either dirty or swapped state
+ fillBlock (stream);
+ }
+ else // init the block if no stream given !
+ {
+ // fill in one empty line !
+ KateTextLine::Ptr textLine = new KateTextLine ();
+ m_stringList.push_back (textLine);
+ m_lines++;
+
+ // if we have allready enough blocks around, swap one
+ if (m_parent->m_loadedBlocks.count() >= KateBuffer::maxLoadedBlocks())
+ m_parent->m_loadedBlocks.first()->swapOut();
+
+ // we are a new nearly empty dirty block
+ m_state = KateBufBlock::stateDirty;
+ m_parent->m_loadedBlocks.append (this);
+ }
+}
+
+KateBufBlock::~KateBufBlock ()
+{
+ // sync prev/next pointers
+ if (m_prev)
+ m_prev->m_next = m_next;
+
+ if (m_next)
+ m_next->m_prev = m_prev;
+
+ // if we have some swapped data allocated, free it now or never
+ if (m_vmblock)
+ KateFactory::self()->vm()->free(m_vmblock);
+
+ // remove me from the list I belong
+ KateBufBlockList::remove (this);
+}
+
+void KateBufBlock::fillBlock (KateFileLoader *stream)
+{
+ // is allready too much stuff around in mem ?
+ bool swap = m_parent->m_loadedBlocks.count() >= KateBuffer::maxLoadedBlocks();
+
+ QByteArray rawData;
+
+ // calcs the approx size for KATE_AVG_BLOCK_SIZE chars !
+ if (swap)
+ rawData.resize ((KATE_AVG_BLOCK_SIZE * sizeof(QChar)) + ((KATE_AVG_BLOCK_SIZE/80) * 8));
+
+ char *buf = rawData.data ();
+ uint size = 0;
+ uint blockSize = 0;
+ while (!stream->eof() && (blockSize < KATE_AVG_BLOCK_SIZE) && (m_lines < KATE_MAX_BLOCK_LINES))
+ {
+ uint offset = 0, length = 0;
+ stream->readLine(offset, length);
+ const QChar *unicodeData = stream->unicode () + offset;
+
+ // strip spaces at end of line
+ if ( stream->removeTrailingSpaces() )
+ {
+ while (length > 0)
+ {
+ if (unicodeData[length-1].isSpace())
+ --length;
+ else
+ break;
+ }
+ }
+
+ blockSize += length;
+
+ if (swap)
+ {
+ // create the swapped data on the fly, no need to waste time
+ // via going over the textline classes and dump them !
+ char attr = KateTextLine::flagNoOtherData;
+ uint pos = size;
+
+ // calc new size
+ size = size + 1 + sizeof(uint) + (sizeof(QChar)*length);
+
+ if (size > rawData.size ())
+ {
+ rawData.resize (size);
+ buf = rawData.data ();
+ }
+
+ memcpy(buf+pos, (char *) &attr, 1);
+ pos += 1;
+
+ memcpy(buf+pos, (char *) &length, sizeof(uint));
+ pos += sizeof(uint);
+
+ memcpy(buf+pos, (char *) unicodeData, sizeof(QChar)*length);
+ pos += sizeof(QChar)*length;
+ }
+ else
+ {
+ KateTextLine::Ptr textLine = new KateTextLine ();
+ textLine->insertText (0, length, unicodeData);
+ m_stringList.push_back (textLine);
+ }
+
+ m_lines++;
+ }
+
+ if (swap)
+ {
+ m_vmblock = KateFactory::self()->vm()->allocate(size);
+ m_vmblockSize = size;
+
+ if (!rawData.isEmpty())
+ {
+ if (!KateFactory::self()->vm()->copyBlock(m_vmblock, rawData.data(), 0, size))
+ {
+ if (m_vmblock)
+ KateFactory::self()->vm()->free(m_vmblock);
+
+ m_vmblock = 0;
+ m_vmblockSize = 0;
+
+ m_parent->m_cacheWriteError = true;
+ }
+ }
+
+ // fine, we are swapped !
+ m_state = KateBufBlock::stateSwapped;
+ }
+ else
+ {
+ // we are a new dirty block without any swap data
+ m_state = KateBufBlock::stateDirty;
+ m_parent->m_loadedBlocks.append (this);
+ }
+
+ kdDebug (13020) << "A BLOCK LOADED WITH LINES: " << m_lines << endl;
+}
+
+KateTextLine::Ptr KateBufBlock::line(uint i)
+{
+ // take care that the string list is around !!!
+ if (m_state == KateBufBlock::stateSwapped)
+ swapIn ();
+
+ // LRU
+ if (!m_parent->m_loadedBlocks.isLast(this))
+ m_parent->m_loadedBlocks.append (this);
+
+ return m_stringList[i];
+}
+
+void KateBufBlock::insertLine(uint i, KateTextLine::Ptr line)
+{
+ // take care that the string list is around !!!
+ if (m_state == KateBufBlock::stateSwapped)
+ swapIn ();
+
+ m_stringList.insert (m_stringList.begin()+i, line);
+ m_lines++;
+
+ markDirty ();
+}
+
+void KateBufBlock::removeLine(uint i)
+{
+ // take care that the string list is around !!!
+ if (m_state == KateBufBlock::stateSwapped)
+ swapIn ();
+
+ m_stringList.erase (m_stringList.begin()+i);
+ m_lines--;
+
+ markDirty ();
+}
+
+void KateBufBlock::markDirty ()
+{
+ if (m_state != KateBufBlock::stateSwapped)
+ {
+ // LRU
+ if (!m_parent->m_loadedBlocks.isLast(this))
+ m_parent->m_loadedBlocks.append (this);
+
+ if (m_state == KateBufBlock::stateClean)
+ {
+ // if we have some swapped data allocated which is dirty, free it now
+ if (m_vmblock)
+ KateFactory::self()->vm()->free(m_vmblock);
+
+ m_vmblock = 0;
+ m_vmblockSize = 0;
+
+ // we are dirty
+ m_state = KateBufBlock::stateDirty;
+ }
+ }
+}
+
+void KateBufBlock::swapIn ()
+{
+ if (m_state != KateBufBlock::stateSwapped)
+ return;
+
+ QByteArray rawData (m_vmblockSize);
+
+ // what to do if that fails ?
+ if (!KateFactory::self()->vm()->copyBlock(rawData.data(), m_vmblock, 0, rawData.size()))
+ m_parent->m_cacheReadError = true;
+
+ // reserve mem, keep realloc away on push_back
+ m_stringList.reserve (m_lines);
+
+ char *buf = rawData.data();
+ for (uint i=0; i < m_lines; i++)
+ {
+ KateTextLine::Ptr textLine = new KateTextLine ();
+ buf = textLine->restore (buf);
+ m_stringList.push_back (textLine);
+ }
+
+ // if we have allready enough blocks around, swap one
+ if (m_parent->m_loadedBlocks.count() >= KateBuffer::maxLoadedBlocks())
+ m_parent->m_loadedBlocks.first()->swapOut();
+
+ // fine, we are now clean again, save state + append to clean list
+ m_state = KateBufBlock::stateClean;
+ m_parent->m_loadedBlocks.append (this);
+}
+
+void KateBufBlock::swapOut ()
+{
+ if (m_state == KateBufBlock::stateSwapped)
+ return;
+
+ if (m_state == KateBufBlock::stateDirty)
+ {
+ bool haveHl = m_parent->m_highlight && !m_parent->m_highlight->noHighlighting();
+
+ // Calculate size.
+ uint size = 0;
+ for (uint i=0; i < m_lines; i++)
+ size += m_stringList[i]->dumpSize (haveHl);
+
+ QByteArray rawData (size);
+ char *buf = rawData.data();
+
+ // Dump textlines
+ for (uint i=0; i < m_lines; i++)
+ buf = m_stringList[i]->dump (buf, haveHl);
+
+ m_vmblock = KateFactory::self()->vm()->allocate(rawData.size());
+ m_vmblockSize = rawData.size();
+
+ if (!rawData.isEmpty())
+ {
+ if (!KateFactory::self()->vm()->copyBlock(m_vmblock, rawData.data(), 0, rawData.size()))
+ {
+ if (m_vmblock)
+ KateFactory::self()->vm()->free(m_vmblock);
+
+ m_vmblock = 0;
+ m_vmblockSize = 0;
+
+ m_parent->m_cacheWriteError = true;
+
+ return;
+ }
+ }
+ }
+
+ m_stringList.clear();
+
+ // we are now swapped out, set state + remove us out of the lists !
+ m_state = KateBufBlock::stateSwapped;
+ KateBufBlockList::remove (this);
+}
+
+//END KateBufBlock
+
+//BEGIN KateBufBlockList
+
+KateBufBlockList::KateBufBlockList ()
+ : m_count (0),
+ m_first (0),
+ m_last (0)
+{
+}
+
+void KateBufBlockList::append (KateBufBlock *buf)
+{
+ if (buf->list)
+ buf->list->removeInternal (buf);
+
+ m_count++;
+
+ // append a element
+ if (m_last)
+ {
+ m_last->listNext = buf;
+
+ buf->listPrev = m_last;
+ buf->listNext = 0;
+
+ m_last = buf;
+
+ buf->list = this;
+
+ return;
+ }
+
+ // insert the first element
+ m_last = buf;
+ m_first = buf;
+
+ buf->listPrev = 0;
+ buf->listNext = 0;
+
+ buf->list = this;
+}
+
+void KateBufBlockList::removeInternal (KateBufBlock *buf)
+{
+ if (buf->list != this)
+ return;
+
+ m_count--;
+
+ if ((buf == m_first) && (buf == m_last))
+ {
+ // last element removed !
+ m_first = 0;
+ m_last = 0;
+ }
+ else if (buf == m_first)
+ {
+ // first element removed
+ m_first = buf->listNext;
+ m_first->listPrev = 0;
+ }
+ else if (buf == m_last)
+ {
+ // last element removed
+ m_last = buf->listPrev;
+ m_last->listNext = 0;
+ }
+ else
+ {
+ buf->listPrev->listNext = buf->listNext;
+ buf->listNext->listPrev = buf->listPrev;
+ }
+
+ buf->listPrev = 0;
+ buf->listNext = 0;
+
+ buf->list = 0;
+}
+
+//END KateBufBlockList
+
+// kate: space-indent on; indent-width 2; replace-tabs on;