• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

Kate

katevinormalmode.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002  * Copyright (C) 2008 Erlend Hamberg <ehamberg@gmail.com>
00003  * Copyright (C) 2008 Evgeniy Ivanov <powerfox@kde.ru>
00004  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU Library General Public
00007  * License as published by the Free Software Foundation; either
00008  * version 2 of the License, or (at your option) version 3.
00009  *
00010  * This library is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Library General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Library General Public License
00016  * along with this library; see the file COPYING.LIB.  If not, write to
00017  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
00019  */
00020 
00021 #include "katevinormalmode.h"
00022 #include "katevivisualmode.h"
00023 #include "kateviinputmodemanager.h"
00024 #include "katesmartmanager.h"
00025 #include "katesmartrange.h"
00026 #include "katebuffer.h"
00027 #include <QApplication>
00028 #include <QList>
00029 
00030 KateViNormalMode::KateViNormalMode( KateViInputModeManager *viInputModeManager, KateView * view,
00031     KateViewInternal * viewInternal ) : KateViModeBase()
00032 {
00033   m_view = view;
00034   m_viewInternal = viewInternal;
00035   m_viInputModeManager = viInputModeManager;
00036   m_stickyColumn = -1;
00037 
00038   // FIXME: make configurable:
00039   m_extraWordCharacters = "";
00040   m_matchingItems["/*"] = "*/";
00041   m_matchingItems["*/"] = "-/*";
00042 
00043   m_matchItemRegex = generateMatchingItemRegex();
00044 
00045   m_defaultRegister = '"';
00046   m_marks = new QMap<QChar, KTextEditor::SmartCursor*>;
00047   m_keyParser = new KateViKeySequenceParser();
00048 
00049   m_timeoutlen = 1000; // FIXME: make configurable
00050   m_mappingKeyPress = false; // temporarily set to true when an aborted mapping sends key presses
00051   m_mappingTimer = new QTimer( this );
00052   connect(m_mappingTimer, SIGNAL(timeout()), this, SLOT(mappingTimerTimeOut()));
00053 
00054   initializeCommands();
00055   resetParser(); // initialise with start configuration
00056 }
00057 
00058 KateViNormalMode::~KateViNormalMode()
00059 {
00060   delete m_marks;
00061   delete m_keyParser;
00062 }
00063 
00064 void KateViNormalMode::mappingTimerTimeOut()
00065 {
00066   kDebug( 13070 ) << "timeout! key presses: " << m_mappingKeys;
00067   m_mappingKeyPress = true;
00068   m_viInputModeManager->feedKeyPresses( m_mappingKeys );
00069   m_mappingKeyPress = false;
00070   m_mappingKeys.clear();
00071 }
00072 
00077 bool KateViNormalMode::handleKeypress( const QKeyEvent *e )
00078 {
00079   int keyCode = e->key();
00080   QString text = e->text();
00081 
00082   // ignore modifier keys alone
00083   if ( keyCode == Qt::Key_Shift || keyCode == Qt::Key_Control
00084       || keyCode == Qt::Key_Alt || keyCode == Qt::Key_Meta ) {
00085     return false;
00086   }
00087 
00088   if ( keyCode == Qt::Key_Escape ) {
00089     reset();
00090     return true;
00091   }
00092 
00093   QChar key = m_keyParser->KeyEventToQChar( keyCode, text, e->modifiers(), e->nativeScanCode() );
00094 
00095   // check for matching mappings
00096   if ( !m_mappingKeyPress ) {
00097     m_mappingKeys.append( key );
00098 
00099     foreach ( const QString &str, m_mappings.keys() ) {
00100       if ( str.startsWith( m_mappingKeys ) ) {
00101         if ( str == m_mappingKeys ) {
00102           m_viInputModeManager->feedKeyPresses( m_mappings.value( str ) );
00103           m_mappingTimer->stop();
00104           return true;
00105         } else {
00106           m_mappingTimer->start( m_timeoutlen );
00107           m_mappingTimer->setSingleShot( true );
00108           return true;
00109         }
00110       } else {
00111         m_mappingKeys.clear();
00112       }
00113     }
00114   } else {
00115     // FIXME:
00116     //m_mappingKeyPress = false; // key press ignored wrt mappings, re-set m_mappingKeyPress
00117   }
00118 
00119   m_keysVerbatim.append( m_keyParser->decodeKeySequence( key ) );
00120 
00121   QChar c = QChar::Null;
00122   if ( m_keys.size() > 0 ) {
00123     c = m_keys.at( m_keys.size()-1 ); // last char
00124   }
00125 
00126   if ( ( keyCode >= Qt::Key_0 && keyCode <= Qt::Key_9 && c != '"' )       // key 0-9
00127       && ( m_countTemp != 0 || keyCode != Qt::Key_0 )                     // first digit can't be 0
00128       && ( c != 'f' && c != 't' && c != 'F' && c != 'T' && c != 'r' ) ) { // "find char" motions
00129 
00130     m_countTemp *= 10;
00131     m_countTemp += keyCode-Qt::Key_0;
00132 
00133     return true;
00134   } else if ( m_countTemp != 0 ) {
00135     m_count = getCount() * m_countTemp;
00136     m_countTemp = 0;
00137 
00138     kDebug( 13070 ) << "count = " << getCount();
00139   }
00140 
00141   m_keys.append( key );
00142 
00143   // Special case: "cw" and "cW" work the same as "ce" and "cE" if the cursor is
00144   // on a non-blank.  This is because Vim interprets "cw" as change-word, and a
00145   // word does not include the following white space. (:help cw in vim)
00146   if ( ( m_keys == "cw" || m_keys == "cW" ) && !getCharUnderCursor().isSpace() ) {
00147     // Special case of the special case: :-)
00148     // If the cursor is at the end of the current word rewrite to "cl"
00149     KTextEditor::Cursor c1( m_view->cursorPosition() ); // current position
00150     KTextEditor::Cursor c2 = findWordEnd(c1.line(), c1.column()-1, true); // word end
00151 
00152     if ( c1 == c2 ) { // the cursor is at the end of a word
00153       m_keys = "cl";
00154     } else {
00155       if ( m_keys.at(1) == 'w' ) {
00156         m_keys = "ce";
00157       } else {
00158         m_keys = "cE";
00159       }
00160     }
00161   }
00162 
00163   if ( m_keys[ 0 ] == Qt::Key_QuoteDbl ) {
00164     if ( m_keys.size() < 2 ) {
00165       return true; // waiting for a register
00166     }
00167     else {
00168       QChar r = m_keys[ 1 ].toLower();
00169 
00170       if ( ( r >= '0' && r <= '9' ) || ( r >= 'a' && r <= 'z' ) || r == '_' || r == '+' || r == '*' ) {
00171         m_register = r;
00172         kDebug( 13070 ) << "Register set to " << r;
00173         m_keys.clear();
00174         return true;
00175       }
00176       else {
00177         resetParser();
00178         return true;
00179       }
00180     }
00181   }
00182 
00183 
00184   // if we have any matching commands so far, check which ones still match
00185   if ( m_matchingCommands.size() > 0 ) {
00186     int n = m_matchingCommands.size()-1;
00187 
00188     // remove commands not matching anymore
00189     for ( int i = n; i >= 0; i-- ) {
00190       if ( !m_commands.at( m_matchingCommands.at( i ) )->matches( m_keys ) ) {
00191         //kDebug( 13070 ) << "removing " << m_commands.at( m_matchingCommands.at( i ) )->pattern() << ", size before remove is " << m_matchingCommands.size();
00192         if ( m_commands.at( m_matchingCommands.at( i ) )->needsMotion() ) {
00193           // "cache" command needing a motion for later
00194           //kDebug( 13070 ) << "m_motionOperatorIndex set to " << m_motionOperatorIndex;
00195           m_motionOperatorIndex = m_matchingCommands.at( i );
00196         }
00197         m_matchingCommands.remove( i );
00198       }
00199     }
00200 
00201     // check if any of the matching commands need a motion/text object, if so
00202     // push the current command length to m_awaitingMotionOrTextObject so one
00203     // knows where to split the command between the operator and the motion
00204     for ( int i = 0; i < m_matchingCommands.size(); i++ ) {
00205       if ( m_commands.at( m_matchingCommands.at( i ) )->needsMotion() ) {
00206         m_awaitingMotionOrTextObject.push( m_keys.size() );
00207         break;
00208       }
00209     }
00210   } else {
00211     // go through all registered commands and put possible matches in m_matchingCommands
00212     for ( int i = 0; i < m_commands.size(); i++ ) {
00213       if ( m_commands.at( i )->matches( m_keys ) ) {
00214         m_matchingCommands.push_back( i );
00215         if ( m_commands.at( i )->needsMotion() && m_commands.at( i )->pattern().length() == m_keys.size() ) {
00216           m_awaitingMotionOrTextObject.push( m_keys.size() );
00217         }
00218       }
00219     }
00220   }
00221 
00222   // this indicates where in the command string one should start looking for a motion command
00223   int checkFrom = ( m_awaitingMotionOrTextObject.isEmpty() ? 0 : m_awaitingMotionOrTextObject.top() );
00224 
00225   //kDebug( 13070 ) << "checkFrom: " << checkFrom;
00226 
00227   // look for matching motion commands from position 'checkFrom'
00228   // FIXME: if checkFrom hasn't changed, only motions whose index is in
00229   // m_matchingMotions shold be checked
00230   if ( checkFrom < m_keys.size() ) {
00231     for ( int i = 0; i < m_motions.size(); i++ ) {
00232       //kDebug( 13070 )  << "\tchecking " << m_keys.mid( checkFrom )  << " against " << m_motions.at( i )->pattern();
00233       if ( m_motions.at( i )->matches( m_keys.mid( checkFrom ) ) ) {
00234         //kDebug( 13070 )  << m_keys.mid( checkFrom ) << " matches!";
00235         m_matchingMotions.push_back( i );
00236 
00237         // if it matches exact, we have found the motion command to execute
00238         if ( m_motions.at( i )->matchesExact( m_keys.mid( checkFrom ) ) ) {
00239           if ( checkFrom == 0 ) {
00240             // no command given before motion, just move the cursor to wherever
00241             // the motion says it should go to
00242             KateViRange r = m_motions.at( i )->execute();
00243 
00244             // make sure the position is valid before moving the cursor there
00245             if ( r.valid
00246                 && r.endLine >= 0
00247                 && ( r.endLine == 0 || r.endLine <= doc()->lines()-1 )
00248                 && r.endColumn >= 0
00249                 && ( r.endColumn == 0 || r.endColumn < doc()->lineLength( r.endLine ) ) ) {
00250               kDebug( 13070 ) << "No command given, going to position ("
00251                 << r.endLine << "," << r.endColumn << ")";
00252               goToPos( r );
00253               m_viInputModeManager->clearLog();
00254             } else {
00255               kDebug( 13070 ) << "Invalid position: (" << r.endLine << "," << r.endColumn << ")";
00256             }
00257 
00258             resetParser();
00259             return true;
00260           } else {
00261             // execute the specified command and supply the position returned from
00262             // the motion
00263 
00264             m_commandRange = m_motions.at( i )->execute();
00265 
00266             // if we didn't get an explicit start position, use the current cursor position
00267             if ( m_commandRange.startLine == -1 ) {
00268               KTextEditor::Cursor c( m_view->cursorPosition() );
00269               m_commandRange.startLine = c.line();
00270               m_commandRange.startColumn = c.column();
00271             }
00272 
00273             // Special case: "word motions" should never cross a line boundary when they are the
00274             // input to a command
00275             if ( ( m_keys.right(1) == "w" || m_keys.right(1) == "W" )
00276                 && m_commandRange.endLine > m_commandRange.startLine ) {
00277               m_commandRange = motionToEOL();
00278 
00279               KTextEditor::Cursor c( m_view->cursorPosition() );
00280               m_commandRange.startLine = c.line();
00281               m_commandRange.startColumn = c.column();
00282             }
00283 
00284             if ( m_commandRange.valid ) {
00285               kDebug( 13070 ) << "Run command" << m_commands.at( m_motionOperatorIndex )->pattern()
00286                 << "from (" << m_commandRange.startLine << "," << m_commandRange.endLine << ")"
00287                 << "to (" << m_commandRange.endLine << "," << m_commandRange.endColumn << ")";
00288               executeCommand( m_commands.at( m_motionOperatorIndex ) );
00289             } else {
00290               kDebug( 13070 ) << "Invalid range: "
00291                 << "from (" << m_commandRange.startLine << "," << m_commandRange.endLine << ")"
00292                 << "to (" << m_commandRange.endLine << "," << m_commandRange.endColumn << ")";
00293             }
00294 
00295             reset();
00296             return true;
00297           }
00298         }
00299       }
00300     }
00301   }
00302 
00303   //kDebug( 13070 ) << "'" << m_keys << "' MATCHING COMMANDS: " << m_matchingCommands.size();
00304   //kDebug( 13070 ) << "'" << m_keys << "' MATCHING MOTIONS: " << m_matchingMotions.size();
00305   //kDebug( 13070 ) << "'" << m_keys << "' AWAITING MOTION OR TO (INDEX): " << ( m_awaitingMotionOrTextObject.isEmpty() ? 0 : m_awaitingMotionOrTextObject.top() );
00306 
00307   // if we have only one match, check if it is a perfect match and if so, execute it
00308   // if it's not waiting for a motion or a text object
00309   if ( m_matchingCommands.size() == 1 ) {
00310     if ( m_commands.at( m_matchingCommands.at( 0 ) )->matchesExact( m_keys )
00311         && !m_commands.at( m_matchingCommands.at( 0 ) )->needsMotion() ) {
00312       //kDebug( 13070 ) << "Running command at index " << m_matchingCommands.at( 0 );
00313 
00314       KateViCommand *cmd = m_commands.at( m_matchingCommands.at( 0 ) );
00315       executeCommand( cmd );
00316 
00317       // check if reset() should be called. some commands in visual mode should not end visual mode
00318       if ( cmd->shouldReset() ) {
00319         reset();
00320       }
00321       resetParser();
00322 
00323       return true;
00324     }
00325   } else if ( m_matchingCommands.size() == 0 && m_matchingMotions.size() == 0 ) {
00326     //if ( m_awaitingMotionOrTextObject.size() == 0 ) {
00327       resetParser();
00328       return false;
00329     //} else {
00330 
00331     //}
00332   }
00333 
00334   m_matchingMotions.clear();
00335   return false;
00336 }
00337 
00342 void KateViNormalMode::resetParser()
00343 {
00344   kDebug( 13070 ) << "***RESET***";
00345   m_keys.clear();
00346   m_keysVerbatim.clear();
00347   m_count = 0;
00348   m_countTemp = 0;
00349   m_register = QChar::Null;
00350   m_findWaitingForChar = false;
00351   m_waitingForMotionOrTextObject = -1;
00352   m_matchingCommands.clear();
00353   m_matchingMotions.clear();
00354   m_awaitingMotionOrTextObject.clear();
00355   m_motionOperatorIndex = 0;
00356 }
00357 
00358 // reset the command parser
00359 void KateViNormalMode::reset()
00360 {
00361     resetParser();
00362     m_commandRange.startLine = -1;
00363     m_commandRange.startColumn = -1;
00364 }
00365 
00366 void KateViNormalMode::goToPos( const KateViRange &r )
00367 {
00368   KTextEditor::Cursor c;
00369   c.setLine( r.endLine );
00370   c.setColumn( r.endColumn );
00371 
00372   if ( r.jump ) {
00373     addCurrentPositionToJumpList();
00374   }
00375 
00376   if ( c.line() >= doc()->lines() ) {
00377     c.setLine( doc()->lines()-1 );
00378   }
00379 
00380   updateCursor( c );
00381 }
00382 
00383 void KateViNormalMode::executeCommand( const KateViCommand* cmd )
00384 {
00385   cmd->execute();
00386 
00387   // if the command was a change, and it didn't enter insert mode, store the key presses so that
00388   // they can be repeated with '.'
00389   if ( m_viInputModeManager->getCurrentViMode() != InsertMode ) {
00390     if ( cmd->isChange() && !m_viInputModeManager->isRunningMacro() ) {
00391       m_viInputModeManager->storeChangeCommand();
00392     }
00393 
00394     m_viInputModeManager->clearLog();
00395   }
00396 
00397   // make sure the cursor does not end up after the end of the line
00398   KTextEditor::Cursor c( m_view->cursorPosition() );
00399   if ( m_viInputModeManager->getCurrentViMode() == NormalMode ) {
00400     int lineLength = doc()->lineLength( c.line() );
00401 
00402     if ( c.column() >= lineLength ) {
00403       if ( lineLength == 0 ) {
00404         c.setColumn( 0 );
00405       } else {
00406         c.setColumn( lineLength-1 );
00407       }
00408     }
00409     updateCursor( c );
00410   }
00411 }
00412 
00413 void KateViNormalMode::addCurrentPositionToJumpList()
00414 {
00415     KTextEditor::Cursor c( m_view->cursorPosition() );
00416 
00417     KateSmartCursor *cursor = doc()->smartManager()->newSmartCursor( c );
00418 
00419     m_marks->insert( '\'', cursor );
00420 }
00421 
00423 // COMMANDS AND OPERATORS
00425 
00430 bool KateViNormalMode::commandEnterInsertMode()
00431 {
00432   return startInsertMode();
00433 }
00434 
00439 bool KateViNormalMode::commandEnterInsertModeAppend()
00440 {
00441   KTextEditor::Cursor c( m_view->cursorPosition() );
00442   c.setColumn( c.column()+1 );
00443 
00444   // if empty line, the cursor should start at column 0
00445   if ( doc()->lineLength( c.line() ) == 0 ) {
00446     c.setColumn( 0 );
00447   }
00448 
00449   updateCursor( c );
00450 
00451   return startInsertMode();
00452 }
00453 
00458 bool KateViNormalMode::commandEnterInsertModeAppendEOL()
00459 {
00460   KTextEditor::Cursor c( m_view->cursorPosition() );
00461   c.setColumn( doc()->lineLength( c.line() ) );
00462   updateCursor( c );
00463 
00464   return startInsertMode();
00465 }
00466 
00467 bool KateViNormalMode::commandEnterInsertModeBeforeFirstCharacterOfLine()
00468 {
00469   KTextEditor::Cursor cursor( m_view->cursorPosition() );
00470   QRegExp nonSpace( "\\S" );
00471   int c = getLine().indexOf( nonSpace );
00472   if ( c == -1 ) {
00473     c = 0;
00474   }
00475   cursor.setColumn( c );
00476   updateCursor( cursor );
00477 
00478   return startInsertMode();
00479 }
00480 
00481 bool KateViNormalMode::commandEnterVisualLineMode()
00482 {
00483   if ( m_viInputModeManager->getCurrentViMode() == VisualLineMode ) {
00484     reset();
00485     return true;
00486   }
00487 
00488   return startVisualLineMode();
00489 }
00490 
00491 bool KateViNormalMode::commandEnterVisualMode()
00492 {
00493   if ( m_viInputModeManager->getCurrentViMode() == VisualMode ) {
00494     reset();
00495     return true;
00496   }
00497 
00498   return startVisualMode();
00499 }
00500 
00501 bool KateViNormalMode::commandToOtherEnd()
00502 {
00503   if ( m_viInputModeManager->getCurrentViMode() == VisualLineMode
00504       || m_viInputModeManager->getCurrentViMode() == VisualMode ) {
00505     m_viInputModeManager->getViVisualMode()->switchStartEnd();
00506     return true;
00507   }
00508 
00509   return false;
00510 }
00511 
00512 bool KateViNormalMode::commandDeleteLine()
00513 {
00514   KTextEditor::Cursor c( m_view->cursorPosition() );
00515 
00516   KateViRange r;
00517 
00518   r.startLine = c.line();
00519   r.endLine = c.line()+getCount()-1;
00520 
00521   int column = c.column();
00522 
00523   bool ret = deleteRange( r, true );
00524 
00525   c = m_view->cursorPosition();
00526   if ( column > doc()->lineLength( c.line() )-1 ) {
00527     column = doc()->lineLength( c.line() )-1;
00528   }
00529   if ( column < 0 ) {
00530     column = 0;
00531   }
00532 
00533   if ( c.line() > doc()->lines()-1 ) {
00534     c.setLine( doc()->lines()-1 );
00535   }
00536 
00537   c.setColumn( column );
00538   updateCursor( c );
00539 
00540   return ret;
00541 }
00542 
00543 bool KateViNormalMode::commandDelete()
00544 {
00545   bool linewise = m_viInputModeManager->getCurrentViMode() == VisualLineMode
00546     || ( m_commandRange.startLine != m_commandRange.endLine
00547       && m_viInputModeManager->getCurrentViMode() != VisualMode );
00548 
00549   return deleteRange( m_commandRange, linewise );
00550 }
00551 
00552 bool KateViNormalMode::commandDeleteToEOL()
00553 {
00554   KTextEditor::Cursor c( m_view->cursorPosition() );
00555 
00556   m_commandRange.endLine = c.line()+getCount()-1;
00557   m_commandRange.endColumn = doc()->lineLength( m_commandRange.endLine );
00558 
00559   if ( m_viInputModeManager->getCurrentViMode() == NormalMode ) {
00560     m_commandRange.startLine = c.line();
00561     m_commandRange.startColumn = c.column();
00562   }
00563 
00564   bool linewise = ( m_viInputModeManager->getCurrentViMode() == VisualMode
00565       || m_viInputModeManager->getCurrentViMode() == VisualLineMode );
00566 
00567   bool r = deleteRange( m_commandRange, linewise );
00568 
00569   if ( !linewise ) {
00570     c.setColumn( doc()->lineLength( c.line() )-1 );
00571   } else {
00572     c.setLine( m_commandRange.startLine-1 );
00573     c.setColumn( m_commandRange.startColumn );
00574   }
00575 
00576   // make sure cursor position is valid after deletion
00577   if ( c.line() < 0 ) {
00578     c.setLine( 0 );
00579   }
00580   if ( c.column() > doc()->lineLength( c.line() )-1 ) {
00581     c.setColumn( doc()->lineLength( c.line() )-1 );
00582   }
00583   if ( c.column() < 0 ) {
00584     c.setColumn( 0 );
00585   }
00586 
00587   updateCursor( c );
00588 
00589   return r;
00590 }
00591 
00592 bool KateViNormalMode::commandMakeLowercase()
00593 {
00594   KTextEditor::Cursor c( m_view->cursorPosition() );
00595 
00596   int line1 = m_commandRange.startLine;
00597   int line2 = m_commandRange.endLine;
00598 
00599   if ( line1 == line2 ) { // characterwise
00600     int endColumn = ( m_commandRange.endColumn > c.column() ) ? m_commandRange.endColumn : c.column();
00601     int startColumn = ( m_commandRange.startColumn < c.column() ) ? m_commandRange.startColumn : c.column();
00602     if ( m_commandRange.isInclusive() )
00603       endColumn++;
00604 
00605     KTextEditor::Range range( KTextEditor::Cursor( c.line(), startColumn ), KTextEditor::Cursor( c.line(), endColumn ) );
00606     doc()->replaceText( range, getLine().mid( startColumn, endColumn-startColumn ).toLower() );
00607   }
00608   else { // linewise
00609     QString s;
00610     for ( int i = ( line1 < line2 ? line1 : line2 ); i <= ( line1 < line2 ? line2 : line1 ); i++ ) {
00611        s.append( doc()->line( i ).toLower() + '\n' );
00612     }
00613 
00614     // remove the laste \n
00615     s.chop( 1 );
00616 
00617     KTextEditor::Range range( KTextEditor::Cursor( c.line(), 0 ),
00618         KTextEditor::Cursor( line2, doc()->lineLength( line2 ) ) );
00619 
00620     doc()->replaceText( range, s );
00621   }
00622 
00623   updateCursor( c );
00624 
00625   return true;
00626 }
00627 
00628 bool KateViNormalMode::commandMakeLowercaseLine()
00629 {
00630   KTextEditor::Cursor c( m_view->cursorPosition() );
00631 
00632   m_commandRange.startLine = c.line();
00633   m_commandRange.endLine = c.line();
00634   m_commandRange.startColumn = 0;
00635   m_commandRange.endColumn = doc()->lineLength( c.line() );
00636 
00637   return commandMakeLowercase();
00638 }
00639 
00640 bool KateViNormalMode::commandMakeUppercase()
00641 {
00642   KTextEditor::Cursor c( m_view->cursorPosition() );
00643 
00644   int line1 = m_commandRange.startLine;
00645   int line2 = m_commandRange.endLine;
00646 
00647   if ( line1 == line2 ) { // characterwise
00648     int endColumn = ( m_commandRange.endColumn > c.column() ) ? m_commandRange.endColumn : c.column();
00649     int startColumn = ( m_commandRange.startColumn < c.column() ) ? m_commandRange.startColumn : c.column();
00650     if ( m_commandRange.isInclusive() )
00651       endColumn++;
00652 
00653     KTextEditor::Range range( KTextEditor::Cursor( c.line(), startColumn ), KTextEditor::Cursor( c.line(), endColumn ) );
00654     doc()->replaceText( range, getLine().mid( startColumn, endColumn-startColumn ).toUpper() );
00655   }
00656   else { // linewise
00657     QString s;
00658     for ( int i = ( line1 < line2 ? line1 : line2 ); i <= ( line1 < line2 ? line2 : line1 ); i++ ) {
00659        s.append( doc()->line( i ).toUpper() + '\n' );
00660     }
00661 
00662     // remove the laste \n
00663     s.chop( 1 );
00664 
00665     KTextEditor::Range range( KTextEditor::Cursor( c.line(), 0 ),
00666         KTextEditor::Cursor( line2, doc()->lineLength( line2 ) ) );
00667 
00668     doc()->replaceText( range, s );
00669   }
00670 
00671   updateCursor( c );
00672 
00673   return true;
00674 }
00675 
00676 bool KateViNormalMode::commandMakeUppercaseLine()
00677 {
00678   KTextEditor::Cursor c( m_view->cursorPosition() );
00679 
00680   m_commandRange.startLine = c.line();
00681   m_commandRange.endLine = c.line();
00682   m_commandRange.startColumn = 0;
00683   m_commandRange.endColumn = doc()->lineLength( c.line() );
00684 
00685   return commandMakeUppercase();
00686 }
00687 
00688 bool KateViNormalMode::commandChangeCase()
00689 {
00690   QString text;
00691   KTextEditor::Range range;
00692   KTextEditor::Cursor c( m_view->cursorPosition() );
00693 
00694   // in visual mode, the range is from start position to end position...
00695   if ( m_viInputModeManager->getCurrentViMode() == VisualMode ) {
00696     KTextEditor::Cursor c2 = m_viInputModeManager->getViVisualMode()->getStart();
00697 
00698     if ( c2 > c ) {
00699       c2.setColumn( c2.column()+1 );
00700     } else {
00701       c.setColumn( c.column()+1 );
00702     }
00703 
00704     range.setRange( c, c2 );
00705   // ... in visual line mode, the range is from column 0 on the first line to
00706   // the line length of the last line...
00707   } else if ( m_viInputModeManager->getCurrentViMode() == VisualLineMode ) {
00708     KTextEditor::Cursor c2 = m_viInputModeManager->getViVisualMode()->getStart();
00709 
00710     if ( c2 > c ) {
00711       c2.setColumn( doc()->lineLength( c2.line() ) );
00712       c.setColumn( 0 );
00713     } else {
00714       c.setColumn( doc()->lineLength( c.line() ) );
00715       c2.setColumn( 0 );
00716     }
00717 
00718     range.setRange( c, c2 );
00719   // ... and in normal mode the range is from the current position to the
00720   // current position + count
00721   } else {
00722     KTextEditor::Cursor c2 = c;
00723     c2.setColumn( c.column()+getCount() );
00724 
00725     if ( c2.column() > doc()->lineLength( c.line() ) ) {
00726       c2.setColumn( doc()->lineLength( c.line() ) );
00727     }
00728 
00729     range.setRange( c, c2 );
00730   }
00731 
00732   // get the text the command should operate on
00733   text = doc()->text ( range );
00734 
00735   // for every character, switch its case
00736   for ( int i = 0; i < text.length(); i++ ) {
00737     if ( text.at(i).isUpper() ) {
00738       text[i] = text.at(i).toLower();
00739     } else if ( text.at(i).isLower() ) {
00740       text[i] = text.at(i).toUpper();
00741     }
00742   }
00743 
00744   // replace the old text with the modified text
00745   doc()->replaceText( range, text );
00746 
00747   // in normal mode, move the cursor to the right, in visual mode move the
00748   // cursor to the start of the selection
00749   if ( m_viInputModeManager->getCurrentViMode() == NormalMode ) {
00750     updateCursor( range.end() );
00751   } else {
00752     updateCursor( range.start() );
00753   }
00754 
00755   return true;
00756 }
00757 
00758 bool KateViNormalMode::commandOpenNewLineUnder()
00759 {
00760   KTextEditor::Cursor c( m_view->cursorPosition() );
00761 
00762   c.setColumn( doc()->lineLength( c.line() ) );
00763   updateCursor( c );
00764 
00765   for ( unsigned int i = 0; i < getCount(); i++ ) {
00766     doc()->newLine( m_view );
00767   }
00768 
00769   startInsertMode();
00770   m_viewInternal->repaint ();
00771 
00772   return true;
00773 }
00774 
00775 bool KateViNormalMode::commandOpenNewLineOver()
00776 {
00777   KTextEditor::Cursor c( m_view->cursorPosition() );
00778 
00779   if ( c.line() == 0 ) {
00780     for (unsigned int i = 0; i < getCount(); i++ ) {
00781       doc()->insertLine( 0, QString() );
00782     }
00783     c.setColumn( 0 );
00784     c.setLine( 0 );
00785     updateCursor( c );
00786   } else {
00787     c.setLine( c.line()-1 );
00788     c.setColumn( getLine( c.line() ).length() );
00789     updateCursor( c );
00790     for ( unsigned int i = 0; i < getCount(); i++ ) {
00791         doc()->newLine( m_view );
00792     }
00793 
00794     if ( getCount() > 1 ) {
00795       c = m_view->cursorPosition();
00796       c.setLine( c.line()-(getCount()-1 ) );
00797       updateCursor( c );
00798     }
00799     //c.setLine( c.line()-getCount() );
00800   }
00801 
00802   startInsertMode();
00803   m_viewInternal->repaint ();
00804 
00805   return true;
00806 }
00807 
00808 bool KateViNormalMode::commandJoinLines()
00809 {
00810   KTextEditor::Cursor c( m_view->cursorPosition() );
00811 
00812   int n = getCount();
00813 
00814   // if we were given a range of lines, this information overrides the previous
00815   if ( m_commandRange.startLine != -1 && m_commandRange.endLine != -1 ) {
00816     c.setLine ( m_commandRange.startLine );
00817     n = m_commandRange.endLine-m_commandRange.startLine;
00818   }
00819 
00820   // make sure we don't try to join lines past the document end
00821   if ( n > doc()->lines()-1-c.line() ) {
00822       n = doc()->lines()-1-c.line();
00823   }
00824 
00825   doc()->joinLines( c.line(), c.line()+n );
00826 
00827   return true;
00828 }
00829 
00830 bool KateViNormalMode::commandChange()
00831 {
00832   KTextEditor::Cursor c( m_view->cursorPosition() );
00833 
00834   bool linewise = ( m_commandRange.startLine != m_commandRange.endLine
00835       && m_viInputModeManager->getCurrentViMode() != VisualMode );
00836 
00837   doc()->editStart();
00838   commandDelete();
00839 
00840   // if we deleted several lines, insert an empty line and put the cursor there
00841   if ( linewise ) {
00842     doc()->insertLine( m_commandRange.startLine, QString() );
00843     c.setLine( m_commandRange.startLine );
00844     c.setColumn(0);
00845   }
00846   doc()->editEnd();
00847 
00848   if ( linewise ) {
00849     updateCursor( c );
00850   }
00851 
00852   commandEnterInsertMode();
00853 
00854   return true;
00855 }
00856 
00857 bool KateViNormalMode::commandChangeToEOL()
00858 {
00859   commandDeleteToEOL();
00860   commandEnterInsertModeAppend();
00861 
00862   return true;
00863 }
00864 
00865 bool KateViNormalMode::commandChangeLine()
00866 {
00867   KTextEditor::Cursor c( m_view->cursorPosition() );
00868   c.setColumn( 0 );
00869   updateCursor( c );
00870 
00871   doc()->editStart();
00872 
00873   // if count >= 2 start by deleting the whole lines
00874   if ( getCount() >= 2 ) {
00875     KateViRange r( c.line(), 0, c.line()+getCount()-2, 0, ViMotion::InclusiveMotion );
00876     deleteRange( r );
00877   }
00878 
00879   // ... then delete the _contents_ of the last line, but keep the line
00880   KateViRange r( c.line(), c.column(), c.line(), doc()->lineLength( c.line() )-1,
00881       ViMotion::InclusiveMotion );
00882   deleteRange( r, false, true );
00883   doc()->editEnd();
00884 
00885   // ... then enter insert mode
00886   commandEnterInsertModeAppend();
00887 
00888   return true;
00889 }
00890 
00891 bool KateViNormalMode::commandSubstituteChar()
00892 {
00893   if ( commandDeleteChar() ) {
00894     return commandEnterInsertMode();
00895   }
00896 
00897   return false;
00898 }
00899 
00900 bool KateViNormalMode::commandSubstituteLine()
00901 {
00902   return commandChangeLine();
00903 }
00904 
00905 bool KateViNormalMode::commandYank()
00906 {
00907   KTextEditor::Cursor c( m_view->cursorPosition() );
00908 
00909   bool r = false;
00910   QString yankedText;
00911 
00912   bool linewise = m_viInputModeManager->getCurrentViMode() == VisualLineMode
00913     || ( m_commandRange.startLine != m_commandRange.endLine
00914       && m_viInputModeManager->getCurrentViMode() != VisualMode );
00915 
00916   yankedText = getRange( m_commandRange, linewise );
00917 
00918   fillRegister( getChosenRegister( '0' ), yankedText );
00919 
00920   return r;
00921 }
00922 
00923 bool KateViNormalMode::commandYankLine()
00924 {
00925   KTextEditor::Cursor c( m_view->cursorPosition() );
00926   QString lines;
00927   int linenum = c.line();
00928 
00929   for ( unsigned int i = 0; i < getCount(); i++ ) {
00930       lines.append( getLine( linenum + i ) + '\n' );
00931   }
00932   fillRegister( getChosenRegister( '0' ), lines );
00933 
00934   return true;
00935 }
00936 
00937 bool KateViNormalMode::commandYankToEOL()
00938 {
00939   KTextEditor::Cursor c( m_view->cursorPosition() );
00940 
00941   bool r = false;
00942   QString yankedText;
00943 
00944   m_commandRange.endLine = c.line()+getCount()-1;
00945   m_commandRange.endColumn = doc()->lineLength( m_commandRange.endLine );
00946 
00947   bool linewise = ( m_viInputModeManager->getCurrentViMode() == VisualMode
00948       || m_viInputModeManager->getCurrentViMode() == VisualLineMode );
00949 
00950   if ( m_viInputModeManager->getCurrentViMode() == NormalMode ) {
00951     m_commandRange.startLine = c.line();
00952     m_commandRange.startColumn = c.column();
00953   }
00954 
00955   yankedText = getRange( m_commandRange, linewise );
00956 
00957   fillRegister( getChosenRegister( '0' ), yankedText );
00958 
00959   return r;
00960 }
00961 
00962 // insert the text in the given register at the cursor position
00963 // the cursor should end up at the beginning of what was pasted
00964 bool KateViNormalMode::commandPaste()
00965 {
00966   KTextEditor::Cursor c( m_view->cursorPosition() );
00967   KTextEditor::Cursor cAfter = c;
00968   QChar reg = getChosenRegister( m_defaultRegister );
00969 
00970   QString textToInsert = getRegisterContent( reg );
00971 
00972   if ( getCount() > 1 ) {
00973     textToInsert = textToInsert.repeated( getCount() );
00974   }
00975 
00976   if ( textToInsert.endsWith('\n') ) { // line(s)
00977     textToInsert.chop( 1 ); // remove the last \n
00978     c.setColumn( doc()->lineLength( c.line() ) ); // paste after the current line and ...
00979     textToInsert.prepend( QChar( '\n' ) ); // ... prepend a \n, so the text starts on a new line
00980 
00981     cAfter.setLine( cAfter.line()+1 );
00982     cAfter.setColumn( 0 );
00983   } else {
00984     if ( getLine( c.line() ).length() > 0 ) {
00985       c.setColumn( c.column()+1 );
00986     }
00987 
00988     cAfter = c;
00989   }
00990 
00991   doc()->insertText( c, textToInsert );
00992 
00993   updateCursor( cAfter );
00994 
00995   return true;
00996 }
00997 
00998 // insert the text in the given register before the cursor position
00999 // the cursor should end up at the beginning of what was pasted
01000 bool KateViNormalMode::commandPasteBefore()
01001 {
01002   KTextEditor::Cursor c( m_view->cursorPosition() );
01003   KTextEditor::Cursor cAfter = c;
01004   QChar reg = getChosenRegister( m_defaultRegister );
01005 
01006   QString textToInsert = getRegisterContent( reg );
01007 
01008   if ( getCount() > 1 ) {
01009     textToInsert = textToInsert.repeated( getCount() );
01010   }
01011 
01012   if ( textToInsert.endsWith('\n') ) { // lines
01013     c.setColumn( 0 );
01014     cAfter.setColumn( 0 );
01015   }
01016 
01017   doc()->insertText( c, textToInsert );
01018 
01019   updateCursor( cAfter );
01020 
01021   return true;
01022 }
01023 
01024 bool KateViNormalMode::commandDeleteChar()
01025 {
01026     KTextEditor::Cursor c( m_view->cursorPosition() );
01027     KateViRange r( c.line(), c.column(), c.line(), c.column()+getCount(), ViMotion::ExclusiveMotion );
01028 
01029     if ( m_commandRange.startLine != -1 && m_commandRange.startColumn != -1 ) {
01030       r = m_commandRange;
01031     } else {
01032       if ( r.endColumn > doc()->lineLength( r.startLine ) ) {
01033         r.endColumn = doc()->lineLength( r.startLine );
01034       }
01035     }
01036 
01037     // should only delete entire lines if in visual line mode
01038     bool linewise = m_viInputModeManager->getCurrentViMode() == VisualLineMode;
01039 
01040     return deleteRange( r, linewise );
01041 }
01042 
01043 bool KateViNormalMode::commandDeleteCharBackward()
01044 {
01045     KTextEditor::Cursor c( m_view->cursorPosition() );
01046 
01047     KateViRange r( c.line(), c.column()-getCount(), c.line(), c.column(), ViMotion::ExclusiveMotion );
01048 
01049     if ( m_commandRange.startLine != -1 && m_commandRange.startColumn != -1 ) {
01050       r = m_commandRange;
01051     } else {
01052       if ( r.startColumn < 0 ) {
01053         r.startColumn = 0;
01054       }
01055     }
01056 
01057     // should only delete entire lines if in visual line mode
01058     bool linewise = m_viInputModeManager->getCurrentViMode() == VisualLineMode;
01059 
01060     return deleteRange( r, linewise );
01061 }
01062 
01063 bool KateViNormalMode::commandReplaceCharacter()
01064 {
01065   KTextEditor::Cursor c1( m_view->cursorPosition() );
01066   KTextEditor::Cursor c2( m_view->cursorPosition() );
01067 
01068   c2.setColumn( c2.column()+1 );
01069 
01070   bool r = doc()->replaceText( KTextEditor::Range( c1, c2 ), m_keys.right( 1 ) );
01071 
01072   updateCursor( c1 );
01073 
01074   return r;
01075 }
01076 
01077 bool KateViNormalMode::commandSwitchToCmdLine()
01078 {
01079     m_view->switchToCmdLine();
01080     return true;
01081 }
01082 
01083 bool KateViNormalMode::commandSearch()
01084 {
01085     m_view->find();
01086     return true;
01087 }
01088 
01089 bool KateViNormalMode::commandUndo()
01090 {
01091     doc()->undo();
01092     return true;
01093 }
01094 
01095 bool KateViNormalMode::commandRedo()
01096 {
01097     doc()->redo();
01098     return true;
01099 }
01100 
01101 bool KateViNormalMode::commandSetMark()
01102 {
01103   KTextEditor::Cursor c( m_view->cursorPosition() );
01104 
01105   KateSmartCursor *cursor = doc()->smartManager()->newSmartCursor( c );
01106 
01107   m_marks->insert( m_keys.at( m_keys.size()-1 ), cursor );
01108   kDebug( 13070 ) << "set mark at (" << c.line() << "," << c.column() << ")";
01109 
01110   return true;
01111 }
01112 
01113 bool KateViNormalMode::commandFindPrev()
01114 {
01115     m_view->findPrevious();
01116 
01117     return true;
01118 }
01119 
01120 bool KateViNormalMode::commandFindNext()
01121 {
01122     m_view->findNext();
01123 
01124     return true;
01125 }
01126 
01127 bool KateViNormalMode::commandIndentLine()
01128 {
01129     KTextEditor::Cursor c( m_view->cursorPosition() );
01130 
01131     for ( unsigned int i = 0; i < getCount(); i++ ) {
01132         doc()->indent( m_view, c.line()+i, 1 );
01133     }
01134 
01135     return true;
01136 }
01137 
01138 bool KateViNormalMode::commandUnindentLine()
01139 {
01140     KTextEditor::Cursor c( m_view->cursorPosition() );
01141 
01142     for ( unsigned int i = 0; i < getCount(); i++ ) {
01143         doc()->indent( m_view, c.line()+i, -1 );
01144     }
01145 
01146     return true;
01147 }
01148 
01149 bool KateViNormalMode::commandIndentLines()
01150 {
01151   KTextEditor::Cursor c( m_view->cursorPosition() );
01152 
01153   m_commandRange.normalize();
01154 
01155   int line1 = m_commandRange.startLine;
01156   int line2 = m_commandRange.endLine;
01157 
01158   doc()->editStart();
01159   for ( int i = line1; i <= line2; i++ ) {
01160       doc()->indent( m_view, i, getCount() );
01161   }
01162   doc()->editEnd();
01163 
01164   return true;
01165 }
01166 
01167 bool KateViNormalMode::commandUnindentLines()
01168 {
01169   KTextEditor::Cursor c( m_view->cursorPosition() );
01170 
01171   m_commandRange.normalize();
01172 
01173   int line1 = m_commandRange.startLine;
01174   int line2 = m_commandRange.endLine;
01175 
01176   doc()->editStart();
01177   for ( int i = line1; i <= line2; i++ ) {
01178       doc()->indent( m_view, i, -getCount() );
01179   }
01180   doc()->editEnd();
01181 
01182   return true;
01183 }
01184 
01185 bool KateViNormalMode::commandScrollPageDown()
01186 {
01187   m_view->pageDown();
01188 
01189   return true;
01190 }
01191 
01192 bool KateViNormalMode::commandScrollPageUp()
01193 {
01194   m_view->pageUp();
01195 
01196   return true;
01197 }
01198 
01199 bool KateViNormalMode::commandAbort()
01200 {
01201   reset();
01202   return true;
01203 }
01204 
01205 bool KateViNormalMode::commandPrintCharacterCode()
01206 {
01207   QChar ch = getCharUnderCursor();
01208 
01209   if ( ch == QChar::Null ) {
01210       message( QString( "NUL" ) );
01211   } else {
01212 
01213     int code = ch.unicode();
01214 
01215     message( QString("<%1> %2,  Hex %3,  Octal %4")
01216         .arg( ch )                          // char
01217         .arg( code )                        // decimal
01218         .arg( code, 0, 16 )                 // hexadecimal
01219         .arg( code, 3, 8, QChar('0') ) );   // octal
01220   }
01221 
01222   return true;
01223 }
01224 
01225 bool KateViNormalMode::commandRepeatLastChange()
01226 {
01227   resetParser();
01228   m_viInputModeManager->repeatLastChange();
01229 
01230   return true;
01231 }
01232 
01233 bool KateViNormalMode::commandAlignLine()
01234 {
01235   const int line = m_view->cursorPosition().line();
01236   KTextEditor::Range alignRange( KTextEditor::Cursor(line, 0), KTextEditor::Cursor(line, 0) );
01237 
01238   doc()->align( m_view, alignRange );
01239 
01240   return true;
01241 }
01242 
01243 bool KateViNormalMode::commandAlignLines()
01244 {
01245   KTextEditor::Cursor c( m_view->cursorPosition() );
01246   m_commandRange.normalize();
01247 
01248   KTextEditor::Cursor start(m_commandRange.startLine, 0);
01249   KTextEditor::Cursor end(m_commandRange.endLine, 0);
01250 
01251   doc()->align( m_view, KTextEditor::Range( start, end ) );
01252 
01253   return true;
01254 }
01255 
01257 // MOTIONS
01259 
01260 KateViRange KateViNormalMode::motionDown()
01261 {
01262   return goLineDown();
01263 }
01264 
01265 
01266 KateViRange KateViNormalMode::motionUp()
01267 {
01268   return goLineUp();
01269 }
01270 
01271 KateViRange KateViNormalMode::motionLeft()
01272 {
01273   KTextEditor::Cursor cursor ( m_view->cursorPosition() );
01274   m_stickyColumn = -1;
01275   KateViRange r( cursor.line(), cursor.column(), ViMotion::ExclusiveMotion );
01276   r.endColumn -= getCount();
01277 
01278   return r;
01279 }
01280 
01281 KateViRange KateViNormalMode::motionRight()
01282 {
01283   KTextEditor::Cursor cursor ( m_view->cursorPosition() );
01284   m_stickyColumn = -1;
01285   KateViRange r( cursor.line(), cursor.column(), ViMotion::ExclusiveMotion );
01286   r.endColumn += getCount();
01287 
01288   return r;
01289 }
01290 
01291 KateViRange KateViNormalMode::motionWordForward()
01292 {
01293   KTextEditor::Cursor c( m_view->cursorPosition() );
01294   KateViRange r( c.line(), c.column(), ViMotion::ExclusiveMotion );
01295 
01296   m_stickyColumn = -1;
01297 
01298   // Special case: If we're already on the very last character in the document, the motion should be
01299   // inclusive so the last character gets included
01300   if ( c.line() == doc()->lines()-1 && c.column() == doc()->lineLength( c.line() )-1 ) {
01301     r.motionType = ViMotion::InclusiveMotion;
01302   } else {
01303     for ( unsigned int i = 0; i < getCount(); i++ ) {
01304       c = findNextWordStart( c.line(), c.column() );
01305 
01306       // stop when at the last char in the document
01307       if ( c.line() == doc()->lines()-1 && c.column() == doc()->lineLength( c.line() )-1 ) {
01308         // if we still haven't "used up the count", make the motion inclusive, so that the last char
01309         // is included
01310         if ( i < getCount() ) {
01311           r.motionType = ViMotion::InclusiveMotion;
01312         }
01313         break;
01314       }
01315     }
01316   }
01317 
01318   r.endColumn = c.column();
01319   r.endLine = c.line();
01320 
01321   return r;
01322 }
01323 
01324 KateViRange KateViNormalMode::motionWordBackward()
01325 {
01326   KTextEditor::Cursor c( m_view->cursorPosition() );
01327   KateViRange r( c.line(), c.column(), ViMotion::ExclusiveMotion );
01328 
01329   m_stickyColumn = -1;
01330 
01331   for ( unsigned int i = 0; i < getCount(); i++ ) {
01332     c = findPrevWordStart( c.line(), c.column() );
01333 
01334     // stop when at the first char in the document
01335     if ( c.line() == 0 && c.column() == 0 ) {
01336       break;
01337     }
01338   }
01339 
01340   r.endColumn = c.column();
01341   r.endLine = c.line();
01342 
01343   return r;
01344 }
01345 
01346 KateViRange KateViNormalMode::motionWORDForward()
01347 {
01348   KTextEditor::Cursor c( m_view->cursorPosition() );
01349   KateViRange r( c.line(), c.column(), ViMotion::ExclusiveMotion );
01350 
01351   m_stickyColumn = -1;
01352 
01353   for ( unsigned int i = 0; i < getCount(); i++ ) {
01354     c = findNextWORDStart( c.line(), c.column() );
01355 
01356     // stop when at the last char in the document
01357     if ( c.line() == doc()->lines()-1 && c.column() == doc()->lineLength( c.line() )-1 ) {
01358       break;
01359     }
01360   }
01361 
01362   r.endColumn = c.column();
01363   r.endLine = c.line();
01364 
01365   return r;
01366 }
01367 
01368 KateViRange KateViNormalMode::motionWORDBackward()
01369 {
01370   KTextEditor::Cursor c( m_view->cursorPosition() );
01371   KateViRange r( c.line(), c.column(), ViMotion::ExclusiveMotion );
01372 
01373   m_stickyColumn = -1;
01374 
01375   for ( unsigned int i = 0; i < getCount(); i++ ) {
01376     c = findPrevWORDStart( c.line(), c.column() );
01377 
01378     // stop when at the first char in the document
01379     if ( c.line() == 0 && c.column() == 0 ) {
01380       break;
01381     }
01382   }
01383 
01384   r.endColumn = c.column();
01385   r.endLine = c.line();
01386 
01387   return r;
01388 }
01389 
01390 KateViRange KateViNormalMode::motionToEndOfWord()
01391 {
01392     KTextEditor::Cursor c( m_view->cursorPosition() );
01393     KateViRange r( c.line(), c.column(), ViMotion::InclusiveMotion );
01394 
01395     m_stickyColumn = -1;
01396 
01397     for ( unsigned int i = 0; i < getCount(); i++ ) {
01398         c = findWordEnd( c.line(), c.column() );
01399     }
01400 
01401     r.endColumn = c.column();
01402     r.endLine = c.line();
01403 
01404     return r;
01405 }
01406 
01407 KateViRange KateViNormalMode::motionToEndOfWORD()
01408 {
01409     KTextEditor::Cursor c( m_view->cursorPosition() );
01410     KateViRange r( c.line(), c.column(), ViMotion::InclusiveMotion );
01411 
01412     m_stickyColumn = -1;
01413 
01414     for ( unsigned int i = 0; i < getCount(); i++ ) {
01415         c = findWORDEnd( c.line(), c.column() );
01416     }
01417 
01418     r.endColumn = c.column();
01419     r.endLine = c.line();
01420 
01421     return r;
01422 }
01423 
01424 KateViRange KateViNormalMode::motionToEndOfPrevWord()
01425 {
01426     KTextEditor::Cursor c( m_view->cursorPosition() );
01427     KateViRange r( c.line(), c.column(), ViMotion::InclusiveMotion );
01428 
01429     m_stickyColumn = -1;
01430 
01431     for ( unsigned int i = 0; i < getCount(); i++ ) {
01432       c = findPrevWordEnd( c.line(), c.column() );
01433 
01434       // stop when at the first char in the document
01435       if ( c.line() == 0 && c.column() == 0 ) {
01436         break;
01437       }
01438     }
01439 
01440     r.endColumn = c.column();
01441     r.endLine = c.line();
01442 
01443     return r;
01444 }
01445 
01446 KateViRange KateViNormalMode::motionToEndOfPrevWORD()
01447 {
01448     KTextEditor::Cursor c( m_view->cursorPosition() );
01449     KateViRange r( c.line(), c.column(), ViMotion::InclusiveMotion );
01450 
01451     m_stickyColumn = -1;
01452 
01453     for ( unsigned int i = 0; i < getCount(); i++ ) {
01454       c = findPrevWORDEnd( c.line(), c.column() );
01455 
01456       // stop when at the first char in the document
01457       if ( c.line() == 0 && c.column() == 0 ) {
01458         break;
01459       }
01460     }
01461 
01462     r.endColumn = c.column();
01463     r.endLine = c.line();
01464 
01465     return r;
01466 }
01467 
01468 KateViRange KateViNormalMode::motionToEOL()
01469 {
01470   KTextEditor::Cursor c( m_view->cursorPosition() );
01471 
01472   // set sticky column to a rediculously high value so that the cursor will stick to EOL,
01473   // but only if it's a regular motion
01474   if ( m_keys.size() == 1 ) {
01475     m_stickyColumn = 100000;
01476   }
01477 
01478   unsigned int line = c.line() + ( getCount() - 1 );
01479   KateViRange r( line, doc()->lineLength(line )-1, ViMotion::InclusiveMotion );
01480 
01481   return r;
01482 }
01483 
01484 KateViRange KateViNormalMode::motionToColumn0()
01485 {
01486   m_stickyColumn = -1;
01487   KTextEditor::Cursor cursor ( m_view->cursorPosition() );
01488   KateViRange r( cursor.line(), 0, ViMotion::ExclusiveMotion );
01489 
01490   return r;
01491 }
01492 
01493 KateViRange KateViNormalMode::motionToFirstCharacterOfLine()
01494 {
01495   m_stickyColumn = -1;
01496 
01497   KTextEditor::Cursor cursor ( m_view->cursorPosition() );
01498   QRegExp nonSpace( "\\S" );
01499   int c = getLine().indexOf( nonSpace );
01500 
01501   KateViRange r( cursor.line(), c, ViMotion::ExclusiveMotion );
01502 
01503   return r;
01504 }
01505 
01506 KateViRange KateViNormalMode::motionFindChar()
01507 {
01508   m_lastTFcommand = m_keys;
01509   KTextEditor::Cursor cursor ( m_view->cursorPosition() );
01510   QString line = getLine();
01511 
01512   m_stickyColumn = -1;
01513 
01514   int matchColumn = cursor.column();
01515 
01516   for ( unsigned int i = 0; i < getCount(); i++ ) {
01517     matchColumn = line.indexOf( m_keys.right( 1 ), matchColumn+1 );
01518     if ( matchColumn == -1 )
01519       break;
01520   }
01521 
01522   KateViRange r;
01523 
01524   r.startColumn = cursor.column();
01525   r.startLine = cursor.line();
01526   r.endColumn = matchColumn;
01527   r.endLine = cursor.line();
01528 
01529   return r;
01530 }
01531 
01532 KateViRange KateViNormalMode::motionFindCharBackward()
01533 {
01534   m_lastTFcommand = m_keys;
01535   KTextEditor::Cursor cursor ( m_view->cursorPosition() );
01536   QString line = getLine();
01537 
01538   m_stickyColumn = -1;
01539 
01540   int matchColumn = -1;
01541 
01542   unsigned int hits = 0;
01543   int i = cursor.column()-1;
01544 
01545   while ( hits != getCount() && i >= 0 ) {
01546     if ( line.at( i ) == m_keys.at( m_keys.size()-1 ) )
01547       hits++;
01548 
01549     if ( hits == getCount() )
01550       matchColumn = i;
01551 
01552     i--;
01553   }
01554 
01555   KateViRange r;
01556 
01557   r.endColumn = matchColumn;
01558   r.endLine = cursor.line();
01559 
01560   return r;
01561 }
01562 
01563 KateViRange KateViNormalMode::motionToChar()
01564 {
01565   m_lastTFcommand = m_keys;
01566   KTextEditor::Cursor cursor ( m_view->cursorPosition() );
01567   QString line = getLine();
01568 
01569   m_stickyColumn = -1;
01570 
01571   int matchColumn = cursor.column()+1;
01572 
01573   for ( unsigned int i = 0; i < getCount(); i++ ) {
01574     matchColumn = line.indexOf( m_keys.right( 1 ), matchColumn );
01575     if ( matchColumn == -1 )
01576       break;
01577   }
01578 
01579   KateViRange r;
01580 
01581   r.endColumn = matchColumn-1;
01582   r.endLine = cursor.line();
01583 
01584   return r;
01585 }
01586 
01587 KateViRange KateViNormalMode::motionToCharBackward()
01588 {
01589   m_lastTFcommand = m_keys;
01590   KTextEditor::Cursor cursor ( m_view->cursorPosition() );
01591   QString line = getLine();
01592 
01593   m_stickyColumn = -1;
01594 
01595   int matchColumn = -1;
01596 
01597   unsigned int hits = 0;
01598   int i = cursor.column()-1;
01599 
01600   while ( hits != getCount() && i >= 0 ) {
01601     if ( line.at( i ) == m_keys.at( m_keys.size()-1 ) )
01602       hits++;
01603 
01604     if ( hits == getCount() )
01605       matchColumn = i;
01606 
01607     i--;
01608   }
01609 
01610   KateViRange r;
01611 
01612   r.endColumn = matchColumn+1;
01613   r.endLine = cursor.line();
01614 
01615   return r;
01616 }
01617 
01618 KateViRange KateViNormalMode::motionRepeatlastTF()
01619 {
01620   if ( !m_lastTFcommand.isEmpty() ) {
01621     m_keys = m_lastTFcommand;
01622     if ( m_keys.at( 0 ) == 'f' ) {
01623       return motionFindChar();
01624     }
01625     else if ( m_keys.at( 0 ) == 'F' ) {
01626       return motionFindCharBackward();
01627     }
01628     else if ( m_keys.at( 0 ) == 't' ) {
01629       return motionToChar();
01630     }
01631     else if ( m_keys.at( 0 ) == 'T' ) {
01632       return motionToCharBackward();
01633     }
01634   }
01635 
01636   // there was no previous t/f command
01637 
01638   KateViRange r;
01639   r.valid = false;
01640 
01641   return r;
01642 }
01643 
01644 KateViRange KateViNormalMode::motionRepeatlastTFBackward()
01645 {
01646   if ( !m_lastTFcommand.isEmpty() ) {
01647     m_keys = m_lastTFcommand;
01648     if ( m_keys.at( 0 ) == 'f' ) {
01649       return motionFindCharBackward();
01650     }
01651     else if ( m_keys.at( 0 ) == 'F' ) {
01652       return motionFindChar();
01653     }
01654     else if ( m_keys.at( 0 ) == 't' ) {
01655       return motionToCharBackward();
01656     }
01657     else if ( m_keys.at( 0 ) == 'T' ) {
01658       return motionToChar();
01659     }
01660   }
01661 
01662   // there was no previous t/f command
01663 
01664   KateViRange r;
01665   r.valid = false;
01666 
01667   return r;
01668 }
01669 
01670 
01671 KateViRange KateViNormalMode::motionToLineFirst()
01672 {
01673     KateViRange r( getCount()-1, 0, ViMotion::InclusiveMotion );
01674     m_stickyColumn = -1;
01675 
01676     if ( r.endLine > doc()->lines() - 1 ) {
01677       r.endLine = doc()->lines() - 1;
01678     }
01679     r.jump = true;
01680 
01681     return r;
01682 }
01683 
01684 KateViRange KateViNormalMode::motionToLineLast()
01685 {
01686   KateViRange r( doc()->lines()-1, 0, ViMotion::InclusiveMotion );
01687   m_stickyColumn = -1;
01688 
01689   // don't use getCount() here, no count and a count of 1 is different here...
01690   if ( m_count != 0 ) {
01691     r.endLine = m_count-1;
01692   }
01693 
01694   if ( r.endLine > doc()->lines() - 1 ) {
01695     r.endLine = doc()->lines() - 1;
01696   }
01697   r.jump = true;
01698 
01699   return r;
01700 }
01701 
01702 KateViRange KateViNormalMode::motionToScreenColumn()
01703 {
01704   m_stickyColumn = -1;
01705 
01706   KTextEditor::Cursor c( m_view->cursorPosition() );
01707 
01708   int column = getCount()-1;
01709 
01710   if ( doc()->lineLength( c.line() )-1 < (int)getCount()-1 ) {
01711       column = doc()->lineLength( c.line() )-1;
01712   }
01713 
01714   return KateViRange( c.line(), column, ViMotion::ExclusiveMotion );
01715 }
01716 
01717 KateViRange KateViNormalMode::motionToMark()
01718 {
01719   KateViRange r;
01720 
01721   m_stickyColumn = -1;
01722 
01723   QChar reg = m_keys.at( m_keys.size()-1 );
01724 
01725   // ` and ' is the same register (position before jump)
01726   if ( reg == '`' ) {
01727       reg = '\'';
01728   }
01729 
01730   KTextEditor::SmartCursor* cursor;
01731   if ( m_marks->contains( reg ) ) {
01732     cursor = m_marks->value( reg );
01733     r.endLine = cursor->line();
01734     r.endColumn = cursor->column();
01735   } else {
01736     error(QString("Mark not set: ") + m_keys.right( 1 ) );
01737     r.valid = false;
01738   }
01739 
01740   r.jump = true;
01741 
01742   return r;
01743 }
01744 
01745 KateViRange KateViNormalMode::motionToMarkLine()
01746 {
01747   KateViRange r = motionToMark();
01748   r.endColumn = 0; // FIXME: should be first non-blank on line
01749 
01750   m_stickyColumn = -1;
01751 
01752   r.jump = true;
01753 
01754   return r;
01755 }
01756 
01757 KateViRange KateViNormalMode::motionToMatchingItem()
01758 {
01759   KateViRange r;
01760   KTextEditor::Cursor c( m_view->cursorPosition() );
01761   int lines = doc()->lines();
01762   QString l = getLine();
01763   int n1 = l.indexOf( m_matchItemRegex, c.column() );
01764   int n2;
01765 
01766   m_stickyColumn = -1;
01767 
01768   if ( n1 == -1 ) {
01769     r.valid = false;
01770     return r;
01771   } else {
01772     n2 = l.indexOf( QRegExp( "\\b|\\s|$" ), n1 );
01773   }
01774 
01775   // text item we want to find a matching item for
01776   QString item = l.mid( n1, n2-n1 );
01777 
01778   // use kate's built-in matching bracket finder for brackets
01779   if ( QString("{}()[]").indexOf( item ) != -1 ) {
01780 
01781     // move the cursor to the first bracket
01782     c.setColumn( n1+1 );
01783     updateCursor( c );
01784 
01785     // find the matching one
01786     c = m_viewInternal->findMatchingBracket();
01787 
01788     if ( c > m_view->cursorPosition() ) {
01789       c.setColumn( c.column()-1 );
01790     }
01791   } else {
01792     int toFind = 1;
01793     //int n2 = l.indexOf( QRegExp( "\\s|$" ), n1 );
01794 
01795     //QString item = l.mid( n1, n2-n1 );
01796     QString matchingItem = m_matchingItems[ item ];
01797 
01798     int line = c.line();
01799     int column = n2-item.length();
01800     bool reverse = false;
01801 
01802     if ( matchingItem.left( 1 ) == "-" ) {
01803       matchingItem.remove( 0, 1 ); // remove the '-'
01804       reverse = true;
01805     }
01806 
01807     // make sure we don't hit the text item we start the search from
01808     if ( column == 0 && reverse ) {
01809       column -= item.length();
01810     }
01811 
01812     int itemIdx;
01813     int matchItemIdx;
01814 
01815     while ( toFind > 0 ) {
01816       if ( !reverse ) {
01817         itemIdx = l.indexOf( item, column );
01818         matchItemIdx = l.indexOf( matchingItem, column );
01819 
01820         if ( itemIdx != -1 && ( matchItemIdx == -1 || itemIdx < matchItemIdx ) ) {
01821             toFind++;
01822         }
01823       } else {
01824         itemIdx = l.lastIndexOf( item, column-1 );
01825         matchItemIdx = l.lastIndexOf( matchingItem, column-1 );
01826 
01827         if ( itemIdx != -1 && ( matchItemIdx == -1 || itemIdx > matchItemIdx ) ) {
01828             toFind++;
01829         }
01830       }
01831 
01832       if ( matchItemIdx != -1 || itemIdx != -1 ) {
01833           if ( !reverse ) {
01834             column = qMin( (unsigned int)itemIdx, (unsigned int)matchItemIdx );
01835           } else {
01836             column = qMax( itemIdx, matchItemIdx );
01837           }
01838       }
01839 
01840       if ( matchItemIdx != -1 ) { // match on current line
01841           if ( matchItemIdx == column ) {
01842               toFind--;
01843               c.setLine( line );
01844               c.setColumn( column );
01845           }
01846       } else { // no match, advance one line if possible
01847         ( reverse) ? line-- : line++;
01848         column = 0;
01849 
01850         if ( ( !reverse && line >= lines ) || ( reverse && line < 0 ) ) {
01851           r.valid = false;
01852           break;
01853         } else {
01854           l = getLine( line );
01855         }
01856       }
01857     }
01858   }
01859 
01860   r.endLine = c.line();
01861   r.endColumn = c.column();
01862   r.jump = true;
01863 
01864   return r;
01865 }
01866 
01867 KateViRange KateViNormalMode::motionToNextBraceBlockStart()
01868 {
01869   KateViRange r;
01870 
01871   m_stickyColumn = -1;
01872 
01873   int line = findLineStartingWitchChar( '{', getCount() );
01874 
01875   if ( line == -1 ) {
01876     r.valid = false;
01877     return r;
01878   }
01879 
01880   r.endLine = line;
01881   r.endColumn = 0;
01882   r.jump = true;
01883 
01884   return r;
01885 }
01886 
01887 KateViRange KateViNormalMode::motionToPreviousBraceBlockStart()
01888 {
01889   KateViRange r;
01890 
01891   m_stickyColumn = -1;
01892 
01893   int line = findLineStartingWitchChar( '{', getCount(), false );
01894 
01895   if ( line == -1 ) {
01896     r.valid = false;
01897     return r;
01898   }
01899 
01900   r.endLine = line;
01901   r.endColumn = 0;
01902   r.jump = true;
01903 
01904   return r;
01905 }
01906 
01907 KateViRange KateViNormalMode::motionToNextBraceBlockEnd()
01908 {
01909   KateViRange r;
01910 
01911   m_stickyColumn = -1;
01912 
01913   int line = findLineStartingWitchChar( '}', getCount() );
01914 
01915   if ( line == -1 ) {
01916     r.valid = false;
01917     return r;
01918   }
01919 
01920   r.endLine = line;
01921   r.endColumn = 0;
01922   r.jump = true;
01923 
01924   return r;
01925 }
01926 
01927 KateViRange KateViNormalMode::motionToPreviousBraceBlockEnd()
01928 {
01929   KateViRange r;
01930 
01931   m_stickyColumn = -1;
01932 
01933   int line = findLineStartingWitchChar( '{', getCount(), false );
01934 
01935   if ( line == -1 ) {
01936     r.valid = false;
01937     return r;
01938   }
01939 
01940   r.endLine = line;
01941   r.endColumn = 0;
01942   r.jump = true;
01943 
01944   return r;
01945 }
01946 
01948 // TEXT OBJECTS
01950 
01951 KateViRange KateViNormalMode::textObjectAWord()
01952 {
01953     KTextEditor::Cursor c( m_view->cursorPosition() );
01954 
01955     KTextEditor::Cursor c1 = findPrevWordStart( c.line(), c.column()+1, true );
01956     KTextEditor::Cursor c2( c );
01957 
01958     for ( unsigned int i = 0; i < getCount(); i++ ) {
01959         c2 = findNextWordStart( c2.line(), c2.column(), true );
01960     }
01961 
01962     c2.setColumn( c2.column()-1 ); // don't include the first char of the following word
01963     KateViRange r( c.line(), c.column(), ViMotion::InclusiveMotion );
01964 
01965     // sanity check
01966     if ( c1.line() != c2.line() || c1.column() > c2.column() ) {
01967         r.valid = false;
01968     } else {
01969         r.startLine = c1.line();
01970         r.endLine = c2.line();
01971         r.startColumn = c1.column();
01972         r.endColumn = c2.column();
01973     }
01974 
01975     return r;
01976 }
01977 
01978 KateViRange KateViNormalMode::textObjectInnerWord()
01979 {
01980     KTextEditor::Cursor c( m_view->cursorPosition() );
01981 
01982     KTextEditor::Cursor c1 = findPrevWordStart( c.line(), c.column()+1, true );
01983     // need to start search in column-1 because it might be a one-character word
01984     KTextEditor::Cursor c2( c.line(), c.column()-1 );
01985 
01986     for ( unsigned int i = 0; i < getCount(); i++ ) {
01987         c2 = findWordEnd( c2.line(), c2.column(), true );
01988     }
01989 
01990     KateViRange r;
01991 
01992     // sanity check
01993     if ( c1.line() != c2.line() || c1.column() > c2.column() ) {
01994         r.valid = false;
01995     } else {
01996         r.startLine = c1.line();
01997         r.endLine = c2.line();
01998         r.startColumn = c1.column();
01999         r.endColumn = c2.column();
02000     }
02001 
02002     return r;
02003 }
02004 
02005 KateViRange KateViNormalMode::textObjectAWORD()
02006 {
02007     KTextEditor::Cursor c( m_view->cursorPosition() );
02008 
02009     KTextEditor::Cursor c1 = findPrevWORDStart( c.line(), c.column()+1, true );
02010     KTextEditor::Cursor c2( c );
02011 
02012     for ( unsigned int i = 0; i < getCount(); i++ ) {
02013         c2 = findNextWORDStart( c2.line(), c2.column(), true );
02014     }
02015 
02016     KateViRange r( c.line(), c.column(), ViMotion::ExclusiveMotion );
02017 
02018     // sanity check
02019     if ( c1.line() != c2.line() || c1.column() > c2.column() ) {
02020         r.valid = false;
02021     } else {
02022         r.startLine = c1.line();
02023         r.endLine = c2.line();
02024         r.startColumn = c1.column();
02025         r.endColumn = c2.column();
02026     }
02027 
02028     return r;
02029 }
02030 
02031 KateViRange KateViNormalMode::textObjectInnerWORD()
02032 {
02033     KTextEditor::Cursor c( m_view->cursorPosition() );
02034 
02035     KTextEditor::Cursor c1 = findPrevWORDStart( c.line(), c.column()+1, true );
02036     KTextEditor::Cursor c2( c );
02037 
02038     for ( unsigned int i = 0; i < getCount(); i++ ) {
02039         c2 = findWORDEnd( c2.line(), c2.column(), true );
02040     }
02041 
02042     KateViRange r;
02043 
02044     // sanity check
02045     if ( c1.line() != c2.line() || c1.column() > c2.column() ) {
02046         r.valid = false;
02047     } else {
02048         r.startLine = c1.line();
02049         r.endLine = c2.line();
02050         r.startColumn = c1.column();
02051         r.endColumn = c2.column();
02052     }
02053 
02054     return r;
02055 }
02056 
02057 KateViRange KateViNormalMode::textObjectAQuoteDouble()
02058 {
02059     return findSurrounding( '"', '"', false );
02060 }
02061 
02062 KateViRange KateViNormalMode::textObjectInnerQuoteDouble()
02063 {
02064     return findSurrounding( '"', '"', true );
02065 }
02066 
02067 KateViRange KateViNormalMode::textObjectAQuoteSingle()
02068 {
02069     return findSurrounding( '\'', '\'', false );
02070 }
02071 
02072 KateViRange KateViNormalMode::textObjectInnerQuoteSingle()
02073 {
02074     return findSurrounding( '\'', '\'', true );
02075 }
02076 
02077 KateViRange KateViNormalMode::textObjectAParen()
02078 {
02079     return findSurrounding( '(', ')', false );
02080 }
02081 
02082 KateViRange KateViNormalMode::textObjectInnerParen()
02083 {
02084     return findSurrounding( '(', ')', true );
02085 }
02086 
02087 KateViRange KateViNormalMode::textObjectABracket()
02088 {
02089     return findSurrounding( '[', ']', false );
02090 }
02091 
02092 KateViRange KateViNormalMode::textObjectInnerBracket()
02093 {
02094     return findSurrounding( '[', ']', true );
02095 }
02096 
02097 KateViRange KateViNormalMode::textObjectAComma()
02098 {
02099     KateViRange r = findSurrounding( ',', ',', false );
02100 
02101     if ( !r.valid ) {
02102       r = findSurrounding( QRegExp(","), QRegExp("[\\])}]"), false );
02103     }
02104 
02105     if ( !r.valid ) {
02106       r = findSurrounding( QRegExp("[\\[({]"), QRegExp(","), false );
02107     }
02108 
02109     return r;
02110 }
02111 
02112 KateViRange KateViNormalMode::textObjectInnerComma()
02113 {
02114     KateViRange r = findSurrounding( ',', ',', true );
02115 
02116     if ( !r.valid ) {
02117       r = findSurrounding( QRegExp(","), QRegExp("[\\])}]"), true );
02118     }
02119 
02120     if ( !r.valid ) {
02121       r = findSurrounding( QRegExp("[\\[({]"), QRegExp(","), true );
02122     }
02123 
02124     return r;
02125 }
02126 
02127 // add commands
02128 // when adding commands here, remember to add them to visual mode too (if applicable)
02129 void KateViNormalMode::initializeCommands()
02130 {
02131   m_commands.push_back( new KateViCommand( this, "a", &KateViNormalMode::commandEnterInsertModeAppend, IS_CHANGE ) );
02132   m_commands.push_back( new KateViCommand( this, "A", &KateViNormalMode::commandEnterInsertModeAppendEOL, IS_CHANGE ) );
02133   m_commands.push_back( new KateViCommand( this, "i", &KateViNormalMode::commandEnterInsertMode, IS_CHANGE ) );
02134   m_commands.push_back( new KateViCommand( this, "I", &KateViNormalMode::commandEnterInsertModeBeforeFirstCharacterOfLine, IS_CHANGE ) );
02135   m_commands.push_back( new KateViCommand( this, "v", &KateViNormalMode::commandEnterVisualMode ) );
02136   m_commands.push_back( new KateViCommand( this, "V", &KateViNormalMode::commandEnterVisualLineMode ) );
02137   m_commands.push_back( new KateViCommand( this, "o", &KateViNormalMode::commandOpenNewLineUnder, IS_CHANGE ) );
02138   m_commands.push_back( new KateViCommand( this, "O", &KateViNormalMode::commandOpenNewLineOver, IS_CHANGE ) );
02139   m_commands.push_back( new KateViCommand( this, "J", &KateViNormalMode::commandJoinLines, IS_CHANGE ) );
02140   m_commands.push_back( new KateViCommand( this, "c", &KateViNormalMode::commandChange, IS_CHANGE | NEEDS_MOTION ) );
02141   m_commands.push_back( new KateViCommand( this, "C", &KateViNormalMode::commandChangeToEOL, IS_CHANGE ) );
02142   m_commands.push_back( new KateViCommand( this, "cc", &KateViNormalMode::commandChangeLine, IS_CHANGE ) );
02143   m_commands.push_back( new KateViCommand( this, "s", &KateViNormalMode::commandSubstituteChar, IS_CHANGE ) );
02144   m_commands.push_back( new KateViCommand( this, "S", &KateViNormalMode::commandSubstituteLine, IS_CHANGE ) );
02145   m_commands.push_back( new KateViCommand( this, "dd", &KateViNormalMode::commandDeleteLine, IS_CHANGE ) );
02146   m_commands.push_back( new KateViCommand( this, "d", &KateViNormalMode::commandDelete, IS_CHANGE | NEEDS_MOTION ) );
02147   m_commands.push_back( new KateViCommand( this, "D", &KateViNormalMode::commandDeleteToEOL, IS_CHANGE ) );
02148   m_commands.push_back( new KateViCommand( this, "x", &KateViNormalMode::commandDeleteChar, IS_CHANGE ) );
02149   m_commands.push_back( new KateViCommand( this, "X", &KateViNormalMode::commandDeleteCharBackward, IS_CHANGE ) );
02150   m_commands.push_back( new KateViCommand( this, "gu", &KateViNormalMode::commandMakeLowercase, IS_CHANGE | NEEDS_MOTION ) );
02151   m_commands.push_back( new KateViCommand( this, "guu", &KateViNormalMode::commandMakeLowercaseLine, IS_CHANGE ) );
02152   m_commands.push_back( new KateViCommand( this, "gU", &KateViNormalMode::commandMakeUppercase, IS_CHANGE | NEEDS_MOTION ) );
02153   m_commands.push_back( new KateViCommand( this, "gUU", &KateViNormalMode::commandMakeUppercaseLine, IS_CHANGE ) );
02154   m_commands.push_back( new KateViCommand( this, "y", &KateViNormalMode::commandYank, NEEDS_MOTION ) );
02155   m_commands.push_back( new KateViCommand( this, "yy", &KateViNormalMode::commandYankLine ) );
02156   m_commands.push_back( new KateViCommand( this, "Y", &KateViNormalMode::commandYankToEOL ) );
02157   m_commands.push_back( new KateViCommand( this, "p", &KateViNormalMode::commandPaste, IS_CHANGE ) );
02158   m_commands.push_back( new KateViCommand( this, "P", &KateViNormalMode::commandPasteBefore, IS_CHANGE ) );
02159   m_commands.push_back( new KateViCommand( this, "r.", &KateViNormalMode::commandReplaceCharacter, IS_CHANGE | REGEX_PATTERN ) );
02160   m_commands.push_back( new KateViCommand( this, ":", &KateViNormalMode::commandSwitchToCmdLine ) );
02161   m_commands.push_back( new KateViCommand( this, "/", &KateViNormalMode::commandSearch ) );
02162   m_commands.push_back( new KateViCommand( this, "u", &KateViNormalMode::commandUndo) );
02163   m_commands.push_back( new KateViCommand( this, "<c-r>", &KateViNormalMode::commandRedo ) );
02164   m_commands.push_back( new KateViCommand( this, "U", &KateViNormalMode::commandRedo ) );
02165   m_commands.push_back( new KateViCommand( this, "m.", &KateViNormalMode::commandSetMark, REGEX_PATTERN ) );
02166   m_commands.push_back( new KateViCommand( this, "n", &KateViNormalMode::commandFindNext ) );
02167   m_commands.push_back( new KateViCommand( this, "N", &KateViNormalMode::commandFindPrev ) );
02168   m_commands.push_back( new KateViCommand( this, ">>", &KateViNormalMode::commandIndentLine, IS_CHANGE ) );
02169   m_commands.push_back( new KateViCommand( this, "<<", &KateViNormalMode::commandUnindentLine, IS_CHANGE ) );
02170   m_commands.push_back( new KateViCommand( this, ">", &KateViNormalMode::commandIndentLines, IS_CHANGE | NEEDS_MOTION ) );
02171   m_commands.push_back( new KateViCommand( this, "<", &KateViNormalMode::commandUnindentLines, IS_CHANGE | NEEDS_MOTION ) );
02172   m_commands.push_back( new KateViCommand( this, "<c-f>", &KateViNormalMode::commandScrollPageDown ) );
02173   m_commands.push_back( new KateViCommand( this, "<pagedown>", &KateViNormalMode::commandScrollPageDown ) );
02174   m_commands.push_back( new KateViCommand( this, "<c-b>", &KateViNormalMode::commandScrollPageUp ) );
02175   m_commands.push_back( new KateViCommand( this, "<pageup>", &KateViNormalMode::commandScrollPageUp ) );
02176   m_commands.push_back( new KateViCommand( this, "ga", &KateViNormalMode::commandPrintCharacterCode, SHOULD_NOT_RESET ) );
02177   m_commands.push_back( new KateViCommand( this, ".", &KateViNormalMode::commandRepeatLastChange ) );
02178   m_commands.push_back( new KateViCommand( this, "==", &KateViNormalMode::commandAlignLine, IS_CHANGE ) );
02179   m_commands.push_back( new KateViCommand( this, "=", &KateViNormalMode::commandAlignLines, IS_CHANGE | NEEDS_MOTION) );
02180   m_commands.push_back( new KateViCommand( this, "~", &KateViNormalMode::commandChangeCase, IS_CHANGE ) );
02181 
02182   // regular motions
02183   m_motions.push_back( new KateViMotion( this, "h", &KateViNormalMode::motionLeft ) );
02184   m_motions.push_back( new KateViMotion( this, "<left>", &KateViNormalMode::motionLeft ) );
02185   m_motions.push_back( new KateViMotion( this, "<backspace>", &KateViNormalMode::motionLeft ) );
02186   m_motions.push_back( new KateViMotion( this, "j", &KateViNormalMode::motionDown ) );
02187   m_motions.push_back( new KateViMotion( this, "<down>", &KateViNormalMode::motionDown ) );
02188   m_motions.push_back( new KateViMotion( this, "k", &KateViNormalMode::motionUp ) );
02189   m_motions.push_back( new KateViMotion( this, "<up>", &KateViNormalMode::motionUp ) );
02190   m_motions.push_back( new KateViMotion( this, "l", &KateViNormalMode::motionRight ) );
02191   m_motions.push_back( new KateViMotion( this, "<right>", &KateViNormalMode::motionRight ) );
02192   m_motions.push_back( new KateViMotion( this, " ", &KateViNormalMode::motionRight ) );
02193   m_motions.push_back( new KateViMotion( this, "$", &KateViNormalMode::motionToEOL ) );
02194   m_motions.push_back( new KateViMotion( this, "<end>", &KateViNormalMode::motionToEOL ) );
02195   m_motions.push_back( new KateViMotion( this, "0", &KateViNormalMode::motionToColumn0 ) );
02196   m_motions.push_back( new KateViMotion( this, "<home>", &KateViNormalMode::motionToColumn0 ) );
02197   m_motions.push_back( new KateViMotion( this, "^", &KateViNormalMode::motionToFirstCharacterOfLine ) );
02198   m_motions.push_back( new KateViMotion( this, "f.", &KateViNormalMode::motionFindChar, REGEX_PATTERN ) );
02199   m_motions.push_back( new KateViMotion( this, "F.", &KateViNormalMode::motionFindCharBackward, REGEX_PATTERN ) );
02200   m_motions.push_back( new KateViMotion( this, "t.", &KateViNormalMode::motionToChar, REGEX_PATTERN ) );
02201   m_motions.push_back( new KateViMotion( this, "T.", &KateViNormalMode::motionToCharBackward, REGEX_PATTERN ) );
02202   m_motions.push_back( new KateViMotion( this, ";", &KateViNormalMode::motionRepeatlastTF ) );
02203   m_motions.push_back( new KateViMotion( this, ",", &KateViNormalMode::motionRepeatlastTFBackward ) );
02204   m_motions.push_back( new KateViMotion( this, "gg", &KateViNormalMode::motionToLineFirst ) );
02205   m_motions.push_back( new KateViMotion( this, "G", &KateViNormalMode::motionToLineLast ) );
02206   m_motions.push_back( new KateViMotion( this, "w", &KateViNormalMode::motionWordForward ) );
02207   m_motions.push_back( new KateViMotion( this, "W", &KateViNormalMode::motionWORDForward ) );
02208   m_motions.push_back( new KateViMotion( this, "b", &KateViNormalMode::motionWordBackward ) );
02209   m_motions.push_back( new KateViMotion( this, "B", &KateViNormalMode::motionWORDBackward ) );
02210   m_motions.push_back( new KateViMotion( this, "e", &KateViNormalMode::motionToEndOfWord ) );
02211   m_motions.push_back( new KateViMotion( this, "E", &KateViNormalMode::motionToEndOfWORD ) );
02212   m_motions.push_back( new KateViMotion( this, "ge", &KateViNormalMode::motionToEndOfPrevWord ) );
02213   m_motions.push_back( new KateViMotion( this, "gE", &KateViNormalMode::motionToEndOfPrevWORD ) );
02214   m_motions.push_back( new KateViMotion( this, "|", &KateViNormalMode::motionToScreenColumn ) );
02215   m_motions.push_back( new KateViMotion( this, "%", &KateViNormalMode::motionToMatchingItem ) );
02216   m_motions.push_back( new KateViMotion( this, "`[a-zA-Z]", &KateViNormalMode::motionToMark, REGEX_PATTERN ) );
02217   m_motions.push_back( new KateViMotion( this, "'[a-zA-Z]", &KateViNormalMode::motionToMarkLine, REGEX_PATTERN ) );
02218   m_motions.push_back( new KateViMotion( this, "[[", &KateViNormalMode::motionToPreviousBraceBlockStart ) );
02219   m_motions.push_back( new KateViMotion( this, "]]", &KateViNormalMode::motionToNextBraceBlockStart ) );
02220   m_motions.push_back( new KateViMotion( this, "[]", &KateViNormalMode::motionToPreviousBraceBlockEnd ) );
02221   m_motions.push_back( new KateViMotion( this, "][", &KateViNormalMode::motionToNextBraceBlockEnd ) );
02222 
02223   // text objects
02224   m_motions.push_back( new KateViMotion( this, "iw", &KateViNormalMode::textObjectInnerWord ) );
02225   m_motions.push_back( new KateViMotion( this, "aw", &KateViNormalMode::textObjectAWord ) );
02226   m_motions.push_back( new KateViMotion( this, "i\"", &KateViNormalMode::textObjectInnerQuoteDouble ) );
02227   m_motions.push_back( new KateViMotion( this, "a\"", &KateViNormalMode::textObjectAQuoteDouble ) );
02228   m_motions.push_back( new KateViMotion( this, "i'", &KateViNormalMode::textObjectInnerQuoteSingle ) );
02229   m_motions.push_back( new KateViMotion( this, "a'", &KateViNormalMode::textObjectAQuoteSingle ) );
02230   m_motions.push_back( new KateViMotion( this, "i[()]", &KateViNormalMode::textObjectInnerParen, REGEX_PATTERN ) );
02231   m_motions.push_back( new KateViMotion( this, "a[()]", &KateViNormalMode::textObjectAParen, REGEX_PATTERN ) );
02232   m_motions.push_back( new KateViMotion( this, "i[\\[\\]]", &KateViNormalMode::textObjectInnerBracket, REGEX_PATTERN ) );
02233   m_motions.push_back( new KateViMotion( this, "a[\\[\\]]", &KateViNormalMode::textObjectABracket, REGEX_PATTERN ) );
02234   m_motions.push_back( new KateViMotion( this, "i,", &KateViNormalMode::textObjectInnerComma ) );
02235   m_motions.push_back( new KateViMotion( this, "a,", &KateViNormalMode::textObjectAComma ) );
02236 }
02237 
02238 QRegExp KateViNormalMode::generateMatchingItemRegex()
02239 {
02240   QString pattern("\\[|\\]|\\{|\\}|\\(|\\)|");
02241   QList<QString> keys = m_matchingItems.keys();
02242 
02243   for ( int i = 0; i < keys.size(); i++ ) {
02244     QString s = m_matchingItems[ keys[ i ] ];
02245     s = s.replace( QRegExp( "^-" ), QChar() );
02246     s = s.replace( QRegExp( "\\*" ), "\\*" );
02247     s = s.replace( QRegExp( "\\+" ), "\\+" );
02248     s = s.replace( QRegExp( "\\[" ), "\\[" );
02249     s = s.replace( QRegExp( "\\]" ), "\\]" );
02250     s = s.replace( QRegExp( "\\(" ), "\\(" );
02251     s = s.replace( QRegExp( "\\)" ), "\\)" );
02252     s = s.replace( QRegExp( "\\{" ), "\\{" );
02253     s = s.replace( QRegExp( "\\}" ), "\\}" );
02254 
02255     pattern.append( s );
02256 
02257     if ( i != keys.size()-1 ) {
02258       pattern.append( '|' );
02259     }
02260   }
02261 
02262   return QRegExp( pattern );
02263 }

Kate

Skip menu "Kate"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal