00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "katecodefolding.h"
00020 #include "katecodefolding.moc"
00021
00022 #include "katebuffer.h"
00023 #include "katecursor.h"
00024 #include <kdebug.h>
00025
00026 #include <QtCore/QString>
00027
00028 #define JW_DEBUG 0
00029
00030 bool KateCodeFoldingTree::trueVal = true;
00031
00032 KateCodeFoldingNode::KateCodeFoldingNode() :
00033 parentNode(0),
00034 startLineRel(0),
00035 endLineRel(0),
00036 startCol(0),
00037 endCol(0),
00038 startLineValid(false),
00039 endLineValid(false),
00040 type(0),
00041 visible(true),
00042 deleteOpening(false),
00043 deleteEnding(false)
00044 {
00045 }
00046
00047 KateCodeFoldingNode::KateCodeFoldingNode(KateCodeFoldingNode *par, signed char typ, unsigned int sLRel):
00048 parentNode(par),
00049 startLineRel(sLRel),
00050 endLineRel(10000),
00051 startCol(0),
00052 endCol(0),
00053 startLineValid(true),
00054 endLineValid(false),
00055 type(typ),
00056 visible(true),
00057 deleteOpening(false),
00058 deleteEnding(false)
00059 {
00060 }
00061
00062 KateCodeFoldingNode::~KateCodeFoldingNode()
00063 {
00064
00065 clearChildren ();
00066 }
00067
00068 bool KateCodeFoldingNode::getBegin(KateCodeFoldingTree *tree, KTextEditor::Cursor* begin) {
00069 if (!startLineValid) return false;
00070 unsigned int line=startLineRel;
00071 for (KateCodeFoldingNode *n=parentNode;n;n=n->parentNode)
00072 line+=n->startLineRel;
00073
00074 tree->m_buffer->codeFoldingColumnUpdate(line);
00075 begin->setLine(line);
00076 begin->setColumn(startCol);
00077
00078 return true;
00079 }
00080
00081 bool KateCodeFoldingNode::getEnd(KateCodeFoldingTree *tree, KTextEditor::Cursor *end) {
00082 if (!endLineValid) return false;
00083 unsigned int line=startLineRel+endLineRel;
00084 for (KateCodeFoldingNode *n=parentNode;n;n=n->parentNode)
00085 line+=n->startLineRel;
00086
00087 tree->m_buffer->codeFoldingColumnUpdate(line);
00088 end->setLine(line);
00089 end->setColumn(endCol);
00090
00091 return true;
00092 }
00093
00094 int KateCodeFoldingNode::cmpPos(KateCodeFoldingTree *tree, uint line,uint col) {
00095 KTextEditor::Cursor cur(line,col);
00096 KTextEditor::Cursor start,end;
00097 kDebug(13000)<<"KateCodeFoldingNode::cmpPos (1)";
00098 bool startValid=getBegin(tree, &start);
00099 kDebug(13000)<<"KateCodeFoldingNode::cmpPos (2)";
00100 bool endValid=getEnd(tree, &end);
00101 kDebug(13000)<<"KateCodeFoldingNode::cmpPos (3)";
00102 if ((!endValid) && startValid) {
00103 return ((start>cur)?-1:0);
00104 }
00105 if ((!startValid) && endValid) {
00106 return ((cur>end)?1:0);
00107 }
00108
00109 Q_ASSERT(startValid && endValid);
00110 return ( (cur<start)?(-1):( (cur>end) ? 1:0));
00111 }
00112
00113 void KateCodeFoldingNode::insertChild (uint index, KateCodeFoldingNode *node)
00114 {
00115 uint s = m_children.size ();
00116
00117 if (index > s)
00118 return;
00119
00120 m_children.resize (++s);
00121
00122 for (uint i=s-1; i > index; --i)
00123 m_children[i] = m_children[i-1];
00124
00125 m_children[index] = node;
00126 }
00127
00128 KateCodeFoldingNode *KateCodeFoldingNode::takeChild (uint index)
00129 {
00130 uint s = m_children.size ();
00131
00132 if (index >= s)
00133 return 0;
00134
00135 KateCodeFoldingNode *n = m_children[index];
00136
00137 for (uint i=index; (i+1) < s; ++i)
00138 m_children[i] = m_children[i+1];
00139
00140 m_children.resize (s-1);
00141
00142 return n;
00143 }
00144
00145 void KateCodeFoldingNode::clearChildren ()
00146 {
00147 for (int i=0; i < m_children.size(); ++i)
00148 delete m_children[i];
00149
00150 m_children.resize (0);
00151 }
00152
00153 KateCodeFoldingTree::KateCodeFoldingTree(KateBuffer *buffer): QObject(buffer), m_buffer (buffer)
00154 {
00155 clear();
00156 }
00157
00158 void KateCodeFoldingTree::fixRoot(int endLRel)
00159 {
00160 m_root.endLineRel = endLRel;
00161 }
00162
00163 void KateCodeFoldingTree::clear()
00164 {
00165 m_root.clearChildren();
00166
00167
00168 m_root.startLineValid=true;
00169 m_root.endLineValid=true;
00170 m_root.endLineRel=1;
00171
00172 hiddenLinesCountCacheValid=false;
00173 hiddenLines.clear();
00174 lineMapping.clear();
00175 nodesForLine.clear();
00176 markedForDeleting.clear();
00177 dontIgnoreUnchangedLines.clear();
00178 }
00179
00180 KateCodeFoldingTree::~KateCodeFoldingTree()
00181 {
00182 }
00183
00184 bool KateCodeFoldingTree::isTopLevel(unsigned int line)
00185 {
00186 if (m_root.noChildren())
00187 return true;
00188
00189
00190 for ( int i=0; i < m_root.childCount(); ++i )
00191 {
00192 KateCodeFoldingNode *node = m_root.child(i);
00193
00194 if ((node->startLineRel<=line) && (line<=node->startLineRel+node->endLineRel))
00195 return false;
00196 }
00197
00198 return true;
00199 }
00200
00201 void KateCodeFoldingTree::getLineInfo(KateLineInfo *info, unsigned int line)
00202 {
00203
00204
00205 info->topLevel = true;
00206 info->startsVisibleBlock = false;
00207 info->startsInVisibleBlock = false;
00208 info->endsBlock = false;
00209 info->invalidBlockEnd = false;
00210 info->depth=0;
00211 if (m_root.noChildren())
00212 return;
00213
00214
00215 for ( int i=0; i < m_root.childCount(); ++i )
00216 {
00217 KateCodeFoldingNode *node = m_root.child(i);
00218
00219 if ((node->startLineRel<=line) && (line<=node->startLineRel+node->endLineRel))
00220 {
00221 info->topLevel = false;
00222 findAllNodesOpenedOrClosedAt(line);
00223
00224 foreach (KateCodeFoldingNode* node, nodesForLine)
00225 {
00226 uint startLine = getStartLine(node);
00227
00228
00229
00230 if (node->type < 0)
00231 info->invalidBlockEnd=true;
00232 else
00233 {
00234 if (startLine != line)
00235 info->endsBlock = true;
00236 else
00237 {
00238
00239 if (node->visible)
00240 info->startsVisibleBlock=true;
00241 else
00242 info->startsInVisibleBlock=true;
00243 }
00244 }
00245 }
00246 KateCodeFoldingNode *node = findNodeForLine(line);
00247 int depth=0;
00248 while (node)
00249 {
00250 node = node->getParentNode();
00251 depth++;
00252 }
00253 if (depth>0) depth--;
00254 info->depth=depth;
00255 return;
00256 }
00257 }
00258
00259 return;
00260 }
00261
00262
00263 KateCodeFoldingNode *KateCodeFoldingTree::findNodeForLine(unsigned int line)
00264 {
00265 if (m_root.noChildren())
00266 return &m_root;
00267
00268
00269 for ( int i=0; i < m_root.childCount(); ++i )
00270 {
00271 KateCodeFoldingNode *node = m_root.child(i);
00272
00273 if (node->startLineValid && (node->startLineRel<=line) && (line<=node->startLineRel+node->endLineRel))
00274 {
00275
00276 return findNodeForLineDescending(node,line,0);
00277 }
00278 }
00279
00280 return &m_root;
00281 }
00282
00283
00284 KateCodeFoldingNode *KateCodeFoldingTree::findNodeForLineDescending ( KateCodeFoldingNode *node,
00285 unsigned int line, unsigned int offset, bool oneStepOnly )
00286 {
00287 if (node->noChildren())
00288 return node;
00289
00290
00291 offset += node->startLineRel;
00292
00293 for ( int i=0; i < node->childCount(); ++i )
00294 {
00295 KateCodeFoldingNode *subNode = node->child(i);
00296
00297 if ((subNode->startLineRel+offset<=line) && (line<=subNode->endLineRel+subNode->startLineRel+offset))
00298 {
00299
00300
00301
00302 if (oneStepOnly)
00303 return subNode;
00304 else
00305 return findNodeForLineDescending (subNode,line,offset);
00306 }
00307 }
00308
00309 return node;
00310 }
00311
00312 KateCodeFoldingNode *KateCodeFoldingTree::findNodeForPosition(unsigned int line, unsigned int column)
00313 {
00314 KateCodeFoldingNode *node=findNodeForLine(line);
00315
00316 if (node==&m_root) return &m_root;
00317
00318 kDebug(13000)<<"initial cmpPos";
00319
00320 KateCodeFoldingNode *tmp;
00321 int leq=node->cmpPos(this, line,column);
00322 while (true) {
00323 switch (leq) {
00324 case 0: {
00325 if (node->noChildren())
00326 return node;
00327 else
00328 {
00329 tmp=node;
00330 for ( int i=0; i < node->childCount(); ++i )
00331 {
00332 KateCodeFoldingNode *subNode = node->child(i);
00333 kDebug(13000)<<"cmdPos(case0):calling";
00334 leq=subNode->cmpPos(this, line,column);
00335 kDebug(13000)<<"cmdPos(case0):returned";
00336 if (leq==0) {
00337 tmp=subNode;
00338 break;
00339 } else if (leq==-1) break;
00340 }
00341 if (tmp!=node) node=tmp; else return node;
00342 }
00343 break;
00344 }
00345
00346 case -1:
00347 case 1: {
00348 if (!(node->parentNode)) return &m_root;
00349 kDebug(13000)<<"current node type"<<node->type;
00350 node=node->parentNode;
00351 kDebug(13000)<<"cmdPos(case-1/1):calling:"<<node;
00352 leq=node->cmpPos(this, line,column);
00353 kDebug(13000)<<"cmdPos(case-1/1):returned";
00354 break;
00355 }
00356 }
00357
00358 }
00359 Q_ASSERT(false);
00360 return &m_root;
00361 }
00362
00363 void KateCodeFoldingTree::debugDump()
00364 {
00365
00366 kDebug(13000)<<"The parsed region/block tree for code folding";
00367 dumpNode(&m_root, "");
00368 }
00369
00370 void KateCodeFoldingTree::dumpNode(KateCodeFoldingNode *node, const QString &prefix)
00371 {
00372
00373 kDebug(13000)<<prefix<<QString("Type: %1, startLineValid %2, startLineRel %3, endLineValid %4, endLineRel %5, visible %6").
00374 arg(node->type).arg(node->startLineValid).arg(node->startLineRel).arg(node->endLineValid).
00375 arg(node->endLineRel).arg(node->visible)<<endl;
00376
00377
00378 if (node->noChildren())
00379 return;
00380
00381 QString newprefix(prefix + " ");
00382 for ( int i=0; i < node->childCount(); ++i )
00383 dumpNode (node->child(i),newprefix);
00384 }
00385
00386
00387
00388
00389 void KateCodeFoldingTree::updateLine(unsigned int line,
00390 QVector<int> *regionChanges, bool *updated,bool changed,bool colsChanged)
00391 {
00392 if ( (!changed) || colsChanged)
00393 {
00394 if (dontIgnoreUnchangedLines.isEmpty())
00395 return;
00396
00397 if (dontIgnoreUnchangedLines.contains(line))
00398 dontIgnoreUnchangedLines.remove(line);
00399 else
00400 return;
00401 }
00402
00403 something_changed = false;
00404
00405 findAndMarkAllNodesforRemovalOpenedOrClosedAt(line);
00406
00407 if (regionChanges->isEmpty())
00408 {
00409
00410
00411
00412 }
00413 else
00414 {
00415 for (int i=0;i<regionChanges->size() / 4;i++)
00416 {
00417 signed char tmp=(*regionChanges)[regionChanges->size()-2-i*2];
00418 uint tmppos=(*regionChanges)[regionChanges->size()-1-i*2];
00419 (*regionChanges)[regionChanges->size()-2-i*2]=(*regionChanges)[i*2];
00420 (*regionChanges)[regionChanges->size()-1-i*2]=(*regionChanges)[i*2+1];
00421 (*regionChanges)[i*2]=tmp;
00422 (*regionChanges)[i*2+1]=tmppos;
00423 }
00424
00425
00426 signed char data= (*regionChanges)[regionChanges->size()-2];
00427 uint charPos=(*regionChanges)[regionChanges->size()-1];
00428 regionChanges->resize (regionChanges->size()-2);
00429
00430 int insertPos=-1;
00431 KateCodeFoldingNode *node = findNodeForLine(line);
00432
00433 if (data<0)
00434 {
00435
00436 {
00437 unsigned int tmpLine=line-getStartLine(node);
00438
00439 for ( int i=0; i < node->childCount(); ++i )
00440 {
00441 if (node->child(i)->startLineRel >= tmpLine)
00442 {
00443 insertPos=i;
00444 break;
00445 }
00446 }
00447 }
00448 }
00449 else
00450 {
00451 for (; (node->parentNode) && (getStartLine(node->parentNode)==line) &&
00452 (node->parentNode->type!=0); node=node->parentNode) {
00453 ;
00454 }
00455
00456 if ((getStartLine(node)==line) && (node->type!=0))
00457 {
00458 insertPos=node->parentNode->findChild(node);
00459 node = node->parentNode;
00460 }
00461 else
00462 {
00463 for ( int i=0; i < node->childCount(); ++i )
00464 {
00465 if (getStartLine(node->child(i))>=line)
00466 {
00467 insertPos=i;
00468 break;
00469 }
00470 }
00471 }
00472 }
00473
00474 do
00475 {
00476 if (data<0)
00477 {
00478 if (correctEndings(data,node,line,charPos,insertPos))
00479 {
00480 insertPos=node->parentNode->findChild(node)+1;
00481 node=node->parentNode;
00482 }
00483 else
00484 {
00485 if (insertPos!=-1) insertPos++;
00486 }
00487 }
00488 else
00489 {
00490 int startLine=getStartLine(node);
00491 if ((insertPos==-1) || (insertPos>=(int)node->childCount()))
00492 {
00493 KateCodeFoldingNode *newNode = new KateCodeFoldingNode (node,data,line-startLine);
00494 something_changed = true;
00495 node->appendChild(newNode);
00496 addOpening(newNode, data, regionChanges, line,charPos);
00497 insertPos = node->findChild(newNode)+1;
00498 }
00499 else
00500 {
00501 if (node->child(insertPos)->startLineRel == line-startLine)
00502 {
00503 addOpening(node->child(insertPos), data, regionChanges, line,charPos);
00504 insertPos++;
00505 }
00506 else
00507 {
00508
00509 KateCodeFoldingNode *newNode = new KateCodeFoldingNode (node,data,line-startLine);
00510 something_changed = true;
00511 node->insertChild(insertPos, newNode);
00512 addOpening(newNode, data, regionChanges, line,charPos);
00513 insertPos++;
00514 }
00515 }
00516 }
00517
00518 if (regionChanges->isEmpty())
00519 data = 0;
00520 else
00521 {
00522 data = (*regionChanges)[regionChanges->size()-2];
00523 charPos=(*regionChanges)[regionChanges->size()-1];
00524 regionChanges->resize (regionChanges->size()-2);
00525 }
00526 } while (data!=0);
00527 }
00528
00529 cleanupUnneededNodes(line);
00530
00531 (*updated) = something_changed;
00532 }
00533
00534
00535 bool KateCodeFoldingTree::removeOpening(KateCodeFoldingNode *node,unsigned int line)
00536 {
00537 signed char type;
00538 if ((type=node->type) == 0)
00539 {
00540 dontDeleteOpening(node);
00541 dontDeleteEnding(node);
00542 return false;
00543 }
00544
00545 if (!node->visible)
00546 {
00547 toggleRegionVisibility(getStartLine(node));
00548 }
00549
00550 KateCodeFoldingNode *parent = node->parentNode;
00551 int mypos = parent->findChild(node);
00552
00553 if (mypos > -1)
00554 {
00555
00556 for(; node->childCount()>0 ;)
00557 {
00558 KateCodeFoldingNode *tmp;
00559 parent->insertChild(mypos, tmp=node->takeChild(0));
00560 tmp->parentNode = parent;
00561 tmp->startLineRel += node->startLineRel;
00562 mypos++;
00563 }
00564
00565
00566
00567 bool endLineValid = node->endLineValid;
00568 int endLineRel = node->endLineRel;
00569 uint endCol=node->endCol;
00570
00571
00572 KateCodeFoldingNode *child = parent->takeChild(mypos);
00573 markedForDeleting.removeAll(child);
00574 delete child;
00575
00576 if ((type>0) && (endLineValid))
00577 correctEndings(-type, parent, line+endLineRel,endCol, mypos);
00578 }
00579
00580 return true;
00581 }
00582
00583 bool KateCodeFoldingTree::removeEnding(KateCodeFoldingNode *node,unsigned int )
00584 {
00585 KateCodeFoldingNode *parent = node->parentNode;
00586
00587 if (!parent)
00588 return false;
00589
00590 if (node->type == 0)
00591 return false;
00592
00593 if (node->type < 0)
00594 {
00595
00596 int i = parent->findChild (node);
00597 if (i >= 0)
00598 {
00599 KateCodeFoldingNode *child = parent->takeChild(i);
00600 markedForDeleting.removeAll(child);
00601 delete child;
00602 }
00603
00604 return true;
00605 }
00606
00607 int mypos = parent->findChild(node);
00608 int count = parent->childCount();
00609
00610 for (int i=mypos+1; i<count; i++)
00611 {
00612 if (parent->child(i)->type == -node->type)
00613 {
00614 node->endLineValid = true;
00615 node->endLineRel = parent->child(i)->startLineRel - node->startLineRel;
00616
00617 KateCodeFoldingNode *child = parent->takeChild(i);
00618 markedForDeleting.removeAll(child);
00619 delete child;
00620
00621 count = i-mypos-1;
00622 if (count > 0)
00623 {
00624 for (int i=0; i<count; i++)
00625 {
00626 KateCodeFoldingNode *tmp = parent->takeChild(mypos+1);
00627 tmp->startLineRel -= node->startLineRel;
00628 tmp->parentNode = node;
00629 node->appendChild(tmp);
00630 }
00631 }
00632 return false;
00633 }
00634 }
00635
00636 if ( (parent->type == node->type) || (!parent->parentNode))
00637 {
00638 for (int i=mypos+1; i<(int)parent->childCount(); i++)
00639 {
00640 KateCodeFoldingNode *tmp = parent->takeChild(mypos+1);
00641 tmp->startLineRel -= node->startLineRel;
00642 tmp->parentNode = node;
00643 node->appendChild(tmp);
00644 }
00645
00646
00647 if (!parent->parentNode)
00648 node->endLineValid=false;
00649 else
00650 node->endLineValid = parent->endLineValid;
00651
00652 node->endLineRel = parent->endLineRel-node->startLineRel;
00653
00654 if (node->endLineValid)
00655 return removeEnding(parent, getStartLine(parent)+parent->endLineRel);
00656
00657 return false;
00658 }
00659
00660 node->endLineValid = false;
00661 node->endLineRel = parent->endLineRel - node->startLineRel;
00662
00663 return false;
00664 }
00665
00666
00667 bool KateCodeFoldingTree::correctEndings(signed char data, KateCodeFoldingNode *node,unsigned int line,unsigned int endCol,int insertPos)
00668 {
00669
00670 uint startLine = getStartLine(node);
00671 if (data != -node->type)
00672 {
00673 #if JW_DEBUG
00674 kDebug(13000)<<"data!=-node->type (correctEndings)";
00675 #endif
00676
00677 dontDeleteEnding(node);
00678 if (data == node->type) {
00679 node->endCol=endCol;
00680 return false;
00681 }
00682 KateCodeFoldingNode *newNode = new KateCodeFoldingNode (node,data,line-startLine);
00683 something_changed = true;
00684 newNode->startLineValid = false;
00685 newNode->endLineValid = true;
00686 newNode->endLineRel = 0;
00687 newNode->endCol=endCol;
00688
00689 if ((insertPos==-1) || (insertPos==(int)node->childCount()))
00690 node->appendChild(newNode);
00691 else
00692 node->insertChild(insertPos,newNode);
00693
00694
00695 return false;
00696 }
00697 else
00698 {
00699 something_changed = true;
00700 dontDeleteEnding(node);
00701
00702
00703 if (!node->endLineValid)
00704 {
00705 node->endLineValid = true;
00706 node->endLineRel = line - startLine;
00707 node->endCol=endCol;
00708
00709
00710 moveSubNodesUp(node);
00711 }
00712 else
00713 {
00714 #if JW_DEBUG
00715 kDebug(13000)<<"Closing a node which had already a valid end";
00716 #endif
00717
00718 if (startLine+node->endLineRel == line)
00719 {
00720 node->endCol=endCol;
00721
00722 #if JW_DEBUG
00723 kDebug(13000)<< "We won, just skipping (correctEndings)";
00724 #endif
00725 }
00726 else
00727 {
00728 int bakEndLine = node->endLineRel+startLine;
00729 uint bakEndCol = node->endCol;
00730 node->endLineRel = line-startLine;
00731 node->endCol=endCol;
00732
00733 #if JW_DEBUG
00734 kDebug(13000)<< "reclosed node had childnodes()";
00735 kDebug(13000)<<"It could be, that childnodes() need to be moved up";
00736 #endif
00737 moveSubNodesUp(node);
00738
00739 if (node->parentNode)
00740 {
00741 correctEndings(data,node->parentNode,bakEndLine, bakEndCol,node->parentNode->findChild(node)+1);
00742 }
00743 else
00744 {
00745
00746 }
00747 }
00748 }
00749 }
00750 return true;
00751 }
00752
00753 void KateCodeFoldingTree::moveSubNodesUp(KateCodeFoldingNode *node)
00754 {
00755 int mypos = node->parentNode->findChild(node);
00756 int removepos=-1;
00757 int count = node->childCount();
00758 for (int i=0; i<count; i++)
00759 if (node->child(i)->startLineRel >= node->endLineRel)
00760 {
00761 removepos=i;
00762 break;
00763 }
00764 #if JW_DEBUG
00765 kDebug(13000)<<QString("remove pos: %1").arg(removepos);
00766 #endif
00767 if (removepos>-1)
00768 {
00769 #if JW_DEBUG
00770 kDebug(13000)<<"Children need to be moved";
00771 #endif
00772 KateCodeFoldingNode *moveNode;
00773 if (mypos == (int)node->parentNode->childCount()-1)
00774 {
00775 while (removepos<(int)node->childCount())
00776 {
00777 node->parentNode->appendChild(moveNode=node->takeChild(removepos));
00778 moveNode->parentNode = node->parentNode;
00779 moveNode->startLineRel += node->startLineRel;
00780 }
00781 }
00782 else
00783 {
00784 int insertPos=mypos;
00785 while (removepos < (int)node->childCount())
00786 {
00787 insertPos++;
00788 node->parentNode->insertChild(insertPos, moveNode=node->takeChild(removepos));
00789 moveNode->parentNode = node->parentNode;
00790 moveNode->startLineRel += node->startLineRel;
00791 }
00792 }
00793 }
00794
00795 }
00796
00797
00798
00799 void KateCodeFoldingTree::addOpening(KateCodeFoldingNode *node,signed char nType, QVector<int>* list,unsigned int line,unsigned int charPos)
00800 {
00801 uint startLine = getStartLine(node);
00802 if ((startLine==line) && (node->type!=0))
00803 {
00804 #if JW_DEBUG
00805 kDebug(13000)<<"startLine equals line";
00806 #endif
00807 if (nType == node->type)
00808 {
00809 #if JW_DEBUG
00810 kDebug(13000)<<"Node exists";
00811 #endif
00812 node->deleteOpening = false;
00813 node->startCol=charPos;
00814 KateCodeFoldingNode *parent = node->parentNode;
00815
00816 if (!node->endLineValid)
00817 {
00818 int current = parent->findChild(node);
00819 int count = parent->childCount()-(current+1);
00820 node->endLineRel = parent->endLineRel - node->startLineRel;
00821
00822
00823
00824 if (parent->type == node->type)
00825 {
00826 if (parent->endLineValid)
00827 {
00828 removeEnding(parent, line);
00829 node->endLineValid = true;
00830 }
00831 }
00832
00833
00834
00835 if (current != (int)parent->childCount()-1)
00836 {
00837
00838 #ifdef __GNUC__
00839 #warning "FIXME: why does this seem to work?"
00840 #endif
00841
00842 {
00843 for (int i=current+1; i<(int)parent->childCount(); i++)
00844 {
00845 if (parent->child(i)->type == -node->type)
00846 {
00847 count = (i-current-1);
00848 node->endLineValid = true;
00849 node->endLineRel = getStartLine(parent->child(i))-line;
00850 node->endCol = parent->child(i)->endCol;
00851 KateCodeFoldingNode *child = parent->takeChild(i);
00852 markedForDeleting.removeAll( child );
00853 delete child;
00854 break;
00855 }
00856 }
00857 }
00858
00859
00860
00861
00862
00863
00864 if (count>0)
00865 {
00866 for (int i=0;i<count;i++)
00867 {
00868 KateCodeFoldingNode *tmp;
00869 node->appendChild(tmp=parent->takeChild(current+1));
00870 tmp->startLineRel -= node->startLineRel;
00871 tmp->parentNode = node;
00872 }
00873 }
00874 }
00875
00876 }
00877
00878 addOpening_further_iterations(node, nType, list, line, 0, startLine,node->startCol);
00879
00880 }
00881 }
00882 else
00883 {
00884 KateCodeFoldingNode *newNode = new KateCodeFoldingNode (node,nType,line-startLine);
00885 something_changed = true;
00886
00887 int insert_position=-1;
00888 for (int i=0; i<(int)node->childCount(); i++)
00889 {
00890 if (startLine+node->child(i)->startLineRel > line)
00891 {
00892 insert_position=i;
00893 break;
00894 }
00895 }
00896
00897 int current;
00898 if (insert_position==-1)
00899 {
00900 node->appendChild(newNode);
00901 current = node->childCount()-1;
00902 }
00903 else
00904 {
00905 node->insertChild(insert_position, newNode);
00906 current = insert_position;
00907 }
00908
00909
00910
00911
00912
00913
00914
00915
00916 int count = node->childCount() - (current+1);
00917 newNode->endLineRel -= newNode->startLineRel;
00918 if (current != (int)node->childCount()-1)
00919 {
00920 if (node->type != newNode->type)
00921 {
00922 for (int i=current+1; i<(int)node->childCount(); i++)
00923 {
00924 if (node->child(i)->type == -newNode->type)
00925 {
00926 count = node->childCount() - i - 1;
00927 newNode->endLineValid = true;
00928 newNode->endLineRel = line - getStartLine(node->child(i));
00929 KateCodeFoldingNode *child = node->takeChild(i);
00930 markedForDeleting.removeAll( child );
00931 delete child;
00932 break;
00933 }
00934 }
00935 }
00936 else
00937 {
00938 node->endLineValid = false;
00939 node->endLineRel = 10000;
00940 }
00941 if (count > 0)
00942 {
00943 for (int i=0;i<count;i++)
00944 {
00945 KateCodeFoldingNode *tmp;
00946 newNode->appendChild(tmp=node->takeChild(current+1));
00947 tmp->parentNode=newNode;
00948 }
00949 }
00950
00951 }
00952
00953 addOpening(newNode, nType, list, line,charPos);
00954
00955 addOpening_further_iterations(node, node->type, list, line, current, startLine,node->startCol);
00956 }
00957 }
00958
00959
00960 void KateCodeFoldingTree::addOpening_further_iterations(KateCodeFoldingNode *node,signed char , QVector<int>*
00961 list,unsigned int line,int current, unsigned int startLine,unsigned int charPos)
00962 {
00963 while (!(list->isEmpty()))
00964 {
00965 if (list->isEmpty())
00966 return;
00967 else
00968 {
00969 signed char data = (*list)[list->size()-2];
00970 uint charPos=(*list)[list->size()-1];
00971 list->resize (list->size()-2);
00972
00973 if (data<0)
00974 {
00975 #if JW_DEBUG
00976 kDebug(13000)<<"An ending was found";
00977 #endif
00978
00979 if (correctEndings(data,node,line,charPos,-1))
00980 return;
00981
00982 #if 0
00983 if(data == -nType)
00984 {
00985 if (node->endLineValid)
00986 {
00987 if (node->endLineRel+startLine==line)
00988 {
00989
00990 }
00991 else
00992 {
00993 node->endLineRel=line-startLine;
00994 node->endLineValid=true;
00995 }
00996 return;
00997 }
00998 else
00999 {
01000 node->endLineRel=line-startLine;
01001 node->endLineValid=true;
01002
01003 }
01004 }
01005 #endif
01006 }
01007 else
01008 {
01009 bool needNew = true;
01010 if (current < (int)node->childCount())
01011 {
01012 if (getStartLine(node->child(current)) == line)
01013 needNew=false;
01014 }
01015 if (needNew)
01016 {
01017 something_changed = true;
01018 KateCodeFoldingNode *newNode = new KateCodeFoldingNode(node, data, line-startLine);
01019 node->insertChild(current, newNode);
01020 }
01021
01022 addOpening(node->child(current), data, list, line,charPos);
01023 current++;
01024
01025 }
01026 }
01027 }
01028 }
01029
01030 unsigned int KateCodeFoldingTree::getStartLine(KateCodeFoldingNode *node)
01031 {
01032 unsigned int lineStart=0;
01033 for (KateCodeFoldingNode *iter=node; iter->type != 0; iter=iter->parentNode)
01034 lineStart += iter->startLineRel;
01035
01036 return lineStart;
01037 }
01038
01039
01040 void KateCodeFoldingTree::lineHasBeenRemoved(unsigned int line)
01041 {
01042 lineMapping.clear();
01043 dontIgnoreUnchangedLines.insert(line);
01044 dontIgnoreUnchangedLines.insert(line-1);
01045 dontIgnoreUnchangedLines.insert(line+1);
01046 hiddenLinesCountCacheValid = false;
01047 #if JW_DEBUG
01048 kDebug(13000)<<QString("KateCodeFoldingTree::lineHasBeenRemoved: %1").arg(line);
01049 #endif
01050
01051
01052 findAndMarkAllNodesforRemovalOpenedOrClosedAt(line);
01053 cleanupUnneededNodes(line);
01054
01055 KateCodeFoldingNode *node = findNodeForLine(line);
01056
01057 {
01058 int startLine = getStartLine(node);
01059 if (startLine == (int)line)
01060 node->startLineRel--;
01061 else
01062 {
01063 if (node->endLineRel == 0)
01064 node->endLineValid = false;
01065 node->endLineRel--;
01066 }
01067
01068 int count = node->childCount();
01069 for (int i=0; i<count; i++)
01070 {
01071 if (node->child(i)->startLineRel+startLine >= line)
01072 node->child(i)->startLineRel--;
01073 }
01074 }
01075
01076 if (node->parentNode)
01077 decrementBy1(node->parentNode, node);
01078
01079 for (QList<KateHiddenLineBlock>::iterator it=hiddenLines.begin(); it != hiddenLines.end(); ++it)
01080 {
01081 if ((*it).start > line)
01082 (*it).start--;
01083 else if ((*it).start+(*it).length > line)
01084 (*it).length--;
01085 }
01086 }
01087
01088
01089 void KateCodeFoldingTree::decrementBy1(KateCodeFoldingNode *node, KateCodeFoldingNode *after)
01090 {
01091 if (node->endLineRel == 0)
01092 node->endLineValid = false;
01093 node->endLineRel--;
01094
01095 for (int i=node->findChild(after)+1; i < node->childCount(); ++i)
01096 node->child(i)->startLineRel--;
01097
01098 if (node->parentNode)
01099 decrementBy1(node->parentNode,node);
01100 }
01101
01102
01103 void KateCodeFoldingTree::lineHasBeenInserted(unsigned int line)
01104 {
01105 lineMapping.clear();
01106 dontIgnoreUnchangedLines.insert(line);
01107 dontIgnoreUnchangedLines.insert(line-1l);
01108 dontIgnoreUnchangedLines.insert(line+1);
01109 hiddenLinesCountCacheValid = false;
01110
01111 #if JW_DEBUG
01112 kDebug(13000)<<QString("KateCodeFoldingTree::lineHasBeenInserted: %1").arg(line);
01113 #endif
01114
01115
01116
01117
01118 KateCodeFoldingNode *node = findNodeForLine(line);
01119
01120 {
01121 int startLine=getStartLine(node);
01122 if (node->type < 0)
01123 node->startLineRel++;
01124 else
01125 node->endLineRel++;
01126
01127 for (int i=0; i < node->childCount(); ++i)
01128 {
01129 KateCodeFoldingNode *iter = node->child(i);
01130
01131 if (iter->startLineRel+startLine >= line)
01132 iter->startLineRel++;
01133 }
01134 }
01135
01136 if (node->parentNode)
01137 incrementBy1(node->parentNode, node);
01138
01139 for (QList<KateHiddenLineBlock>::iterator it=hiddenLines.begin(); it!=hiddenLines.end(); ++it)
01140 {
01141 if ((*it).start > line)
01142 (*it).start++;
01143 else if ((*it).start+(*it).length > line)
01144 (*it).length++;
01145 }
01146 }
01147
01148 void KateCodeFoldingTree::incrementBy1(KateCodeFoldingNode *node, KateCodeFoldingNode *after)
01149 {
01150 node->endLineRel++;
01151
01152 for (int i=node->findChild(after)+1; i < node->childCount(); ++i)
01153 node->child(i)->startLineRel++;
01154
01155 if (node->parentNode)
01156 incrementBy1(node->parentNode,node);
01157 }
01158
01159
01160 void KateCodeFoldingTree::findAndMarkAllNodesforRemovalOpenedOrClosedAt(unsigned int line)
01161 {
01162 #ifdef __GNUC__
01163 #warning "FIXME: make this multiple region changes per line save";
01164 #endif
01165
01166 markedForDeleting.clear();
01167 KateCodeFoldingNode *node = findNodeForLine(line);
01168 if (node->type == 0)
01169 return;
01170
01171 addNodeToRemoveList(node, line);
01172
01173 while (((node->parentNode) && (node->parentNode->type!=0)) && (getStartLine(node->parentNode)==line))
01174 {
01175 node = node->parentNode;
01176 addNodeToRemoveList(node, line);
01177 }
01178 #if JW_DEBUG
01179 kDebug(13000)<<" added line to markedForDeleting list";
01180 #endif
01181 }
01182
01183
01184 void KateCodeFoldingTree::addNodeToRemoveList(KateCodeFoldingNode *node,unsigned int line)
01185 {
01186 bool add=false;
01187 #ifdef __GNUC__
01188 #warning "FIXME: make this multiple region changes per line save";
01189 #endif
01190 unsigned int startLine=getStartLine(node);
01191 if ((startLine==line) && (node->startLineValid))
01192 {
01193 add=true;
01194 node->deleteOpening = true;
01195 }
01196 if ((startLine+node->endLineRel==line) || ((node->endLineValid==false) && (node->deleteOpening)))
01197 {
01198 int myPos=node->parentNode->findChild(node);
01199 if ((int)node->parentNode->childCount()>myPos+1)
01200 addNodeToRemoveList(node->parentNode->child(myPos+1),line);
01201 add=true;
01202 node->deleteEnding = true;
01203 }
01204
01205 if(add)
01206 markedForDeleting.append(node);
01207
01208 }
01209
01210
01211 void KateCodeFoldingTree::findAllNodesOpenedOrClosedAt(unsigned int line)
01212 {
01213 nodesForLine.clear();
01214 KateCodeFoldingNode *node = findNodeForLine(line);
01215 if (node->type == 0)
01216 return;
01217
01218 unsigned int startLine = getStartLine(node);
01219 if (startLine == line)
01220 nodesForLine.append(node);
01221 else if ((startLine+node->endLineRel == line))
01222 nodesForLine.append(node);
01223
01224 while (node->parentNode)
01225 {
01226 addNodeToFoundList(node->parentNode, line, node->parentNode->findChild(node));
01227 node = node->parentNode;
01228 }
01229 #if JW_DEBUG
01230 kDebug(13000)<<" added line to nodesForLine list";
01231 #endif
01232 }
01233
01234
01235 void KateCodeFoldingTree::addNodeToFoundList(KateCodeFoldingNode *node,unsigned int line,int childpos)
01236 {
01237 unsigned int startLine = getStartLine(node);
01238
01239 if ((startLine==line) && (node->type!=0))
01240 nodesForLine.append(node);
01241 else if ((startLine+node->endLineRel==line) && (node->type!=0))
01242 nodesForLine.append(node);
01243
01244 for (int i=childpos+1; i<(int)node->childCount(); i++)
01245 {
01246 KateCodeFoldingNode *child = node->child(i);
01247
01248 if (startLine+child->startLineRel == line)
01249 {
01250 nodesForLine.append(child);
01251 addNodeToFoundList(child, line, 0);
01252 }
01253 else
01254 break;
01255 }
01256 }
01257
01258
01259 void KateCodeFoldingTree::cleanupUnneededNodes(unsigned int line)
01260 {
01261 #if JW_DEBUG
01262 kDebug(13000)<<"void KateCodeFoldingTree::cleanupUnneededNodes(unsigned int line)";
01263 #endif
01264
01265
01266 if (markedForDeleting.isEmpty())
01267 return;
01268
01269 for (int i=0; i<(int)markedForDeleting.count(); i++)
01270 {
01271 KateCodeFoldingNode *node = markedForDeleting.at(i);
01272 if (node->deleteOpening)
01273 kDebug(13000)<<"DELETE OPENING SET";
01274 if (node->deleteEnding)
01275 kDebug(13000)<<"DELETE ENDING SET";
01276
01277 if ((node->deleteOpening) && (node->deleteEnding))
01278 {
01279 #if JW_DEBUG
01280 kDebug(13000)<<"Deleting complete node";
01281 #endif
01282 if (node->endLineValid)
01283 {
01284 int f = node->parentNode->findChild (node);
01285
01286 if (f >= 0)
01287 delete node->parentNode->takeChild(f);
01288 }
01289 else
01290 {
01291 removeOpening(node, line);
01292
01293 }
01294 something_changed = true;
01295 }
01296 else
01297 {
01298 if ((node->deleteOpening) && (node->startLineValid))
01299 {
01300 #if JW_DEBUG
01301 kDebug(13000)<<"calling removeOpening";
01302 #endif
01303 removeOpening(node, line);
01304 something_changed = true;
01305 }
01306 else
01307 {
01308 dontDeleteOpening(node);
01309
01310 if ((node->deleteEnding) && (node->endLineValid))
01311 {
01312 dontDeleteEnding(node);
01313 removeEnding(node, line);
01314 something_changed = true;
01315 }
01316 else
01317 dontDeleteEnding(node);
01318 }
01319 }
01320 }
01321 }
01322
01323 void KateCodeFoldingTree::dontDeleteEnding(KateCodeFoldingNode* node)
01324 {
01325 node->deleteEnding = false;
01326 }
01327
01328
01329 void KateCodeFoldingTree::dontDeleteOpening(KateCodeFoldingNode* node)
01330 {
01331 node->deleteOpening = false;
01332 }
01333
01334
01335 void KateCodeFoldingTree::toggleRegionVisibility(unsigned int line)
01336 {
01337
01338 m_buffer->line (m_buffer->count()-1);
01339
01340 lineMapping.clear();
01341 hiddenLinesCountCacheValid = false;
01342 kDebug(13000)<<QString("KateCodeFoldingTree::toggleRegionVisibility() %1").arg(line);
01343
01344 findAllNodesOpenedOrClosedAt(line);
01345 for (int i=0; i<(int)nodesForLine.count(); i++)
01346 {
01347 KateCodeFoldingNode *node=nodesForLine.at(i);
01348 if ( (!node->startLineValid) || (getStartLine(node) != line) )
01349 {
01350 nodesForLine.removeAt(i);
01351 if (!node->startLineValid) addNodeToRemoveList(node, line);
01352 i--;
01353 }
01354 }
01355
01356 if (nodesForLine.isEmpty())
01357 return;
01358
01359 nodesForLine.at(0)->visible = !nodesForLine.at(0)->visible;
01360
01361 if (!nodesForLine.at(0)->visible)
01362 addHiddenLineBlock(nodesForLine.at(0),line);
01363 else
01364 {
01365 for (QList<KateHiddenLineBlock>::iterator it=hiddenLines.begin(); it!=hiddenLines.end();++it)
01366 if ((*it).start == line+1)
01367 {
01368 hiddenLines.erase(it);
01369 break;
01370 }
01371
01372 updateHiddenSubNodes(nodesForLine.at(0));
01373 }
01374
01375 emit regionVisibilityChangedAt(line);
01376 }
01377
01378 void KateCodeFoldingTree::updateHiddenSubNodes(KateCodeFoldingNode *node)
01379 {
01380 for (int i=0; i < node->childCount(); ++i)
01381 {
01382 KateCodeFoldingNode *iter = node->child(i);
01383
01384 if (!iter->visible)
01385 addHiddenLineBlock(iter, getStartLine(iter));
01386 else
01387 updateHiddenSubNodes(iter);
01388 }
01389 }
01390
01391 void KateCodeFoldingTree::addHiddenLineBlock(KateCodeFoldingNode *node,unsigned int line)
01392 {
01393 KateHiddenLineBlock data;
01394 data.start = line+1;
01395 data.length = node->endLineRel-(existsOpeningAtLineAfter(line+node->endLineRel,node)?1:0);
01396 bool inserted = false;
01397
01398 for (QList<KateHiddenLineBlock>::iterator it=hiddenLines.begin(); it!=hiddenLines.end(); ++it)
01399 {
01400 if (((*it).start>=data.start) && ((*it).start<=data.start+data.length-1))
01401 {
01402
01403
01404 it=hiddenLines.erase(it);
01405 --it;
01406 }
01407 else
01408 {
01409 if ((*it).start > line)
01410 {
01411 hiddenLines.insert(it, data);
01412 inserted = true;
01413
01414 break;
01415 }
01416 }
01417 }
01418
01419 if (!inserted)
01420 hiddenLines.append(data);
01421 }
01422
01423 bool KateCodeFoldingTree::existsOpeningAtLineAfter(unsigned int line, KateCodeFoldingNode *node)
01424 {
01425 for(KateCodeFoldingNode *tmp = node->parentNode; tmp; tmp=tmp->parentNode)
01426 {
01427 KateCodeFoldingNode *tmp2;
01428 unsigned int startLine=getStartLine(tmp);
01429
01430 if ( (tmp->findChild(node)+1) >= tmp->childCount()) return false;
01431 if ((tmp2 = tmp->child(tmp->findChild(node) + 1))
01432 && ((tmp2->startLineRel + startLine) == line))
01433 return true;
01434
01435 if ((startLine + tmp->endLineRel) > line)
01436 return false;
01437 }
01438
01439 return false;
01440 }
01441
01442
01443
01444
01445
01446 unsigned int KateCodeFoldingTree::getRealLine(unsigned int virtualLine)
01447 {
01448
01449 if (hiddenLines.isEmpty())
01450 return virtualLine;
01451
01452
01453
01454 if (lineMapping.contains(virtualLine))
01455 return lineMapping[virtualLine];
01456
01457 unsigned int tmp = virtualLine;
01458 for (QList<KateHiddenLineBlock>::const_iterator it=hiddenLines.begin();it!=hiddenLines.end();++it)
01459 {
01460 if ((*it).start<=virtualLine)
01461 virtualLine += (*it).length;
01462 else
01463 break;
01464 }
01465
01466
01467
01468 lineMapping.insert(tmp, virtualLine);
01469 return virtualLine;
01470 }
01471
01472
01473
01474
01475 unsigned int KateCodeFoldingTree::getVirtualLine(unsigned int realLine)
01476 {
01477
01478 if (hiddenLines.isEmpty())
01479 return realLine;
01480
01481
01482
01483 for (int i = hiddenLines.size()-1; i >= 0; --i)
01484 {
01485 if (hiddenLines[i].start <= realLine)
01486 realLine -= hiddenLines[i].length;
01487
01488
01489 }
01490
01491
01492
01493 return realLine;
01494 }
01495
01496
01497
01498
01499 unsigned int KateCodeFoldingTree::getHiddenLinesCount(unsigned int doclen)
01500 {
01501
01502 if (hiddenLines.isEmpty())
01503 return 0;
01504
01505 if (hiddenLinesCountCacheValid)
01506 return hiddenLinesCountCache;
01507
01508 hiddenLinesCountCacheValid = true;
01509 hiddenLinesCountCache = 0;
01510
01511 for (QList<KateHiddenLineBlock>::const_iterator it=hiddenLines.begin(); it!=hiddenLines.end(); ++it)
01512 {
01513 if ((*it).start+(*it).length<=doclen)
01514 hiddenLinesCountCache += (*it).length;
01515 else
01516 {
01517 hiddenLinesCountCache += ((*it).length- ((*it).length + (*it).start - doclen));
01518 break;
01519 }
01520 }
01521
01522 return hiddenLinesCountCache;
01523 }
01524
01525 void KateCodeFoldingTree::collapseToplevelNodes()
01526 {
01527
01528 m_buffer->line (m_buffer->count()-1);
01529
01530 if (m_root.noChildren ())
01531 return;
01532
01533 for ( int i=0; i < m_root.childCount(); ++i )
01534 {
01535 KateCodeFoldingNode *node = m_root.child(i);
01536
01537 if (node->visible && node->startLineValid && node->endLineValid)
01538 {
01539 node->visible=false;
01540 lineMapping.clear();
01541 hiddenLinesCountCacheValid = false;
01542 addHiddenLineBlock(node,node->startLineRel);
01543 emit regionVisibilityChangedAt(node->startLineRel);
01544 }
01545 }
01546 }
01547
01548 void KateCodeFoldingTree::expandToplevelNodes(int numLines)
01549 {
01550
01551 m_buffer->line (m_buffer->count()-1);
01552
01553 KateLineInfo line;
01554 for (int i = 0; i < numLines; i++) {
01555 getLineInfo(&line, i);
01556
01557 if (line.startsInVisibleBlock)
01558 toggleRegionVisibility(i);
01559 }
01560 }
01561
01562 int KateCodeFoldingTree::collapseOne(int realLine)
01563 {
01564
01565 m_buffer->line (m_buffer->count()-1);
01566
01567 KateLineInfo line;
01568 int unrelatedBlocks = 0;
01569 for (int i = realLine; i >= 0; i--) {
01570 getLineInfo(&line, i);
01571
01572 if (line.topLevel && !line.endsBlock)
01573
01574 break;
01575
01576 if (line.endsBlock && ( line.invalidBlockEnd ) && (i != realLine)) {
01577 unrelatedBlocks++;
01578 }
01579
01580 if (line.startsVisibleBlock) {
01581 unrelatedBlocks--;
01582 if (unrelatedBlocks == -1) {
01583 toggleRegionVisibility(i);
01584 return i;
01585 }
01586 }
01587 }
01588 return -1;
01589 }
01590
01591 void KateCodeFoldingTree::expandOne(int realLine, int numLines)
01592 {
01593
01594 m_buffer->line (m_buffer->count()-1);
01595
01596 KateLineInfo line;
01597 int blockTrack = 0;
01598 for (int i = realLine; i >= 0; i--) {
01599 getLineInfo(&line, i);
01600
01601 if (line.topLevel)
01602
01603 break;
01604
01605 if (line.startsInVisibleBlock && i != realLine) {
01606 if (blockTrack == 0)
01607 toggleRegionVisibility(i);
01608
01609 blockTrack--;
01610 }
01611
01612 if (line.endsBlock)
01613 blockTrack++;
01614
01615 if (blockTrack < 0)
01616
01617 break;
01618 }
01619
01620 blockTrack = 0;
01621 for (int i = realLine; i < numLines; i++) {
01622 getLineInfo(&line, i);
01623
01624 if (line.topLevel)
01625
01626 break;
01627
01628 if (line.startsInVisibleBlock) {
01629 if (blockTrack == 0)
01630 toggleRegionVisibility(i);
01631
01632 blockTrack++;
01633 }
01634
01635 if (line.endsBlock)
01636 blockTrack--;
01637
01638 if (blockTrack < 0)
01639
01640 break;
01641 }
01642 }
01643
01644 void KateCodeFoldingTree::ensureVisible( uint line )
01645 {
01646
01647 bool found=false;
01648 for (QList<KateHiddenLineBlock>::const_iterator it=hiddenLines.begin();it!=hiddenLines.end();++it)
01649 {
01650 if ( ((*it).start<=line) && ((*it).start+(*it).length>line) )
01651 {
01652 found=true;
01653 break;
01654 }
01655 }
01656
01657
01658 if (!found) return;
01659
01660 kDebug(13000)<<"line "<<line<<" is really hidden ->show block";
01661
01662
01663 KateCodeFoldingNode *n = findNodeForLine( line );
01664 do {
01665 if ( ! n->visible )
01666 toggleRegionVisibility( getStartLine( n ) );
01667 n = n->parentNode;
01668 } while( n );
01669
01670 }
01671
01672