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
KDE 4.6 API Reference