00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "katevimodebase.h"
00021 #include "katevirange.h"
00022 #include "kateglobal.h"
00023 #include "kateviglobal.h"
00024 #include "katevivisualmode.h"
00025 #include "katevinormalmode.h"
00026 #include "kateviinputmodemanager.h"
00027
00028 #include <QString>
00029 #include <QRegExp>
00030 #include "katedocument.h"
00031 #include "kateviewinternal.h"
00032 #include "katevimodebar.h"
00033
00034
00035
00036
00037
00038
00039
00041
00043
00044 bool KateViModeBase::deleteRange( KateViRange &r, bool linewise, bool addToRegister)
00045 {
00046 r.normalize();
00047 bool res = false;
00048 QString removedText = getRange( r, linewise );
00049
00050 if ( linewise ) {
00051 doc()->editStart();
00052 for ( int i = 0; i < r.endLine-r.startLine+1; i++ ) {
00053 res = doc()->removeLine( r.startLine );
00054 }
00055 doc()->editEnd();
00056 } else {
00057 res = doc()->removeText( KTextEditor::Range( r.startLine, r.startColumn, r.endLine, r.endColumn) );
00058 }
00059
00060 if ( addToRegister ) {
00061 if ( r.startLine == r.endLine ) {
00062 fillRegister( getChosenRegister( '-' ), removedText );
00063 } else {
00064 fillRegister( getChosenRegister( '0' ), removedText );
00065 }
00066 }
00067
00068 return res;
00069 }
00070
00071 const QString KateViModeBase::getRange( KateViRange &r, bool linewise) const
00072 {
00073 r.normalize();
00074 QString s;
00075
00076 if ( linewise ) {
00077 r.startColumn = 0;
00078 r.endColumn = getLine( r.endLine ).length();
00079 }
00080
00081 if ( r.motionType == ViMotion::InclusiveMotion ) {
00082 r.endColumn++;
00083 }
00084
00085 KTextEditor::Range range( r.startLine, r.startColumn, r.endLine, r.endColumn);
00086
00087 if ( linewise ) {
00088 s = doc()->textLines( range ).join( QChar( '\n' ) );
00089 s.append( QChar( '\n' ) );
00090 } else {
00091 s = doc()->text( range );
00092 }
00093
00094 return s;
00095 }
00096
00097 const QString KateViModeBase::getLine( int lineNumber ) const
00098 {
00099 QString line;
00100
00101 if ( lineNumber == -1 ) {
00102 KTextEditor::Cursor cursor ( m_view->cursorPosition() );
00103 line = m_view->currentTextLine();
00104 } else {
00105 line = doc()->line( lineNumber );
00106 }
00107
00108 return line;
00109 }
00110
00111 const QChar KateViModeBase::getCharUnderCursor() const
00112 {
00113 KTextEditor::Cursor c( m_view->cursorPosition() );
00114
00115 QString line = getLine( c.line() );
00116
00117 if ( line.length() == 0 && c.column() >= line.length() ) {
00118 return QChar::Null;
00119 }
00120
00121 return line.at( c.column() );
00122 }
00123
00124 KTextEditor::Cursor KateViModeBase::findNextWordStart( int fromLine, int fromColumn, bool onlyCurrentLine ) const
00125 {
00126 QString line = getLine( fromLine );
00127
00128
00129 QString startOfWordPattern("\\b(\\w");
00130 if ( m_extraWordCharacters.length() > 0 ) {
00131 startOfWordPattern.append( QLatin1String( "|[" )+m_extraWordCharacters+']' );
00132 }
00133 startOfWordPattern.append( ')' );
00134
00135 QRegExp startOfWord( startOfWordPattern );
00136 QRegExp nonSpaceAfterSpace( "\\s\\S" );
00137 QRegExp nonWordAfterWord( "\\b(?!\\s)\\W" );
00138
00139 int l = fromLine;
00140 int c = fromColumn;
00141
00142 bool found = false;
00143
00144 while ( !found ) {
00145 int c1 = startOfWord.indexIn( line, c + 1 );
00146 int c2 = nonSpaceAfterSpace.indexIn( line, c );
00147 int c3 = nonWordAfterWord.indexIn( line, c + 1 );
00148
00149 if ( c1 == -1 && c2 == -1 && c3 == -1 ) {
00150 if ( onlyCurrentLine ) {
00151 return KTextEditor::Cursor( l, c );
00152 } else if ( l >= doc()->lines()-1 ) {
00153 c = line.length()-1;
00154 return KTextEditor::Cursor( l, c );
00155 } else {
00156 c = 0;
00157 l++;
00158
00159 line = getLine( l );
00160
00161 if ( line.length() == 0 || !line.at( c ).isSpace() ) {
00162 found = true;
00163 }
00164
00165 continue;
00166 }
00167 }
00168
00169 c2++;
00170
00171 if ( c1 <= 0 )
00172 c1 = line.length()-1;
00173 if ( c2 <= 0 )
00174 c2 = line.length()-1;
00175 if ( c3 <= 0 )
00176 c3 = line.length()-1;
00177
00178 c = qMin( c1, qMin( c2, c3 ) );
00179
00180 found = true;
00181 }
00182
00183 return KTextEditor::Cursor( l, c );
00184 }
00185
00186 KTextEditor::Cursor KateViModeBase::findNextWORDStart( int fromLine, int fromColumn, bool onlyCurrentLine ) const
00187 {
00188 KTextEditor::Cursor cursor ( m_view->cursorPosition() );
00189 QString line = getLine();
00190 KateViRange r( cursor.line(), cursor.column(), ViMotion::ExclusiveMotion );
00191
00192 int l = fromLine;
00193 int c = fromColumn;
00194
00195 bool found = false;
00196 QRegExp startOfWORD("\\s\\S");
00197
00198 while ( !found ) {
00199 c = startOfWORD.indexIn( line, c+1 );
00200
00201 if ( c == -1 ) {
00202 if ( onlyCurrentLine ) {
00203 return KTextEditor::Cursor( l, c );
00204 } else if ( l >= doc()->lines()-1 ) {
00205 c = line.length()-1;
00206 break;
00207 } else {
00208 c = 0;
00209 l++;
00210
00211 line = getLine( l );
00212
00213 if ( line.length() == 0 || !line.at( c ).isSpace() ) {
00214 found = true;
00215 }
00216
00217 continue;
00218 }
00219 } else {
00220 c++;
00221 found = true;
00222 }
00223 }
00224
00225 return KTextEditor::Cursor( l, c );
00226 }
00227
00228 KTextEditor::Cursor KateViModeBase::findPrevWordEnd( int fromLine, int fromColumn, bool onlyCurrentLine ) const
00229 {
00230 QString line = getLine( fromLine );
00231
00232 QString endOfWordPattern = "\\S\\s|\\S$|\\w\\W|\\S\\b|^$";
00233
00234 if ( m_extraWordCharacters.length() > 0 ) {
00235 endOfWordPattern.append( "|["+m_extraWordCharacters+"][^" +m_extraWordCharacters+']' );
00236 }
00237
00238 QRegExp endOfWord( endOfWordPattern );
00239
00240 int l = fromLine;
00241 int c = fromColumn;
00242
00243 bool found = false;
00244
00245 while ( !found ) {
00246 int c1 = endOfWord.lastIndexIn( line, c-1 );
00247
00248 if ( c1 != -1 && c-1 != -1 ) {
00249 found = true;
00250 c = c1;
00251 } else {
00252 if ( onlyCurrentLine ) {
00253 return KTextEditor::Cursor( l, c );
00254 } else if ( l > 0 ) {
00255 line = getLine( --l );
00256 c = line.length();
00257
00258 continue;
00259 } else {
00260 c = 0;
00261 return KTextEditor::Cursor( l, c );
00262 }
00263 }
00264 }
00265
00266 return KTextEditor::Cursor( l, c );
00267 }
00268
00269 KTextEditor::Cursor KateViModeBase::findPrevWORDEnd( int fromLine, int fromColumn, bool onlyCurrentLine ) const
00270 {
00271 QString line = getLine( fromLine );
00272
00273 QRegExp endOfWORDPattern( "\\S\\s|\\S$|^$" );
00274
00275 QRegExp endOfWORD( endOfWORDPattern );
00276
00277 int l = fromLine;
00278 int c = fromColumn;
00279
00280 bool found = false;
00281
00282 while ( !found ) {
00283 int c1 = endOfWORD.lastIndexIn( line, c-1 );
00284
00285 if ( c1 != -1 && c-1 != -1 ) {
00286 found = true;
00287 c = c1;
00288 } else {
00289 if ( onlyCurrentLine ) {
00290 return KTextEditor::Cursor( l, c );
00291 } else if ( l > 0 ) {
00292 line = getLine( --l );
00293 c = line.length();
00294
00295 continue;
00296 } else {
00297 c = 0;
00298 return KTextEditor::Cursor( l, c );
00299 }
00300 }
00301 }
00302
00303 return KTextEditor::Cursor( l, c );
00304 }
00305
00306 KTextEditor::Cursor KateViModeBase::findPrevWordStart( int fromLine, int fromColumn, bool onlyCurrentLine ) const
00307 {
00308 QString line = getLine( fromLine );
00309
00310
00311 QString startOfWordPattern("\\b(\\w");
00312 if ( m_extraWordCharacters.length() > 0 ) {
00313 startOfWordPattern.append( QLatin1String( "|[" )+m_extraWordCharacters+']' );
00314 }
00315 startOfWordPattern.append( ')' );
00316
00317 QRegExp startOfWord( startOfWordPattern );
00318 QRegExp nonSpaceAfterSpace( "\\s\\S" );
00319 QRegExp nonWordAfterWord( "\\b(?!\\s)\\W" );
00320 QRegExp startOfLine( "^\\S" );
00321
00322 int l = fromLine;
00323 int c = fromColumn;
00324
00325 bool found = false;
00326
00327 while ( !found ) {
00328 int c1 = startOfWord.lastIndexIn( line, -line.length()+c-1 );
00329 int c2 = nonSpaceAfterSpace.lastIndexIn( line, -line.length()+c-2 );
00330 int c3 = nonWordAfterWord.lastIndexIn( line, -line.length()+c-1 );
00331 int c4 = startOfLine.lastIndexIn( line, -line.length()+c-1 );
00332
00333 if ( c1 == -1 && c2 == -1 && c3 == -1 && c4 == -1 ) {
00334 if ( onlyCurrentLine ) {
00335 return KTextEditor::Cursor( l, c );
00336 } else if ( l <= 0 ) {
00337 return KTextEditor::Cursor( 0, 0 );
00338 } else {
00339 line = getLine( --l );
00340 c = line.length()-1;
00341
00342 if ( line.length() == 0 ) {
00343 c = 0;
00344 found = true;
00345 }
00346
00347 continue;
00348 }
00349 }
00350
00351 c2++;
00352
00353 if ( c1 <= 0 )
00354 c1 = 0;
00355 if ( c2 <= 0 )
00356 c2 = 0;
00357 if ( c3 <= 0 )
00358 c3 = 0;
00359 if ( c4 <= 0 )
00360 c4 = 0;
00361
00362 c = qMax( c1, qMax( c2, qMax( c3, c4 ) ) );
00363
00364 found = true;
00365 }
00366
00367 return KTextEditor::Cursor( l, c );
00368 }
00369
00370 KTextEditor::Cursor KateViModeBase::findPrevWORDStart( int fromLine, int fromColumn, bool onlyCurrentLine ) const
00371 {
00372 QString line = getLine( fromLine );
00373
00374 QRegExp startOfWORD("\\s\\S");
00375 QRegExp startOfLineWORD("^\\S");
00376
00377 int l = fromLine;
00378 int c = fromColumn;
00379
00380 bool found = false;
00381
00382 while ( !found ) {
00383 int c1 = startOfWORD.lastIndexIn( line, -line.length()+c-2 );
00384 int c2 = startOfLineWORD.lastIndexIn( line, -line.length()+c-1 );
00385
00386 if ( c1 == -1 && c2 == -1 ) {
00387 if ( onlyCurrentLine ) {
00388 return KTextEditor::Cursor( l, c );
00389 } else if ( l <= 0 ) {
00390 return KTextEditor::Cursor( 0, 0 );
00391 } else {
00392 line = getLine( --l );
00393 c = line.length()-1;
00394
00395 if ( line.length() == 0 ) {
00396 c = 0;
00397 found = true;
00398 }
00399
00400 continue;
00401 }
00402 }
00403
00404 c1++;
00405
00406 c = qMax( c1, c2 );
00407
00408 if ( c <= 0 )
00409 c = 0;
00410
00411 found = true;
00412 }
00413
00414 return KTextEditor::Cursor( l, c );
00415 }
00416
00417 KTextEditor::Cursor KateViModeBase::findWordEnd( int fromLine, int fromColumn, bool onlyCurrentLine ) const
00418 {
00419 QString line = getLine( fromLine );
00420
00421 QString endOfWordPattern = "\\S\\s|\\S$|\\w\\W|\\S\\b";
00422
00423 if ( m_extraWordCharacters.length() > 0 ) {
00424 endOfWordPattern.append( "|["+m_extraWordCharacters+"][^" +m_extraWordCharacters+']' );
00425 }
00426
00427 QRegExp endOfWORD( endOfWordPattern );
00428
00429 int l = fromLine;
00430 int c = fromColumn;
00431
00432 bool found = false;
00433
00434 while ( !found ) {
00435 int c1 = endOfWORD.indexIn( line, c+1 );
00436
00437 if ( c1 != -1 ) {
00438 found = true;
00439 c = c1;
00440 } else {
00441 if ( onlyCurrentLine ) {
00442 return KTextEditor::Cursor( l, c );
00443 } else if ( l >= doc()->lines()-1 ) {
00444 c = line.length()-1;
00445 return KTextEditor::Cursor( l, c );
00446 } else {
00447 c = -1;
00448 line = getLine( ++l );
00449
00450 continue;
00451 }
00452 }
00453 }
00454
00455 return KTextEditor::Cursor( l, c );
00456 }
00457
00458 KTextEditor::Cursor KateViModeBase::findWORDEnd( int fromLine, int fromColumn, bool onlyCurrentLine ) const
00459 {
00460 QString line = getLine( fromLine );
00461
00462 QRegExp endOfWORD( "\\S\\s|\\S$" );
00463
00464 int l = fromLine;
00465 int c = fromColumn;
00466
00467 bool found = false;
00468
00469 while ( !found ) {
00470 int c1 = endOfWORD.indexIn( line, c+1 );
00471
00472 if ( c1 != -1 ) {
00473 found = true;
00474 c = c1;
00475 } else {
00476 if ( onlyCurrentLine ) {
00477 return KTextEditor::Cursor( l, c );
00478 } else if ( l >= doc()->lines()-1 ) {
00479 c = line.length()-1;
00480 return KTextEditor::Cursor( l, c );
00481 } else {
00482 c = -1;
00483 line = getLine( ++l );
00484
00485 continue;
00486 }
00487 }
00488 }
00489
00490 return KTextEditor::Cursor( l, c );
00491 }
00492
00493
00494 KateViRange KateViModeBase::findSurrounding( const QChar &c1, const QChar &c2, bool inner ) const
00495 {
00496 KTextEditor::Cursor cursor( m_view->cursorPosition() );
00497 QString line = getLine();
00498
00499 int col1 = line.lastIndexOf( c1, cursor.column() );
00500 int col2 = line.indexOf( c2, cursor.column() );
00501
00502 KateViRange r( cursor.line(), col1, cursor.line(), col2, ViMotion::InclusiveMotion );
00503
00504 if ( col1 == -1 || col2 == -1 || col1 > col2 ) {
00505 r.valid = false;
00506 }
00507
00508 if ( inner ) {
00509 r.startColumn++;
00510 r.endColumn--;
00511 }
00512
00513 return r;
00514 }
00515
00516 KateViRange KateViModeBase::findSurrounding( const QRegExp &c1, const QRegExp &c2, bool inner ) const
00517 {
00518 KTextEditor::Cursor cursor( m_view->cursorPosition() );
00519 QString line = getLine();
00520
00521 int col1 = line.lastIndexOf( c1, cursor.column() );
00522 int col2 = line.indexOf( c2, cursor.column() );
00523
00524 KateViRange r( cursor.line(), col1, cursor.line(), col2, ViMotion::InclusiveMotion );
00525
00526 if ( col1 == -1 || col2 == -1 || col1 > col2 ) {
00527 r.valid = false;
00528 }
00529
00530 if ( inner ) {
00531 r.startColumn++;
00532 r.endColumn--;
00533 }
00534
00535 return r;
00536 }
00537
00538 int KateViModeBase::findLineStartingWitchChar( const QChar &c, unsigned int count, bool forward ) const
00539 {
00540 int line = m_view->cursorPosition().line();
00541 int lines = doc()->lines();
00542 unsigned int hits = 0;
00543
00544 if ( forward ) {
00545 line++;
00546 } else {
00547 line--;
00548 }
00549
00550 while ( line < lines && line > 0 && hits < count ) {
00551 QString l = getLine( line );
00552 if ( l.length() > 0 && l.at( 0 ) == c ) {
00553 hits++;
00554 }
00555 if ( hits != count ) {
00556 if ( forward ) {
00557 line++;
00558 } else {
00559 line--;
00560 }
00561 }
00562 }
00563
00564 if ( hits == getCount() ) {
00565 return line;
00566 }
00567
00568 return -1;
00569 }
00570
00571 void KateViModeBase::updateCursor( const KTextEditor::Cursor &c ) const
00572 {
00573 m_viewInternal->updateCursor( c );
00574 }
00575
00579 QChar KateViModeBase::getChosenRegister( const QChar &defaultReg ) const
00580 {
00581 QChar reg = ( m_register != QChar::Null ) ? m_register : defaultReg;
00582
00583 return reg;
00584 }
00585
00586 QString KateViModeBase::getRegisterContent( const QChar ® ) const
00587 {
00588 QString r = KateGlobal::self()->viInputModeGlobal()->getRegisterContent( reg );
00589
00590 if ( r.isNull() ) {
00591 error( QString( "Nothing in register " ) + reg );
00592 }
00593
00594 return r;
00595 }
00596
00597 void KateViModeBase::fillRegister( const QChar ®, const QString &text )
00598 {
00599 KateGlobal::self()->viInputModeGlobal()->fillRegister( reg, text );
00600 }
00601
00602 KateViRange KateViModeBase::goLineDown()
00603 {
00604 return goLineUpDown( getCount() );
00605 }
00606
00607 KateViRange KateViModeBase::goLineUp()
00608 {
00609 return goLineUpDown( -getCount() );
00610 }
00611
00616 KateViRange KateViModeBase::goLineUpDown( int lines )
00617 {
00618 KTextEditor::Cursor c( m_view->cursorPosition() );
00619 KateViRange r( c.line(), c.column(), ViMotion::InclusiveMotion );
00620 int tabstop = doc()->config()->tabWidth();
00621
00622
00623 if ( lines == 0 ) {
00624 return r;
00625 }
00626
00627 r.endLine += lines;
00628
00629
00630 if ( r.endLine < 0 ) {
00631 r.endLine = 0;
00632 } else if ( r.endLine > doc()->lines()-1 ) {
00633 r.endLine = doc()->lines()-1;
00634 }
00635
00636 KateTextLine::Ptr startLine = doc()->plainKateTextLine( c.line() );
00637 KateTextLine::Ptr endLine = doc()->plainKateTextLine( r.endLine );
00638
00639 int endLineLen = doc()->lineLength( r.endLine )-1;
00640
00641 if ( endLineLen < 0 ) {
00642 endLineLen = 0;
00643 }
00644
00645 int endLineLenVirt = endLine->toVirtualColumn(endLineLen, tabstop);
00646 int virtColumnStart = startLine->toVirtualColumn(c.column(), tabstop);
00647
00648
00649 if ( m_stickyColumn == -1 ) {
00650 r.endColumn = endLine->fromVirtualColumn( virtColumnStart, tabstop );
00651 m_stickyColumn = virtColumnStart;
00652 } else {
00653
00654 r.endColumn = endLine->fromVirtualColumn( m_stickyColumn, tabstop );
00655 }
00656
00657
00658 if ( r.endColumn > endLineLen ) {
00659 r.endColumn = endLineLen;
00660 }
00661
00662
00663 if ( virtColumnStart > endLineLenVirt ) {
00664 r.endColumn = endLineLen;
00665 }
00666
00667 return r;
00668 }
00669
00670 bool KateViModeBase::startNormalMode()
00671 {
00672
00673
00674 if (!m_viInputModeManager->isRunningMacro()) {
00675 m_viInputModeManager->storeChangeCommand();
00676 m_viInputModeManager->clearLog();
00677 }
00678
00679 m_viInputModeManager->viEnterNormalMode();
00680 m_view->doc()->setMergeAllEdits(false);
00681 m_view->updateViModeBarMode();
00682
00683 return true;
00684 }
00685
00686 bool KateViModeBase::startInsertMode()
00687 {
00688 m_viInputModeManager->viEnterInsertMode();
00689 m_view->doc()->setMergeAllEdits(true);
00690 m_view->updateViModeBarMode();
00691
00692 return true;
00693 }
00694
00695 bool KateViModeBase::startVisualMode()
00696 {
00697 if ( m_view->getCurrentViMode() == VisualLineMode ) {
00698 m_viInputModeManager->getViVisualMode()->setVisualLine( false );
00699 m_viInputModeManager->changeViMode(VisualMode);
00700 } else {
00701 m_viInputModeManager->viEnterVisualMode();
00702 }
00703
00704 m_view->updateViModeBarMode();
00705
00706 return true;
00707 }
00708
00709 bool KateViModeBase::startVisualLineMode()
00710 {
00711 if ( m_view->getCurrentViMode() == VisualMode ) {
00712 m_viInputModeManager->getViVisualMode()->setVisualLine( true );
00713 m_viInputModeManager->changeViMode(VisualLineMode);
00714 } else {
00715 m_viInputModeManager->viEnterVisualMode( true );
00716 }
00717
00718 m_view->updateViModeBarMode();
00719
00720 return true;
00721 }
00722
00723 void KateViModeBase::error( const QString &errorMsg ) const
00724 {
00725 m_view->viModeBar()->showErrorMessage(errorMsg);
00726 }
00727
00728 void KateViModeBase::message( const QString &msg ) const
00729 {
00730 m_view->viModeBar()->showMessage(msg);
00731 }
00732
00733 QString KateViModeBase::getVerbatimKeys() const
00734 {
00735 return m_keysVerbatim;
00736 }
00737
00738 void KateViModeBase::addMapping( const QString &from, const QString &to )
00739 {
00740 m_mappings[from] = to;
00741 }
00742
00743 const QString KateViModeBase::getMapping( const QString &from ) const
00744 {
00745 return m_mappings[from];
00746 }
00747
00748 const QStringList KateViModeBase::getMappings() const
00749 {
00750 QStringList l;
00751 foreach ( const QString &str, m_mappings.keys() ) {
00752 l << str;
00753 }
00754
00755 return l;
00756 }