You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdelibs/kate/part/katetextline.cpp

444 lines
9.5 KiB

/* 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, (uint)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 &regexp, 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;