00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "katetextline.h"
00024 #include "katerenderer.h"
00025
00026 #include <qregexp.h>
00027 #include <kglobal.h>
00028 #include <kdebug.h>
00029 #include <qstylesheet.h>
00030
00031 KateTextLine::KateTextLine ()
00032 : m_flags(0)
00033 {
00034 }
00035
00036 KateTextLine::~KateTextLine()
00037 {
00038 }
00039
00040 void KateTextLine::insertText (uint pos, uint insLen, const QChar *insText, uchar *insAttribs)
00041 {
00042
00043 if (insLen == 0)
00044 return;
00045
00046
00047 uint oldTextLen = m_text.length();
00048 m_text.insert (pos, insText, insLen);
00049 uint textLen = m_text.length();
00050
00051
00052 m_attributes.resize (textLen);
00053
00054
00055 if (pos >= oldTextLen)
00056 {
00057 for (uint z = oldTextLen; z < pos; z++)
00058 m_attributes[z] = 0;
00059 }
00060
00061 else if (oldTextLen > 0)
00062 {
00063 for (int z = oldTextLen -1; z >= (int) pos; z--)
00064 m_attributes[z+insLen] = m_attributes[z];
00065 }
00066
00067
00068 for (uint z = 0; z < insLen; z++)
00069 {
00070 if (insAttribs == 0)
00071 m_attributes[z+pos] = 0;
00072 else
00073 m_attributes[z+pos] = insAttribs[z];
00074 }
00075 }
00076
00077 void KateTextLine::removeText (uint pos, uint delLen)
00078 {
00079
00080 if (delLen == 0)
00081 return;
00082
00083 uint textLen = m_text.length();
00084
00085 if (textLen == 0)
00086 return;
00087
00088 if (pos >= textLen)
00089 return;
00090
00091 if ((pos + delLen) > textLen)
00092 delLen = textLen - pos;
00093
00094
00095 for (uint z = pos; z < textLen - delLen; z++)
00096 m_attributes[z] = m_attributes[z+delLen];
00097
00098 m_text.remove (pos, delLen);
00099 m_attributes.resize (m_text.length ());
00100 }
00101
00102 void KateTextLine::truncate(uint newLen)
00103 {
00104 if (newLen < m_text.length())
00105 {
00106 m_text.truncate (newLen);
00107 m_attributes.truncate (newLen);
00108 }
00109 }
00110
00111 int KateTextLine::nextNonSpaceChar(uint pos) const
00112 {
00113 for(int i = pos; i < (int)m_text.length(); i++)
00114 {
00115 if(!m_text[i].isSpace())
00116 return i;
00117 }
00118
00119 return -1;
00120 }
00121
00122 int KateTextLine::previousNonSpaceChar(uint pos) const
00123 {
00124 if (pos >= m_text.length())
00125 pos = m_text.length() - 1;
00126
00127 for(int i = pos; i >= 0; i--)
00128 {
00129 if(!m_text[i].isSpace())
00130 return i;
00131 }
00132
00133 return -1;
00134 }
00135
00136 int KateTextLine::firstChar() const
00137 {
00138 return nextNonSpaceChar(0);
00139 }
00140
00141 int KateTextLine::lastChar() const
00142 {
00143 return previousNonSpaceChar(m_text.length() - 1);
00144 }
00145
00146 const QChar *KateTextLine::firstNonSpace() const
00147 {
00148 int first = firstChar();
00149 return (first > -1) ? ((QChar*)m_text.unicode())+first : m_text.unicode();
00150 }
00151
00152 uint KateTextLine::indentDepth (uint tabwidth) const
00153 {
00154 uint d = 0;
00155
00156 for(uint i = 0; i < m_text.length(); i++)
00157 {
00158 if(m_text[i].isSpace())
00159 {
00160 if (m_text[i] == QChar('\t'))
00161 d += tabwidth - (d % tabwidth);
00162 else
00163 d++;
00164 }
00165 else
00166 return d;
00167 }
00168
00169 return d;
00170 }
00171
00172 bool KateTextLine::stringAtPos(uint pos, const QString& match) const
00173 {
00174 if ((pos+match.length()) > m_text.length())
00175 return false;
00176
00177 for (uint i=0; i < match.length(); i++)
00178 if (m_text[i+pos] != match[i])
00179 return false;
00180
00181 return true;
00182 }
00183
00184 bool KateTextLine::startingWith(const QString& match) const
00185 {
00186 if (match.length() > m_text.length())
00187 return false;
00188
00189 for (uint i=0; i < match.length(); i++)
00190 if (m_text[i] != match[i])
00191 return false;
00192
00193 return true;
00194 }
00195
00196 bool KateTextLine::endingWith(const QString& match) const
00197 {
00198 if (match.length() > m_text.length())
00199 return false;
00200
00201 uint start = m_text.length() - match.length();
00202 for (uint i=0; i < match.length(); i++)
00203 if (m_text[start+i] != match[i])
00204 return false;
00205
00206 return true;
00207 }
00208
00209 int KateTextLine::cursorX(uint pos, uint tabChars) const
00210 {
00211 uint x = 0;
00212
00213 for ( uint z = 0; z < kMin (pos, m_text.length()); z++)
00214 {
00215 if (m_text[z] == QChar('\t'))
00216 x += tabChars - (x % tabChars);
00217 else
00218 x++;
00219 }
00220
00221 return x;
00222 }
00223
00224
00225 uint KateTextLine::lengthWithTabs (uint tabChars) const
00226 {
00227 uint x = 0;
00228
00229 for ( uint z = 0; z < m_text.length(); z++)
00230 {
00231 if (m_text[z] == QChar('\t'))
00232 x += tabChars - (x % tabChars);
00233 else
00234 x++;
00235 }
00236
00237 return x;
00238 }
00239
00240 bool KateTextLine::searchText (uint startCol, const QString &text, uint *foundAtCol, uint *matchLen, bool casesensitive, bool backwards)
00241 {
00242 int index;
00243
00244 if (backwards)
00245 {
00246 int col = startCol;
00247 uint l = text.length();
00248
00249 if ( col == m_text.length() ) startCol++;
00250
00251 do {
00252 index = m_text.findRev( text, col, casesensitive );
00253 col--;
00254 } while ( col >= 0 && l + index >= startCol );
00255 }
00256 else
00257 index = m_text.find (text, startCol, casesensitive);
00258
00259 if (index > -1)
00260 {
00261 if (foundAtCol)
00262 (*foundAtCol) = index;
00263 if (matchLen)
00264 (*matchLen)=text.length();
00265 return true;
00266 }
00267
00268 return false;
00269 }
00270
00271 bool KateTextLine::searchText (uint startCol, const QRegExp ®exp, uint *foundAtCol, uint *matchLen, bool backwards)
00272 {
00273 int index;
00274
00275 if (backwards)
00276 {
00277 int col = startCol;
00278
00279
00280 if ( col == m_text.length() ) startCol++;
00281 do {
00282 index = regexp.searchRev (m_text, col);
00283 col--;
00284 } while ( col >= 0 && regexp.matchedLength() + index >= (int)startCol );
00285 }
00286 else
00287 index = regexp.search (m_text, startCol);
00288
00289 if (index > -1)
00290 {
00291 if (foundAtCol)
00292 (*foundAtCol) = index;
00293
00294 if (matchLen)
00295 (*matchLen)=regexp.matchedLength();
00296 return true;
00297 }
00298
00299 return false;
00300 }
00301
00302 char *KateTextLine::dump (char *buf, bool withHighlighting) const
00303 {
00304 uint l = m_text.length();
00305 char f = m_flags;
00306
00307 if (!withHighlighting)
00308 f = f | KateTextLine::flagNoOtherData;
00309
00310 memcpy(buf, (char *) &f, 1);
00311 buf += 1;
00312
00313 memcpy(buf, &l, sizeof(uint));
00314 buf += sizeof(uint);
00315
00316 memcpy(buf, (char *) m_text.unicode(), sizeof(QChar)*l);
00317 buf += sizeof(QChar) * l;
00318
00319 if (!withHighlighting)
00320 return buf;
00321
00322 memcpy(buf, (char *)m_attributes.data(), sizeof(uchar) * l);
00323 buf += sizeof (uchar) * l;
00324
00325 uint lctx = m_ctx.size();
00326 uint lfold = m_foldingList.size();
00327 uint lind = m_indentationDepth.size();
00328
00329 memcpy(buf, &lctx, sizeof(uint));
00330 buf += sizeof(uint);
00331
00332 memcpy(buf, &lfold, sizeof(uint));
00333 buf += sizeof(uint);
00334
00335 memcpy(buf, &lind, sizeof(uint));
00336 buf += sizeof(uint);
00337
00338 memcpy(buf, (char *)m_ctx.data(), sizeof(short) * lctx);
00339 buf += sizeof (short) * lctx;
00340
00341 memcpy(buf, (char *)m_foldingList.data(), sizeof(uint)*lfold);
00342 buf += sizeof (uint) * lfold;
00343
00344 memcpy(buf, (char *)m_indentationDepth.data(), sizeof(unsigned short) * lind);
00345 buf += sizeof (unsigned short) * lind;
00346
00347 return buf;
00348 }
00349
00350 char *KateTextLine::restore (char *buf)
00351 {
00352 uint l = 0;
00353 char f = 0;
00354
00355 memcpy((char *) &f, buf, 1);
00356 buf += 1;
00357
00358
00359 memcpy((char *) &l, buf, sizeof(uint));
00360 buf += sizeof(uint);
00361
00362
00363 m_text.setUnicode ((QChar *) buf, l);
00364 buf += sizeof(QChar) * l;
00365
00366
00367 if (f & KateTextLine::flagNoOtherData)
00368 {
00369 m_flags = 0;
00370
00371 if (f & KateTextLine::flagAutoWrapped)
00372 m_flags = m_flags | KateTextLine::flagAutoWrapped;
00373
00374
00375 m_attributes.fill (0, l);
00376
00377 return buf;
00378 }
00379 else
00380 m_flags = f;
00381
00382 m_attributes.duplicate ((uchar *) buf, l);
00383 buf += sizeof(uchar) * l;
00384
00385 uint lctx = 0;
00386 uint lfold = 0;
00387 uint lind = 0;
00388
00389 memcpy((char *) &lctx, buf, sizeof(uint));
00390 buf += sizeof(uint);
00391
00392 memcpy((char *) &lfold, buf, sizeof(uint));
00393 buf += sizeof(uint);
00394
00395 memcpy((char *) &lind, buf, sizeof(uint));
00396 buf += sizeof(uint);
00397
00398 m_ctx.duplicate ((short *) buf, lctx);
00399 buf += sizeof(short) * lctx;
00400
00401 m_foldingList.duplicate ((uint *) buf, lfold);
00402 buf += sizeof(uint)*lfold;
00403
00404 m_indentationDepth.duplicate ((unsigned short *) buf, lind);
00405 buf += sizeof(unsigned short) * lind;
00406
00407 return buf;
00408 }
00409
00410
00411 void KateTextLine::stringAsHtml(uint startCol, uint length, KateRenderer *renderer, QTextStream *outputStream) const
00412 {
00413 if(length == 0) return;
00414
00415 bool previousCharacterWasBold = false;
00416 bool previousCharacterWasItalic = false;
00417
00418
00419
00420 bool needToReinitializeTags = false;
00421 QColor previousCharacterColor(0,0,0);
00422 QColor blackColor(0,0,0);
00423
00424
00425
00426
00427 for (uint curPos=startCol;curPos<(length+startCol);curPos++)
00428 {
00429 KateAttribute* charAttributes = 0;
00430
00431 charAttributes = renderer->attribute(attribute(curPos));
00432
00433
00434
00435
00436 if ( (charAttributes->textColor() != previousCharacterColor))
00437 {
00438
00439 if (previousCharacterWasBold)
00440 (*outputStream) << "</b>";
00441 if (previousCharacterWasItalic)
00442 (*outputStream) << "</i>";
00443
00444
00445 if(previousCharacterColor != blackColor)
00446 (*outputStream) << "</span>";
00447
00448 int red, green, blue;
00449
00450 charAttributes->textColor().rgb(&red, &green, &blue);
00451 if(!(red == 0 && green == 0 && blue == 0)) {
00452 (*outputStream) << "<span style='color: #"
00453 << ( (red < 0x10)?"0":"")
00454 << QString::number(red, 16)
00455 << ( (green < 0x10)?"0":"")
00456 << QString::number(green, 16)
00457 << ( (blue < 0x10)?"0":"")
00458 << QString::number(blue, 16)
00459 << "'>";
00460 }
00461
00462 needToReinitializeTags = true;
00463 }
00464
00465 if ( (needToReinitializeTags && charAttributes->bold()) ||
00466 (!previousCharacterWasBold && charAttributes->bold()) )
00467
00468 (*outputStream) << "<b>";
00469 if ( !needToReinitializeTags && (previousCharacterWasBold && !charAttributes->bold()) )
00470
00471 (*outputStream) << "</b>";
00472
00473
00474 if ( (needToReinitializeTags && charAttributes->italic()) ||
00475 (!previousCharacterWasItalic && charAttributes->italic()) )
00476
00477 (*outputStream) << "<i>";
00478 if ( !needToReinitializeTags && (previousCharacterWasItalic && !charAttributes->italic()) )
00479
00480 (*outputStream) << "</i>";
00481
00482
00483 (*outputStream) << QStyleSheet::escape(QString(getChar(curPos)));
00484
00485
00486 previousCharacterWasItalic = charAttributes->italic();
00487 previousCharacterWasBold = charAttributes->bold();
00488 previousCharacterColor = charAttributes->textColor();
00489 needToReinitializeTags = false;
00490 }
00491
00492 if (previousCharacterWasBold)
00493 (*outputStream) << "</b>";
00494 if (previousCharacterWasItalic)
00495 (*outputStream) << "</i>";
00496
00497 if(previousCharacterColor != blackColor)
00498 (*outputStream) << "</span>";
00499 }
00500
00501