Kate
katevimodebase.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) 2009 Paul Gideon Dann <pdgiddie@gmail.com> 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Library General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Library General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Library General Public License 00017 * along with this library; see the file COPYING.LIB. If not, write to 00018 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00019 * Boston, MA 02110-1301, USA. 00020 */ 00021 00022 #include "katevimodebase.h" 00023 #include "katevirange.h" 00024 #include "kateglobal.h" 00025 #include "kateviglobal.h" 00026 #include "katevivisualmode.h" 00027 #include "katevinormalmode.h" 00028 #include "katevireplacemode.h" 00029 #include "kateviinputmodemanager.h" 00030 00031 #include <QString> 00032 #include <QRegExp> 00033 #include "kateconfig.h" 00034 #include "katedocument.h" 00035 #include "kateviewinternal.h" 00036 #include "katevimodebar.h" 00037 00038 using KTextEditor::Cursor; 00039 using KTextEditor::Range; 00040 00041 // TODO: the "previous word/WORD [end]" methods should be optimized. now they're being called in a 00042 // loop and all calculations done up to finding a match are trown away when called with a count > 1 00043 // because they will simply be called again from the last found position. 00044 // They should take the count as a parameter and collect the positions in a QList, then return 00045 // element (count - 1) 00046 00048 // HELPER METHODS 00050 00051 bool KateViModeBase::deleteRange( KateViRange &r, bool linewise, bool addToRegister) 00052 { 00053 r.normalize(); 00054 bool res = false; 00055 QString removedText = getRange( r, linewise ); 00056 00057 if ( linewise ) { 00058 doc()->editStart(); 00059 for ( int i = 0; i < r.endLine-r.startLine+1; i++ ) { 00060 res = doc()->removeLine( r.startLine ); 00061 } 00062 doc()->editEnd(); 00063 } else { 00064 res = doc()->removeText( Range( r.startLine, r.startColumn, r.endLine, r.endColumn) ); 00065 } 00066 00067 if ( addToRegister ) { 00068 if ( r.startLine == r.endLine ) { 00069 fillRegister( getChosenRegister( '-' ), removedText ); 00070 } else { 00071 fillRegister( getChosenRegister( '0' ), removedText ); 00072 } 00073 } 00074 00075 return res; 00076 } 00077 00078 const QString KateViModeBase::getRange( KateViRange &r, bool linewise) const 00079 { 00080 r.normalize(); 00081 QString s; 00082 00083 if ( linewise ) { 00084 r.startColumn = 0; 00085 r.endColumn = getLine( r.endLine ).length(); 00086 } 00087 00088 if ( r.motionType == ViMotion::InclusiveMotion ) { 00089 r.endColumn++; 00090 } 00091 00092 Range range( r.startLine, r.startColumn, r.endLine, r.endColumn); 00093 00094 if ( linewise ) { 00095 s = doc()->textLines( range ).join( QChar( '\n' ) ); 00096 s.append( QChar( '\n' ) ); 00097 } else { 00098 s = doc()->text( range ); 00099 } 00100 00101 return s; 00102 } 00103 00104 const QString KateViModeBase::getLine( int lineNumber ) const 00105 { 00106 QString line; 00107 00108 if ( lineNumber == -1 ) { 00109 Cursor cursor ( m_view->cursorPosition() ); 00110 line = m_view->currentTextLine(); 00111 } else { 00112 line = doc()->line( lineNumber ); 00113 } 00114 00115 return line; 00116 } 00117 00118 const QChar KateViModeBase::getCharUnderCursor() const 00119 { 00120 Cursor c( m_view->cursorPosition() ); 00121 00122 QString line = getLine( c.line() ); 00123 00124 if ( line.length() == 0 && c.column() >= line.length() ) { 00125 return QChar::Null; 00126 } 00127 00128 return line.at( c.column() ); 00129 } 00130 00131 const QString KateViModeBase::getWordUnderCursor() const 00132 { 00133 Cursor c( m_view->cursorPosition() ); 00134 Cursor c1 = findPrevWordStart( c.line(), c.column()+1, true ); 00135 Cursor c2 = findWordEnd( c1.line(), c1.column()-1, true ); 00136 c2.setColumn( c2.column()+1 ); 00137 00138 return doc()->text( Range( c1, c2 ) ); 00139 } 00140 00141 KateViRange KateViModeBase::findPattern( const QString &pattern, bool backwards, int count ) const 00142 { 00143 kDebug( 13070 ) << "searching for pattern \"" << pattern << "\", backwards = " << backwards 00144 << ", count = " << count; 00145 if ( pattern.isEmpty() ) { 00146 return KateViRange(); 00147 } 00148 00149 Cursor c( m_view->cursorPosition() ); 00150 00151 KTextEditor::Search::SearchOptions flags = KTextEditor::Search::Regex; 00152 00153 if ( backwards ) { 00154 flags |= KTextEditor::Search::Backwards; 00155 } 00156 00157 for ( int i = count; i > 0; i-- ) { 00158 // prepare two ranges, one from start → cursor and one from cursor → end 00159 Range r1 = Range( Cursor( 0,0 ), c ); 00160 00161 // we want to search from current position + one 00162 if ( c.column() < doc()->lineLength( c.line() ) ) { 00163 c.setColumn( c.column()+1 ); 00164 } else if ( c.line() < doc()->lines() ) { 00165 c.setColumn( 0 ); 00166 c.setLine( c.line()+1 ); 00167 } 00168 00169 Range r2 = Range( c, doc()->documentEnd() ); 00170 00171 //kDebug( 13070 ) << "r1: " << r1; 00172 //kDebug( 13070 ) << "r2: " << r2; 00173 00175 //kDebug( 13070 ) << "searching for " << pattern << " in " << (backwards ? "r1" : "r2") << " backwards = " << backwards; 00176 Range result = doc()->searchText( backwards ? r1 : r2, pattern, flags ).first(); 00177 //kDebug( 13070 ) << "result: " << result; 00178 00179 if ( result.isValid() ) { 00180 c = result.start(); 00181 } else { 00182 00183 // no hits, continue from the top 00184 result = doc()->searchText( backwards ? r2 : r1, pattern, flags ).first(); 00185 00186 c = result.start(); 00187 } 00188 } 00189 00190 return KateViRange( c.line(), c.column(), ViMotion::ExclusiveMotion ); 00191 } 00192 00193 Cursor KateViModeBase::findNextWordStart( int fromLine, int fromColumn, bool onlyCurrentLine ) const 00194 { 00195 QString line = getLine( fromLine ); 00196 00197 // the start of word pattern need to take m_extraWordCharacters into account if defined 00198 QString startOfWordPattern("\\b(\\w"); 00199 if ( m_extraWordCharacters.length() > 0 ) { 00200 startOfWordPattern.append( QLatin1String( "|[" )+m_extraWordCharacters+']' ); 00201 } 00202 startOfWordPattern.append( ')' ); 00203 00204 QRegExp startOfWord( startOfWordPattern ); // start of a word 00205 QRegExp nonSpaceAfterSpace( "\\s\\S" ); // non-space right after space 00206 QRegExp nonWordAfterWord( "\\b(?!\\s)\\W" ); // word-boundary followed by a non-word which is not a space 00207 00208 int l = fromLine; 00209 int c = fromColumn; 00210 00211 bool found = false; 00212 00213 while ( !found ) { 00214 int c1 = startOfWord.indexIn( line, c + 1 ); 00215 int c2 = nonSpaceAfterSpace.indexIn( line, c ); 00216 int c3 = nonWordAfterWord.indexIn( line, c + 1 ); 00217 00218 if ( c1 == -1 && c2 == -1 && c3 == -1 ) { 00219 if ( onlyCurrentLine ) { 00220 return Cursor( l, c ); 00221 } else if ( l >= doc()->lines()-1 ) { 00222 c = line.length()-1; 00223 return Cursor( l, c ); 00224 } else { 00225 c = 0; 00226 l++; 00227 00228 line = getLine( l ); 00229 00230 if ( line.length() == 0 || !line.at( c ).isSpace() ) { 00231 found = true; 00232 } 00233 00234 continue; 00235 } 00236 } 00237 00238 c2++; // the second regexp will match one character *before* the character we want to go to 00239 00240 if ( c1 <= 0 ) 00241 c1 = line.length()-1; 00242 if ( c2 <= 0 ) 00243 c2 = line.length()-1; 00244 if ( c3 <= 0 ) 00245 c3 = line.length()-1; 00246 00247 c = qMin( c1, qMin( c2, c3 ) ); 00248 00249 found = true; 00250 } 00251 00252 return Cursor( l, c ); 00253 } 00254 00255 Cursor KateViModeBase::findNextWORDStart( int fromLine, int fromColumn, bool onlyCurrentLine ) const 00256 { 00257 Cursor cursor ( m_view->cursorPosition() ); 00258 QString line = getLine(); 00259 KateViRange r( cursor.line(), cursor.column(), ViMotion::ExclusiveMotion ); 00260 00261 int l = fromLine; 00262 int c = fromColumn; 00263 00264 bool found = false; 00265 QRegExp startOfWORD("\\s\\S"); 00266 00267 while ( !found ) { 00268 c = startOfWORD.indexIn( line, c+1 ); 00269 00270 if ( c == -1 ) { 00271 if ( onlyCurrentLine ) { 00272 return Cursor( l, c ); 00273 } else if ( l >= doc()->lines()-1 ) { 00274 c = line.length()-1; 00275 break; 00276 } else { 00277 c = 0; 00278 l++; 00279 00280 line = getLine( l ); 00281 00282 if ( line.length() == 0 || !line.at( c ).isSpace() ) { 00283 found = true; 00284 } 00285 00286 continue; 00287 } 00288 } else { 00289 c++; 00290 found = true; 00291 } 00292 } 00293 00294 return Cursor( l, c ); 00295 } 00296 00297 Cursor KateViModeBase::findPrevWordEnd( int fromLine, int fromColumn, bool onlyCurrentLine ) const 00298 { 00299 QString line = getLine( fromLine ); 00300 00301 QString endOfWordPattern = "\\S\\s|\\S$|\\w\\W|\\S\\b|^$"; 00302 00303 if ( m_extraWordCharacters.length() > 0 ) { 00304 endOfWordPattern.append( "|["+m_extraWordCharacters+"][^" +m_extraWordCharacters+']' ); 00305 } 00306 00307 QRegExp endOfWord( endOfWordPattern ); 00308 00309 int l = fromLine; 00310 int c = fromColumn; 00311 00312 bool found = false; 00313 00314 while ( !found ) { 00315 int c1 = endOfWord.lastIndexIn( line, c-1 ); 00316 00317 if ( c1 != -1 && c-1 != -1 ) { 00318 found = true; 00319 c = c1; 00320 } else { 00321 if ( onlyCurrentLine ) { 00322 return Cursor( l, c ); 00323 } else if ( l > 0 ) { 00324 line = getLine( --l ); 00325 c = line.length(); 00326 00327 continue; 00328 } else { 00329 c = 0; 00330 return Cursor( l, c ); 00331 } 00332 } 00333 } 00334 00335 return Cursor( l, c ); 00336 } 00337 00338 Cursor KateViModeBase::findPrevWORDEnd( int fromLine, int fromColumn, bool onlyCurrentLine ) const 00339 { 00340 QString line = getLine( fromLine ); 00341 00342 QRegExp endOfWORDPattern( "\\S\\s|\\S$|^$" ); 00343 00344 QRegExp endOfWORD( endOfWORDPattern ); 00345 00346 int l = fromLine; 00347 int c = fromColumn; 00348 00349 bool found = false; 00350 00351 while ( !found ) { 00352 int c1 = endOfWORD.lastIndexIn( line, c-1 ); 00353 00354 if ( c1 != -1 && c-1 != -1 ) { 00355 found = true; 00356 c = c1; 00357 } else { 00358 if ( onlyCurrentLine ) { 00359 return Cursor( l, c ); 00360 } else if ( l > 0 ) { 00361 line = getLine( --l ); 00362 c = line.length(); 00363 00364 continue; 00365 } else { 00366 c = 0; 00367 return Cursor( l, c ); 00368 } 00369 } 00370 } 00371 00372 return Cursor( l, c ); 00373 } 00374 00375 Cursor KateViModeBase::findPrevWordStart( int fromLine, int fromColumn, bool onlyCurrentLine ) const 00376 { 00377 QString line = getLine( fromLine ); 00378 00379 // the start of word pattern need to take m_extraWordCharacters into account if defined 00380 QString startOfWordPattern("\\b(\\w"); 00381 if ( m_extraWordCharacters.length() > 0 ) { 00382 startOfWordPattern.append( QLatin1String( "|[" )+m_extraWordCharacters+']' ); 00383 } 00384 startOfWordPattern.append( ')' ); 00385 00386 QRegExp startOfWord( startOfWordPattern ); // start of a word 00387 QRegExp nonSpaceAfterSpace( "\\s\\S" ); // non-space right after space 00388 QRegExp nonWordAfterWord( "\\b(?!\\s)\\W" ); // word-boundary followed by a non-word which is not a space 00389 QRegExp startOfLine( "^\\S" ); // non-space at start of line 00390 00391 int l = fromLine; 00392 int c = fromColumn; 00393 00394 bool found = false; 00395 00396 while ( !found ) { 00397 int c1 = startOfWord.lastIndexIn( line, -line.length()+c-1 ); 00398 int c2 = nonSpaceAfterSpace.lastIndexIn( line, -line.length()+c-2 ); 00399 int c3 = nonWordAfterWord.lastIndexIn( line, -line.length()+c-1 ); 00400 int c4 = startOfLine.lastIndexIn( line, -line.length()+c-1 ); 00401 00402 if ( c1 == -1 && c2 == -1 && c3 == -1 && c4 == -1 ) { 00403 if ( onlyCurrentLine ) { 00404 return Cursor( l, c ); 00405 } else if ( l <= 0 ) { 00406 return Cursor( 0, 0 ); 00407 } else { 00408 line = getLine( --l ); 00409 c = line.length(); 00410 00411 if ( line.length() == 0 ) { 00412 c = 0; 00413 found = true; 00414 } 00415 00416 continue; 00417 } 00418 } 00419 00420 c2++; // the second regexp will match one character *before* the character we want to go to 00421 00422 if ( c1 <= 0 ) 00423 c1 = 0; 00424 if ( c2 <= 0 ) 00425 c2 = 0; 00426 if ( c3 <= 0 ) 00427 c3 = 0; 00428 if ( c4 <= 0 ) 00429 c4 = 0; 00430 00431 c = qMax( c1, qMax( c2, qMax( c3, c4 ) ) ); 00432 00433 found = true; 00434 } 00435 00436 return Cursor( l, c ); 00437 } 00438 00439 Cursor KateViModeBase::findPrevWORDStart( int fromLine, int fromColumn, bool onlyCurrentLine ) const 00440 { 00441 QString line = getLine( fromLine ); 00442 00443 QRegExp startOfWORD("\\s\\S"); 00444 QRegExp startOfLineWORD("^\\S"); 00445 00446 int l = fromLine; 00447 int c = fromColumn; 00448 00449 bool found = false; 00450 00451 while ( !found ) { 00452 int c1 = startOfWORD.lastIndexIn( line, -line.length()+c-2 ); 00453 int c2 = startOfLineWORD.lastIndexIn( line, -line.length()+c-1 ); 00454 00455 if ( c1 == -1 && c2 == -1 ) { 00456 if ( onlyCurrentLine ) { 00457 return Cursor( l, c ); 00458 } else if ( l <= 0 ) { 00459 return Cursor( 0, 0 ); 00460 } else { 00461 line = getLine( --l ); 00462 c = line.length(); 00463 00464 if ( line.length() == 0 ) { 00465 c = 0; 00466 found = true; 00467 } 00468 00469 continue; 00470 } 00471 } 00472 00473 c1++; // the startOfWORD pattern matches one character before the word 00474 00475 c = qMax( c1, c2 ); 00476 00477 if ( c <= 0 ) 00478 c = 0; 00479 00480 found = true; 00481 } 00482 00483 return Cursor( l, c ); 00484 } 00485 00486 Cursor KateViModeBase::findWordEnd( int fromLine, int fromColumn, bool onlyCurrentLine ) const 00487 { 00488 QString line = getLine( fromLine ); 00489 00490 QString endOfWordPattern = "\\S\\s|\\S$|\\w\\W|\\S\\b"; 00491 00492 if ( m_extraWordCharacters.length() > 0 ) { 00493 endOfWordPattern.append( "|["+m_extraWordCharacters+"][^" +m_extraWordCharacters+']' ); 00494 } 00495 00496 QRegExp endOfWORD( endOfWordPattern ); 00497 00498 int l = fromLine; 00499 int c = fromColumn; 00500 00501 bool found = false; 00502 00503 while ( !found ) { 00504 int c1 = endOfWORD.indexIn( line, c+1 ); 00505 00506 if ( c1 != -1 ) { 00507 found = true; 00508 c = c1; 00509 } else { 00510 if ( onlyCurrentLine ) { 00511 return Cursor( l, c ); 00512 } else if ( l >= doc()->lines()-1 ) { 00513 c = line.length()-1; 00514 return Cursor( l, c ); 00515 } else { 00516 c = -1; 00517 line = getLine( ++l ); 00518 00519 continue; 00520 } 00521 } 00522 } 00523 00524 return Cursor( l, c ); 00525 } 00526 00527 Cursor KateViModeBase::findWORDEnd( int fromLine, int fromColumn, bool onlyCurrentLine ) const 00528 { 00529 QString line = getLine( fromLine ); 00530 00531 QRegExp endOfWORD( "\\S\\s|\\S$" ); 00532 00533 int l = fromLine; 00534 int c = fromColumn; 00535 00536 bool found = false; 00537 00538 while ( !found ) { 00539 int c1 = endOfWORD.indexIn( line, c+1 ); 00540 00541 if ( c1 != -1 ) { 00542 found = true; 00543 c = c1; 00544 } else { 00545 if ( onlyCurrentLine ) { 00546 return Cursor( l, c ); 00547 } else if ( l >= doc()->lines()-1 ) { 00548 c = line.length()-1; 00549 return Cursor( l, c ); 00550 } else { 00551 c = -1; 00552 line = getLine( ++l ); 00553 00554 continue; 00555 } 00556 } 00557 } 00558 00559 return Cursor( l, c ); 00560 } 00561 00562 // FIXME: i" won't work if the cursor is on one of the chars 00563 KateViRange KateViModeBase::findSurrounding( const QChar &c1, const QChar &c2, bool inner ) const 00564 { 00565 Cursor cursor( m_view->cursorPosition() ); 00566 QString line = getLine(); 00567 00568 int col1 = line.lastIndexOf( c1, cursor.column() ); 00569 int col2 = line.indexOf( c2, cursor.column() ); 00570 00571 KateViRange r( cursor.line(), col1, cursor.line(), col2, ViMotion::InclusiveMotion ); 00572 00573 if ( col1 == -1 || col2 == -1 || col1 > col2 ) { 00574 r.valid = false; 00575 } 00576 00577 if ( inner ) { 00578 r.startColumn++; 00579 r.endColumn--; 00580 } 00581 00582 return r; 00583 } 00584 00585 KateViRange KateViModeBase::findSurrounding( const QRegExp &c1, const QRegExp &c2, bool inner ) const 00586 { 00587 Cursor cursor( m_view->cursorPosition() ); 00588 QString line = getLine(); 00589 00590 int col1 = line.lastIndexOf( c1, cursor.column() ); 00591 int col2 = line.indexOf( c2, cursor.column() ); 00592 00593 KateViRange r( cursor.line(), col1, cursor.line(), col2, ViMotion::InclusiveMotion ); 00594 00595 if ( col1 == -1 || col2 == -1 || col1 > col2 ) { 00596 r.valid = false; 00597 } 00598 00599 if ( inner ) { 00600 r.startColumn++; 00601 r.endColumn--; 00602 } 00603 00604 return r; 00605 } 00606 00607 int KateViModeBase::findLineStartingWitchChar( const QChar &c, unsigned int count, bool forward ) const 00608 { 00609 int line = m_view->cursorPosition().line(); 00610 int lines = doc()->lines(); 00611 unsigned int hits = 0; 00612 00613 if ( forward ) { 00614 line++; 00615 } else { 00616 line--; 00617 } 00618 00619 while ( line < lines && line > 0 && hits < count ) { 00620 QString l = getLine( line ); 00621 if ( l.length() > 0 && l.at( 0 ) == c ) { 00622 hits++; 00623 } 00624 if ( hits != count ) { 00625 if ( forward ) { 00626 line++; 00627 } else { 00628 line--; 00629 } 00630 } 00631 } 00632 00633 if ( hits == getCount() ) { 00634 return line; 00635 } 00636 00637 return -1; 00638 } 00639 00640 void KateViModeBase::updateCursor( const Cursor &c ) const 00641 { 00642 m_viewInternal->updateCursor( c ); 00643 } 00644 00648 QChar KateViModeBase::getChosenRegister( const QChar &defaultReg ) const 00649 { 00650 QChar reg = ( m_register != QChar::Null ) ? m_register : defaultReg; 00651 00652 return reg; 00653 } 00654 00655 QString KateViModeBase::getRegisterContent( const QChar ® ) const 00656 { 00657 QString r = KateGlobal::self()->viInputModeGlobal()->getRegisterContent( reg ); 00658 00659 if ( r.isNull() ) { 00660 error( i18n( "Nothing in register %1" ,reg )); 00661 } 00662 00663 return r; 00664 } 00665 00666 void KateViModeBase::fillRegister( const QChar ®, const QString &text ) 00667 { 00668 KateGlobal::self()->viInputModeGlobal()->fillRegister( reg, text ); 00669 } 00670 00671 KateViRange KateViModeBase::goLineDown() 00672 { 00673 return goLineUpDown( getCount() ); 00674 } 00675 00676 KateViRange KateViModeBase::goLineUp() 00677 { 00678 return goLineUpDown( -getCount() ); 00679 } 00680 00685 KateViRange KateViModeBase::goLineUpDown( int lines ) 00686 { 00687 Cursor c( m_view->cursorPosition() ); 00688 KateViRange r( c.line(), c.column(), ViMotion::InclusiveMotion ); 00689 int tabstop = doc()->config()->tabWidth(); 00690 00691 // if in an empty document, just return 00692 if ( lines == 0 ) { 00693 return r; 00694 } 00695 00696 r.endLine += lines; 00697 00698 // limit end line to be from line 0 through the last line 00699 if ( r.endLine < 0 ) { 00700 r.endLine = 0; 00701 } else if ( r.endLine > doc()->lines()-1 ) { 00702 r.endLine = doc()->lines()-1; 00703 } 00704 00705 Kate::TextLine startLine = doc()->plainKateTextLine( c.line() ); 00706 Kate::TextLine endLine = doc()->plainKateTextLine( r.endLine ); 00707 00708 int endLineLen = doc()->lineLength( r.endLine )-1; 00709 00710 if ( endLineLen < 0 ) { 00711 endLineLen = 0; 00712 } 00713 00714 int endLineLenVirt = endLine->toVirtualColumn(endLineLen, tabstop); 00715 int virtColumnStart = startLine->toVirtualColumn(c.column(), tabstop); 00716 00717 // if sticky column isn't set, set end column and set sticky column to its virtual column 00718 if ( m_stickyColumn == -1 ) { 00719 r.endColumn = endLine->fromVirtualColumn( virtColumnStart, tabstop ); 00720 m_stickyColumn = virtColumnStart; 00721 } else { 00722 // sticky is set - set end column to its value 00723 r.endColumn = endLine->fromVirtualColumn( m_stickyColumn, tabstop ); 00724 } 00725 00726 // make sure end column won't be after the last column of a line 00727 if ( r.endColumn > endLineLen ) { 00728 r.endColumn = endLineLen; 00729 } 00730 00731 // if we move to a line shorter than the current column, go to its end 00732 if ( virtColumnStart > endLineLenVirt ) { 00733 r.endColumn = endLineLen; 00734 } 00735 00736 return r; 00737 } 00738 00739 bool KateViModeBase::startNormalMode() 00740 { 00741 // store the key presses for this "insert mode session" so that it can be repeated with the 00742 // '.' command 00743 if (!m_viInputModeManager->isRunningMacro()) { 00744 m_viInputModeManager->storeChangeCommand(); 00745 m_viInputModeManager->clearLog(); 00746 } 00747 00748 m_viInputModeManager->viEnterNormalMode(); 00749 m_view->doc()->setUndoMergeAllEdits(false); 00750 m_view->updateViModeBarMode(); 00751 00752 return true; 00753 } 00754 00755 bool KateViModeBase::startInsertMode() 00756 { 00757 m_viInputModeManager->viEnterInsertMode(); 00758 m_view->doc()->setUndoMergeAllEdits(true); 00759 m_view->updateViModeBarMode(); 00760 00761 return true; 00762 } 00763 00764 bool KateViModeBase::startReplaceMode() 00765 { 00766 m_view->doc()->setUndoMergeAllEdits(true); 00767 m_viInputModeManager->viEnterReplaceMode(); 00768 m_view->updateViModeBarMode(); 00769 00770 return true; 00771 } 00772 00773 bool KateViModeBase::startVisualMode() 00774 { 00775 if ( m_view->getCurrentViMode() == VisualLineMode ) { 00776 m_viInputModeManager->getViVisualMode()->setVisualLine( false ); 00777 m_viInputModeManager->changeViMode(VisualMode); 00778 } else if (m_view->getCurrentViMode() == VisualBlockMode ) { 00779 m_viInputModeManager->getViVisualMode()->setVisualBlock( false ); 00780 m_viInputModeManager->changeViMode(VisualMode); 00781 } else { 00782 m_viInputModeManager->viEnterVisualMode(); 00783 } 00784 00785 m_view->updateViModeBarMode(); 00786 00787 return true; 00788 } 00789 00790 bool KateViModeBase::startVisualBlockMode() 00791 { 00792 if ( m_view->getCurrentViMode() == VisualMode ) { 00793 m_viInputModeManager->getViVisualMode()->setVisualBlock( true ); 00794 m_viInputModeManager->changeViMode(VisualBlockMode); 00795 } else { 00796 m_viInputModeManager->viEnterVisualMode( VisualBlockMode ); 00797 } 00798 00799 m_view->updateViModeBarMode(); 00800 00801 return true; 00802 } 00803 00804 bool KateViModeBase::startVisualLineMode() 00805 { 00806 if ( m_view->getCurrentViMode() == VisualMode ) { 00807 m_viInputModeManager->getViVisualMode()->setVisualLine( true ); 00808 m_viInputModeManager->changeViMode(VisualLineMode); 00809 } else { 00810 m_viInputModeManager->viEnterVisualMode( VisualLineMode ); 00811 } 00812 00813 m_view->updateViModeBarMode(); 00814 00815 return true; 00816 } 00817 00818 void KateViModeBase::error( const QString &errorMsg ) const 00819 { 00820 m_view->viModeBar()->showErrorMessage(errorMsg); 00821 } 00822 00823 void KateViModeBase::message( const QString &msg ) const 00824 { 00825 m_view->viModeBar()->showMessage(msg); 00826 } 00827 00828 QString KateViModeBase::getVerbatimKeys() const 00829 { 00830 return m_keysVerbatim; 00831 } 00832 00833 const QChar KateViModeBase::getCharAtVirtualColumn( QString &line, int virtualColumn, 00834 int tabWidth ) const 00835 { 00836 int column = 0; 00837 int tempCol = 0; 00838 00839 // sanity check: if the line is empty, there are no chars 00840 if ( line.length() == 0 ) { 00841 return QChar::Null; 00842 } 00843 00844 while ( tempCol < virtualColumn ) { 00845 if ( line.at( column ) == '\t' ) { 00846 tempCol += tabWidth - ( tempCol % tabWidth ); 00847 } else { 00848 tempCol++; 00849 } 00850 00851 if ( tempCol <= virtualColumn ) { 00852 column++; 00853 00854 if ( column >= line.length() ) { 00855 return QChar::Null; 00856 } 00857 } 00858 } 00859 00860 if ( line.length() > column ) 00861 return line.at( column ); 00862 00863 return QChar::Null; 00864 } 00865 00866 void KateViModeBase::addToNumberUnderCursor( int count ) 00867 { 00868 Cursor c( m_view->cursorPosition() ); 00869 QString line = getLine(); 00870 00871 int wordStart = findPrevWordStart( c.line(), c.column()+1, true ).column(); 00872 int wordEnd = findWordEnd( c.line(), c.column()-1, true ).column(); 00873 00874 QRegExp number( "(0x)([0-9a-fA-F]+)|\\d+" ); 00875 00876 int start = number.indexIn( line, wordStart ); 00877 if ( start <= wordEnd ) { 00878 // FIXME: ignore leading zeroes 00879 QString nString = number.cap(); 00880 bool ok = false; 00881 int base = number.cap( 1 ).isEmpty() ? 10 : 16; 00882 int n = nString.toInt( &ok, base ); 00883 00884 kDebug( 13070 ) << "base: " << base; 00885 kDebug( 13070 ) << "n: " << n; 00886 00887 if ( !ok ) { 00888 // conversion to int failed. give up. 00889 return; 00890 } 00891 00892 // increase/decrease number 00893 n += count; 00894 00895 // create the new text string to be inserted. prepend with “0x” if in base 16 00896 QString newText = (base == 16 ? "0x" : "") + QString::number(n, base); 00897 00898 // replace the old number string with the new 00899 doc()->editStart(); 00900 doc()->removeText( KTextEditor::Range( c.line(), start , c.line(), start+nString.length() ) ); 00901 doc()->insertText( KTextEditor::Cursor( c.line(), start ), newText ); 00902 doc()->editEnd(); 00903 } 00904 } 00905
KDE 4.6 API Reference