• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

Kate

katevinormalmode.cpp

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

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
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
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