katetextline.cpp
00001 /* This file is part of the KDE libraries 00002 Copyright (C) 2001-2003 Christoph Cullmann <cullmann@kde.org> 00003 Copyright (C) 2002 Joseph Wenninger <jowenn@kde.org> 00004 00005 Based on: 00006 KateTextLine : Copyright (C) 1999 Jochen Wilhelmy <digisnap@cs.tu-berlin.de> 00007 00008 This library is free software; you can redistribute it and/or 00009 modify it under the terms of the GNU Library General Public 00010 License version 2 as published by the Free Software Foundation. 00011 00012 This library is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 Library General Public License for more details. 00016 00017 You should have received a copy of the GNU Library General Public License 00018 along with this library; see the file COPYING.LIB. If not, write to 00019 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00020 Boston, MA 02110-1301, USA. 00021 */ 00022 00023 #include "katetextline.h" 00024 #include "katerenderer.h" 00025 00026 #include <kglobal.h> 00027 00028 #include <qregexp.h> 00029 00030 KateTextLine::KateTextLine () 00031 : m_flags(0) 00032 { 00033 } 00034 00035 KateTextLine::~KateTextLine() 00036 { 00037 } 00038 00039 void KateTextLine::insertText (uint pos, uint insLen, const QChar *insText, uchar *insAttribs) 00040 { 00041 // nothing to do 00042 if (insLen == 0) 00043 return; 00044 00045 // calc new textLen, store old 00046 uint oldTextLen = m_text.length(); 00047 m_text.insert (pos, insText, insLen); 00048 uint textLen = m_text.length(); 00049 00050 // resize the array 00051 m_attributes.resize (textLen); 00052 00053 // HA, insert behind text end, fill with spaces 00054 if (pos >= oldTextLen) 00055 { 00056 for (uint z = oldTextLen; z < pos; z++) 00057 m_attributes[z] = 0; 00058 } 00059 // HA, insert in text, move the old text behind pos 00060 else if (oldTextLen > 0) 00061 { 00062 for (int z = oldTextLen -1; z >= (int) pos; z--) 00063 m_attributes[z+insLen] = m_attributes[z]; 00064 } 00065 00066 // BUH, actually insert the new text 00067 for (uint z = 0; z < insLen; z++) 00068 { 00069 if (insAttribs == 0) 00070 m_attributes[z+pos] = 0; 00071 else 00072 m_attributes[z+pos] = insAttribs[z]; 00073 } 00074 } 00075 00076 void KateTextLine::removeText (uint pos, uint delLen) 00077 { 00078 // nothing to do 00079 if (delLen == 0) 00080 return; 00081 00082 uint textLen = m_text.length(); 00083 00084 if (textLen == 0) 00085 return; // uh, again nothing real to do ;) 00086 00087 if (pos >= textLen) 00088 return; 00089 00090 if ((pos + delLen) > textLen) 00091 delLen = textLen - pos; 00092 00093 // BU, MOVE THE OLD TEXT AROUND 00094 for (uint z = pos; z < textLen - delLen; z++) 00095 m_attributes[z] = m_attributes[z+delLen]; 00096 00097 m_text.remove (pos, delLen); 00098 m_attributes.resize (m_text.length ()); 00099 } 00100 00101 void KateTextLine::truncate(uint newLen) 00102 { 00103 if (newLen < m_text.length()) 00104 { 00105 m_text.truncate (newLen); 00106 m_attributes.truncate (newLen); 00107 } 00108 } 00109 00110 int KateTextLine::nextNonSpaceChar(uint pos) const 00111 { 00112 const uint len = m_text.length(); 00113 const QChar *unicode = m_text.unicode(); 00114 00115 for(uint i = pos; i < len; i++) 00116 { 00117 if(!unicode[i].isSpace()) 00118 return i; 00119 } 00120 00121 return -1; 00122 } 00123 00124 int KateTextLine::previousNonSpaceChar(uint pos) const 00125 { 00126 const int len = m_text.length(); 00127 00128 if (pos >= (uint)len) 00129 pos = len - 1; 00130 00131 const QChar *unicode = m_text.unicode(); 00132 00133 for(int i = pos; i >= 0; i--) 00134 { 00135 if(!unicode[i].isSpace()) 00136 return i; 00137 } 00138 00139 return -1; 00140 } 00141 00142 int KateTextLine::firstChar() const 00143 { 00144 return nextNonSpaceChar(0); 00145 } 00146 00147 int KateTextLine::lastChar() const 00148 { 00149 return previousNonSpaceChar(m_text.length() - 1); 00150 } 00151 00152 const QChar *KateTextLine::firstNonSpace() const 00153 { 00154 int first = firstChar(); 00155 return (first > -1) ? ((QChar*)m_text.unicode())+first : m_text.unicode(); 00156 } 00157 00158 uint KateTextLine::indentDepth (uint tabwidth) const 00159 { 00160 uint d = 0; 00161 const uint len = m_text.length(); 00162 const QChar *unicode = m_text.unicode(); 00163 00164 for(uint i = 0; i < len; i++) 00165 { 00166 if(unicode[i].isSpace()) 00167 { 00168 if (unicode[i] == QChar('\t')) 00169 d += tabwidth - (d % tabwidth); 00170 else 00171 d++; 00172 } 00173 else 00174 return d; 00175 } 00176 00177 return d; 00178 } 00179 00180 bool KateTextLine::stringAtPos(uint pos, const QString& match) const 00181 { 00182 const uint len = m_text.length(); 00183 const uint matchlen = match.length(); 00184 00185 if ((pos+matchlen) > len) 00186 return false; 00187 00188 // (pos > len) in case the uint pos was assigned a signed -1, pos+matchlen can 00189 // overflow again which (pos+matchlen > len) does not catch; see bugs #129263 and #129580 00190 Q_ASSERT(pos < len); 00191 00192 const QChar *unicode = m_text.unicode(); 00193 const QChar *matchUnicode = match.unicode(); 00194 00195 for (uint i=0; i < matchlen; i++) 00196 if (unicode[i+pos] != matchUnicode[i]) 00197 return false; 00198 00199 return true; 00200 } 00201 00202 bool KateTextLine::startingWith(const QString& match) const 00203 { 00204 const uint matchlen = match.length(); 00205 00206 if (matchlen > m_text.length()) 00207 return false; 00208 00209 const QChar *unicode = m_text.unicode(); 00210 const QChar *matchUnicode = match.unicode(); 00211 00212 for (uint i=0; i < matchlen; i++) 00213 if (unicode[i] != matchUnicode[i]) 00214 return false; 00215 00216 return true; 00217 } 00218 00219 bool KateTextLine::endingWith(const QString& match) const 00220 { 00221 const uint matchlen = match.length(); 00222 00223 if (matchlen > m_text.length()) 00224 return false; 00225 00226 const QChar *unicode = m_text.unicode(); 00227 const QChar *matchUnicode = match.unicode(); 00228 00229 uint start = m_text.length() - matchlen; 00230 for (uint i=0; i < matchlen; i++) 00231 if (unicode[start+i] != matchUnicode[i]) 00232 return false; 00233 00234 return true; 00235 } 00236 00237 int KateTextLine::cursorX(uint pos, uint tabChars) const 00238 { 00239 uint x = 0; 00240 00241 const uint n = kMin (pos, m_text.length()); 00242 const QChar *unicode = m_text.unicode(); 00243 00244 for ( uint z = 0; z < n; z++) 00245 { 00246 if (unicode[z] == QChar('\t')) 00247 x += tabChars - (x % tabChars); 00248 else 00249 x++; 00250 } 00251 00252 return x; 00253 } 00254 00255 00256 uint KateTextLine::lengthWithTabs (uint tabChars) const 00257 { 00258 uint x = 0; 00259 const uint len = m_text.length(); 00260 const QChar *unicode = m_text.unicode(); 00261 00262 for ( uint z = 0; z < len; z++) 00263 { 00264 if (unicode[z] == QChar('\t')) 00265 x += tabChars - (x % tabChars); 00266 else 00267 x++; 00268 } 00269 00270 return x; 00271 } 00272 00273 bool KateTextLine::searchText (uint startCol, const QString &text, uint *foundAtCol, uint *matchLen, bool casesensitive, bool backwards) 00274 { 00275 int index; 00276 00277 if (backwards) 00278 { 00279 int col = startCol; 00280 uint l = text.length(); 00281 // allow finding the string ending at eol 00282 if ( col == (int) m_text.length() ) ++startCol; 00283 00284 do { 00285 index = m_text.findRev( text, col, casesensitive ); 00286 col--; 00287 } while ( col >= 0 && l + index >= startCol ); 00288 } 00289 else 00290 index = m_text.find (text, startCol, casesensitive); 00291 00292 if (index > -1) 00293 { 00294 if (foundAtCol) 00295 (*foundAtCol) = index; 00296 if (matchLen) 00297 (*matchLen)=text.length(); 00298 return true; 00299 } 00300 00301 return false; 00302 } 00303 00304 bool KateTextLine::searchText (uint startCol, const QRegExp ®exp, uint *foundAtCol, uint *matchLen, bool backwards) 00305 { 00306 int index; 00307 00308 if (backwards) 00309 { 00310 int col = startCol; 00311 00312 // allow finding the string ending at eol 00313 if ( col == (int) m_text.length() ) ++startCol; 00314 do { 00315 index = regexp.searchRev (m_text, col); 00316 col--; 00317 } while ( col >= 0 && regexp.matchedLength() + index >= (int)startCol ); 00318 } 00319 else 00320 index = regexp.search (m_text, startCol); 00321 00322 if (index > -1) 00323 { 00324 if (foundAtCol) 00325 (*foundAtCol) = index; 00326 00327 if (matchLen) 00328 (*matchLen)=regexp.matchedLength(); 00329 return true; 00330 } 00331 00332 return false; 00333 } 00334 00335 char *KateTextLine::dump (char *buf, bool withHighlighting) const 00336 { 00337 uint l = m_text.length(); 00338 char f = m_flags; 00339 00340 if (!withHighlighting) 00341 f = f | KateTextLine::flagNoOtherData; 00342 00343 memcpy(buf, (char *) &f, 1); 00344 buf += 1; 00345 00346 memcpy(buf, &l, sizeof(uint)); 00347 buf += sizeof(uint); 00348 00349 memcpy(buf, (char *) m_text.unicode(), sizeof(QChar)*l); 00350 buf += sizeof(QChar) * l; 00351 00352 if (!withHighlighting) 00353 return buf; 00354 00355 memcpy(buf, (char *)m_attributes.data(), sizeof(uchar) * l); 00356 buf += sizeof (uchar) * l; 00357 00358 uint lctx = m_ctx.size(); 00359 uint lfold = m_foldingList.size(); 00360 uint lind = m_indentationDepth.size(); 00361 00362 memcpy(buf, &lctx, sizeof(uint)); 00363 buf += sizeof(uint); 00364 00365 memcpy(buf, &lfold, sizeof(uint)); 00366 buf += sizeof(uint); 00367 00368 memcpy(buf, &lind, sizeof(uint)); 00369 buf += sizeof(uint); 00370 00371 memcpy(buf, (char *)m_ctx.data(), sizeof(short) * lctx); 00372 buf += sizeof (short) * lctx; 00373 00374 memcpy(buf, (char *)m_foldingList.data(), sizeof(uint)*lfold); 00375 buf += sizeof (uint) * lfold; 00376 00377 memcpy(buf, (char *)m_indentationDepth.data(), sizeof(unsigned short) * lind); 00378 buf += sizeof (unsigned short) * lind; 00379 00380 return buf; 00381 } 00382 00383 char *KateTextLine::restore (char *buf) 00384 { 00385 uint l = 0; 00386 char f = 0; 00387 00388 memcpy((char *) &f, buf, 1); 00389 buf += 1; 00390 00391 // text + context length read 00392 memcpy((char *) &l, buf, sizeof(uint)); 00393 buf += sizeof(uint); 00394 00395 // text + attributes 00396 m_text.setUnicode ((QChar *) buf, l); 00397 buf += sizeof(QChar) * l; 00398 00399 // we just restore a KateTextLine from a buffer first time 00400 if (f & KateTextLine::flagNoOtherData) 00401 { 00402 m_flags = 0; 00403 00404 if (f & KateTextLine::flagAutoWrapped) 00405 m_flags = m_flags | KateTextLine::flagAutoWrapped; 00406 00407 // fill with clean empty attribs ! 00408 m_attributes.fill (0, l); 00409 00410 return buf; 00411 } 00412 else 00413 m_flags = f; 00414 00415 m_attributes.duplicate ((uchar *) buf, l); 00416 buf += sizeof(uchar) * l; 00417 00418 uint lctx = 0; 00419 uint lfold = 0; 00420 uint lind = 0; 00421 00422 memcpy((char *) &lctx, buf, sizeof(uint)); 00423 buf += sizeof(uint); 00424 00425 memcpy((char *) &lfold, buf, sizeof(uint)); 00426 buf += sizeof(uint); 00427 00428 memcpy((char *) &lind, buf, sizeof(uint)); 00429 buf += sizeof(uint); 00430 00431 m_ctx.duplicate ((short *) buf, lctx); 00432 buf += sizeof(short) * lctx; 00433 00434 m_foldingList.duplicate ((uint *) buf, lfold); 00435 buf += sizeof(uint)*lfold; 00436 00437 m_indentationDepth.duplicate ((unsigned short *) buf, lind); 00438 buf += sizeof(unsigned short) * lind; 00439 00440 return buf; 00441 } 00442 00443 // kate: space-indent on; indent-width 2; replace-tabs on;