00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "kateautoindent.h"
00022 #include "kateautoindent.moc"
00023
00024 #include "kateconfig.h"
00025 #include "katehighlight.h"
00026 #include "katefactory.h"
00027 #include "katejscript.h"
00028 #include "kateview.h"
00029
00030 #include <klocale.h>
00031 #include <kdebug.h>
00032 #include <kpopupmenu.h>
00033
00034 #include <cctype>
00035
00036
00037
00038 KateAutoIndent *KateAutoIndent::createIndenter (KateDocument *doc, uint mode)
00039 {
00040 if (mode == KateDocumentConfig::imNormal)
00041 return new KateNormalIndent (doc);
00042 else if (mode == KateDocumentConfig::imCStyle)
00043 return new KateCSmartIndent (doc);
00044 else if (mode == KateDocumentConfig::imPythonStyle)
00045 return new KatePythonIndent (doc);
00046 else if (mode == KateDocumentConfig::imXmlStyle)
00047 return new KateXmlIndent (doc);
00048 else if (mode == KateDocumentConfig::imCSAndS)
00049 return new KateCSAndSIndent (doc);
00050 else if ( mode == KateDocumentConfig::imVarIndent )
00051 return new KateVarIndent ( doc );
00052
00053
00054
00055 return new KateAutoIndent (doc);
00056 }
00057
00058 QStringList KateAutoIndent::listModes ()
00059 {
00060 QStringList l;
00061
00062 l << modeDescription(KateDocumentConfig::imNone);
00063 l << modeDescription(KateDocumentConfig::imNormal);
00064 l << modeDescription(KateDocumentConfig::imCStyle);
00065 l << modeDescription(KateDocumentConfig::imPythonStyle);
00066 l << modeDescription(KateDocumentConfig::imXmlStyle);
00067 l << modeDescription(KateDocumentConfig::imCSAndS);
00068 l << modeDescription(KateDocumentConfig::imVarIndent);
00069
00070
00071 return l;
00072 }
00073
00074 QString KateAutoIndent::modeName (uint mode)
00075 {
00076 if (mode == KateDocumentConfig::imNormal)
00077 return QString ("normal");
00078 else if (mode == KateDocumentConfig::imCStyle)
00079 return QString ("cstyle");
00080 else if (mode == KateDocumentConfig::imPythonStyle)
00081 return QString ("python");
00082 else if (mode == KateDocumentConfig::imXmlStyle)
00083 return QString ("xml");
00084 else if (mode == KateDocumentConfig::imCSAndS)
00085 return QString ("csands");
00086 else if ( mode == KateDocumentConfig::imVarIndent )
00087 return QString( "varindent" );
00088
00089
00090
00091 return QString ("none");
00092 }
00093
00094 QString KateAutoIndent::modeDescription (uint mode)
00095 {
00096 if (mode == KateDocumentConfig::imNormal)
00097 return i18n ("Normal");
00098 else if (mode == KateDocumentConfig::imCStyle)
00099 return i18n ("C Style");
00100 else if (mode == KateDocumentConfig::imPythonStyle)
00101 return i18n ("Python Style");
00102 else if (mode == KateDocumentConfig::imXmlStyle)
00103 return i18n ("XML Style");
00104 else if (mode == KateDocumentConfig::imCSAndS)
00105 return i18n ("S&S C Style");
00106 else if ( mode == KateDocumentConfig::imVarIndent )
00107 return i18n("Variable Based Indenter");
00108
00109
00110
00111 return i18n ("None");
00112 }
00113
00114 uint KateAutoIndent::modeNumber (const QString &name)
00115 {
00116 if (modeName(KateDocumentConfig::imNormal) == name)
00117 return KateDocumentConfig::imNormal;
00118 else if (modeName(KateDocumentConfig::imCStyle) == name)
00119 return KateDocumentConfig::imCStyle;
00120 else if (modeName(KateDocumentConfig::imPythonStyle) == name)
00121 return KateDocumentConfig::imPythonStyle;
00122 else if (modeName(KateDocumentConfig::imXmlStyle) == name)
00123 return KateDocumentConfig::imXmlStyle;
00124 else if (modeName(KateDocumentConfig::imCSAndS) == name)
00125 return KateDocumentConfig::imCSAndS;
00126 else if ( modeName( KateDocumentConfig::imVarIndent ) == name )
00127 return KateDocumentConfig::imVarIndent;
00128
00129
00130
00131 return KateDocumentConfig::imNone;
00132 }
00133
00134 bool KateAutoIndent::hasConfigPage (uint mode)
00135 {
00136
00137
00138
00139 return false;
00140 }
00141
00142 IndenterConfigPage* KateAutoIndent::configPage(QWidget *parent, uint mode)
00143 {
00144
00145
00146
00147 return 0;
00148 }
00149
00150 KateAutoIndent::KateAutoIndent (KateDocument *_doc)
00151 : QObject(), doc(_doc)
00152 {
00153 }
00154 KateAutoIndent::~KateAutoIndent ()
00155 {
00156 }
00157
00158
00159
00160
00161 KateViewIndentationAction::KateViewIndentationAction(KateDocument *_doc, const QString& text, QObject* parent, const char* name)
00162 : KActionMenu (text, parent, name), doc(_doc)
00163 {
00164 connect(popupMenu(),SIGNAL(aboutToShow()),this,SLOT(slotAboutToShow()));
00165 }
00166
00167 void KateViewIndentationAction::slotAboutToShow()
00168 {
00169 QStringList modes = KateAutoIndent::listModes ();
00170
00171 popupMenu()->clear ();
00172 for (uint z=0; z<modes.size(); ++z)
00173 popupMenu()->insertItem ( '&' + KateAutoIndent::modeDescription(z).replace('&', "&&"), this, SLOT(setMode(int)), 0, z);
00174
00175 popupMenu()->setItemChecked (doc->config()->indentationMode(), true);
00176 }
00177
00178 void KateViewIndentationAction::setMode (int mode)
00179 {
00180 doc->config()->setIndentationMode((uint)mode);
00181 }
00182
00183
00184
00185
00186 KateNormalIndent::KateNormalIndent (KateDocument *_doc)
00187 : KateAutoIndent (_doc)
00188 {
00189
00190 connect(_doc, SIGNAL(hlChanged()), this, SLOT(updateConfig()));
00191 }
00192
00193 KateNormalIndent::~KateNormalIndent ()
00194 {
00195 }
00196
00197 void KateNormalIndent::updateConfig ()
00198 {
00199 KateDocumentConfig *config = doc->config();
00200
00201 useSpaces = config->configFlags() & KateDocument::cfSpaceIndent || config->configFlags() & KateDocumentConfig::cfReplaceTabsDyn;
00202 mixedIndent = useSpaces && config->configFlags() & KateDocumentConfig::cfMixedIndent;
00203 keepProfile = config->configFlags() & KateDocument::cfKeepIndentProfile;
00204 tabWidth = config->tabWidth();
00205 indentWidth = useSpaces? config->indentationWidth() : tabWidth;
00206
00207 commentAttrib = 255;
00208 doxyCommentAttrib = 255;
00209 regionAttrib = 255;
00210 symbolAttrib = 255;
00211 alertAttrib = 255;
00212 tagAttrib = 255;
00213 wordAttrib = 255;
00214 keywordAttrib = 255;
00215 normalAttrib = 255;
00216 extensionAttrib = 255;
00217 preprocessorAttrib = 255;
00218
00219 KateHlItemDataList items;
00220 doc->highlight()->getKateHlItemDataListCopy (0, items);
00221
00222 for (uint i=0; i<items.count(); i++)
00223 {
00224 QString name = items.at(i)->name;
00225 if (name.find("Comment") != -1 && commentAttrib == 255)
00226 {
00227 commentAttrib = i;
00228 }
00229 else if (name.find("Region Marker") != -1 && regionAttrib == 255)
00230 {
00231 regionAttrib = i;
00232 }
00233 else if (name.find("Symbol") != -1 && symbolAttrib == 255)
00234 {
00235 symbolAttrib = i;
00236 }
00237 else if (name.find("Alert") != -1)
00238 {
00239 alertAttrib = i;
00240 }
00241 else if (name.find("Comment") != -1 && commentAttrib != 255 && doxyCommentAttrib == 255)
00242 {
00243 doxyCommentAttrib = i;
00244 }
00245 else if (name.find("Tags") != -1 && tagAttrib == 255)
00246 {
00247 tagAttrib = i;
00248 }
00249 else if (name.find("Word") != -1 && wordAttrib == 255)
00250 {
00251 wordAttrib = i;
00252 }
00253 else if (name.find("Keyword") != -1 && keywordAttrib == 255)
00254 {
00255 keywordAttrib = i;
00256 }
00257 else if (name.find("Normal") != -1 && normalAttrib == 255)
00258 {
00259 normalAttrib = i;
00260 }
00261 else if (name.find("Extensions") != -1 && extensionAttrib == 255)
00262 {
00263 extensionAttrib = i;
00264 }
00265 else if (name.find("Preprocessor") != -1 && preprocessorAttrib == 255)
00266 {
00267 preprocessorAttrib = i;
00268 }
00269 }
00270 }
00271
00272 bool KateNormalIndent::isBalanced (KateDocCursor &begin, const KateDocCursor &end, QChar open, QChar close, uint &pos) const
00273 {
00274 int parenOpen = 0;
00275 bool atLeastOne = false;
00276 bool getNext = false;
00277
00278 pos = doc->plainKateTextLine(begin.line())->firstChar();
00279
00280
00281
00282 while (begin < end)
00283 {
00284 QChar c = begin.currentChar();
00285 if (begin.currentAttrib() == symbolAttrib)
00286 {
00287 if (c == open)
00288 {
00289 if (!atLeastOne)
00290 {
00291 atLeastOne = true;
00292 getNext = true;
00293 pos = measureIndent(begin) + 1;
00294 }
00295 parenOpen++;
00296 }
00297 else if (c == close)
00298 {
00299 parenOpen--;
00300 }
00301 }
00302 else if (getNext && !c.isSpace())
00303 {
00304 getNext = false;
00305 pos = measureIndent(begin);
00306 }
00307
00308 if (atLeastOne && parenOpen <= 0)
00309 return true;
00310
00311 begin.moveForward(1);
00312 }
00313
00314 return (atLeastOne) ? false : true;
00315 }
00316
00317 bool KateNormalIndent::skipBlanks (KateDocCursor &cur, KateDocCursor &max, bool newline) const
00318 {
00319 int curLine = cur.line();
00320 if (newline)
00321 cur.moveForward(1);
00322
00323 if (cur >= max)
00324 return false;
00325
00326 do
00327 {
00328 uchar attrib = cur.currentAttrib();
00329 const QString hlFile = doc->highlight()->hlKeyForAttrib( attrib );
00330
00331 if (attrib != commentAttrib && attrib != regionAttrib && attrib != alertAttrib && attrib != preprocessorAttrib && !hlFile.endsWith("doxygen.xml"))
00332 {
00333 QChar c = cur.currentChar();
00334 if (!c.isNull() && !c.isSpace())
00335 break;
00336 }
00337
00338 if (!cur.moveForward(1))
00339 {
00340
00341 cur = max;
00342 break;
00343 }
00344
00345 if (curLine != cur.line())
00346 {
00347 if (!newline)
00348 break;
00349 curLine = cur.line();
00350 cur.setCol(0);
00351 }
00352 } while (cur < max);
00353
00354 if (cur > max)
00355 cur = max;
00356 return true;
00357 }
00358
00359 uint KateNormalIndent::measureIndent (KateDocCursor &cur) const
00360 {
00361
00362
00363
00364 return doc->plainKateTextLine(cur.line())->cursorX(cur.col(), tabWidth);
00365 }
00366
00367 QString KateNormalIndent::tabString(uint pos) const
00368 {
00369 QString s;
00370 pos = kMin (pos, 80U);
00371
00372 if (!useSpaces || mixedIndent)
00373 {
00374 while (pos >= tabWidth)
00375 {
00376 s += '\t';
00377 pos -= tabWidth;
00378 }
00379 }
00380 while (pos > 0)
00381 {
00382 s += ' ';
00383 pos--;
00384 }
00385 return s;
00386 }
00387
00388 void KateNormalIndent::processNewline (KateDocCursor &begin, bool )
00389 {
00390 int line = begin.line() - 1;
00391 int pos = begin.col();
00392
00393 while ((line > 0) && (pos < 0))
00394 pos = doc->plainKateTextLine(--line)->firstChar();
00395
00396 if (pos > 0)
00397 {
00398 QString filler = doc->text(line, 0, line, pos);
00399 doc->insertText(begin.line(), 0, filler);
00400 begin.setCol(filler.length());
00401 }
00402 else
00403 begin.setCol(0);
00404 }
00405
00406
00407
00408
00409
00410 KateCSmartIndent::KateCSmartIndent (KateDocument *doc)
00411 : KateNormalIndent (doc),
00412 allowSemi (false),
00413 processingBlock (false)
00414 {
00415 kdDebug(13030)<<"CREATING KATECSMART INTDETER"<<endl;
00416 }
00417
00418 KateCSmartIndent::~KateCSmartIndent ()
00419 {
00420
00421 }
00422
00423 void KateCSmartIndent::processLine (KateDocCursor &line)
00424 {
00425 kdDebug(13030)<<"PROCESSING LINE "<<line.line()<<endl;
00426 KateTextLine::Ptr textLine = doc->plainKateTextLine(line.line());
00427
00428 int firstChar = textLine->firstChar();
00429
00430 if (firstChar == -1 && processingBlock)
00431 return;
00432
00433 uint indent = 0;
00434
00435
00436 QChar first = textLine->getChar(firstChar);
00437 QChar last = textLine->getChar(textLine->lastChar());
00438
00439 if (first == '}')
00440 {
00441 indent = findOpeningBrace(line);
00442 }
00443 else if (first == ')')
00444 {
00445 indent = findOpeningParen(line);
00446 }
00447 else if (first == '{')
00448 {
00449
00450 KateDocCursor temp(line.line(), firstChar, doc);
00451 if (!firstOpeningBrace(temp))
00452 indent = calcIndent(temp, false);
00453 }
00454 else if (first == ':')
00455 {
00456
00457 int pos = findOpeningBrace(line);
00458 if (pos == 0)
00459 indent = indentWidth;
00460 else
00461 indent = pos + (indentWidth * 2);
00462 }
00463 else if (last == ':')
00464 {
00465 if (textLine->stringAtPos (firstChar, "case") ||
00466 textLine->stringAtPos (firstChar, "default") ||
00467 textLine->stringAtPos (firstChar, "public") ||
00468 textLine->stringAtPos (firstChar, "private") ||
00469 textLine->stringAtPos (firstChar, "protected") ||
00470 textLine->stringAtPos (firstChar, "signals") ||
00471 textLine->stringAtPos (firstChar, "Q_SIGNALS") ||
00472 textLine->stringAtPos (firstChar, "Q_SLOTS") ||
00473 textLine->stringAtPos (firstChar, "slots"))
00474 {
00475 indent = findOpeningBrace(line) + indentWidth;
00476 }
00477 }
00478 else if (first == '*')
00479 {
00480 if (last == '/')
00481 {
00482 int lineEnd = textLine->lastChar();
00483 if (lineEnd > 0 && textLine->getChar(lineEnd - 1) == '*')
00484 {
00485 indent = findOpeningComment(line);
00486 if (textLine->attribute(firstChar) == doxyCommentAttrib)
00487 indent++;
00488 }
00489 else
00490 return;
00491 }
00492 else
00493 {
00494 KateDocCursor temp = line;
00495 if (textLine->attribute(firstChar) == doxyCommentAttrib)
00496 indent = calcIndent(temp, false) + 1;
00497 else
00498 indent = calcIndent(temp, true);
00499 }
00500 }
00501 else if (first == '#')
00502 {
00503
00504 if (textLine->stringAtPos (firstChar, "#region") ||
00505 textLine->stringAtPos (firstChar, "#endregion"))
00506 {
00507 KateDocCursor temp = line;
00508 indent = calcIndent(temp, true);
00509 }
00510 }
00511 else
00512 {
00513
00514 if (first == '/' && last != '/')
00515 return;
00516
00517 KateDocCursor temp = line;
00518 indent = calcIndent(temp, true);
00519 if (indent == 0)
00520 {
00521 KateNormalIndent::processNewline(line, true);
00522 return;
00523 }
00524 }
00525
00526
00527 if (indent != measureIndent(line) || first == '}' || first == '{' || first == '#')
00528 {
00529 doc->removeText(line.line(), 0, line.line(), firstChar);
00530 QString filler = tabString(indent);
00531 if (indent > 0) doc->insertText(line.line(), 0, filler);
00532 if (!processingBlock) line.setCol(filler.length());
00533 }
00534 }
00535
00536 void KateCSmartIndent::processSection (const KateDocCursor &begin, const KateDocCursor &end)
00537 {
00538 kdDebug(13030)<<"PROCESS SECTION"<<endl;
00539 KateDocCursor cur = begin;
00540 QTime t;
00541 t.start();
00542
00543 processingBlock = (end.line() - cur.line() > 0) ? true : false;
00544
00545 while (cur.line() <= end.line())
00546 {
00547 processLine (cur);
00548 if (!cur.gotoNextLine())
00549 break;
00550 }
00551
00552 processingBlock = false;
00553 kdDebug(13030) << "+++ total: " << t.elapsed() << endl;
00554 }
00555
00556 bool KateCSmartIndent::handleDoxygen (KateDocCursor &begin)
00557 {
00558
00559 int line = begin.line();
00560 int first = -1;
00561 while ((line > 0) && (first < 0))
00562 first = doc->plainKateTextLine(--line)->firstChar();
00563
00564 if (first >= 0)
00565 {
00566 KateTextLine::Ptr textLine = doc->plainKateTextLine(line);
00567 bool insideDoxygen = false;
00568 bool justAfterDoxygen = false;
00569 if (textLine->attribute(first) == doxyCommentAttrib || textLine->attribute(textLine->lastChar()) == doxyCommentAttrib)
00570 {
00571 const int last = textLine->lastChar();
00572 if (last <= 0 || !(justAfterDoxygen = textLine->stringAtPos(last-1, "*/")))
00573 insideDoxygen = true;
00574 if (justAfterDoxygen)
00575 justAfterDoxygen &= textLine->string().find("/**") < 0;
00576 while (textLine->attribute(first) != doxyCommentAttrib && first <= textLine->lastChar())
00577 first++;
00578 if (textLine->stringAtPos(first, "//"))
00579 return false;
00580 }
00581
00582
00583 if (insideDoxygen)
00584 {
00585 textLine = doc->plainKateTextLine(begin.line());
00586 first = textLine->firstChar();
00587 int indent = findOpeningComment(begin);
00588 QString filler = tabString (indent);
00589
00590 bool doxygenAutoInsert = doc->config()->configFlags() & KateDocumentConfig::cfDoxygenAutoTyping;
00591
00592 if ( doxygenAutoInsert &&
00593 ((first < 0) || (!textLine->stringAtPos(first, "*/") && !textLine->stringAtPos(first, "*"))))
00594 {
00595 filler = filler + " * ";
00596 }
00597
00598 doc->removeText (begin.line(), 0, begin.line(), first);
00599 doc->insertText (begin.line(), 0, filler);
00600 begin.setCol(filler.length());
00601
00602 return true;
00603 }
00604
00605
00606 else if (justAfterDoxygen)
00607 {
00608 textLine = doc->plainKateTextLine(begin.line());
00609 first = textLine->firstChar();
00610 int indent = findOpeningComment(begin);
00611 QString filler = tabString (indent);
00612
00613 doc->removeText (begin.line(), 0, begin.line(), first);
00614 doc->insertText (begin.line(), 0, filler);
00615 begin.setCol(filler.length());
00616
00617 return true;
00618 }
00619 }
00620
00621 return false;
00622 }
00623
00624 void KateCSmartIndent::processNewline (KateDocCursor &begin, bool needContinue)
00625 {
00626 if (!handleDoxygen (begin))
00627 {
00628 KateTextLine::Ptr textLine = doc->plainKateTextLine(begin.line());
00629 bool inMiddle = textLine->firstChar() > -1;
00630
00631 int indent = calcIndent (begin, needContinue);
00632
00633 if (indent > 0 || inMiddle)
00634 {
00635 QString filler = tabString (indent);
00636 doc->insertText (begin.line(), 0, filler);
00637 begin.setCol(filler.length());
00638
00639
00640 if (inMiddle)
00641 {
00642 processLine(begin);
00643 begin.setCol(textLine->firstChar());
00644 }
00645 }
00646 else
00647 {
00648 KateNormalIndent::processNewline (begin, needContinue);
00649 }
00650
00651 if (begin.col() < 0)
00652 begin.setCol(0);
00653 }
00654 }
00655
00656 void KateCSmartIndent::processChar(QChar c)
00657 {
00658
00659
00660
00661 static const QString triggers("}{)/:#n");
00662 static const QString firstTriggers("}{)/:#");
00663 static const QString lastTriggers(":n");
00664 if (triggers.find(c) < 0)
00665 return;
00666
00667 KateView *view = doc->activeView();
00668 KateDocCursor begin(view->cursorLine(), 0, doc);
00669
00670 KateTextLine::Ptr textLine = doc->plainKateTextLine(begin.line());
00671 const int first = textLine->firstChar();
00672 const QChar firstChar = textLine->getChar(first);
00673 if (c == 'n')
00674 {
00675 if (firstChar != '#')
00676 return;
00677 }
00678
00679 if ( c == '/' )
00680 {
00681
00682 if ( textLine->attribute( begin.col() ) == doxyCommentAttrib )
00683 {
00684
00685
00686 if ( first != -1
00687 && firstChar == '*'
00688 && textLine->nextNonSpaceChar( first+1 ) == view->cursorColumnReal()-1 )
00689 doc->removeText( view->cursorLine(), first+1, view->cursorLine(), view->cursorColumnReal()-1);
00690 }
00691
00692
00693 return;
00694 }
00695
00696
00697
00698
00699
00700 const QChar lastChar = textLine->getChar(textLine->lastChar());
00701 if ((c == firstChar && firstTriggers.find(firstChar) >= 0)
00702 || (c == lastChar && lastTriggers.find(lastChar) >= 0))
00703 processLine(begin);
00704 }
00705
00706
00707 uint KateCSmartIndent::calcIndent(KateDocCursor &begin, bool needContinue)
00708 {
00709 KateTextLine::Ptr textLine;
00710 KateDocCursor cur = begin;
00711
00712 uint anchorIndent = 0;
00713 int anchorPos = 0;
00714 int parenCount = 0;
00715 bool found = false;
00716 bool isSpecial = false;
00717 bool potentialAnchorSeen = false;
00718
00719
00720
00721
00722 while (cur.gotoPreviousLine())
00723 {
00724 isSpecial = found = false;
00725 textLine = doc->plainKateTextLine(cur.line());
00726
00727
00728 int pos = textLine->lastChar();
00729 int openCount = 0;
00730 int otherAnchor = -1;
00731 do
00732 {
00733 if (textLine->attribute(pos) == symbolAttrib)
00734 {
00735 QChar tc = textLine->getChar (pos);
00736 if ((tc == ';' || tc == ':' || tc == ',') && otherAnchor == -1 && parenCount <= 0)
00737 otherAnchor = pos, potentialAnchorSeen = true;
00738 else if (tc == ')')
00739 parenCount++;
00740 else if (tc == '(')
00741 parenCount--;
00742 else if (tc == '}')
00743 openCount--;
00744 else if (tc == '{')
00745 {
00746 openCount++, potentialAnchorSeen = true;
00747 if (openCount == 1)
00748 break;
00749 }
00750 }
00751 } while (--pos >= textLine->firstChar());
00752
00753 if (openCount != 0 || otherAnchor != -1)
00754 {
00755 found = true;
00756 QChar c;
00757 if (openCount > 0)
00758 c = '{';
00759 else if (openCount < 0)
00760 c = '}';
00761 else if (otherAnchor >= 0)
00762 c = textLine->getChar (otherAnchor);
00763
00764 int specialIndent = 0;
00765 if (c == ':' && needContinue)
00766 {
00767 QChar ch;
00768 specialIndent = textLine->firstChar();
00769 if (textLine->stringAtPos(specialIndent, "case"))
00770 ch = textLine->getChar(specialIndent + 4);
00771 else if (textLine->stringAtPos(specialIndent, "default"))
00772 ch = textLine->getChar(specialIndent + 7);
00773 else if (textLine->stringAtPos(specialIndent, "public"))
00774 ch = textLine->getChar(specialIndent + 6);
00775 else if (textLine->stringAtPos(specialIndent, "private"))
00776 ch = textLine->getChar(specialIndent + 7);
00777 else if (textLine->stringAtPos(specialIndent, "protected"))
00778 ch = textLine->getChar(specialIndent + 9);
00779 else if (textLine->stringAtPos(specialIndent, "signals"))
00780 ch = textLine->getChar(specialIndent + 7);
00781 else if (textLine->stringAtPos(specialIndent, "Q_SIGNALS"))
00782 ch = textLine->getChar(specialIndent + 9);
00783 else if (textLine->stringAtPos(specialIndent, "slots"))
00784 ch = textLine->getChar(specialIndent + 5);
00785 else if (textLine->stringAtPos(specialIndent, "Q_SLOTS"))
00786 ch = textLine->getChar(specialIndent + 7);
00787
00788 if (ch.isNull() || (!ch.isSpace() && ch != '(' && ch != ':'))
00789 continue;
00790
00791 KateDocCursor lineBegin = cur;
00792 lineBegin.setCol(specialIndent);
00793 specialIndent = measureIndent(lineBegin);
00794 isSpecial = true;
00795 }
00796
00797
00798 KateDocCursor skip = cur;
00799 skip.setCol(textLine->lastChar());
00800 bool result = skipBlanks(skip, begin, true);
00801
00802 anchorPos = skip.col();
00803 anchorIndent = measureIndent(skip);
00804
00805
00806
00807
00808 if (result && skip < begin)
00809 {
00810 cur = skip;
00811 break;
00812 }
00813 else if (isSpecial)
00814 {
00815 anchorIndent = specialIndent;
00816 break;
00817 }
00818
00819
00820 if ((c == '{' || c == '}') && textLine->getChar(textLine->firstChar()) == c)
00821 {
00822 cur.setCol(anchorPos = textLine->firstChar());
00823 anchorIndent = measureIndent (cur);
00824 break;
00825 }
00826 }
00827 }
00828
00829
00830 if (cur.line() == 0 && cur.col() == 0 && potentialAnchorSeen)
00831 found = true;
00832
00833 if (!found)
00834 return 0;
00835
00836 uint continueIndent = (needContinue) ? calcContinue (cur, begin) : 0;
00837
00838
00839
00840
00841 textLine = doc->plainKateTextLine(cur.line());
00842 QChar lastChar = textLine->getChar (anchorPos);
00843 int lastLine = cur.line();
00844 if (lastChar == '#' || lastChar == '[')
00845 {
00846
00847
00848 continueIndent = 0;
00849 }
00850
00851 int openCount = 0;
00852 while (cur.validPosition() && cur < begin)
00853 {
00854 if (!skipBlanks(cur, begin, true))
00855 return 0;
00856
00857 QChar tc = cur.currentChar();
00858
00859 if (cur == begin || tc.isNull())
00860 break;
00861
00862 if (!tc.isSpace() && cur < begin)
00863 {
00864 uchar attrib = cur.currentAttrib();
00865 if (tc == '{' && attrib == symbolAttrib)
00866 openCount++;
00867 else if (tc == '}' && attrib == symbolAttrib)
00868 openCount--;
00869
00870 lastChar = tc;
00871 lastLine = cur.line();
00872 }
00873 }
00874 if (openCount > 0)
00875 lastChar = '{';
00876
00877 uint indent = 0;
00878
00879
00880 if (lastChar == '{' || (lastChar == ':' && isSpecial && needContinue))
00881 {
00882 indent = anchorIndent + indentWidth;
00883 }
00884 else if (lastChar == '}')
00885 {
00886 indent = anchorIndent;
00887 }
00888 else if (lastChar == ';')
00889 {
00890 indent = anchorIndent + ((allowSemi && needContinue) ? continueIndent : 0);
00891 }
00892 else if (lastChar == ',')
00893 {
00894 textLine = doc->plainKateTextLine(lastLine);
00895 KateDocCursor start(lastLine, textLine->firstChar(), doc);
00896 KateDocCursor finish(lastLine, textLine->lastChar(), doc);
00897 uint pos = 0;
00898
00899 if (isBalanced(start, finish, QChar('('), QChar(')'), pos))
00900 indent = anchorIndent;
00901 else
00902 {
00903
00904 indent = ((pos < 48) ? pos : anchorIndent + (indentWidth * 2));
00905 }
00906 }
00907 else if (!lastChar.isNull())
00908 {
00909 if (anchorIndent != 0)
00910 indent = anchorIndent + continueIndent;
00911 else
00912 indent = continueIndent;
00913 }
00914
00915 return indent;
00916 }
00917
00918 uint KateCSmartIndent::calcContinue(KateDocCursor &start, KateDocCursor &end)
00919 {
00920 KateDocCursor cur = start;
00921
00922 bool needsBalanced = true;
00923 bool isFor = false;
00924 allowSemi = false;
00925
00926 KateTextLine::Ptr textLine = doc->plainKateTextLine(cur.line());
00927
00928
00929 if (textLine->attribute(cur.col()) == symbolAttrib)
00930 {
00931 cur.moveForward(1);
00932 skipBlanks(cur, end, false);
00933 }
00934
00935 if (textLine->getChar(cur.col()) == '}')
00936 {
00937 skipBlanks(cur, end, true);
00938 if (cur.line() != start.line())
00939 textLine = doc->plainKateTextLine(cur.line());
00940
00941 if (textLine->stringAtPos(cur.col(), "else"))
00942 cur.setCol(cur.col() + 4);
00943 else
00944 return indentWidth * 2;
00945
00946 needsBalanced = false;
00947 }
00948 else if (textLine->stringAtPos(cur.col(), "else"))
00949 {
00950 cur.setCol(cur.col() + 4);
00951 needsBalanced = false;
00952 int next = textLine->nextNonSpaceChar(cur.col());
00953 if (next >= 0 && textLine->stringAtPos(next, "if"))
00954 {
00955 cur.setCol(next + 2);
00956 needsBalanced = true;
00957 }
00958 }
00959 else if (textLine->stringAtPos(cur.col(), "if"))
00960 {
00961 cur.setCol(cur.col() + 2);
00962 }
00963 else if (textLine->stringAtPos(cur.col(), "do"))
00964 {
00965 cur.setCol(cur.col() + 2);
00966 needsBalanced = false;
00967 }
00968 else if (textLine->stringAtPos(cur.col(), "for"))
00969 {
00970 cur.setCol(cur.col() + 3);
00971 isFor = true;
00972 }
00973 else if (textLine->stringAtPos(cur.col(), "while"))
00974 {
00975 cur.setCol(cur.col() + 5);
00976 }
00977 else if (textLine->stringAtPos(cur.col(), "switch"))
00978 {
00979 cur.setCol(cur.col() + 6);
00980 }
00981 else if (textLine->stringAtPos(cur.col(), "using"))
00982 {
00983 cur.setCol(cur.col() + 5);
00984 }
00985 else
00986 {
00987 return indentWidth * 2;
00988 }
00989
00990 uint openPos = 0;
00991 if (needsBalanced && !isBalanced (cur, end, QChar('('), QChar(')'), openPos))
00992 {
00993 allowSemi = isFor;
00994 if (openPos > 0)
00995 return (openPos - textLine->firstChar());
00996 else
00997 return indentWidth * 2;
00998 }
00999
01000
01001 skipBlanks(cur, end, false);
01002 if (cur == end)
01003 return indentWidth;
01004
01005 if (skipBlanks(cur, end, true))
01006 {
01007 if (cur == end)
01008 return indentWidth;
01009 else
01010 return indentWidth + calcContinue(cur, end);
01011 }
01012
01013 return 0;
01014 }
01015
01016 uint KateCSmartIndent::findOpeningBrace(KateDocCursor &start)
01017 {
01018 KateDocCursor cur = start;
01019 int count = 1;
01020
01021
01022
01023 while (cur.moveBackward(1))
01024 {
01025 if (cur.currentAttrib() == symbolAttrib)
01026 {
01027 QChar ch = cur.currentChar();
01028 if (ch == '{')
01029 count--;
01030 else if (ch == '}')
01031 count++;
01032
01033 if (count == 0)
01034 {
01035 KateDocCursor temp(cur.line(), doc->plainKateTextLine(cur.line())->firstChar(), doc);
01036 return measureIndent(temp);
01037 }
01038 }
01039 }
01040
01041 return 0;
01042 }
01043
01044 bool KateCSmartIndent::firstOpeningBrace(KateDocCursor &start)
01045 {
01046 KateDocCursor cur = start;
01047
01048
01049 while(cur.moveBackward(1))
01050 {
01051 if (cur.currentAttrib() == symbolAttrib)
01052 {
01053 QChar ch = cur.currentChar();
01054 if (ch == '{')
01055 return false;
01056 else if (ch == '}' && cur.col() == 0)
01057 break;
01058 }
01059 }
01060