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