• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

Kate

katebuffer.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002    Copyright (c) 2000 Waldo Bastian <bastian@kde.org>
00003    Copyright (C) 2002-2004 Christoph Cullmann <cullmann@kde.org>
00004    Copyright (C) 2007 Mirko Stocker <me@misto.ch>
00005 
00006    This library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Library General Public
00008    License version 2 as published by the Free Software Foundation.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018    Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include "katebuffer.h"
00022 #include "katebuffer.moc"
00023 
00024 #include <sys/types.h>
00025 #include <sys/stat.h>
00026 #include <unistd.h>
00027 #include <stdlib.h>
00028 
00029 #include "katedocument.h"
00030 #include "katehighlight.h"
00031 #include "kateconfig.h"
00032 #include "kateglobal.h"
00033 #include "kateautoindent.h"
00034 
00035 #include <kdebug.h>
00036 #include <kglobal.h>
00037 #include <kcharsets.h>
00038 #include <kencodingdetector.h>
00039 
00040 #include <QtCore/QFile>
00041 #include <QtCore/QTextStream>
00042 #include <QtCore/QTimer>
00043 #include <QtCore/QTextCodec>
00044 #include <QtCore/QDate>
00045 
00046 #include <limits.h>
00047 
00053 static const qint64 KATE_FILE_LOADER_BS  = 256 * 1024;
00054 
00060 static const int KATE_HL_LOOKAHEAD = 64;
00061 
00065 static const int KATE_MAX_DYNAMIC_CONTEXTS = 512;
00066 
00067 class KateFileLoader: private KEncodingDetector
00068 {
00069   public:
00070     KateFileLoader (const QString &filename, QTextCodec *codec, bool removeTrailingSpaces, KEncodingDetector::AutoDetectScript script)
00071       : KEncodingDetector(codec,
00072                           script==KEncodingDetector::None?KEncodingDetector::UserChosenEncoding:KEncodingDetector::DefaultEncoding,
00073                           script)
00074       , m_eof (false) // default to not eof
00075       , m_lastWasEndOfLine (true) // at start of file, we had a virtual newline
00076       , m_lastWasR (false) // we have not found a \r as last char
00077       , m_binary (false)
00078       , m_removeTrailingSpaces (removeTrailingSpaces)
00079       , m_utf8Borked (false)
00080       , m_position (0)
00081       , m_lastLineStart (0)
00082       , m_eol (-1) // no eol type detected atm
00083       , m_file (filename)
00084       , m_buffer (qMin (m_file.size() == 0 ? KATE_FILE_LOADER_BS : m_file.size(), KATE_FILE_LOADER_BS), 0) // handle zero sized files special, like in /proc
00085     {
00086       kDebug (13020) << "OPEN USES ENCODING: " << codec->name();
00087     }
00088 
00089     ~KateFileLoader ()
00090     {
00091       //delete m_decoder;
00092     }
00093 
00097     bool open ()
00098     {
00099       if (m_file.open (QIODevice::ReadOnly))
00100       {
00101         int c = m_file.read (m_buffer.data(), m_buffer.size());
00102 
00103         if (c > 0)
00104         {
00105           // fixes utf16 LE
00106           //may change codec if autodetection was set or BOM was found
00107           analyze(m_buffer.data(), c);
00108           m_utf8Borked=errorsIfUtf8(m_buffer.data(), c);
00109           m_binary=processNull(m_buffer.data(), c);
00110           m_text = decoder()->toUnicode(m_buffer, c);
00111         }
00112 
00113         m_eof = (c == -1) || (c == 0);
00114 
00115         for (int i=0; i < m_text.length(); i++)
00116         {
00117           if (m_text[i] == '\n')
00118           {
00119             m_eol = KateDocumentConfig::eolUnix;
00120             break;
00121           }
00122           else if ((m_text[i] == '\r'))
00123           {
00124             if (((i+1) < m_text.length()) && (m_text[i+1] == '\n'))
00125             {
00126               m_eol = KateDocumentConfig::eolDos;
00127               break;
00128             }
00129             else
00130             {
00131               m_eol = KateDocumentConfig::eolMac;
00132               break;
00133             }
00134           }
00135         }
00136 
00137         return true;
00138       }
00139 
00140       return false;
00141     }
00142 
00143     inline const char* actualEncoding () const { return encoding(); }
00144 
00145     // no new lines around ?
00146     inline bool eof () const { return m_eof && !m_lastWasEndOfLine && (m_lastLineStart == m_text.length()); }
00147 
00148     // eol mode ? autodetected on open(), -1 for no eol found in the first block!
00149     inline int eol () const { return m_eol; }
00150 
00151     // binary ?
00152     inline bool binary () const { return m_binary; }
00153 
00154     // broken utf8?
00155     inline bool brokenUTF8 () const { return m_utf8Borked; }
00156 
00157     // should spaces be ignored at end of line?
00158     inline bool removeTrailingSpaces () const { return m_removeTrailingSpaces; }
00159 
00160     // internal unicode data array
00161     inline const QChar *unicode () const { return m_text.unicode(); }
00162 
00163     // read a line, return length + offset in unicode data
00164     void readLine (int &offset, int &length)
00165     {
00166       length = 0;
00167       offset = 0;
00168 
00169       while (m_position <= m_text.length())
00170       {
00171         if (m_position == m_text.length())
00172         {
00173           // try to load more text if something is around
00174           if (!m_eof)
00175           {
00176             int c = m_file.read (m_buffer.data(), m_buffer.size());
00177 
00178             int readString = 0;
00179             if (c > 0)
00180             {
00181               m_binary=processNull(m_buffer.data(), c)||m_binary;
00182               m_utf8Borked=m_utf8Borked||errorsIfUtf8(m_buffer.data(), c);
00183 
00184               QString str (decoder()->toUnicode (m_buffer.data(), c));
00185               readString = str.length();
00186 
00187               m_text = m_text.mid (m_lastLineStart, m_position-m_lastLineStart)
00188                        + str;
00189             }
00190             else
00191               m_text = m_text.mid (m_lastLineStart, m_position-m_lastLineStart);
00192 
00193             // is file completely read ?
00194             m_eof = (c == -1) || (c == 0);
00195 
00196             // recalc current pos and last pos
00197             m_position -= m_lastLineStart;
00198             m_lastLineStart = 0;
00199           }
00200 
00201           // oh oh, end of file, escape !
00202           if (m_eof && (m_position == m_text.length()))
00203           {
00204             m_lastWasEndOfLine = false;
00205 
00206             // line data
00207             offset = m_lastLineStart;
00208             length = m_position-m_lastLineStart;
00209 
00210             m_lastLineStart = m_position;
00211 
00212             return;
00213           }
00214         }
00215 
00216         if (m_text[m_position] == '\n')
00217         {
00218           m_lastWasEndOfLine = true;
00219 
00220           if (m_lastWasR)
00221           {
00222             m_lastLineStart++;
00223             m_lastWasR = false;
00224           }
00225           else
00226           {
00227             // line data
00228             offset = m_lastLineStart;
00229             length = m_position-m_lastLineStart;
00230 
00231             m_lastLineStart = m_position+1;
00232             m_position++;
00233 
00234             return;
00235           }
00236         }
00237         else if (m_text[m_position] == '\r')
00238         {
00239           m_lastWasEndOfLine = true;
00240           m_lastWasR = true;
00241 
00242           // line data
00243           offset = m_lastLineStart;
00244           length = m_position-m_lastLineStart;
00245 
00246           m_lastLineStart = m_position+1;
00247           m_position++;
00248 
00249           return;
00250         }
00251         else
00252         {
00253           m_lastWasEndOfLine = false;
00254           m_lastWasR = false;
00255         }
00256 
00257         m_position++;
00258       }
00259     }
00260 
00261 
00262   private:
00263     bool m_eof;
00264     bool m_lastWasEndOfLine;
00265     bool m_lastWasR;
00266     bool m_binary;
00267     bool m_removeTrailingSpaces;
00268     bool m_utf8Borked;
00269     int m_position;
00270     int m_lastLineStart;
00271     int m_eol;
00272     QFile m_file;
00273     QByteArray m_buffer;
00274     QString m_text;
00275 };
00276 
00280 KateBuffer::KateBuffer(KateDocument *doc)
00281  : QObject (doc),
00282    editSessionNumber (0),
00283    editIsRunning (false),
00284    editTagLineStart (0xffffffff),
00285    editTagLineEnd (0),
00286    editTagLineFrom (false),
00287    editChangesDone (false),
00288    m_doc (doc),
00289    m_binary (false),
00290    m_brokenUTF8 (false),
00291    m_highlight (0),
00292    m_regionTree (this),
00293    m_tabWidth (8),
00294    m_lineHighlightedMax (0),
00295    m_lineHighlighted (0),
00296    m_maxDynamicContexts (KATE_MAX_DYNAMIC_CONTEXTS)
00297 {
00298   clear();
00299 }
00300 
00304 KateBuffer::~KateBuffer()
00305 {
00306   // release HL
00307   if (m_highlight)
00308     m_highlight->release();
00309 }
00310 
00311 void KateBuffer::editStart ()
00312 {
00313   editSessionNumber++;
00314 
00315   if (editSessionNumber > 1)
00316     return;
00317 
00318   editIsRunning = true;
00319 
00320   editTagLineStart = INT_MAX;
00321   editTagLineEnd = 0;
00322   editTagLineFrom = false;
00323 
00324   editChangesDone = false;
00325 }
00326 
00327 void KateBuffer::editEnd ()
00328 {
00329   if (editSessionNumber == 0)
00330     return;
00331 
00332   editSessionNumber--;
00333 
00334   if (editSessionNumber > 0)
00335     return;
00336 
00337   if (editChangesDone)
00338   {
00339     // hl update !!!
00340     if (m_highlight && editTagLineStart <= editTagLineEnd && editTagLineEnd <= m_lineHighlighted)
00341     {
00342       // look one line too far, needed for linecontinue stuff
00343       ++editTagLineEnd;
00344 
00345       // look one line before, needed nearly 100% only for indentation based folding !
00346       if (editTagLineStart > 0)
00347         --editTagLineStart;
00348 
00349       bool needContinue = doHighlight (
00350           editTagLineStart,
00351           editTagLineEnd,
00352           true);
00353 
00354       editTagLineStart = editTagLineEnd;
00355 
00356       if (needContinue)
00357         m_lineHighlighted = editTagLineStart;
00358 
00359       if (editTagLineStart > m_lineHighlightedMax)
00360         m_lineHighlightedMax = editTagLineStart;
00361     }
00362     else if (editTagLineStart < m_lineHighlightedMax)
00363       m_lineHighlightedMax = editTagLineStart;
00364   }
00365 
00366   editIsRunning = false;
00367 }
00368 
00369 void KateBuffer::clear()
00370 {
00371   m_regionTree.clear();
00372 
00373   // one line
00374   m_lines.clear ();
00375   KateTextLine::Ptr textLine (new KateTextLine ());
00376   m_lines.push_back (textLine);
00377 
00378   // reset the state
00379   m_binary = false;
00380   m_brokenUTF8 = false;
00381 
00382   m_lineHighlightedMax = 0;
00383   m_lineHighlighted = 0;
00384 }
00385 
00386 bool KateBuffer::openFile (const QString &m_file)
00387 {
00388    QTime t;
00389     t.start();
00390 
00391   KateFileLoader file (m_file, m_doc->config()->codec(), m_doc->config()->configFlags() & KateDocumentConfig::cfRemoveSpaces, m_doc->scriptForEncodingAutoDetection());
00392 
00393   bool ok = false;
00394   struct stat sbuf;
00395   if (stat(QFile::encodeName(m_file), &sbuf) == 0)
00396   {
00397     if (S_ISREG(sbuf.st_mode) && file.open())
00398       ok = true;
00399   }
00400 
00401   if (!ok)
00402   {
00403     clear();
00404     return false; // Error
00405   }
00406 
00407   m_doc->config()->setEncoding(file.actualEncoding());
00408 
00409   // set eol mode, if a eol char was found in the first 256kb block and we allow this at all!
00410   if (m_doc->config()->allowEolDetection() && (file.eol() != -1))
00411     m_doc->config()->setEol (file.eol());
00412 
00413   // flush current content, one line stays, therefor, remove that
00414   clear ();
00415   m_lines.clear ();
00416 
00417   // read in all lines...
00418   while ( !file.eof() )
00419   {
00420     int offset = 0, length = 0;
00421     file.readLine(offset, length);
00422     const QChar *unicodeData = file.unicode () + offset;
00423 
00424     // strip spaces at end of line
00425     if ( file.removeTrailingSpaces() )
00426     {
00427       while (length > 0)
00428       {
00429         if (unicodeData[length-1].isSpace())
00430           --length;
00431         else
00432           break;
00433       }
00434     }
00435 
00436     KateTextLine::Ptr textLine (new KateTextLine (unicodeData, length));
00437     m_lines.push_back (textLine);
00438   }
00439 
00440   // file was really empty, but we need ONE LINE!!!
00441   if (m_lines.isEmpty())
00442   {
00443     KateTextLine::Ptr textLine (new KateTextLine ());
00444     m_lines.push_back (textLine);
00445   }
00446 
00447   // fix region tree
00448   m_regionTree.fixRoot (m_lines.size());
00449 
00450   // binary?
00451   m_binary = file.binary ();
00452 
00453   // broken utf-8?
00454   m_brokenUTF8 = file.brokenUTF8();
00455   
00456   kDebug (13020) << "Broken UTF-8: " << m_brokenUTF8;
00457 
00458   kDebug (13020) << "LOADING DONE " << t.elapsed();
00459 
00460   return true;
00461 }
00462 
00463 bool KateBuffer::canEncode ()
00464 {
00465   QTextCodec *codec = m_doc->config()->codec();
00466 
00467   kDebug(13020) << "ENC NAME: " << codec->name();
00468 
00469   // hardcode some unicode encodings which can encode all chars
00470   if ((QString(codec->name()) == "UTF-8") || (QString(codec->name()) == "ISO-10646-UCS-2"))
00471     return true;
00472 
00473   for (int i=0; i < m_lines.size(); i++)
00474   {
00475     if (!codec->canEncode (plainLine(i)->string()))
00476     {
00477       kDebug(13020) << "STRING LINE: " << plainLine(i)->string();
00478       kDebug(13020) << "ENC WORKING: FALSE";
00479 
00480       return false;
00481     }
00482   }
00483 
00484   return true;
00485 }
00486 
00487 bool KateBuffer::saveFile (const QString &m_file)
00488 {
00489   QFile file (m_file);
00490   QTextStream stream (&file);
00491 
00492   if ( !file.open( QIODevice::WriteOnly ) )
00493   {
00494     return false; // Error
00495   }
00496 
00497   QTextCodec *codec = m_doc->config()->codec();
00498 
00499   // disable Unicode headers
00500   stream.setCodec(QTextCodec::codecForName("UTF-16"));
00501 
00502   // this line sets the mapper to the correct codec
00503   stream.setCodec(codec);
00504 
00505   // our loved eol string ;)
00506   QString eol = m_doc->config()->eolString ();
00507 
00508   // should we strip spaces?
00509   bool removeTrailingSpaces = m_doc->config()->configFlags() & KateDocumentConfig::cfRemoveSpaces;
00510 
00511   // just dump the lines out ;)
00512   for (int i=0; i < m_lines.size(); i++)
00513   {
00514     KateTextLine::Ptr textline = plainLine(i);
00515 
00516     // strip spaces
00517     if (removeTrailingSpaces)
00518     {
00519       int lastChar = textline->lastChar();
00520 
00521       if (lastChar > -1)
00522       {
00523         stream << textline->string().left(lastChar+1);
00524       }
00525     }
00526     else // simple, dump the line
00527       stream << textline->string();
00528 
00529     if ((i+1) < m_lines.size())
00530       stream << eol;
00531   }
00532 
00533   file.close ();
00534 
00535   return (file.error() == QFile::NoError);
00536 }
00537 
00538 KateTextLine::Ptr KateBuffer::line (int line)
00539 {
00540   // valid line at all?
00541   if (line < 0 || line >= m_lines.size())
00542     return KateTextLine::Ptr();
00543 
00544   // already hl up-to-date for this line?
00545   if (line < m_lineHighlighted)
00546     return m_lines[line];
00547 
00548   // update hl until this line + max KATE_HL_LOOKAHEAD
00549   int end = qMin(line + KATE_HL_LOOKAHEAD, m_lines.size()-1);
00550 
00551   doHighlight ( m_lineHighlighted, end, false );
00552 
00553   m_lineHighlighted = end;
00554 
00555   // update hl max
00556   if (m_lineHighlighted > m_lineHighlightedMax)
00557     m_lineHighlightedMax = m_lineHighlighted;
00558 
00559   return m_lines[line];
00560 }
00561 
00562 void KateBuffer::changeLine(int i)
00563 {
00564   if (i < 0 || i >= m_lines.size())
00565     return;
00566 
00567   // mark buffer changed
00568   editChangesDone = true;
00569 
00570   // tag this line as changed
00571   if (i < editTagLineStart)
00572     editTagLineStart = i;
00573 
00574   if (i > editTagLineEnd)
00575     editTagLineEnd = i;
00576 }
00577 
00578 void KateBuffer::insertLine(int i, KateTextLine::Ptr line)
00579 {
00580   if (i < 0 || i > m_lines.size())
00581     return;
00582 
00583   m_lines.insert (i, line);
00584 
00585   if (m_lineHighlightedMax > i)
00586     m_lineHighlightedMax++;
00587 
00588   if (m_lineHighlighted > i)
00589     m_lineHighlighted++;
00590 
00591   // mark buffer changed
00592   editChangesDone = true;
00593 
00594   // tag this line as inserted
00595   if (i < editTagLineStart)
00596     editTagLineStart = i;
00597 
00598   if (i <= editTagLineEnd)
00599     editTagLineEnd++;
00600 
00601   if (i > editTagLineEnd)
00602     editTagLineEnd = i;
00603 
00604   // line inserted
00605   editTagLineFrom = true;
00606 
00607   m_regionTree.lineHasBeenInserted (i);
00608 }
00609 
00610 void KateBuffer::removeLine(int i)
00611 {
00612   if (i < 0 || i >= m_lines.size())
00613     return;
00614 
00615   m_lines.remove (i);
00616 
00617   if (m_lineHighlightedMax > i)
00618     m_lineHighlightedMax--;
00619 
00620   if (m_lineHighlighted > i)
00621     m_lineHighlighted--;
00622 
00623   // mark buffer changed
00624   editChangesDone = true;
00625 
00626   // tag this line as removed
00627    if (i < editTagLineStart)
00628     editTagLineStart = i;
00629 
00630   if (i < editTagLineEnd)
00631     editTagLineEnd--;
00632 
00633   if (i > editTagLineEnd)
00634     editTagLineEnd = i;
00635 
00636   // make sure tags do not reach past the last line
00637   // see https://bugs.kde.org/show_bug.cgi?id=152497
00638   if (editTagLineEnd >= m_lines.size())
00639     editTagLineEnd = m_lines.size() - 1;
00640 
00641   if (editTagLineStart > editTagLineEnd)
00642     editTagLineStart = editTagLineEnd;
00643 
00644   // line removed
00645   editTagLineFrom = true;
00646 
00647   m_regionTree.lineHasBeenRemoved (i);
00648 }
00649 
00650 void KateBuffer::setTabWidth (int w)
00651 {
00652   if ((m_tabWidth != w) && (m_tabWidth > 0))
00653   {
00654     m_tabWidth = w;
00655 
00656     if (m_highlight && m_highlight->foldingIndentationSensitive())
00657       invalidateHighlighting();
00658   }
00659 }
00660 
00661 void KateBuffer::setHighlight(int hlMode)
00662 {
00663   KateHighlighting *h = KateHlManager::self()->getHl(hlMode);
00664 
00665    // aha, hl will change
00666   if (h != m_highlight)
00667   {
00668     bool invalidate = !h->noHighlighting();
00669 
00670     if (m_highlight)
00671     {
00672       m_highlight->release();
00673       invalidate = true;
00674     }
00675 
00676     h->use();
00677 
00678     // Clear code folding tree (see bug #124102)
00679     m_regionTree.clear();
00680     m_regionTree.fixRoot(m_lines.size());
00681 
00682     // try to set indentation
00683     if (!h->indentation().isEmpty())
00684       m_doc->config()->setIndentationMode (h->indentation());
00685 
00686     m_highlight = h;
00687 
00688     if (invalidate)
00689       invalidateHighlighting();
00690 
00691     // inform the document that the hl was really changed
00692     // needed to update attributes and more ;)
00693     m_doc->bufferHlChanged ();
00694   }
00695 }
00696 
00697 void KateBuffer::invalidateHighlighting()
00698 {
00699   m_lineHighlightedMax = 0;
00700   m_lineHighlighted = 0;
00701 }
00702 
00703 
00704 void KateBuffer::updatePreviousNotEmptyLine(int current_line,bool addindent,int deindent)
00705 {
00706   KateTextLine::Ptr textLine;
00707   do {
00708     if (current_line == 0) return;
00709 
00710     --current_line;
00711 
00712     textLine = m_lines[current_line];
00713   } while (textLine->firstChar()==-1);
00714 
00715   kDebug(13020)<<"updatePreviousNotEmptyLine: updating line:"<<current_line;
00716   QVector<int> foldingList=textLine->foldingListArray();
00717   while ( (foldingList.size()>0)  && ( abs(foldingList[foldingList.size()-2])==1)) {
00718     foldingList.resize(foldingList.size()-2);
00719   }
00720   addIndentBasedFoldingInformation(foldingList,textLine->length(),addindent,deindent);
00721   textLine->setFoldingList(foldingList);
00722 
00723   bool retVal_folding = false;
00724   m_regionTree.updateLine (current_line, &foldingList, &retVal_folding, true,false);
00725 
00726   // tagLines() is emitted from KatBuffer::doHighlight()!
00727 }
00728 
00729 void KateBuffer::addIndentBasedFoldingInformation(QVector<int> &foldingList,int linelength,bool addindent,int deindent)
00730 {
00731   if (addindent) {
00732     //kDebug(13020)<<"adding indent for line :"<<current_line + buf->startLine()<<"  textLine->noIndentBasedFoldingAtStart"<<textLine->noIndentBasedFoldingAtStart();
00733     kDebug(13020)<<"adding ident";
00734     foldingList.resize (foldingList.size() + 2);
00735     foldingList[foldingList.size()-2] = 1;
00736     foldingList[foldingList.size()-1] = 0;
00737   }
00738   kDebug(13020)<<"DEINDENT: "<<deindent;
00739   if (deindent > 0)
00740   {
00741     //foldingList.resize (foldingList.size() + (deindent*2));
00742 
00743     //Make the whole last line marked as still belonging to the block
00744     for (int z=0;z<deindent;z++) {
00745       //FIXME: Not sure if this is really a performance problem
00746       foldingList.prepend(linelength+1);
00747       foldingList.prepend(-1);
00748     }
00749 
00750 /*    for (int z= foldingList.size()-(deindent*2); z < foldingList.size(); z=z+2)
00751     {
00752       foldingList[z] = -1;
00753       foldingList[z+1] = 0;
00754     }*/
00755   }
00756 }
00757 
00758 
00759 bool KateBuffer::isEmptyLine(KateTextLine::Ptr textline)
00760 {
00761   QLinkedList<QRegExp> l;
00762   l=m_highlight->emptyLines(textline->attribute(0));
00763   kDebug(13020)<<"trying to find empty line data";
00764   if (l.isEmpty()) return false;
00765   QString txt=textline->string();
00766   kDebug(13020)<<"checking empty line regexp";
00767   foreach(const QRegExp &re,l) {
00768     if (re.exactMatch(txt)) return true;
00769   }
00770   kDebug(13020)<<"no matches";
00771   return false;
00772 }
00773 
00774 bool KateBuffer::doHighlight (int startLine, int endLine, bool invalidate)
00775 {
00776   // no hl around, no stuff to do
00777   if (!m_highlight)
00778     return false;
00779 
00780   /*if (m_highlight->foldingIndentationSensitive())
00781   {
00782     startLine=0;
00783     endLine=50;
00784   }*/
00785 
00786   //QTime t;
00787   //t.start();
00788   //kDebug (13020) << "HIGHLIGHTED START --- NEED HL, LINESTART: " << startLine << " LINEEND: " << endLine;
00789   //kDebug (13020) << "HL UNTIL LINE: " << m_lineHighlighted << " MAX: " << m_lineHighlightedMax;
00790   //kDebug (13020) << "HL DYN COUNT: " << KateHlManager::self()->countDynamicCtxs() << " MAX: " << m_maxDynamicContexts;
00791 
00792   // see if there are too many dynamic contexts; if yes, invalidate HL of all documents
00793   if (KateHlManager::self()->countDynamicCtxs() >= m_maxDynamicContexts)
00794   {
00795     {
00796       if (KateHlManager::self()->resetDynamicCtxs())
00797       {
00798         kDebug (13020) << "HL invalidated - too many dynamic contexts ( >= " << m_maxDynamicContexts << ")";
00799 
00800         // avoid recursive invalidation
00801         KateHlManager::self()->setForceNoDCReset(true);
00802 
00803         for (int i=0; i < KateGlobal::self()->kateDocuments().size(); ++i)
00804           (KateGlobal::self()->kateDocuments())[i]->makeAttribs();
00805 
00806         // doHighlight *shall* do his work. After invalidation, some highlight has
00807         // been recalculated, but *maybe not* until endLine ! So we shall force it manually...
00808         doHighlight ( m_lineHighlighted, endLine, false );
00809         m_lineHighlighted = endLine;
00810 
00811         KateHlManager::self()->setForceNoDCReset(false);
00812 
00813         return false;
00814       }
00815       else
00816       {
00817         m_maxDynamicContexts *= 2;
00818         kDebug (13020) << "New dynamic contexts limit: " << m_maxDynamicContexts;
00819       }
00820     }
00821   }
00822 
00823   // get previous line, if any
00824   KateTextLine::Ptr prevLine;
00825 
00826   if (startLine >= 1)
00827     prevLine = m_lines[startLine-1];
00828   else
00829     prevLine = new KateTextLine ();
00830 
00831   // does we need to emit a signal for the folding changes ?
00832   bool codeFoldingUpdate = false;
00833 
00834   // here we are atm, start at start line in the block
00835   int current_line = startLine;
00836 
00837   // do we need to continue
00838   bool stillcontinue=false;
00839   bool indentContinueWhitespace=false;
00840   bool indentContinueNextWhitespace=false;
00841   // loop over the lines of the block, from startline to endline or end of block
00842   // if stillcontinue forces us to do so
00843   while ( (current_line < m_lines.size()) && (stillcontinue || (current_line <= endLine)) )
00844   {
00845     // current line
00846     KateTextLine::Ptr textLine = m_lines[current_line];
00847 
00848     QVector<int> foldingList;
00849     bool ctxChanged = false;
00850 
00851     m_highlight->doHighlight (prevLine.data(), textLine.data(), foldingList, ctxChanged);
00852 
00853     // debug stuff
00854     //kDebug( 13020 ) << "current line to hl: " << current_line + buf->startLine();
00855     //kDebug( 13020 ) << "text length: " << textLine->length() << " attribute list size: " << textLine->attributesList().size();
00856     /*
00857     const QVector<int> &ml (textLine->attributesList());
00858     for (int i=2; i < ml.size(); i+=3)
00859     {
00860       kDebug( 13020 ) << "start: " << ml[i-2] << " len: " << ml[i-1] << " at: " << ml[i] << " ";
00861     }
00862     kDebug( 13020 );
00863 */
00864     //
00865     // indentation sensitive folding
00866     //
00867     bool indentChanged = false;
00868     if (m_highlight->foldingIndentationSensitive())
00869     {
00870       // get the indentation array of the previous line to start with !
00871       QVector<unsigned short> indentDepth (prevLine->indentationDepthArray());
00872 
00873       // current indentation of this line
00874       int iDepth = textLine->indentDepth(m_tabWidth);
00875       if (current_line==0)
00876       {
00877           indentDepth.resize (1);
00878           indentDepth[0] = iDepth;
00879       }
00880 
00881       textLine->setNoIndentBasedFoldingAtStart(prevLine->noIndentBasedFolding());
00882       // this line is empty, beside spaces, or has indentaion based folding disabled, use indentation depth of the previous line !
00883       kDebug(13020)<<"current_line:"<<current_line<<" textLine->noIndentBasedFoldingAtStart"<<textLine->noIndentBasedFoldingAtStart();
00884       if ( (textLine->firstChar() == -1) || textLine->noIndentBasedFoldingAtStart() || isEmptyLine(textLine) )
00885       {
00886         // do this to get skipped empty lines indent right, which was given in the indenation array
00887         if (!prevLine->indentationDepthArray().isEmpty())
00888         {
00889           iDepth = (prevLine->indentationDepthArray())[prevLine->indentationDepthArray().size()-1];
00890           kDebug(13020)<<"reusing old depth as current";
00891         }
00892         else
00893         {
00894           iDepth = prevLine->indentDepth(m_tabWidth);
00895           kDebug(13020)<<"creating indentdepth for previous line";
00896         }
00897       }
00898 
00899       kDebug(13020)<<"iDepth:"<<iDepth;
00900 
00901       // query the next line indentation, if we are at the end of the block
00902       // use the first line of the next buf block
00903       int nextLineIndentation = 0;
00904       bool nextLineIndentationValid=true;
00905       indentContinueNextWhitespace=false;
00906       if ((current_line+1) < m_lines.size())
00907       {
00908         if ( (m_lines[current_line+1]->firstChar() == -1) || isEmptyLine(m_lines[current_line+1]) )
00909         {
00910           nextLineIndentation = iDepth;
00911           indentContinueNextWhitespace=true;
00912         }
00913         else
00914           nextLineIndentation = m_lines[current_line+1]->indentDepth(m_tabWidth);
00915       }
00916       else
00917       {
00918         nextLineIndentationValid=false;
00919       }
00920 
00921       if  (!textLine->noIndentBasedFoldingAtStart()) {
00922 
00923         if ((iDepth > 0) && (indentDepth.isEmpty() || (indentDepth[indentDepth.size()-1] < iDepth)))
00924         {
00925           kDebug(13020)<<"adding depth to \"stack\":"<<iDepth;
00926           indentDepth.append (iDepth);
00927         } else {
00928           if (!indentDepth.isEmpty())
00929           {
00930             for (int z=indentDepth.size()-1; z > -1; z--)
00931               if (indentDepth[z]>iDepth)
00932                 indentDepth.resize(z);
00933             if ((iDepth > 0) && (indentDepth.isEmpty() || (indentDepth[indentDepth.size()-1] < iDepth)))
00934             {
00935               kDebug(13020)<<"adding depth to \"stack\":"<<iDepth;
00936               indentDepth.append (iDepth);
00937               if (prevLine->firstChar()==-1) {
00938 
00939               }
00940             }
00941           }
00942         }
00943       }
00944 
00945       if (!textLine->noIndentBasedFolding())
00946       {
00947         if (nextLineIndentationValid)
00948         {
00949           //if (textLine->firstChar()!=-1)
00950           {
00951             kDebug(13020)<<"nextLineIndentation:"<<nextLineIndentation;
00952             bool addindent=false;
00953             int deindent=0;
00954             if (!indentDepth.isEmpty())
00955               kDebug(13020)<<"indentDepth[indentDepth.size()-1]:"<<indentDepth[indentDepth.size()-1];
00956             if ((nextLineIndentation>0) && ( indentDepth.isEmpty() || (indentDepth[indentDepth.size()-1]<nextLineIndentation)))
00957             {
00958               kDebug(13020)<<"addindent==true";
00959               addindent=true;
00960             } else {
00961             if ((!indentDepth.isEmpty()) && (indentDepth[indentDepth.size()-1]>nextLineIndentation))
00962               {
00963                 kDebug(13020)<<"....";
00964                 for (int z=indentDepth.size()-1; z > -1; z--)
00965                 {
00966                   kDebug(13020)<<indentDepth[z]<<"  "<<nextLineIndentation;
00967                   if (indentDepth[z]>nextLineIndentation)
00968                     deindent++;
00969                 }
00970               }
00971             }
00972 /*        }
00973         if (textLine->noIndentBasedFolding()) kDebug(13020)<<"=============================indentation based folding disabled======================";
00974         if (!textLine->noIndentBasedFolding()) {*/
00975             if ((textLine->firstChar()==-1)) {
00976               updatePreviousNotEmptyLine(current_line,addindent,deindent);
00977               codeFoldingUpdate=true;
00978             }
00979             else
00980             {
00981               addIndentBasedFoldingInformation(foldingList,textLine->length(),addindent,deindent);
00982             }
00983           }
00984         }
00985       }
00986       indentChanged = !(indentDepth == textLine->indentationDepthArray());
00987 
00988       // assign the new array to the textline !
00989       if (indentChanged)
00990         textLine->setIndentationDepth (indentDepth);
00991 
00992       indentContinueWhitespace=textLine->firstChar()==-1;
00993     }
00994     bool foldingColChanged=false;
00995     bool foldingChanged = false; 
00996     if (foldingList.size()!=textLine->foldingListArray().size()) {
00997       foldingChanged=true;
00998     } else {
00999       QVector<int>::ConstIterator it=foldingList.begin();
01000       QVector<int>::ConstIterator it1=textLine->foldingListArray().begin();
01001       bool markerType=true;
01002       for(;it!=foldingList.end();++it,++it1) {
01003         if  (markerType) {
01004           if ( ((*it)!=(*it1))) {
01005             foldingChanged=true;
01006             foldingColChanged=false;
01007             break;
01008           }
01009         } else {
01010             if ((*it)!=(*it1)) {
01011               foldingColChanged=true;
01012             }
01013         }
01014         markerType=!markerType;
01015       }
01016     }
01017 
01018     if (foldingChanged || foldingColChanged) {
01019       textLine->setFoldingList(foldingList);
01020       if (foldingChanged==false){
01021         textLine->setFoldingColumnsOutdated(textLine->foldingColumnsOutdated() | foldingColChanged);
01022       } else textLine->setFoldingColumnsOutdated(false);
01023     }
01024     bool retVal_folding = false;
01025     //perhaps make en enums out of the change flags
01026     m_regionTree.updateLine (current_line, &foldingList, &retVal_folding, foldingChanged,foldingColChanged);
01027 
01028     codeFoldingUpdate = codeFoldingUpdate | retVal_folding;
01029 
01030     // need we to continue ?
01031     stillcontinue = ctxChanged || indentChanged || indentContinueWhitespace || indentContinueNextWhitespace;
01032 
01033     // move around the lines
01034     prevLine = textLine;
01035 
01036     // increment line
01037     current_line++;
01038   }
01039 
01040   // tag the changed lines !
01041   if (invalidate)
01042     emit tagLines (startLine, current_line);
01043 
01044   // emit that we have changed the folding
01045   if (codeFoldingUpdate)
01046     emit codeFoldingUpdated();
01047 
01048   //kDebug (13020) << "HIGHLIGHTED END --- NEED HL, LINESTART: " << startLine << " LINEEND: " << endLine;
01049   //kDebug (13020) << "HL UNTIL LINE: " << m_lineHighlighted << " MAX: " << m_lineHighlightedMax;
01050   //kDebug (13020) << "HL DYN COUNT: " << KateHlManager::self()->countDynamicCtxs() << " MAX: " << m_maxDynamicContexts;
01051   //kDebug (13020) << "TIME TAKEN: " << t.elapsed();
01052 
01053   // if we are at the last line of the block + we still need to continue
01054   // return the need of that !
01055   return stillcontinue;
01056 }
01057 
01058 void KateBuffer::codeFoldingColumnUpdate(int lineNr) {
01059   KateTextLine::Ptr line=plainLine(lineNr);
01060   if (!line) return;
01061   if (line->foldingColumnsOutdated()) {
01062     line->setFoldingColumnsOutdated(false);
01063     bool tmp;
01064     QVector<int> folding=line->foldingListArray();
01065     m_regionTree.updateLine(lineNr,&folding,&tmp,true,false);
01066   }
01067 }
01068 
01069 // kate: space-indent on; indent-width 2; replace-tabs on;

Kate

Skip menu "Kate"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • KIO
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal