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 begin.setCol(begin.col() - 1);
00488 }
00489
00490 if (begin.col() < 0)
00491 begin.setCol(0);
00492 }
00493 }
00494
00495 void KateCSmartIndent::processChar(QChar c)
00496 {
00497 static const QString triggers("}{)/:;#n");
00498 if (triggers.find(c, true) == -1)
00499 return;
00500
00501 KateView *view = doc->activeView();
00502 KateDocCursor begin(view->cursorLine(), 0, doc);
00503
00504 if (c == 'n')
00505 {
00506 KateTextLine::Ptr textLine = doc->plainKateTextLine(begin.line());
00507 if (textLine->getChar(textLine->firstChar()) != '#')
00508 return;
00509 }
00510
00511 processLine(begin);
00512 }
00513
00514 uint KateCSmartIndent::calcIndent(KateDocCursor &begin, bool needContinue)
00515 {
00516 KateTextLine::Ptr textLine;
00517 KateDocCursor cur = begin;
00518
00519 uint anchorIndent = 0;
00520 int anchorPos = 0;
00521 int parenCount = 0;
00522 bool found = false;
00523 bool isSpecial = false;
00524
00525
00526
00527
00528 while (cur.gotoPreviousLine())
00529 {
00530 isSpecial = found = false;
00531 textLine = doc->plainKateTextLine(cur.line());
00532
00533
00534 int pos = textLine->lastChar();
00535 int openCount = 0;
00536 int otherAnchor = -1;
00537 do
00538 {
00539 if (textLine->attribute(pos) == symbolAttrib)
00540 {
00541 QChar tc = textLine->getChar (pos);
00542 if ((tc == ';' || tc == ':' || tc == ',') && otherAnchor == -1 && parenCount <= 0)
00543 otherAnchor = pos;
00544 else if (tc == ')')
00545 parenCount++;
00546 else if (tc == '(')
00547 parenCount--;
00548 else if (tc == '}')
00549 openCount--;
00550 else if (tc == '{')
00551 {
00552 openCount++;
00553 if (openCount == 1)
00554 break;
00555 }
00556 }
00557 } while (--pos >= textLine->firstChar());
00558
00559 if (openCount != 0 || otherAnchor != -1)
00560 {
00561 found = true;
00562 QChar c;
00563 if (openCount > 0)
00564 c = '{';
00565 else if (openCount < 0)
00566 c = '}';
00567 else if (otherAnchor >= 0)
00568 c = textLine->getChar (otherAnchor);
00569
00570 int specialIndent = 0;
00571 if (c == ':' && needContinue)
00572 {
00573 QChar ch;
00574 specialIndent = textLine->firstChar();
00575 if (textLine->stringAtPos(specialIndent, "case"))
00576 ch = textLine->getChar(specialIndent + 4);
00577 else if (textLine->stringAtPos(specialIndent, "default"))
00578 ch = textLine->getChar(specialIndent + 7);
00579 else if (textLine->stringAtPos(specialIndent, "public"))
00580 ch = textLine->getChar(specialIndent + 6);
00581 else if (textLine->stringAtPos(specialIndent, "private"))
00582 ch = textLine->getChar(specialIndent + 7);
00583 else if (textLine->stringAtPos(specialIndent, "protected"))
00584 ch = textLine->getChar(specialIndent + 9);
00585 else if (textLine->stringAtPos(specialIndent, "signals"))
00586 ch = textLine->getChar(specialIndent + 7);
00587 else if (textLine->stringAtPos(specialIndent, "slots"))
00588 ch = textLine->getChar(specialIndent + 5);
00589
00590 if (ch.isNull() || (!ch.isSpace() && ch != '(' && ch != ':'))
00591 continue;
00592
00593 KateDocCursor lineBegin = cur;
00594 lineBegin.setCol(specialIndent);
00595 specialIndent = measureIndent(lineBegin);
00596 isSpecial = true;
00597 }
00598
00599
00600 KateDocCursor skip = cur;
00601 skip.setCol(textLine->lastChar());
00602 bool result = skipBlanks(skip, begin, true);
00603
00604 anchorPos = skip.col();
00605 anchorIndent = measureIndent(skip);
00606
00607
00608
00609
00610 if (result && skip < begin)
00611 {
00612 cur = skip;
00613 break;
00614 }
00615 else if (isSpecial)
00616 {
00617 anchorIndent = specialIndent;
00618 break;
00619 }
00620
00621
00622 if ((c == '{' || c == '}') && textLine->getChar(textLine->firstChar()) == c)
00623 {
00624 cur.setCol(anchorPos = textLine->firstChar());
00625 anchorIndent = measureIndent (cur);
00626 break;
00627 }
00628 }
00629 }
00630
00631 if (!found)
00632 return 0;
00633
00634 uint continueIndent = (needContinue) ? calcContinue (cur, begin) : 0;
00635
00636
00637
00638
00639 textLine = doc->plainKateTextLine(cur.line());
00640 QChar lastChar = textLine->getChar (anchorPos);
00641 int lastLine = cur.line();
00642 if (lastChar == '#' || lastChar == '[')
00643 {
00644
00645
00646 continueIndent = 0;
00647 }
00648
00649 int openCount = 0;
00650 while (cur.validPosition() && cur < begin)
00651 {
00652 if (!skipBlanks(cur, begin, true))
00653 return 0;
00654
00655 QChar tc = cur.currentChar();
00656
00657 if (cur == begin || tc.isNull())
00658 break;
00659
00660 if (!tc.isSpace() && cur < begin)
00661 {
00662 uchar attrib = cur.currentAttrib();
00663 if (tc == '{' && attrib == symbolAttrib)
00664 openCount++;
00665 else if (tc == '}' && attrib == symbolAttrib)
00666 openCount--;
00667
00668 lastChar = tc;
00669 lastLine = cur.line();
00670 }
00671 }
00672 if (openCount > 0)
00673 lastChar = '{';
00674
00675 uint indent = 0;
00676
00677
00678 if (lastChar == '{' || (lastChar == ':' && isSpecial && needContinue))
00679 {
00680 indent = anchorIndent + indentWidth;
00681 }
00682 else if (lastChar == '}')
00683 {
00684 indent = anchorIndent;
00685 }
00686 else if (lastChar == ';')
00687 {
00688 indent = anchorIndent + ((allowSemi && needContinue) ? continueIndent : 0);
00689 }
00690 else if (lastChar == ',')
00691 {
00692 textLine = doc->plainKateTextLine(lastLine);
00693 KateDocCursor start(lastLine, textLine->firstChar(), doc);
00694 KateDocCursor finish(lastLine, textLine->lastChar(), doc);
00695 uint pos = 0;
00696
00697 if (isBalanced(start, finish, QChar('('), QChar(')'), pos))
00698 indent = anchorIndent;
00699 else
00700 {
00701
00702 indent = ((pos < 48) ? pos : anchorIndent + (indentWidth * 2));
00703 }
00704 }
00705 else if (!lastChar.isNull())
00706 {
00707 if (anchorIndent != 0)
00708 indent = anchorIndent + continueIndent;
00709 else
00710 indent = continueIndent;
00711 }
00712
00713 return indent;
00714 }
00715
00716 uint KateCSmartIndent::calcContinue(KateDocCursor &start, KateDocCursor &end)
00717 {
00718 KateDocCursor cur = start;
00719
00720 bool needsBalanced = true;
00721 bool isFor = false;
00722 allowSemi = false;
00723
00724 KateTextLine::Ptr textLine = doc->plainKateTextLine(cur.line());
00725
00726
00727 if (textLine->attribute(cur.col()) == symbolAttrib)
00728 {
00729 cur.moveForward(1);
00730 skipBlanks(cur, end, false);
00731 }
00732
00733 if (textLine->getChar(cur.col()) == '}')
00734 {
00735 skipBlanks(cur, end, true);
00736 if (cur.line() != start.line())
00737 textLine = doc->plainKateTextLine(cur.line());
00738
00739 if (textLine->stringAtPos(cur.col(), "else"))
00740 cur.setCol(cur.col() + 4);
00741 else
00742 return indentWidth * 2;
00743
00744 needsBalanced = false;
00745 }
00746 else if (textLine->stringAtPos(cur.col(), "else"))
00747 {
00748 cur.setCol(cur.col() + 4);
00749 needsBalanced = false;
00750 if (textLine->stringAtPos(textLine->nextNonSpaceChar(cur.col()), "if"))
00751 {
00752 cur.setCol(textLine->nextNonSpaceChar(cur.col()) + 2);
00753 needsBalanced = true;
00754 }
00755 }
00756 else if (textLine->stringAtPos(cur.col(), "if"))
00757 {
00758 cur.setCol(cur.col() + 2);
00759 }
00760 else if (textLine->stringAtPos(cur.col(), "do"))
00761 {
00762 cur.setCol(cur.col() + 2);
00763 needsBalanced = false;
00764 }
00765 else if (textLine->stringAtPos(cur.col(), "for"))
00766 {
00767 cur.setCol(cur.col() + 3);
00768 isFor = true;
00769 }
00770 else if (textLine->stringAtPos(cur.col(), "while"))
00771 {
00772 cur.setCol(cur.col() + 5);
00773 }
00774 else if (textLine->stringAtPos(cur.col(), "switch"))
00775 {
00776 cur.setCol(cur.col() + 6);
00777 }
00778 else if (textLine->stringAtPos(cur.col(), "using"))
00779 {
00780 cur.setCol(cur.col() + 5);
00781 }
00782 else
00783 {
00784 return indentWidth * 2;
00785 }
00786
00787 uint openPos = 0;
00788 if (needsBalanced && !isBalanced (cur, end, QChar('('), QChar(')'), openPos))
00789 {
00790 allowSemi = isFor;
00791 if (openPos > 0)
00792 return (openPos - textLine->firstChar());
00793 else
00794 return indentWidth * 2;
00795 }
00796
00797
00798 skipBlanks(cur, end, false);
00799 if (cur == end)
00800 return indentWidth;
00801
00802 if (skipBlanks(cur, end, true))
00803 {
00804 if (cur == end)
00805 return indentWidth;
00806 else
00807 return indentWidth + calcContinue(cur, end);
00808 }
00809
00810 return 0;
00811 }
00812
00813 uint KateCSmartIndent::findOpeningBrace(KateDocCursor &start)
00814 {
00815 KateDocCursor cur = start;
00816 int count = 1;
00817
00818
00819
00820 while (cur.moveBackward(1))
00821 {
00822 if (cur.currentAttrib() == symbolAttrib)
00823 {
00824 QChar ch = cur.currentChar();
00825 if (ch == '{')
00826 count--;
00827 else if (ch == '}')
00828 count++;
00829
00830 if (count == 0)
00831 {
00832 KateDocCursor temp(cur.line(), doc->plainKateTextLine(cur.line())->firstChar(), doc);
00833 return measureIndent(temp);
00834 }
00835 }
00836 }
00837
00838 return 0;
00839 }
00840
00841 bool KateCSmartIndent::firstOpeningBrace(KateDocCursor &start)
00842 {
00843 KateDocCursor cur = start;
00844
00845
00846 while(cur.moveBackward(1))
00847 {
00848 if (cur.currentAttrib() == symbolAttrib)
00849 {
00850 QChar ch = cur.currentChar();
00851 if (ch == '{')
00852 return false;
00853 else if (ch == '}' && cur.col() == 0)
00854 break;
00855 }
00856 }
00857
00858 return true;
00859 }
00860
00861 uint KateCSmartIndent::findOpeningParen(KateDocCursor &start)
00862 {
00863 KateDocCursor cur = start;
00864 int count = 1;
00865
00866
00867
00868 while (cur.moveBackward(1))
00869 {
00870 if (cur.currentAttrib() == symbolAttrib)
00871 {
00872 QChar ch = cur.currentChar();
00873 if (ch == '(')
00874 count--;
00875 else if (ch == ')')
00876 count++;
00877
00878 if (count == 0)
00879 return measureIndent(cur);
00880 }
00881 }
00882
00883 return 0;
00884 }
00885
00886 uint KateCSmartIndent::findOpeningComment(KateDocCursor &start)
00887 {
00888 KateDocCursor cur = start;
00889
00890
00891 do
00892 {
00893 KateTextLine::Ptr textLine = doc->plainKateTextLine(cur.line());
00894
00895 int pos = textLine->string().find("/*", false);
00896 if (pos >= 0)
00897 {
00898 KateDocCursor temp(cur.line(), pos, doc);
00899 return measureIndent(temp);
00900 }
00901
00902 } while (cur.gotoPreviousLine());
00903
00904 return 0;
00905 }
00906
00907
00908
00909
00910
00911 QRegExp KatePythonIndent::endWithColon = QRegExp( "^[^#]*:\\s*(#.*)?$" );
00912 QRegExp KatePythonIndent::stopStmt = QRegExp( "^\\s*(break|continue|raise|return|pass)\\b.*" );
00913 QRegExp KatePythonIndent::blockBegin = QRegExp( "^\\s*(def|if|elif|else|for|while|try)\\b.*" );
00914
00915 KatePythonIndent::KatePythonIndent (KateDocument *doc)
00916 : KateAutoIndent (doc)
00917 {
00918 }
00919 KatePythonIndent::~KatePythonIndent ()
00920 {
00921 }
00922
00923 void KatePythonIndent::processNewline (KateDocCursor &begin, bool )
00924 {
00925 int prevLine = begin.line() - 1;
00926 int prevPos = begin.col();
00927
00928 while ((prevLine > 0) && (prevPos < 0))
00929 prevPos = doc->plainKateTextLine(--prevLine)->firstChar();
00930
00931 int prevBlock = prevLine;
00932 int prevBlockPos = prevPos;
00933 int extraIndent = calcExtra (prevBlock, prevBlockPos, begin);
00934
00935 int indent = doc->plainKateTextLine(prevBlock)->cursorX(prevBlockPos, tabWidth);
00936 if (extraIndent == 0)
00937 {
00938 if (!stopStmt.exactMatch(doc->plainKateTextLine(prevLine)->string()))
00939 {
00940 if (endWithColon.exactMatch(doc->plainKateTextLine(prevLine)->string()))
00941 indent += indentWidth;
00942 else
00943 indent = doc->plainKateTextLine(prevLine)->cursorX(prevPos, tabWidth);
00944 }
00945 }
00946 else
00947 indent += extraIndent;
00948
00949 if (indent > 0)
00950 {
00951 QString filler = tabString (indent);
00952 doc->insertText (begin.line(), 0, filler);
00953 begin.setCol(filler.length());
00954 }
00955 else
00956 begin.setCol(0);
00957 }
00958
00959 int KatePythonIndent::calcExtra (int &prevBlock, int &pos, KateDocCursor &end)
00960 {
00961 int nestLevel = 0;
00962 bool levelFound = false;
00963 while ((prevBlock > 0))
00964 {
00965 if (blockBegin.exactMatch(doc->plainKateTextLine(prevBlock)->string()))
00966 {
00967 if ((!levelFound && nestLevel == 0) || (levelFound && nestLevel - 1 <= 0))
00968 {
00969 pos = doc->plainKateTextLine(prevBlock)->firstChar();
00970 break;
00971 }
00972
00973 nestLevel --;
00974 }
00975 else if (stopStmt.exactMatch(doc->plainKateTextLine(prevBlock)->string()))
00976 {
00977 nestLevel ++;
00978 levelFound = true;
00979 }
00980
00981 --prevBlock;
00982 }
00983
00984 KateDocCursor cur (prevBlock, pos, doc);
00985 QChar c;
00986 int extraIndent = 0;
00987 while (cur.line() < end.line())
00988 {
00989 c = cur.currentChar();
00990
00991 if (c == '(')
00992 extraIndent += indentWidth;
00993 else if (c == ')')
00994 extraIndent -= indentWidth;
00995 else if (c == ':')
00996 break;
00997
00998 if (c.isNull() || c == '#')
00999 cur.gotoNextLine();
01000 else
01001 cur.moveForward(1);
01002 }
01003
01004 return extraIndent;
01005 }
01006
01007
01008
01009