|
|
|
/* This file is part of the KDE libraries
|
|
|
|
Copyright (C) 2001-2003 Christoph Cullmann <cullmann@kde.org>
|
|
|
|
Copyright (C) 2002 Joseph Wenninger <jowenn@kde.org>
|
|
|
|
|
|
|
|
Based on:
|
|
|
|
KateTextLine : Copyright (C) 1999 Jochen Wilhelmy <digisnap@cs.tu-berlin.de>
|
|
|
|
|
|
|
|
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 "katetextline.h"
|
|
|
|
#include "katerenderer.h"
|
|
|
|
|
|
|
|
#include <kglobal.h>
|
|
|
|
|
|
|
|
#include <tqregexp.h>
|
|
|
|
|
|
|
|
KateTextLine::KateTextLine ()
|
|
|
|
: m_flags(0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
KateTextLine::~KateTextLine()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void KateTextLine::insertText (uint pos, uint insLen, const TQChar *insText, uchar *insAttribs)
|
|
|
|
{
|
|
|
|
// nothing to do
|
|
|
|
if (insLen == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// calc new textLen, store old
|
|
|
|
uint oldTextLen = m_text.length();
|
|
|
|
m_text.insert (pos, insText, insLen);
|
|
|
|
uint textLen = m_text.length();
|
|
|
|
|
|
|
|
// resize the array
|
|
|
|
m_attributes.resize (textLen);
|
|
|
|
|
|
|
|
// HA, insert behind text end, fill with spaces
|
|
|
|
if (pos >= oldTextLen)
|
|
|
|
{
|
|
|
|
for (uint z = oldTextLen; z < pos; z++)
|
|
|
|
m_attributes[z] = 0;
|
|
|
|
}
|
|
|
|
// HA, insert in text, move the old text behind pos
|
|
|
|
else if (oldTextLen > 0)
|
|
|
|
{
|
|
|
|
for (int z = oldTextLen -1; z >= (int) pos; z--)
|
|
|
|
m_attributes[z+insLen] = m_attributes[z];
|
|
|
|
}
|
|
|
|
|
|
|
|
// BUH, actually insert the new text
|
|
|
|
for (uint z = 0; z < insLen; z++)
|
|
|
|
{
|
|
|
|
if (insAttribs == 0)
|
|
|
|
m_attributes[z+pos] = 0;
|
|
|
|
else
|
|
|
|
m_attributes[z+pos] = insAttribs[z];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KateTextLine::removeText (uint pos, uint delLen)
|
|
|
|
{
|
|
|
|
// nothing to do
|
|
|
|
if (delLen == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
uint textLen = m_text.length();
|
|
|
|
|
|
|
|
if (textLen == 0)
|
|
|
|
return; // uh, again nothing real to do ;)
|
|
|
|
|
|
|
|
if (pos >= textLen)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ((pos + delLen) > textLen)
|
|
|
|
delLen = textLen - pos;
|
|
|
|
|
|
|
|
// BU, MOVE THE OLD TEXT AROUND
|
|
|
|
for (uint z = pos; z < textLen - delLen; z++)
|
|
|
|
m_attributes[z] = m_attributes[z+delLen];
|
|
|
|
|
|
|
|
m_text.remove (pos, delLen);
|
|
|
|
m_attributes.resize (m_text.length ());
|
|
|
|
}
|
|
|
|
|
|
|
|
void KateTextLine::truncate(uint newLen)
|
|
|
|
{
|
|
|
|
if (newLen < m_text.length())
|
|
|
|
{
|
|
|
|
m_text.truncate (newLen);
|
|
|
|
m_attributes.truncate (newLen);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int KateTextLine::nextNonSpaceChar(uint pos) const
|
|
|
|
{
|
|
|
|
const uint len = m_text.length();
|
|
|
|
const TQChar *unicode = m_text.unicode();
|
|
|
|
|
|
|
|
for(uint i = pos; i < len; i++)
|
|
|
|
{
|
|
|
|
if(!unicode[i].isSpace())
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int KateTextLine::previousNonSpaceChar(uint pos) const
|
|
|
|
{
|
|
|
|
const int len = m_text.length();
|
|
|
|
|
|
|
|
if (pos >= (uint)len)
|
|
|
|
pos = len - 1;
|
|
|
|
|
|
|
|
const TQChar *unicode = m_text.unicode();
|
|
|
|
|
|
|
|
for(int i = pos; i >= 0; i--)
|
|
|
|
{
|
|
|
|
if(!unicode[i].isSpace())
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int KateTextLine::firstChar() const
|
|
|
|
{
|
|
|
|
return nextNonSpaceChar(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int KateTextLine::lastChar() const
|
|
|
|
{
|
|
|
|
return previousNonSpaceChar(m_text.length() - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
const TQChar *KateTextLine::firstNonSpace() const
|
|
|
|
{
|
|
|
|
int first = firstChar();
|
|
|
|
return (first > -1) ? ((TQChar*)m_text.unicode())+first : m_text.unicode();
|
|
|
|
}
|
|
|
|
|
|
|
|
uint KateTextLine::indentDepth (uint tabwidth) const
|
|
|
|
{
|
|
|
|
uint d = 0;
|
|
|
|
const uint len = m_text.length();
|
|
|
|
const TQChar *unicode = m_text.unicode();
|
|
|
|
|
|
|
|
for(uint i = 0; i < len; i++)
|
|
|
|
{
|
|
|
|
if(unicode[i].isSpace())
|
|
|
|
{
|
|
|
|
if (unicode[i] == TQChar('\t'))
|
|
|
|
d += tabwidth - (d % tabwidth);
|
|
|
|
else
|
|
|
|
d++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KateTextLine::stringAtPos(uint pos, const TQString& match) const
|
|
|
|
{
|
|
|
|
const uint len = m_text.length();
|
|
|
|
const uint matchlen = match.length();
|
|
|
|
|
|
|
|
if ((pos+matchlen) > len)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// (pos > len) in case the uint pos was assigned a signed -1, pos+matchlen can
|
|
|
|
// overflow again which (pos+matchlen > len) does not catch; see bugs #129263 and #129580
|
|
|
|
Q_ASSERT(pos < len);
|
|
|
|
|
|
|
|
const TQChar *unicode = m_text.unicode();
|
|
|
|
const TQChar *matchUnicode = match.unicode();
|
|
|
|
|
|
|
|
for (uint i=0; i < matchlen; i++)
|
|
|
|
if (unicode[i+pos] != matchUnicode[i])
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KateTextLine::startingWith(const TQString& match) const
|
|
|
|
{
|
|
|
|
const uint matchlen = match.length();
|
|
|
|
|
|
|
|
if (matchlen > m_text.length())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const TQChar *unicode = m_text.unicode();
|
|
|
|
const TQChar *matchUnicode = match.unicode();
|
|
|
|
|
|
|
|
for (uint i=0; i < matchlen; i++)
|
|
|
|
if (unicode[i] != matchUnicode[i])
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KateTextLine::endingWith(const TQString& match) const
|
|
|
|
{
|
|
|
|
const uint matchlen = match.length();
|
|
|
|
|
|
|
|
if (matchlen > m_text.length())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const TQChar *unicode = m_text.unicode();
|
|
|
|
const TQChar *matchUnicode = match.unicode();
|
|
|
|
|
|
|
|
uint start = m_text.length() - matchlen;
|
|
|
|
for (uint i=0; i < matchlen; i++)
|
|
|
|
if (unicode[start+i] != matchUnicode[i])
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int KateTextLine::cursorX(uint pos, uint tabChars) const
|
|
|
|
{
|
|
|
|
uint x = 0;
|
|
|
|
|
|
|
|
const uint n = kMin (pos, m_text.length());
|
|
|
|
const TQChar *unicode = m_text.unicode();
|
|
|
|
|
|
|
|
for ( uint z = 0; z < n; z++)
|
|
|
|
{
|
|
|
|
if (unicode[z] == TQChar('\t'))
|
|
|
|
x += tabChars - (x % tabChars);
|
|
|
|
else
|
|
|
|
x++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint KateTextLine::lengthWithTabs (uint tabChars) const
|
|
|
|
{
|
|
|
|
uint x = 0;
|
|
|
|
const uint len = m_text.length();
|
|
|
|
const TQChar *unicode = m_text.unicode();
|
|
|
|
|
|
|
|
for ( uint z = 0; z < len; z++)
|
|
|
|
{
|
|
|
|
if (unicode[z] == TQChar('\t'))
|
|
|
|
x += tabChars - (x % tabChars);
|
|
|
|
else
|
|
|
|
x++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KateTextLine::searchText (uint startCol, const TQString &text, uint *foundAtCol, uint *matchLen, bool casesensitive, bool backwards)
|
|
|
|
{
|
|
|
|
int index;
|
|
|
|
|
|
|
|
if (backwards)
|
|
|
|
{
|
|
|
|
int col = startCol;
|
|
|
|
uint l = text.length();
|
|
|
|
// allow finding the string ending at eol
|
|
|
|
if ( col == (int) m_text.length() ) ++startCol;
|
|
|
|
|
|
|
|
do {
|
|
|
|
index = m_text.findRev( text, col, casesensitive );
|
|
|
|
col--;
|
|
|
|
} while ( col >= 0 && l + index >= startCol );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
index = m_text.find (text, startCol, casesensitive);
|
|
|
|
|
|
|
|
if (index > -1)
|
|
|
|
{
|
|
|
|
if (foundAtCol)
|
|
|
|
(*foundAtCol) = index;
|
|
|
|
if (matchLen)
|
|
|
|
(*matchLen)=text.length();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KateTextLine::searchText (uint startCol, const TQRegExp ®exp, uint *foundAtCol, uint *matchLen, bool backwards)
|
|
|
|
{
|
|
|
|
int index;
|
|
|
|
|
|
|
|
if (backwards)
|
|
|
|
{
|
|
|
|
int col = startCol;
|
|
|
|
|
|
|
|
// allow finding the string ending at eol
|
|
|
|
if ( col == (int) m_text.length() ) ++startCol;
|
|
|
|
do {
|
|
|
|
index = regexp.searchRev (m_text, col);
|
|
|
|
col--;
|
|
|
|
} while ( col >= 0 && regexp.matchedLength() + index >= (int)startCol );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
index = regexp.search (m_text, startCol);
|
|
|
|
|
|
|
|
if (index > -1)
|
|
|
|
{
|
|
|
|
if (foundAtCol)
|
|
|
|
(*foundAtCol) = index;
|
|
|
|
|
|
|
|
if (matchLen)
|
|
|
|
(*matchLen)=regexp.matchedLength();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *KateTextLine::dump (char *buf, bool withHighlighting) const
|
|
|
|
{
|
|
|
|
uint l = m_text.length();
|
|
|
|
char f = m_flags;
|
|
|
|
|
|
|
|
if (!withHighlighting)
|
|
|
|
f = f | KateTextLine::flagNoOtherData;
|
|
|
|
|
|
|
|
memcpy(buf, (char *) &f, 1);
|
|
|
|
buf += 1;
|
|
|
|
|
|
|
|
memcpy(buf, &l, sizeof(uint));
|
|
|
|
buf += sizeof(uint);
|
|
|
|
|
|
|
|
memcpy(buf, (char *) m_text.unicode(), sizeof(TQChar)*l);
|
|
|
|
buf += sizeof(TQChar) * l;
|
|
|
|
|
|
|
|
if (!withHighlighting)
|
|
|
|
return buf;
|
|
|
|
|
|
|
|
memcpy(buf, (char *)m_attributes.data(), sizeof(uchar) * l);
|
|
|
|
buf += sizeof (uchar) * l;
|
|
|
|
|
|
|
|
uint lctx = m_ctx.size();
|
|
|
|
uint lfold = m_foldingList.size();
|
|
|
|
uint lind = m_indentationDepth.size();
|
|
|
|
|
|
|
|
memcpy(buf, &lctx, sizeof(uint));
|
|
|
|
buf += sizeof(uint);
|
|
|
|
|
|
|
|
memcpy(buf, &lfold, sizeof(uint));
|
|
|
|
buf += sizeof(uint);
|
|
|
|
|
|
|
|
memcpy(buf, &lind, sizeof(uint));
|
|
|
|
buf += sizeof(uint);
|
|
|
|
|
|
|
|
memcpy(buf, (char *)m_ctx.data(), sizeof(short) * lctx);
|
|
|
|
buf += sizeof (short) * lctx;
|
|
|
|
|
|
|
|
memcpy(buf, (char *)m_foldingList.data(), sizeof(uint)*lfold);
|
|
|
|
buf += sizeof (uint) * lfold;
|
|
|
|
|
|
|
|
memcpy(buf, (char *)m_indentationDepth.data(), sizeof(unsigned short) * lind);
|
|
|
|
buf += sizeof (unsigned short) * lind;
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *KateTextLine::restore (char *buf)
|
|
|
|
{
|
|
|
|
uint l = 0;
|
|
|
|
char f = 0;
|
|
|
|
|
|
|
|
memcpy((char *) &f, buf, 1);
|
|
|
|
buf += 1;
|
|
|
|
|
|
|
|
// text + context length read
|
|
|
|
memcpy((char *) &l, buf, sizeof(uint));
|
|
|
|
buf += sizeof(uint);
|
|
|
|
|
|
|
|
// text + attributes
|
|
|
|
m_text.setUnicode ((TQChar *) buf, l);
|
|
|
|
buf += sizeof(TQChar) * l;
|
|
|
|
|
|
|
|
// we just restore a KateTextLine from a buffer first time
|
|
|
|
if (f & KateTextLine::flagNoOtherData)
|
|
|
|
{
|
|
|
|
m_flags = 0;
|
|
|
|
|
|
|
|
if (f & KateTextLine::flagAutoWrapped)
|
|
|
|
m_flags = m_flags | KateTextLine::flagAutoWrapped;
|
|
|
|
|
|
|
|
// fill with clean empty attribs !
|
|
|
|
m_attributes.fill (0, l);
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
m_flags = f;
|
|
|
|
|
|
|
|
m_attributes.duplicate ((uchar *) buf, l);
|
|
|
|
buf += sizeof(uchar) * l;
|
|
|
|
|
|
|
|
uint lctx = 0;
|
|
|
|
uint lfold = 0;
|
|
|
|
uint lind = 0;
|
|
|
|
|
|
|
|
memcpy((char *) &lctx, buf, sizeof(uint));
|
|
|
|
buf += sizeof(uint);
|
|
|
|
|
|
|
|
memcpy((char *) &lfold, buf, sizeof(uint));
|
|
|
|
buf += sizeof(uint);
|
|
|
|
|
|
|
|
memcpy((char *) &lind, buf, sizeof(uint));
|
|
|
|
buf += sizeof(uint);
|
|
|
|
|
|
|
|
m_ctx.duplicate ((short *) buf, lctx);
|
|
|
|
buf += sizeof(short) * lctx;
|
|
|
|
|
|
|
|
m_foldingList.duplicate ((uint *) buf, lfold);
|
|
|
|
buf += sizeof(uint)*lfold;
|
|
|
|
|
|
|
|
m_indentationDepth.duplicate ((unsigned short *) buf, lind);
|
|
|
|
buf += sizeof(unsigned short) * lind;
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
// kate: space-indent on; indent-width 2; replace-tabs on;
|