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