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( "|["+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( "|["+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 int KateViModeBase::findLineStartingWitchChar( const QChar &c, unsigned int count, bool forward ) const
00517 {
00518 int line = m_view->cursorPosition().line();
00519 int lines = doc()->lines();
00520 unsigned int hits = 0;
00521
00522 if ( forward ) {
00523 line++;
00524 } else {
00525 line--;
00526 }
00527
00528 while ( line < lines && line > 0 && hits < count ) {
00529 QString l = getLine( line );
00530 if ( l.length() > 0 && l.at( 0 ) == c ) {
00531 hits++;
00532 }
00533 if ( hits != count ) {
00534 if ( forward ) {
00535 line++;
00536 } else {
00537 line--;
00538 }
00539 }
00540 }
00541
00542 if ( hits == getCount() ) {
00543 return line;
00544 }
00545
00546 return -1;
00547 }
00548
00549 void KateViModeBase::updateCursor( const KTextEditor::Cursor &c ) const
00550 {
00551 m_viewInternal->updateCursor( c );
00552 }
00553
00557 QChar KateViModeBase::getChosenRegister( const QChar &defaultReg ) const
00558 {
00559 QChar reg = ( m_register != QChar::Null ) ? m_register : defaultReg;
00560
00561 return reg;
00562 }
00563
00564 QString KateViModeBase::getRegisterContent( const QChar ® ) const
00565 {
00566 QString r = KateGlobal::self()->viInputModeGlobal()->getRegisterContent( reg );
00567
00568 if ( r.isNull() ) {
00569 error( QString( "Nothing in register " ) + reg );
00570 }
00571
00572 return r;
00573 }
00574
00575 void KateViModeBase::fillRegister( const QChar ®, const QString &text )
00576 {
00577 KateGlobal::self()->viInputModeGlobal()->fillRegister( reg, text );
00578 }
00579
00580 KateViRange KateViModeBase::goLineDown()
00581 {
00582 return goLineUpDown( getCount() );
00583 }
00584
00585 KateViRange KateViModeBase::goLineUp()
00586 {
00587 return goLineUpDown( -getCount() );
00588 }
00589
00590 KateViRange KateViModeBase::goLineUpDown( int lines )
00591 {
00592 KTextEditor::Cursor c( m_view->cursorPosition() );
00593 KateViRange r( c.line(), c.column(), ViMotion::InclusiveMotion );
00594 if ( lines == 0 ) {
00595 return r;
00596 } else {
00597 r.endLine += lines;
00598 }
00599
00600 if ( r.endLine < 0 ) {
00601 r.endLine = 0;
00602 } else if ( r.endLine > doc()->lines()-1 ) {
00603 r.endLine = doc()->lines()-1;
00604 }
00605
00606 if ( m_stickyColumn == -1 ) {
00607 r.endColumn = m_stickyColumn = c.column();
00608 } else {
00609 r.endColumn = m_stickyColumn;
00610 }
00611
00612 int lineLen = doc()->lineLength( r.endLine );
00613 KateTextLine::Ptr textLine = doc()->plainKateTextLine( r.endLine );
00614 int realColumn = textLine->fromVirtualColumn(r.endColumn, doc()->config()->tabWidth());
00615 int lastVirtColumn = textLine->toVirtualColumn(lineLen-1,
00616 doc()->config()->tabWidth());
00617
00618 if ( realColumn != r.endColumn && lastVirtColumn >= r.endColumn ) {
00619 r.endColumn = realColumn;
00620 } else {
00621
00622
00623 if ( m_stickyColumn != -1 ) {
00624 if ( lineLen-1 >= m_stickyColumn ) {
00625 r.endColumn = m_stickyColumn;
00626 } else if ( lineLen-1 < m_stickyColumn ) {
00627 if ( lineLen > 0 ) {
00628 r.endColumn = lineLen-1;
00629 } else {
00630 r.endColumn = 0;
00631 }
00632 }
00633 }
00634 }
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648 return r;
00649 }
00650
00651 bool KateViModeBase::startNormalMode()
00652 {
00653
00654
00655 if (!m_viInputModeManager->isRunningMacro()) {
00656 m_viInputModeManager->storeChangeCommand();
00657 m_viInputModeManager->clearLog();
00658 }
00659
00660 m_viInputModeManager->viEnterNormalMode();
00661 m_view->doc()->setMergeAllEdits(false);
00662 m_view->updateViModeBarMode();
00663
00664 return true;
00665 }
00666
00667 bool KateViModeBase::startInsertMode()
00668 {
00669 m_viInputModeManager->viEnterInsertMode();
00670 m_view->doc()->setMergeAllEdits(true);
00671 m_view->updateViModeBarMode();
00672
00673 return true;
00674 }
00675
00676 bool KateViModeBase::startVisualMode()
00677 {
00678 if ( m_view->getCurrentViMode() == VisualLineMode ) {
00679 m_viInputModeManager->getViVisualMode()->setVisualLine( false );
00680 m_viInputModeManager->changeViMode(VisualMode);
00681 } else {
00682 m_viInputModeManager->viEnterVisualMode();
00683 }
00684
00685 m_view->updateViModeBarMode();
00686
00687 return true;
00688 }
00689
00690 bool KateViModeBase::startVisualLineMode()
00691 {
00692 if ( m_view->getCurrentViMode() == VisualMode ) {
00693 m_viInputModeManager->getViVisualMode()->setVisualLine( true );
00694 m_viInputModeManager->changeViMode(VisualLineMode);
00695 } else {
00696 m_viInputModeManager->viEnterVisualMode( true );
00697 }
00698
00699 m_view->updateViModeBarMode();
00700
00701 return true;
00702 }
00703
00704 void KateViModeBase::error( const QString &errorMsg ) const
00705 {
00706 m_view->viModeBar()->showErrorMessage(errorMsg);
00707 }
00708
00709 void KateViModeBase::message( const QString &msg ) const
00710 {
00711 m_view->viModeBar()->showMessage(msg);
00712 }
00713
00714 QString KateViModeBase::getVerbatimKeys() const
00715 {
00716 return m_keysVerbatim;
00717 }