PageRenderTime 38ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/part/vimode/katevinormalmode.cpp

https://bitbucket.org/totte/kate
C++ | 3313 lines | 2459 code | 646 blank | 208 comment | 539 complexity | 7e727612fd6052ec7d0afb2f067f6b31 MD5 | raw file
Possible License(s): LGPL-2.0
  1. /* This file is part of the KDE libraries and the Kate part.
  2. *
  3. * Copyright (C) 2008-2009 Erlend Hamberg <ehamberg@gmail.com>
  4. * Copyright (C) 2008 Evgeniy Ivanov <powerfox@kde.ru>
  5. * Copyright (C) 2009 Paul Gideon Dann <pdgiddie@gmail.com>
  6. * Copyright (C) 2011 Svyatoslav Kuzmich <svatoslav1@gmail.com>
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Library General Public
  10. * License as published by the Free Software Foundation; either
  11. * version 2 of the License, or (at your option) any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Library General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Library General Public License
  19. * along with this library; see the file COPYING.LIB. If not, write to
  20. * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  21. * Boston, MA 02110-1301, USA.
  22. */
  23. #include "katevinormalmode.h"
  24. #include "katevivisualmode.h"
  25. #include "kateviinsertmode.h"
  26. #include "kateviinputmodemanager.h"
  27. #include "kateviglobal.h"
  28. #include "kateglobal.h"
  29. #include "katebuffer.h"
  30. #include "kateviewhelpers.h"
  31. #include <QApplication>
  32. #include <QList>
  33. using KTextEditor::Cursor;
  34. using KTextEditor::Range;
  35. #define ADDCMD(STR, FUNC, FLGS) m_commands.push_back( \
  36. new KateViCommand( this, STR, &KateViNormalMode::FUNC, FLGS ) );
  37. #define ADDMOTION(STR, FUNC, FLGS) m_motions.push_back( \
  38. new KateViMotion( this, STR, &KateViNormalMode::FUNC, FLGS ) );
  39. KateViNormalMode::KateViNormalMode( KateViInputModeManager *viInputModeManager, KateView * view,
  40. KateViewInternal * viewInternal ) : KateViModeBase()
  41. {
  42. m_view = view;
  43. m_viewInternal = viewInternal;
  44. m_viInputModeManager = viInputModeManager;
  45. m_stickyColumn = -1;
  46. // FIXME: make configurable
  47. m_extraWordCharacters = "";
  48. m_matchingItems["/*"] = "*/";
  49. m_matchingItems["*/"] = "-/*";
  50. m_matchItemRegex = generateMatchingItemRegex();
  51. m_defaultRegister = '"';
  52. m_scroll_count_limit = 1000; // Limit of count for scroll commands.
  53. m_timeoutlen = 1000; // FIXME: make configurable
  54. m_mappingKeyPress = false; // temporarily set to true when an aborted mapping sends key presses
  55. m_mappingTimer = new QTimer( this );
  56. connect(m_mappingTimer, SIGNAL(timeout()), this, SLOT(mappingTimerTimeOut()));
  57. initializeCommands();
  58. m_ignoreMapping = false;
  59. m_pendingResetIsDueToExit = false;
  60. m_isRepeatedTFcommand = false;
  61. resetParser(); // initialise with start configuration
  62. }
  63. KateViNormalMode::~KateViNormalMode()
  64. {
  65. qDeleteAll( m_commands );
  66. qDeleteAll( m_motions) ;
  67. }
  68. void KateViNormalMode::mappingTimerTimeOut()
  69. {
  70. kDebug( 13070 ) << "timeout! key presses: " << m_mappingKeys;
  71. m_mappingKeyPress = true;
  72. if (!m_fullMappingMatch.isNull())
  73. {
  74. executeMapping();
  75. }
  76. else
  77. {
  78. m_viInputModeManager->feedKeyPresses( m_mappingKeys );
  79. }
  80. m_mappingKeyPress = false;
  81. m_mappingKeys.clear();
  82. }
  83. /**
  84. * parses a key stroke to check if it's a valid (part of) a command
  85. * @return true if a command was completed and executed, false otherwise
  86. */
  87. bool KateViNormalMode::handleKeypress( const QKeyEvent *e )
  88. {
  89. int keyCode = e->key();
  90. QString text = e->text();
  91. // ignore modifier keys alone
  92. if ( keyCode == Qt::Key_Shift || keyCode == Qt::Key_Control
  93. || keyCode == Qt::Key_Alt || keyCode == Qt::Key_Meta ) {
  94. return false;
  95. }
  96. if ( keyCode == Qt::Key_AltGr ) {
  97. KateViKeyParser::self()->setAltGrStatus( true );
  98. return true;
  99. }
  100. if ( keyCode == Qt::Key_Escape ) {
  101. m_view->setCaretStyle( KateRenderer::Block, true );
  102. m_pendingResetIsDueToExit = true;
  103. reset();
  104. return true;
  105. }
  106. QChar key = KateViKeyParser::self()->KeyEventToQChar( keyCode, text, e->modifiers(), e->nativeScanCode() );
  107. // check for matching mappings
  108. if ( !m_mappingKeyPress && !m_ignoreMapping) {
  109. m_mappingKeys.append( key );
  110. bool isPartialMapping = false;
  111. bool isFullMapping = false;
  112. m_fullMappingMatch.clear();
  113. foreach ( const QString &mapping, getMappings() ) {
  114. if ( mapping.startsWith( m_mappingKeys ) ) {
  115. if ( mapping == m_mappingKeys ) {
  116. isFullMapping = true;
  117. m_fullMappingMatch = mapping;
  118. } else {
  119. isPartialMapping = true;
  120. }
  121. }
  122. }
  123. if (isFullMapping && !isPartialMapping)
  124. {
  125. // Great - m_mappingKeys is a mapping, and one that can't be extended to
  126. // a longer one - execute it immediately.
  127. executeMapping();
  128. return true;
  129. }
  130. if (isPartialMapping)
  131. {
  132. // Need to wait for more characters (or a timeout) before we decide what to
  133. // do with this.
  134. m_mappingTimer->start( m_timeoutlen );
  135. m_mappingTimer->setSingleShot( true );
  136. return true;
  137. }
  138. // We've been swallowing all the keypresses meant for m_keys for our mapping keys; now that we know
  139. // this cannot be a mapping, restore them. The current key will be appended further down.
  140. Q_ASSERT(!isPartialMapping && !isFullMapping);
  141. if (m_keys.isEmpty())
  142. m_keys = m_mappingKeys.mid(0, m_mappingKeys.length() - 1);
  143. m_mappingKeys.clear();
  144. } else {
  145. // FIXME:
  146. //m_mappingKeyPress = false; // key press ignored wrt mappings, re-set m_mappingKeyPress
  147. }
  148. if ( m_ignoreMapping ) m_ignoreMapping = false;
  149. if ( key == 'f' || key == 'F' || key == 't' || key == 'T' || key == 'r' ) {
  150. // don't translate next character, we need the actual character so that
  151. // 'ab' is translated to 'fb' if the mapping 'a' -> 'f' exists
  152. m_ignoreMapping = true;
  153. }
  154. // Use replace caret when reading a character for "r"
  155. if ( key == 'r' ) {
  156. m_view->setCaretStyle( KateRenderer::Underline, true );
  157. }
  158. m_keysVerbatim.append( KateViKeyParser::self()->decodeKeySequence( key ) );
  159. QChar c = QChar::Null;
  160. if ( m_keys.size() > 0 ) {
  161. c = m_keys.at( m_keys.size()-1 ); // last char
  162. }
  163. if ( ( keyCode >= Qt::Key_0 && keyCode <= Qt::Key_9 && c != '"' ) // key 0-9
  164. && ( m_countTemp != 0 || keyCode != Qt::Key_0 ) // first digit can't be 0
  165. && ( c != 'f' && c != 't' && c != 'F' && c != 'T' && c != 'r' ) ) { // "find char" motions
  166. m_countTemp *= 10;
  167. m_countTemp += keyCode-Qt::Key_0;
  168. return true;
  169. } else if ( m_countTemp != 0 ) {
  170. m_count = getCount() * m_countTemp;
  171. m_countTemp = 0;
  172. m_iscounted = true;
  173. kDebug( 13070 ) << "count = " << getCount();
  174. }
  175. m_keys.append( key );
  176. // Special case: "cw" and "cW" work the same as "ce" and "cE" if the cursor is
  177. // on a non-blank. This is because Vim interprets "cw" as change-word, and a
  178. // word does not include the following white space. (:help cw in vim)
  179. if ( ( m_keys == "cw" || m_keys == "cW" ) && !getCharUnderCursor().isSpace() ) {
  180. // Special case of the special case: :-)
  181. // If the cursor is at the end of the current word rewrite to "cl"
  182. Cursor c1( m_view->cursorPosition() ); // current position
  183. Cursor c2 = findWordEnd(c1.line(), c1.column()-1, true); // word end
  184. if ( c1 == c2 ) { // the cursor is at the end of a word
  185. m_keys = "cl";
  186. } else {
  187. if ( m_keys.at(1) == 'w' ) {
  188. m_keys = "ce";
  189. } else {
  190. m_keys = "cE";
  191. }
  192. }
  193. }
  194. if ( m_keys[ 0 ] == Qt::Key_QuoteDbl ) {
  195. if ( m_keys.size() < 2 ) {
  196. return true; // waiting for a register
  197. }
  198. else {
  199. QChar r = m_keys[ 1 ].toLower();
  200. if ( ( r >= '0' && r <= '9' ) || ( r >= 'a' && r <= 'z' ) ||
  201. r == '_' || r == '+' || r == '*' || r == '#' || r == '^' ) {
  202. m_register = r;
  203. kDebug( 13070 ) << "Register set to " << r;
  204. m_keys.clear();
  205. return true;
  206. }
  207. else {
  208. resetParser();
  209. return true;
  210. }
  211. }
  212. }
  213. // if we have any matching commands so far, check which ones still match
  214. if ( m_matchingCommands.size() > 0 ) {
  215. int n = m_matchingCommands.size()-1;
  216. // remove commands not matching anymore
  217. for ( int i = n; i >= 0; i-- ) {
  218. if ( !m_commands.at( m_matchingCommands.at( i ) )->matches( m_keys ) ) {
  219. //kDebug( 13070 ) << "removing " << m_commands.at( m_matchingCommands.at( i ) )->pattern() << ", size before remove is " << m_matchingCommands.size();
  220. if ( m_commands.at( m_matchingCommands.at( i ) )->needsMotion() ) {
  221. // "cache" command needing a motion for later
  222. //kDebug( 13070 ) << "m_motionOperatorIndex set to " << m_motionOperatorIndex;
  223. m_motionOperatorIndex = m_matchingCommands.at( i );
  224. }
  225. m_matchingCommands.remove( i );
  226. }
  227. }
  228. // check if any of the matching commands need a motion/text object, if so
  229. // push the current command length to m_awaitingMotionOrTextObject so one
  230. // knows where to split the command between the operator and the motion
  231. for ( int i = 0; i < m_matchingCommands.size(); i++ ) {
  232. if ( m_commands.at( m_matchingCommands.at( i ) )->needsMotion() ) {
  233. m_awaitingMotionOrTextObject.push( m_keys.size() );
  234. break;
  235. }
  236. }
  237. } else {
  238. // go through all registered commands and put possible matches in m_matchingCommands
  239. for ( int i = 0; i < m_commands.size(); i++ ) {
  240. if ( m_commands.at( i )->matches( m_keys ) ) {
  241. m_matchingCommands.push_back( i );
  242. if ( m_commands.at( i )->needsMotion() && m_commands.at( i )->pattern().length() == m_keys.size() ) {
  243. m_awaitingMotionOrTextObject.push( m_keys.size() );
  244. }
  245. }
  246. }
  247. }
  248. // this indicates where in the command string one should start looking for a motion command
  249. int checkFrom = ( m_awaitingMotionOrTextObject.isEmpty() ? 0 : m_awaitingMotionOrTextObject.top() );
  250. // Use operator-pending caret when reading a motion for an operator
  251. // in normal mode. We need to check that we are indeed in normal mode
  252. // since visual mode inherits from it.
  253. if( m_viInputModeManager->getCurrentViMode() == NormalMode &&
  254. !m_awaitingMotionOrTextObject.isEmpty() ) {
  255. m_view->setCaretStyle( KateRenderer::Half, true );
  256. }
  257. //kDebug( 13070 ) << "checkFrom: " << checkFrom;
  258. // look for matching motion commands from position 'checkFrom'
  259. // FIXME: if checkFrom hasn't changed, only motions whose index is in
  260. // m_matchingMotions should be checked
  261. if ( checkFrom < m_keys.size() ) {
  262. for ( int i = 0; i < m_motions.size(); i++ ) {
  263. //kDebug( 13070 ) << "\tchecking " << m_keys.mid( checkFrom ) << " against " << m_motions.at( i )->pattern();
  264. if ( m_motions.at( i )->matches( m_keys.mid( checkFrom ) ) ) {
  265. //kDebug( 13070 ) << m_keys.mid( checkFrom ) << " matches!";
  266. m_matchingMotions.push_back( i );
  267. // if it matches exact, we have found the motion command to execute
  268. if ( m_motions.at( i )->matchesExact( m_keys.mid( checkFrom ) ) ) {
  269. if ( checkFrom == 0 ) {
  270. // no command given before motion, just move the cursor to wherever
  271. // the motion says it should go to
  272. KateViRange r = m_motions.at( i )->execute();
  273. // jump over folding regions since we are just moving the cursor
  274. int currLine = m_view->cursorPosition().line();
  275. int delta = r.endLine - currLine;
  276. int vline = doc()->foldingTree()->getVirtualLine( currLine );
  277. r.endLine = doc()->foldingTree()->getRealLine( vline+delta );
  278. if ( r.endLine >= doc()->lines() ) r.endLine = doc()->lines()-1;
  279. // make sure the position is valid before moving the cursor there
  280. // TODO: can this be simplified? :/
  281. if ( r.valid
  282. && r.endLine >= 0
  283. && ( r.endLine == 0 || r.endLine <= doc()->lines()-1 )
  284. && r.endColumn >= 0 ) {
  285. if ( r.endColumn >= doc()->lineLength( r.endLine )
  286. && doc()->lineLength( r.endLine ) > 0 ) {
  287. r.endColumn = doc()->lineLength( r.endLine ) - 1;
  288. }
  289. kDebug( 13070 ) << "No command given, going to position ("
  290. << r.endLine << "," << r.endColumn << ")";
  291. goToPos( r );
  292. m_viInputModeManager->clearLog();
  293. } else {
  294. kDebug( 13070 ) << "Invalid position: (" << r.endLine << "," << r.endColumn << ")";
  295. }
  296. resetParser();
  297. // if normal mode was started by using Ctrl-O in insert mode,
  298. // it's time to go back to insert mode.
  299. if (m_viInputModeManager->getTemporaryNormalMode()) {
  300. startInsertMode();
  301. m_viewInternal->repaint();
  302. }
  303. return true;
  304. } else {
  305. // execute the specified command and supply the position returned from
  306. // the motion
  307. m_commandRange = m_motions.at( i )->execute();
  308. m_linewiseCommand = m_motions.at( i )->isLineWise();
  309. // if we didn't get an explicit start position, use the current cursor position
  310. if ( m_commandRange.startLine == -1 ) {
  311. Cursor c( m_view->cursorPosition() );
  312. m_commandRange.startLine = c.line();
  313. m_commandRange.startColumn = c.column();
  314. }
  315. // special case: When using the "w" motion in combination with an operator and
  316. // the last word moved over is at the end of a line, the end of that word
  317. // becomes the end of the operated text, not the first word in the next line.
  318. if ( m_keys.right(1) == "w" || m_keys.right(1) == "W" ) {
  319. if(m_commandRange.endLine != m_commandRange.startLine &&
  320. m_commandRange.endColumn == getLine(m_commandRange.endLine).indexOf( QRegExp("\\S") )){
  321. m_commandRange.endLine--;
  322. m_commandRange.endColumn = doc()->lineLength(m_commandRange.endLine );
  323. }
  324. }
  325. m_commandWithMotion = true;
  326. if ( m_commandRange.valid ) {
  327. kDebug( 13070 ) << "Run command" << m_commands.at( m_motionOperatorIndex )->pattern()
  328. << "from (" << m_commandRange.startLine << "," << m_commandRange.endLine << ")"
  329. << "to (" << m_commandRange.endLine << "," << m_commandRange.endColumn << ")";
  330. executeCommand( m_commands.at( m_motionOperatorIndex ) );
  331. } else {
  332. kDebug( 13070 ) << "Invalid range: "
  333. << "from (" << m_commandRange.startLine << "," << m_commandRange.endLine << ")"
  334. << "to (" << m_commandRange.endLine << "," << m_commandRange.endColumn << ")";
  335. }
  336. if( m_viInputModeManager->getCurrentViMode() == NormalMode ) {
  337. m_view->setCaretStyle( KateRenderer::Block, true );
  338. }
  339. m_commandWithMotion = false;
  340. reset();
  341. return true;
  342. }
  343. }
  344. }
  345. }
  346. }
  347. //kDebug( 13070 ) << "'" << m_keys << "' MATCHING COMMANDS: " << m_matchingCommands.size();
  348. //kDebug( 13070 ) << "'" << m_keys << "' MATCHING MOTIONS: " << m_matchingMotions.size();
  349. //kDebug( 13070 ) << "'" << m_keys << "' AWAITING MOTION OR TO (INDEX): " << ( m_awaitingMotionOrTextObject.isEmpty() ? 0 : m_awaitingMotionOrTextObject.top() );
  350. // if we have only one match, check if it is a perfect match and if so, execute it
  351. // if it's not waiting for a motion or a text object
  352. if ( m_matchingCommands.size() == 1 ) {
  353. if ( m_commands.at( m_matchingCommands.at( 0 ) )->matchesExact( m_keys )
  354. && !m_commands.at( m_matchingCommands.at( 0 ) )->needsMotion() ) {
  355. //kDebug( 13070 ) << "Running command at index " << m_matchingCommands.at( 0 );
  356. if( m_viInputModeManager->getCurrentViMode() == NormalMode ) {
  357. m_view->setCaretStyle( KateRenderer::Block, true );
  358. }
  359. KateViCommand *cmd = m_commands.at( m_matchingCommands.at( 0 ) );
  360. executeCommand( cmd );
  361. // check if reset() should be called. some commands in visual mode should not end visual mode
  362. if ( cmd->shouldReset() ) {
  363. reset();
  364. m_view->setBlockSelectionMode(false);
  365. }
  366. resetParser();
  367. return true;
  368. }
  369. } else if ( m_matchingCommands.size() == 0 && m_matchingMotions.size() == 0 ) {
  370. resetParser();
  371. return false;
  372. }
  373. m_matchingMotions.clear();
  374. return false;
  375. }
  376. /**
  377. * (re)set to start configuration. This is done when a command is completed
  378. * executed or when a command is aborted
  379. */
  380. void KateViNormalMode::resetParser()
  381. {
  382. // kDebug( 13070 ) << "***RESET***";
  383. m_keys.clear();
  384. m_keysVerbatim.clear();
  385. m_count = 0;
  386. m_iscounted = false;
  387. m_countTemp = 0;
  388. m_register = QChar::Null;
  389. m_findWaitingForChar = false;
  390. m_matchingCommands.clear();
  391. m_matchingMotions.clear();
  392. m_awaitingMotionOrTextObject.clear();
  393. m_motionOperatorIndex = 0;
  394. m_commandWithMotion = false;
  395. m_linewiseCommand = true;
  396. m_deleteCommand = false;
  397. m_commandShouldKeepSelection = false;
  398. }
  399. // reset the command parser
  400. void KateViNormalMode::reset()
  401. {
  402. resetParser();
  403. m_commandRange.startLine = -1;
  404. m_commandRange.startColumn = -1;
  405. }
  406. void KateViNormalMode::setMappingTimeout(int timeoutMS)
  407. {
  408. m_timeoutlen = timeoutMS;
  409. }
  410. void KateViNormalMode::goToPos( const KateViRange &r )
  411. {
  412. Cursor c;
  413. c.setLine( r.endLine );
  414. c.setColumn( r.endColumn );
  415. if ( r.jump ) {
  416. addCurrentPositionToJumpList();
  417. }
  418. if ( c.line() >= doc()->lines() ) {
  419. c.setLine( doc()->lines()-1 );
  420. }
  421. updateCursor( c );
  422. }
  423. void KateViNormalMode::executeCommand( const KateViCommand* cmd )
  424. {
  425. cmd->execute();
  426. // if normal mode was started by using Ctrl-O in insert mode,
  427. // it's time to go back to insert mode.
  428. if (m_viInputModeManager->getTemporaryNormalMode()) {
  429. startInsertMode();
  430. m_viewInternal->repaint();
  431. }
  432. // if the command was a change, and it didn't enter insert mode, store the key presses so that
  433. // they can be repeated with '.'
  434. if ( m_viInputModeManager->getCurrentViMode() != InsertMode ) {
  435. if ( cmd->isChange() && !m_viInputModeManager->isReplayingLastChange() ) {
  436. m_viInputModeManager->storeChangeCommand();
  437. }
  438. m_viInputModeManager->clearLog();
  439. }
  440. // make sure the cursor does not end up after the end of the line
  441. Cursor c( m_view->cursorPosition() );
  442. if ( m_viInputModeManager->getCurrentViMode() == NormalMode ) {
  443. int lineLength = doc()->lineLength( c.line() );
  444. if ( c.column() >= lineLength ) {
  445. if ( lineLength == 0 ) {
  446. c.setColumn( 0 );
  447. } else {
  448. c.setColumn( lineLength-1 );
  449. }
  450. }
  451. updateCursor( c );
  452. }
  453. }
  454. void KateViNormalMode::addCurrentPositionToJumpList() {
  455. m_viInputModeManager->addJump(m_view->cursorPosition());
  456. }
  457. ////////////////////////////////////////////////////////////////////////////////
  458. // COMMANDS AND OPERATORS
  459. ////////////////////////////////////////////////////////////////////////////////
  460. /**
  461. * enter insert mode at the cursor position
  462. */
  463. bool KateViNormalMode::commandEnterInsertMode()
  464. {
  465. m_stickyColumn = -1;
  466. return startInsertMode();
  467. }
  468. /**
  469. * enter insert mode after the current character
  470. */
  471. bool KateViNormalMode::commandEnterInsertModeAppend()
  472. {
  473. Cursor c( m_view->cursorPosition() );
  474. c.setColumn( c.column()+1 );
  475. // if empty line, the cursor should start at column 0
  476. if ( doc()->lineLength( c.line() ) == 0 ) {
  477. c.setColumn( 0 );
  478. }
  479. // cursor should never be in a column > number of columns
  480. if ( c.column() > doc()->lineLength( c.line() ) ) {
  481. c.setColumn( doc()->lineLength( c.line() ) );
  482. }
  483. updateCursor( c );
  484. m_stickyColumn = -1;
  485. return startInsertMode();
  486. }
  487. /**
  488. * start insert mode after the last character of the line
  489. */
  490. bool KateViNormalMode::commandEnterInsertModeAppendEOL()
  491. {
  492. Cursor c( m_view->cursorPosition() );
  493. c.setColumn( doc()->lineLength( c.line() ) );
  494. updateCursor( c );
  495. m_stickyColumn = -1;
  496. return startInsertMode();
  497. }
  498. bool KateViNormalMode::commandEnterInsertModeBeforeFirstNonBlankInLine()
  499. {
  500. Cursor cursor( m_view->cursorPosition() );
  501. QRegExp nonSpace( "\\S" );
  502. int c = getLine().indexOf( nonSpace );
  503. if ( c == -1 ) {
  504. c = 0;
  505. }
  506. cursor.setColumn( c );
  507. updateCursor( cursor );
  508. m_stickyColumn = -1;
  509. return startInsertMode();
  510. }
  511. /**
  512. * enter insert mode at the last insert position
  513. */
  514. bool KateViNormalMode::commandEnterInsertModeLast()
  515. {
  516. Cursor c = m_view->getViInputModeManager()->getMarkPosition( '^' );
  517. if ( c.isValid() ) {
  518. updateCursor( c );
  519. }
  520. m_stickyColumn = -1;
  521. return startInsertMode();
  522. }
  523. bool KateViNormalMode::commandEnterVisualLineMode()
  524. {
  525. if ( m_viInputModeManager->getCurrentViMode() == VisualLineMode ) {
  526. reset();
  527. return true;
  528. }
  529. return startVisualLineMode();
  530. }
  531. bool KateViNormalMode::commandEnterVisualBlockMode()
  532. {
  533. if ( m_viInputModeManager->getCurrentViMode() == VisualBlockMode ) {
  534. reset();
  535. return true;
  536. }
  537. return startVisualBlockMode();
  538. }
  539. bool KateViNormalMode::commandReselectVisual()
  540. {
  541. // start last visual mode and set start = `< and cursor = `>
  542. Cursor c1 = m_view->getViInputModeManager()->getMarkPosition( '<' );
  543. Cursor c2 = m_view->getViInputModeManager()->getMarkPosition( '>' );
  544. // we should either get two valid cursors or two invalid cursors
  545. Q_ASSERT( c1.isValid() == c2.isValid() );
  546. if ( c1.isValid() && c2.isValid() ) {
  547. m_viInputModeManager->getViVisualMode()->setStart( c1 );
  548. updateCursor( c2 );
  549. switch ( m_viInputModeManager->getViVisualMode()->getLastVisualMode() ) {
  550. case VisualMode:
  551. return commandEnterVisualMode();
  552. break;
  553. case VisualLineMode:
  554. return commandEnterVisualLineMode();
  555. break;
  556. case VisualBlockMode:
  557. return commandEnterVisualBlockMode();
  558. break;
  559. default:
  560. Q_ASSERT( "invalid visual mode" );
  561. }
  562. } else {
  563. error("No previous visual selection");
  564. }
  565. return false;
  566. }
  567. bool KateViNormalMode::commandEnterVisualMode()
  568. {
  569. if ( m_viInputModeManager->getCurrentViMode() == VisualMode ) {
  570. reset();
  571. return true;
  572. }
  573. return startVisualMode();
  574. }
  575. bool KateViNormalMode::commandToOtherEnd()
  576. {
  577. if ( m_viInputModeManager->getCurrentViMode() == VisualMode
  578. || m_viInputModeManager->getCurrentViMode() == VisualLineMode
  579. || m_viInputModeManager->getCurrentViMode() == VisualBlockMode ) {
  580. m_viInputModeManager->getViVisualMode()->switchStartEnd();
  581. return true;
  582. }
  583. return false;
  584. }
  585. bool KateViNormalMode::commandEnterReplaceMode()
  586. {
  587. return startReplaceMode();
  588. }
  589. bool KateViNormalMode::commandDeleteLine()
  590. {
  591. Cursor c( m_view->cursorPosition() );
  592. KateViRange r;
  593. r.startLine = c.line();
  594. r.endLine = c.line()+getCount()-1;
  595. int column = c.column();
  596. bool ret = deleteRange( r, LineWise );
  597. c = m_view->cursorPosition();
  598. if ( column > doc()->lineLength( c.line() )-1 ) {
  599. column = doc()->lineLength( c.line() )-1;
  600. }
  601. if ( column < 0 ) {
  602. column = 0;
  603. }
  604. if ( c.line() > doc()->lines()-1 ) {
  605. c.setLine( doc()->lines()-1 );
  606. }
  607. c.setColumn( column );
  608. m_stickyColumn = -1;
  609. updateCursor( c );
  610. m_deleteCommand = true;
  611. return ret;
  612. }
  613. bool KateViNormalMode::commandDelete()
  614. {
  615. m_deleteCommand = true;
  616. return deleteRange( m_commandRange, getOperationMode() );
  617. }
  618. bool KateViNormalMode::commandDeleteToEOL()
  619. {
  620. Cursor c( m_view->cursorPosition() );
  621. OperationMode m = CharWise;
  622. if ( m_viInputModeManager->getCurrentViMode() == NormalMode ) {
  623. m_commandRange.startLine = c.line();
  624. m_commandRange.startColumn = c.column();
  625. m_commandRange.endLine = c.line()+getCount()-1;
  626. m_commandRange.endColumn = doc()->lineLength( m_commandRange.endLine )-1;
  627. }
  628. if ( m_viInputModeManager->getCurrentViMode() == VisualMode
  629. || m_viInputModeManager->getCurrentViMode() == VisualLineMode ) {
  630. m = LineWise;
  631. } else if ( m_viInputModeManager->getCurrentViMode() == VisualBlockMode ) {
  632. m_commandRange.normalize();
  633. m_commandRange.endColumn = KateVi::EOL;
  634. m = Block;
  635. }
  636. bool r = deleteRange( m_commandRange, m );
  637. switch (m) {
  638. case CharWise:
  639. c.setColumn( doc()->lineLength( c.line() )-1 );
  640. break;
  641. case LineWise:
  642. c.setLine( m_commandRange.startLine );
  643. c.setColumn( 0 ); // FIXME: should be first non-blank
  644. break;
  645. case Block:
  646. c.setLine( m_commandRange.startLine );
  647. c.setColumn( m_commandRange.startColumn-1 );
  648. break;
  649. }
  650. // make sure cursor position is valid after deletion
  651. if ( c.line() < 0 ) {
  652. c.setLine( 0 );
  653. }
  654. if ( c.line() > doc()->lastLine() ) {
  655. c.setLine( doc()->lastLine() );
  656. }
  657. if ( c.column() > doc()->lineLength( c.line() )-1 ) {
  658. c.setColumn( doc()->lineLength( c.line() )-1 );
  659. }
  660. if ( c.column() < 0 ) {
  661. c.setColumn( 0 );
  662. }
  663. updateCursor( c );
  664. m_deleteCommand = true;
  665. return r;
  666. }
  667. bool KateViNormalMode::commandMakeLowercase()
  668. {
  669. Cursor c = m_view->cursorPosition();
  670. OperationMode m = getOperationMode();
  671. QString text = getRange( m_commandRange, m );
  672. if (m == LineWise)
  673. text = text.left(text.size() - 1); // don't need '\n' at the end;
  674. QString lowerCase = text.toLower();
  675. m_commandRange.normalize();
  676. Cursor start( m_commandRange.startLine, m_commandRange.startColumn );
  677. Cursor end( m_commandRange.endLine, m_commandRange.endColumn );
  678. Range range( start, end );
  679. doc()->replaceText( range, lowerCase, m == Block );
  680. if (m_viInputModeManager->getCurrentViMode() == NormalMode)
  681. updateCursor( start );
  682. else
  683. updateCursor(c);
  684. return true;
  685. }
  686. bool KateViNormalMode::commandMakeLowercaseLine()
  687. {
  688. Cursor c( m_view->cursorPosition() );
  689. m_commandRange.startLine = c.line();
  690. m_commandRange.endLine = c.line() + getCount() - 1;
  691. m_commandRange.startColumn = 0;
  692. m_commandRange.endColumn = doc()->lineLength( c.line() )-1;
  693. return commandMakeLowercase();
  694. }
  695. bool KateViNormalMode::commandMakeUppercase()
  696. {
  697. Cursor c = m_view->cursorPosition();
  698. OperationMode m = getOperationMode();
  699. QString text = getRange( m_commandRange, m );
  700. if (m == LineWise)
  701. text = text.left(text.size() - 1); // don't need '\n' at the end;
  702. QString upperCase = text.toUpper();
  703. m_commandRange.normalize();
  704. Cursor start( m_commandRange.startLine, m_commandRange.startColumn );
  705. Cursor end( m_commandRange.endLine, m_commandRange.endColumn );
  706. Range range( start, end );
  707. doc()->replaceText( range, upperCase, m == Block );
  708. if (m_viInputModeManager->getCurrentViMode() == NormalMode)
  709. updateCursor( start );
  710. else
  711. updateCursor(c);
  712. return true;
  713. }
  714. bool KateViNormalMode::commandMakeUppercaseLine()
  715. {
  716. Cursor c( m_view->cursorPosition() );
  717. m_commandRange.startLine = c.line();
  718. m_commandRange.endLine = c.line() + getCount() - 1;
  719. m_commandRange.startColumn = 0;
  720. m_commandRange.endColumn = doc()->lineLength( c.line() )-1;
  721. return commandMakeUppercase();
  722. }
  723. bool KateViNormalMode::commandChangeCase()
  724. {
  725. switchView();
  726. QString text;
  727. Range range;
  728. Cursor c( m_view->cursorPosition() );
  729. // in visual mode, the range is from start position to end position...
  730. if ( m_viInputModeManager->getCurrentViMode() == VisualMode
  731. || m_viInputModeManager->getCurrentViMode() == VisualBlockMode ) {
  732. Cursor c2 = m_viInputModeManager->getViVisualMode()->getStart();
  733. if ( c2 > c ) {
  734. c2.setColumn( c2.column()+1 );
  735. } else {
  736. c.setColumn( c.column()+1 );
  737. }
  738. range.setRange( c, c2 );
  739. // ... in visual line mode, the range is from column 0 on the first line to
  740. // the line length of the last line...
  741. } else if ( m_viInputModeManager->getCurrentViMode() == VisualLineMode ) {
  742. Cursor c2 = m_viInputModeManager->getViVisualMode()->getStart();
  743. if ( c2 > c ) {
  744. c2.setColumn( doc()->lineLength( c2.line() ) );
  745. c.setColumn( 0 );
  746. } else {
  747. c.setColumn( doc()->lineLength( c.line() ) );
  748. c2.setColumn( 0 );
  749. }
  750. range.setRange( c, c2 );
  751. // ... and in normal mode the range is from the current position to the
  752. // current position + count
  753. } else {
  754. Cursor c2 = c;
  755. c2.setColumn( c.column()+getCount() );
  756. if ( c2.column() > doc()->lineLength( c.line() ) ) {
  757. c2.setColumn( doc()->lineLength( c.line() ) );
  758. }
  759. range.setRange( c, c2 );
  760. }
  761. bool block = m_viInputModeManager->getCurrentViMode() == VisualBlockMode;
  762. // get the text the command should operate on
  763. text = doc()->text ( range, block );
  764. // for every character, switch its case
  765. for ( int i = 0; i < text.length(); i++ ) {
  766. if ( text.at(i).isUpper() ) {
  767. text[i] = text.at(i).toLower();
  768. } else if ( text.at(i).isLower() ) {
  769. text[i] = text.at(i).toUpper();
  770. }
  771. }
  772. // replace the old text with the modified text
  773. doc()->replaceText( range, text, block );
  774. // in normal mode, move the cursor to the right, in visual mode move the
  775. // cursor to the start of the selection
  776. if ( m_viInputModeManager->getCurrentViMode() == NormalMode ) {
  777. updateCursor( range.end() );
  778. } else {
  779. updateCursor( range.start() );
  780. }
  781. return true;
  782. }
  783. bool KateViNormalMode::commandOpenNewLineUnder()
  784. {
  785. Cursor c( m_view->cursorPosition() );
  786. c.setColumn( doc()->lineLength( c.line() ) );
  787. updateCursor( c );
  788. for ( unsigned int i = 0; i < getCount(); i++ ) {
  789. doc()->newLine( m_view );
  790. }
  791. m_stickyColumn = -1;
  792. startInsertMode();
  793. m_viewInternal->repaint ();
  794. return true;
  795. }
  796. bool KateViNormalMode::commandOpenNewLineOver()
  797. {
  798. Cursor c( m_view->cursorPosition() );
  799. if ( c.line() == 0 ) {
  800. for (unsigned int i = 0; i < getCount(); i++ ) {
  801. doc()->insertLine( 0, QString() );
  802. }
  803. c.setColumn( 0 );
  804. c.setLine( 0 );
  805. updateCursor( c );
  806. } else {
  807. c.setLine( c.line()-1 );
  808. c.setColumn( getLine( c.line() ).length() );
  809. updateCursor( c );
  810. for ( unsigned int i = 0; i < getCount(); i++ ) {
  811. doc()->newLine( m_view );
  812. }
  813. if ( getCount() > 1 ) {
  814. c = m_view->cursorPosition();
  815. c.setLine( c.line()-(getCount()-1 ) );
  816. updateCursor( c );
  817. }
  818. //c.setLine( c.line()-getCount() );
  819. }
  820. m_stickyColumn = -1;
  821. startInsertMode();
  822. m_viewInternal->repaint ();
  823. return true;
  824. }
  825. bool KateViNormalMode::commandJoinLines()
  826. {
  827. Cursor c( m_view->cursorPosition() );
  828. // remember line length so the cursor can be put between the joined lines
  829. int l = doc()->lineLength( c.line() );
  830. unsigned int from = c.line();
  831. unsigned int to = c.line()+getCount();
  832. // if we were given a range of lines, this information overrides the previous
  833. if ( m_commandRange.startLine != -1 && m_commandRange.endLine != -1 ) {
  834. m_commandRange.normalize();
  835. c.setLine ( m_commandRange.startLine );
  836. to = m_commandRange.endLine;
  837. }
  838. joinLines( from, to );
  839. // position cursor between the joined lines
  840. c.setColumn( l );
  841. updateCursor( c );
  842. m_deleteCommand = true;
  843. return true;
  844. }
  845. bool KateViNormalMode::commandChange()
  846. {
  847. Cursor c( m_view->cursorPosition() );
  848. OperationMode m = getOperationMode();
  849. doc()->editStart();
  850. commandDelete();
  851. // if we deleted several lines, insert an empty line and put the cursor there
  852. if ( m == LineWise ) {
  853. doc()->insertLine( m_commandRange.startLine, QString() );
  854. c.setLine( m_commandRange.startLine );
  855. c.setColumn(0);
  856. }
  857. doc()->editEnd();
  858. if ( m == LineWise ) {
  859. updateCursor( c );
  860. }
  861. // block substitute can be simulated by first deleting the text (done above) and then starting
  862. // block prepend
  863. if ( m == Block ) {
  864. return commandPrependToBlock();
  865. }
  866. commandEnterInsertMode();
  867. // correct indentation level
  868. if ( m == LineWise ) {
  869. m_view->align();
  870. }
  871. m_deleteCommand = true;
  872. return true;
  873. }
  874. bool KateViNormalMode::commandChangeToEOL()
  875. {
  876. commandDeleteToEOL();
  877. if ( getOperationMode() == Block ) {
  878. return commandPrependToBlock();
  879. }
  880. m_deleteCommand = true;
  881. return commandEnterInsertModeAppend();
  882. }
  883. bool KateViNormalMode::commandChangeLine()
  884. {
  885. m_deleteCommand = true;
  886. Cursor c( m_view->cursorPosition() );
  887. c.setColumn( 0 );
  888. updateCursor( c );
  889. doc()->editStart();
  890. // if count >= 2 start by deleting the whole lines
  891. if ( getCount() >= 2 ) {
  892. KateViRange r( c.line(), 0, c.line()+getCount()-2, 0, ViMotion::InclusiveMotion );
  893. deleteRange( r );
  894. }
  895. // ... then delete the _contents_ of the last line, but keep the line
  896. KateViRange r( c.line(), c.column(), c.line(), doc()->lineLength( c.line() )-1,
  897. ViMotion::InclusiveMotion );
  898. deleteRange( r, CharWise, true );
  899. doc()->editEnd();
  900. // ... then enter insert mode
  901. if ( getOperationMode() == Block ) {
  902. return commandPrependToBlock();
  903. }
  904. commandEnterInsertModeAppend();
  905. // correct indentation level
  906. m_view->align();
  907. return true;
  908. }
  909. bool KateViNormalMode::commandSubstituteChar()
  910. {
  911. if ( commandDeleteChar() ) {
  912. return commandEnterInsertMode();
  913. }
  914. m_deleteCommand = true;
  915. return false;
  916. }
  917. bool KateViNormalMode::commandSubstituteLine()
  918. {
  919. m_deleteCommand = true;
  920. return commandChangeLine();
  921. }
  922. bool KateViNormalMode::commandYank()
  923. {
  924. Cursor c( m_view->cursorPosition() );
  925. bool r = false;
  926. QString yankedText;
  927. OperationMode m = getOperationMode();
  928. yankedText = getRange( m_commandRange, m );
  929. fillRegister( getChosenRegister( '0' ), yankedText, m );
  930. return r;
  931. }
  932. bool KateViNormalMode::commandYankLine()
  933. {
  934. Cursor c( m_view->cursorPosition() );
  935. QString lines;
  936. int linenum = c.line();
  937. for ( unsigned int i = 0; i < getCount(); i++ ) {
  938. lines.append( getLine( linenum + i ) + '\n' );
  939. }
  940. fillRegister( getChosenRegister( '0' ), lines, LineWise );
  941. return true;
  942. }
  943. bool KateViNormalMode::commandYankToEOL()
  944. {
  945. Cursor c( m_view->cursorPosition() );
  946. bool r = false;
  947. QString yankedText;
  948. m_commandRange.endLine = c.line()+getCount()-1;
  949. m_commandRange.endColumn = doc()->lineLength( m_commandRange.endLine )-1;
  950. OperationMode m = CharWise;
  951. if ( m_viInputModeManager->getCurrentViMode() == VisualMode
  952. || m_viInputModeManager->getCurrentViMode() == VisualLineMode ) {
  953. m = LineWise;
  954. KateViVisualMode* visualmode = static_cast<KateViVisualMode*>(this);
  955. visualmode->setStart( Cursor(visualmode->getStart().line(),0) );
  956. } else if (m_viInputModeManager->getCurrentViMode() == VisualBlockMode ) {
  957. m = Block;;
  958. }
  959. if ( m_viInputModeManager->getCurrentViMode() == NormalMode ) {
  960. m_commandRange.startLine = c.line();
  961. m_commandRange.startColumn = c.column();
  962. }
  963. yankedText = getRange( m_commandRange, m );
  964. fillRegister( getChosenRegister( '0' ), yankedText, m );
  965. return r;
  966. }
  967. // insert the text in the given register at the cursor position
  968. // the cursor should end up at the beginning of what was pasted
  969. bool KateViNormalMode::commandPasteLeaveCursorAtStart()
  970. {
  971. return paste(true);
  972. }
  973. // insert the text in the given register before the cursor position
  974. // the cursor should end up at the beginning of what was pasted
  975. bool KateViNormalMode::commandPasteBeforeLeaveCursorAtStart()
  976. {
  977. return pasteBefore(true);
  978. }
  979. // as with commandPasteLeaveCursorAtStart, but leaves the cursor at the end
  980. // of what was pasted
  981. bool KateViNormalMode::commandPasteLeaveCursorAtEnd()
  982. {
  983. return paste(false);
  984. }
  985. // as with commandPasteBeforeLeaveCursorAtStart, but leaves the cursor at the end
  986. // of what was pasted
  987. bool KateViNormalMode::commandPasteBeforeLeaveCursorAtEnd()
  988. {
  989. return pasteBefore(false);
  990. }
  991. bool KateViNormalMode::commandDeleteChar()
  992. {
  993. Cursor c( m_view->cursorPosition() );
  994. KateViRange r( c.line(), c.column(), c.line(), c.column()+getCount(), ViMotion::ExclusiveMotion );
  995. if ( m_commandRange.startLine != -1 && m_commandRange.startColumn != -1 ) {
  996. r = m_commandRange;
  997. } else {
  998. if ( r.endColumn > doc()->lineLength( r.startLine ) ) {
  999. r.endColumn = doc()->lineLength( r.startLine );
  1000. }
  1001. }
  1002. // should delete entire lines if in visual line mode and selection in visual block mode
  1003. OperationMode m = CharWise;
  1004. if ( m_viInputModeManager->getCurrentViMode() == VisualLineMode ) {
  1005. m = LineWise;
  1006. } else if ( m_viInputModeManager->getCurrentViMode() == VisualBlockMode ) {
  1007. m = Block;
  1008. }
  1009. m_deleteCommand = true;
  1010. return deleteRange( r, m );
  1011. }
  1012. bool KateViNormalMode::commandDeleteCharBackward()
  1013. {
  1014. Cursor c( m_view->cursorPosition() );
  1015. KateViRange r( c.line(), c.column()-getCount(), c.line(), c.column(), ViMotion::ExclusiveMotion );
  1016. if ( m_commandRange.startLine != -1 && m_commandRange.startColumn != -1 ) {
  1017. r = m_commandRange;
  1018. } else {
  1019. if ( r.startColumn < 0 ) {
  1020. r.startColumn = 0;
  1021. }
  1022. }
  1023. // should delete entire lines if in visual line mode and selection in visual block mode
  1024. OperationMode m = CharWise;
  1025. if ( m_viInputModeManager->getCurrentViMode() == VisualLineMode ) {
  1026. m = LineWise;
  1027. } else if ( m_viInputModeManager->getCurrentViMode() == VisualBlockMode ) {
  1028. m = Block;
  1029. }
  1030. m_deleteCommand = true;
  1031. return deleteRange( r, m );
  1032. }
  1033. bool KateViNormalMode::commandReplaceCharacter()
  1034. {
  1035. bool r;
  1036. if ( m_viInputModeManager->getCurrentViMode() == VisualMode
  1037. || m_viInputModeManager->getCurrentViMode() == VisualLineMode
  1038. || m_viInputModeManager->getCurrentViMode() == VisualBlockMode ) {
  1039. OperationMode m = getOperationMode();
  1040. QString text = getRange( m_commandRange, m );
  1041. if (m == LineWise)
  1042. text = text.left(text.size() - 1); // don't need '\n' at the end;
  1043. text.replace( QRegExp( "[^\n]" ), m_keys.right( 1 ) );
  1044. m_commandRange.normalize();
  1045. Cursor start( m_commandRange.startLine, m_commandRange.startColumn );
  1046. Cursor end( m_commandRange.endLine, m_commandRange.endColumn );
  1047. Range range( start, end );
  1048. r = doc()->replaceText( range, text, m == Block );
  1049. } else {
  1050. Cursor c1( m_view->cursorPosition() );
  1051. Cursor c2( m_view->cursorPosition() );
  1052. c2.setColumn( c2.column()+1 );
  1053. r = doc()->replaceText( Range( c1, c2 ), m_keys.right( 1 ) );
  1054. updateCursor( c1 );
  1055. }
  1056. m_ignoreMapping = false;
  1057. return r;
  1058. }
  1059. bool KateViNormalMode::commandSwitchToCmdLine()
  1060. {
  1061. Cursor c( m_view->cursorPosition() );
  1062. m_view->switchToCmdLine();
  1063. if ( m_viInputModeManager->getCurrentViMode() == VisualMode
  1064. || m_viInputModeManager->getCurrentViMode() == VisualLineMode
  1065. || m_viInputModeManager->getCurrentViMode() == VisualBlockMode ) {
  1066. // if in visual mode, make command range == visual selection
  1067. m_viInputModeManager->getViVisualMode()->saveRangeMarks();
  1068. m_view->cmdLineBar()->setText( "'<,'>", false );
  1069. }
  1070. else if ( getCount() != 1 ) {
  1071. // if a count is given, the range [current line] to [current line] +
  1072. // count should be prepended to the command line
  1073. m_view->cmdLineBar()->setText( ".,.+" +QString::number( getCount()-1 ), false);
  1074. }
  1075. m_commandShouldKeepSelection = true;
  1076. return true;
  1077. }
  1078. bool KateViNormalMode::commandSearchBackward()
  1079. {
  1080. m_view->find();
  1081. m_viInputModeManager->setLastSearchBackwards( true );
  1082. return true;
  1083. }
  1084. bool KateViNormalMode::commandSearchForward()
  1085. {
  1086. m_view->find();
  1087. m_viInputModeManager->setLastSearchBackwards( false );
  1088. return true;
  1089. }
  1090. bool KateViNormalMode::commandUndo()
  1091. {
  1092. doc()->undo();
  1093. return true;
  1094. }
  1095. bool KateViNormalMode::commandRedo()
  1096. {
  1097. doc()->redo();
  1098. return true;
  1099. }
  1100. bool KateViNormalMode::commandSetMark()
  1101. {
  1102. Cursor c( m_view->cursorPosition() );
  1103. m_view->getViInputModeManager()->addMark( doc(), m_keys.at( m_keys.size()-1 ), c );
  1104. kDebug( 13070 ) << "set mark at (" << c.line() << "," << c.column() << ")";
  1105. return true;
  1106. }
  1107. bool KateViNormalMode::commandIndentLine()
  1108. {
  1109. Cursor c( m_view->cursorPosition() );
  1110. for ( unsigned int i = 0; i < getCount(); i++ ) {
  1111. doc()->indent( KTextEditor::Range( c.line()+i, 0, c.line()+i, 0), 1 );
  1112. }
  1113. return true;
  1114. }
  1115. bool KateViNormalMode::commandUnindentLine()
  1116. {
  1117. Cursor c( m_view->cursorPosition() );
  1118. for ( unsigned int i = 0; i < getCount(); i++ ) {
  1119. doc()->indent( KTextEditor::Range( c.line()+i, 0, c.line()+i, 0), -1 );
  1120. }
  1121. return true;
  1122. }
  1123. bool KateViNormalMode::commandIndentLines()
  1124. {
  1125. Cursor c( m_view->cursorPosition() );
  1126. m_commandRange.normalize();
  1127. int line1 = m_commandRange.startLine;
  1128. int line2 = m_commandRange.endLine;
  1129. int col = getLine( line2 ).length();
  1130. doc()->indent( KTextEditor::Range( line1, 0, line2, col ), getCount() );
  1131. return true;
  1132. }
  1133. bool KateViNormalMode::commandUnindentLines()
  1134. {
  1135. Cursor c( m_view->cursorPosition() );
  1136. m_commandRange.normalize();
  1137. int line1 = m_commandRange.startLine;
  1138. int line2 = m_commandRange.endLine;
  1139. doc()->indent( KTextEditor::Range( line1, 0, line2, doc()->lineLength( line2 ) ), -getCount() );
  1140. return true;
  1141. }
  1142. bool KateViNormalMode::commandScrollPageDown()
  1143. {
  1144. if ( getCount() < m_scroll_count_limit ) {
  1145. for(uint i = 0; i < getCount(); i++)
  1146. m_view->pageDown();
  1147. }
  1148. return true;
  1149. }
  1150. bool KateViNormalMode::commandScrollPageUp()
  1151. {
  1152. if ( getCount() < m_scroll_count_limit ) {
  1153. for(uint i=0; i < getCount(); i++)
  1154. m_view->pageUp();
  1155. }
  1156. return true;
  1157. }
  1158. bool KateViNormalMode::commandScrollHalfPageUp()
  1159. {
  1160. if ( getCount() < m_scroll_count_limit ) {
  1161. for(uint i=0; i < getCount(); i++)
  1162. m_viewInternal->pageUp(false, true);
  1163. }
  1164. return true;
  1165. }
  1166. bool KateViNormalMode::commandScrollHalfPageDown()
  1167. {
  1168. if ( getCount() < m_scroll_count_limit ) {
  1169. for(uint i=0; i < getCount(); i++)
  1170. m_viewInternal->pageDown(false, true);
  1171. }
  1172. return true;
  1173. }
  1174. bool KateViNormalMode::commandCentreViewOnCursor()
  1175. {
  1176. Cursor c( m_view->cursorPosition() );
  1177. int linesToScroll = (m_viewInternal->endLine()-linesDisplayed()/2)-c.line();
  1178. scrollViewLines( -linesToScroll );
  1179. return true;
  1180. }
  1181. bool KateViNormalMode::commandAbort()
  1182. {
  1183. m_pendingResetIsDueToExit = true;
  1184. reset();
  1185. return true;
  1186. }
  1187. bool KateViNormalMode::commandPrintCharacterCode()
  1188. {
  1189. QChar ch = getCharUnderCursor();
  1190. if ( ch == QChar::Null ) {
  1191. message( QString( "NUL" ) );
  1192. } else {
  1193. int code = ch.unicode();
  1194. QString dec = QString::number( code );
  1195. QString hex = QString::number( code, 16 );
  1196. QString oct = QString::number( code, 8 );
  1197. if ( oct.length() < 3 ) { oct.prepend( '0' ); }
  1198. if ( code > 0x80 && code < 0x1000 ) { hex.prepend( ( code < 0x100 ? "00" : "0" ) ); }
  1199. message( i18n("'%1' %2, Hex %3, Octal %4", ch, dec, hex, oct ) );
  1200. }
  1201. return true;
  1202. }
  1203. bool KateViNormalMode::commandRepeatLastChange()
  1204. {
  1205. resetParser();
  1206. doc()->editStart();
  1207. m_viInputModeManager->repeatLastChange();
  1208. doc()->editEnd();
  1209. return true;
  1210. }
  1211. bool KateViNormalMode::commandAlignLine()
  1212. {
  1213. const int line = m_view->cursorPosition().line();
  1214. Range alignRange( Cursor(line, 0), Cursor(line, 0) );
  1215. doc()->align( m_view, alignRange );
  1216. return true;
  1217. }
  1218. bool KateViNormalMode::commandAlignLines()
  1219. {
  1220. Cursor c( m_view->cursorPosition() );
  1221. m_commandRange.normalize();
  1222. Cursor start(m_commandRange.startLine, 0);
  1223. Cursor end(m_commandRange.endLine, 0);
  1224. doc()->align( m_view, Range( start, end ) );
  1225. return true;
  1226. }
  1227. bool KateViNormalMode::commandAddToNumber()
  1228. {
  1229. addToNumberUnderCursor( getCount() );
  1230. return true;
  1231. }
  1232. bool KateViNormalMode::commandSubtractFromNumber()
  1233. {
  1234. addToNumberUnderCursor( -getCount() );
  1235. return true;
  1236. }
  1237. bool KateViNormalMode::commandPrependToBlock()
  1238. {
  1239. Cursor c( m_view->cursorPosition() );
  1240. // move cursor to top left corner of selection
  1241. m_commandRange.normalize();
  1242. c.setColumn( m_commandRange.startColumn );
  1243. c.setLine( m_commandRange.startLine );
  1244. updateCursor( c );
  1245. m_stickyColumn = -1;
  1246. m_viInputModeManager->getViInsertMode()->setBlockPrependMode( m_commandRange );
  1247. return startInsertMode();
  1248. }
  1249. bool KateViNormalMode::commandAppendToBlock()
  1250. {
  1251. Cursor c( m_view->cursorPosition() );
  1252. m_commandRange.normalize();
  1253. if ( m_stickyColumn == (unsigned int)KateVi::EOL ) { // append to EOL
  1254. // move cursor to end of first line
  1255. c.setLine( m_commandRange.startLine );
  1256. c.setColumn( doc()->lineLength( c.line() ) );
  1257. updateCursor( c );
  1258. m_viInputModeManager->getViInsertMode()->setBlockAppendMode( m_commandRange, AppendEOL );
  1259. } else {
  1260. m_viInputModeManager->getViInsertMode()->setBlockAppendMode( m_commandRange, Append );
  1261. // move cursor to top right corner of selection
  1262. c.setColumn( m_commandRange.endColumn+1 );
  1263. c.setLine( m_commandRange.startLine );
  1264. updateCursor( c );
  1265. }
  1266. m_stickyColumn = -1;
  1267. return startInsertMode();
  1268. }
  1269. bool KateViNormalMode::commandGoToNextJump() {
  1270. Cursor c = getNextJump(m_view->cursorPosition());
  1271. updateCursor(c);
  1272. return true;
  1273. }
  1274. bool KateViNormalMode::commandGoToPrevJump() {
  1275. Cursor c = getPrevJump(m_view->cursorPosition());
  1276. updateCursor(c);
  1277. return true;
  1278. }
  1279. bool KateViNormalMode::commandSwitchToLeftView() {
  1280. switchView(Left);
  1281. return true;
  1282. }
  1283. bool KateViNormalMode::commandSwitchToDownView() {
  1284. switchView(Down);
  1285. return true;
  1286. }
  1287. bool KateViNormalMode::commandSwitchToUpView() {
  1288. switchView(Up);
  1289. return true;
  1290. }
  1291. bool KateViNormalMode::commandSwitchToRightView() {
  1292. switchView(Right);
  1293. return true;
  1294. }
  1295. bool KateViNormalMode::commandSwitchToNextView() {
  1296. switchView(Next);
  1297. return true;
  1298. }
  1299. bool KateViNormalMode::commandSplitHoriz() {
  1300. m_view->cmdLineBar()->execute("split");
  1301. return true;
  1302. }
  1303. bool KateViNormalMode::commandSplitVert() {
  1304. m_view->cmdLineBar()->execute("vsplit");
  1305. return true;
  1306. }
  1307. bool KateViNormalMode::commandSwitchToNextTab() {
  1308. QString command = "bn";
  1309. if ( m_iscounted )
  1310. command = command + " " + QString::number(getCount());
  1311. m_view->cmdLineBar()->execute(command);
  1312. return true;
  1313. }
  1314. bool KateViNormalMode::commandSwitchToPrevTab() {
  1315. QString command = "bp";
  1316. if ( m_iscounted )
  1317. command = command + " " + QString::number(getCount());
  1318. m_view->cmdLineBar()->execute(command);
  1319. return true;
  1320. }
  1321. bool KateViNormalMode::commandFormatLine()
  1322. {
  1323. Cursor c( m_view->cursorPosition() );
  1324. reformatLines( c.line(), c.line()+getCount()-1 );
  1325. return true;
  1326. }
  1327. bool KateViNormalMode::commandFormatLines()
  1328. {
  1329. reformatLines( m_commandRange.startLine, m_commandRange.endLine );
  1330. return true;
  1331. }
  1332. bool KateViNormalMode::commandCollapseToplevelNodes()
  1333. {
  1334. doc()->foldingTree()->collapseToplevelNodes();
  1335. return true;
  1336. }
  1337. bool KateViNormalMode::commandCollapseLocal()
  1338. {
  1339. Cursor c( m_view->cursorPosition() );
  1340. doc()->foldingTree()->collapseOne( c.line(), c.column() );
  1341. return true;
  1342. }
  1343. bool KateViNormalMode::commandExpandAll() {
  1344. doc()->foldingTree()->expandAll();
  1345. return true;
  1346. }
  1347. bool KateViNormalMode::commandExpandLocal()
  1348. {
  1349. Cursor c( m_view->cursorPosition() );
  1350. doc()->foldingTree()->expandOne( c.line() + 1, c.column() );
  1351. return true;
  1352. }
  1353. bool KateViNormalMode::commandToggleRegionVisibility()
  1354. {
  1355. Cursor c( m_view->cursorPosition() );
  1356. doc()->foldingTree()->toggleRegionVisibility( c.line() );
  1357. return true;
  1358. }
  1359. ////////////////////////////////////////////////////////////////////////////////
  1360. // MOTIONS
  1361. ////////////////////////////////////////////////////////////////////////////////
  1362. KateViRange KateViNormalMode::motionDown()
  1363. {
  1364. return goLineDown();
  1365. }
  1366. KateViRange KateViNormalMode::motionUp()
  1367. {
  1368. return goLineUp();
  1369. }
  1370. KateViRange KateViNormalMode::motionLeft()
  1371. {
  1372. Cursor cursor ( m_view->cursorPosition() );
  1373. m_stickyColumn = -1;
  1374. KateViRange r( cursor.line(), cursor.column(), ViMotion::ExclusiveMotion );
  1375. r.endColumn -= getCount();
  1376. if ( r.endColumn < 0 ) {
  1377. r.endColumn = 0;
  1378. }
  1379. return r;
  1380. }
  1381. KateViRange KateViNormalMode::motionRight()
  1382. {
  1383. Cursor cursor ( m_view->cursorPosition() );
  1384. m_stickyColumn = -1;
  1385. KateViRange r( cursor.line(), cursor.column(), ViMotion::ExclusiveMotion );
  1386. r.endColumn += getCount();
  1387. // make sure end position isn't > line length
  1388. if ( r.endColumn > doc()->lineLength( r.endLine ) ) {
  1389. r.endColumn = doc()->lineLength( r.endLine );
  1390. }
  1391. return r;
  1392. }
  1393. KateViRange KateViNormalMode::motionPageDown()
  1394. {
  1395. Cursor c( m_view->cursorPosition() );
  1396. int linesToScroll = linesDisplayed();
  1397. KateViRange r( c.line()+linesToScroll, c.column(), ViMotion::InclusiveMotion );
  1398. if ( r.endLine >= doc()->lines() ) {
  1399. r.endLine = doc()->lines()-1;
  1400. }
  1401. return r;
  1402. }
  1403. KateViRange KateViNormalMode::motionPageUp()
  1404. {
  1405. Cursor c( m_view->cursorPosition() );
  1406. int linesToScroll = linesDisplayed();
  1407. KateViRange r( c.line()-linesToScroll, c.column(), ViMotion::InclusiveMotion );
  1408. if ( r.endLine < 0 ) {
  1409. r.endLine = 0;
  1410. }
  1411. return r;
  1412. }
  1413. KateViRange KateViNormalMode::motionDownToFirstNonBlank()
  1414. {
  1415. Cursor c( m_view->cursorPosition() );
  1416. KateViRange r = goLineDown();
  1417. r.endColumn = getLine( r.endLine ).indexOf( QRegExp( "\\S" ) );
  1418. if ( r.endColumn < 0 ) {
  1419. r.endColumn = 0;
  1420. }
  1421. return r;
  1422. }
  1423. KateViRange KateViNormalMode::motionUpToFirstNonBlank()
  1424. {
  1425. Cursor c( m_view->cursorPosition() );
  1426. KateViRange r = goLineUp();
  1427. r.endColumn = getLine( r.endLine ).indexOf( QRegExp( "\\S" ) );
  1428. if ( r.endColumn < 0 ) {
  1429. r.endColumn = 0;
  1430. }
  1431. return r;
  1432. }
  1433. KateViRange KateViNormalMode::motionWordForward()
  1434. {
  1435. Cursor c( m_view->cursorPosition() );
  1436. KateViRange r( c.line(), c.column(), ViMotion::ExclusiveMotion );
  1437. m_stickyColumn = -1;
  1438. // Special case: If we're already on the very last character in the document, the motion should be
  1439. // inclusive so the last character gets included
  1440. if ( c.line() == doc()->lines()-1 && c.column() == doc()->lineLength( c.line() )-1 ) {
  1441. r.motionType = ViMotion::InclusiveMotion;
  1442. } else {
  1443. for ( unsigned int i = 0; i < getCount(); i++ ) {
  1444. c = findNextWordStart( c.line(), c.column() );
  1445. // stop when at the last char in the document
  1446. if ( c.line() == doc()->lines()-1 && c.column() == doc()->lineLength( c.line() )-1 ) {
  1447. // if we still haven't "used up the count", make the motion inclusive, so that the last char
  1448. // is included
  1449. if ( i < getCount() ) {
  1450. r.motionType = ViMotion::InclusiveMotion;
  1451. }
  1452. break;
  1453. }
  1454. }
  1455. }
  1456. r.endColumn = c.column();
  1457. r.endLine = c.line();
  1458. return r;
  1459. }
  1460. KateViRange KateViNormalMode::motionWordBackward()
  1461. {
  1462. Cursor c( m_view->cursorPosition() );
  1463. KateViRange r( c.line(), c.column(), ViMotion::ExclusiveMotion );
  1464. m_stickyColumn = -1;
  1465. for ( unsigned int i = 0; i < getCount(); i++ ) {
  1466. c = findPrevWordStart( c.line(), c.column() );
  1467. // stop when at the first char in the document
  1468. if ( c.line() == 0 && c.column() == 0 ) {
  1469. break;
  1470. }
  1471. }
  1472. r.endColumn = c.column();
  1473. r.endLine = c.line();
  1474. return r;
  1475. }
  1476. KateViRange KateViNormalMode::motionWORDForward()
  1477. {
  1478. Cursor c( m_view->cursorPosition() );
  1479. KateViRange r( c.line(), c.column(), ViMotion::ExclusiveMotion );
  1480. m_stickyColumn = -1;
  1481. for ( unsigned int i = 0; i < getCount(); i++ ) {
  1482. c = findNextWORDStart( c.line(), c.column() );
  1483. // stop when at the last char in the document
  1484. if ( c.line() == doc()->lines()-1 && c.column() == doc()->lineLength( c.line() )-1 ) {
  1485. break;
  1486. }
  1487. }
  1488. r.endColumn = c.column();
  1489. r.endLine = c.line();
  1490. return r;
  1491. }
  1492. KateViRange KateViNormalMode::motionWORDBackward()
  1493. {
  1494. Cursor c( m_view->cursorPosition() );
  1495. KateViRange r( c.line(), c.column(), ViMotion::ExclusiveMotion );
  1496. m_stickyColumn = -1;
  1497. for ( unsigned int i = 0; i < getCount(); i++ ) {
  1498. c = findPrevWORDStart( c.line(), c.column() );
  1499. // stop when at the first char in the document
  1500. if ( c.line() == 0 && c.column() == 0 ) {
  1501. break;
  1502. }
  1503. }
  1504. r.endColumn = c.column();
  1505. r.endLine = c.line();
  1506. return r;
  1507. }
  1508. KateViRange KateViNormalMode::motionToEndOfWord()
  1509. {
  1510. Cursor c( m_view->cursorPosition() );
  1511. KateViRange r( c.line(), c.column(), ViMotion::InclusiveMotion );
  1512. m_stickyColumn = -1;
  1513. for ( unsigned int i = 0; i < getCount(); i++ ) {
  1514. c = findWordEnd( c.line(), c.column() );
  1515. }
  1516. r.endColumn = c.column();
  1517. r.endLine = c.line();
  1518. return r;
  1519. }
  1520. KateViRange KateViNormalMode::motionToEndOfWORD()
  1521. {
  1522. Cursor c( m_view->cursorPosition() );
  1523. KateViRange r( c.line(), c.column(), ViMotion::InclusiveMotion );
  1524. m_stickyColumn = -1;
  1525. for ( unsigned int i = 0; i < getCount(); i++ ) {
  1526. c = findWORDEnd( c.line(), c.column() );
  1527. }
  1528. r.endColumn = c.column();
  1529. r.endLine = c.line();
  1530. return r;
  1531. }
  1532. KateViRange KateViNormalMode::motionToEndOfPrevWord()
  1533. {
  1534. Cursor c( m_view->cursorPosition() );
  1535. KateViRange r( c.line(), c.column(), ViMotion::InclusiveMotion );
  1536. m_stickyColumn = -1;
  1537. for ( unsigned int i = 0; i < getCount(); i++ ) {
  1538. c = findPrevWordEnd( c.line(), c.column() );
  1539. // stop when at the first char in the document
  1540. if ( c.line() == 0 && c.column() == 0 ) {
  1541. break;
  1542. }
  1543. }
  1544. r.endColumn = c.column();
  1545. r.endLine = c.line();
  1546. return r;
  1547. }
  1548. KateViRange KateViNormalMode::motionToEndOfPrevWORD()
  1549. {
  1550. Cursor c( m_view->cursorPosition() );
  1551. KateViRange r( c.line(), c.column(), ViMotion::InclusiveMotion );
  1552. m_stickyColumn = -1;
  1553. for ( unsigned int i = 0; i < getCount(); i++ ) {
  1554. c = findPrevWORDEnd( c.line(), c.column() );
  1555. // stop when at the first char in the document
  1556. if ( c.line() == 0 && c.column() == 0 ) {
  1557. break;
  1558. }
  1559. }
  1560. r.endColumn = c.column();
  1561. r.endLine = c.line();
  1562. return r;
  1563. }
  1564. KateViRange KateViNormalMode::motionToEOL()
  1565. {
  1566. Cursor c( m_view->cursorPosition() );
  1567. // set sticky column to a ridiculously high value so that the cursor will stick to EOL,
  1568. // but only if it's a regular motion
  1569. if ( m_keys.size() == 1 ) {
  1570. m_stickyColumn = KateVi::EOL;
  1571. }
  1572. unsigned int line = c.line() + ( getCount() - 1 );
  1573. KateViRange r( line, doc()->lineLength(line )-1, ViMotion::InclusiveMotion );
  1574. return r;
  1575. }
  1576. KateViRange KateViNormalMode::motionToColumn0()
  1577. {
  1578. m_stickyColumn = -1;
  1579. Cursor cursor ( m_view->cursorPosition() );
  1580. KateViRange r( cursor.line(), 0, ViMotion::ExclusiveMotion );
  1581. return r;
  1582. }
  1583. KateViRange KateViNormalMode::motionToFirstCharacterOfLine()
  1584. {
  1585. m_stickyColumn = -1;
  1586. Cursor cursor ( m_view->cursorPosition() );
  1587. QRegExp nonSpace( "\\S" );
  1588. int c = getLine().indexOf( nonSpace );
  1589. KateViRange r( cursor.line(), c, ViMotion::ExclusiveMotion );
  1590. return r;
  1591. }
  1592. KateViRange KateViNormalMode::motionFindChar()
  1593. {
  1594. m_lastTFcommand = m_keys;
  1595. Cursor cursor ( m_view->cursorPosition() );
  1596. QString line = getLine();
  1597. m_stickyColumn = -1;
  1598. int matchColumn = cursor.column();
  1599. for ( unsigned int i = 0; i < getCount(); i++ ) {
  1600. matchColumn = line.indexOf( m_keys.right( 1 ), matchColumn+1 );
  1601. if ( matchColumn == -1 )
  1602. break;
  1603. }
  1604. KateViRange r;
  1605. r.startColumn = cursor.column();
  1606. r.startLine = cursor.line();
  1607. r.endColumn = matchColumn;
  1608. r.endLine = cursor.line();
  1609. return r;
  1610. }
  1611. KateViRange KateViNormalMode::motionFindCharBackward()
  1612. {
  1613. m_lastTFcommand = m_keys;
  1614. Cursor cursor ( m_view->cursorPosition() );
  1615. QString line = getLine();
  1616. m_stickyColumn = -1;
  1617. int matchColumn = -1;
  1618. unsigned int hits = 0;
  1619. int i = cursor.column()-1;
  1620. while ( hits != getCount() && i >= 0 ) {
  1621. if ( line.at( i ) == m_keys.at( m_keys.size()-1 ) )
  1622. hits++;
  1623. if ( hits == getCount() )
  1624. matchColumn = i;
  1625. i--;
  1626. }
  1627. KateViRange r;
  1628. r.endColumn = matchColumn;
  1629. r.endLine = cursor.line();
  1630. return r;
  1631. }
  1632. KateViRange KateViNormalMode::motionToChar()
  1633. {
  1634. m_lastTFcommand = m_keys;
  1635. Cursor cursor ( m_view->cursorPosition() );
  1636. QString line = getLine();
  1637. m_stickyColumn = -1;
  1638. int matchColumn = cursor.column()+ (m_isRepeatedTFcommand ? 2 : 1);
  1639. for ( unsigned int i = 0; i < getCount(); i++ ) {
  1640. matchColumn = line.indexOf( m_keys.right( 1 ), matchColumn );
  1641. if ( matchColumn == -1 )
  1642. break;
  1643. }
  1644. KateViRange r;
  1645. r.endColumn = matchColumn-1;
  1646. r.endLine = cursor.line();
  1647. m_isRepeatedTFcommand = false;
  1648. return r;
  1649. }
  1650. KateViRange KateViNormalMode::motionToCharBackward()
  1651. {
  1652. m_lastTFcommand = m_keys;
  1653. Cursor cursor ( m_view->cursorPosition() );
  1654. QString line = getLine();
  1655. m_stickyColumn = -1;
  1656. int matchColumn = -1;
  1657. unsigned int hits = 0;
  1658. int i = cursor.column()- (m_isRepeatedTFcommand ? 2 : 1);
  1659. while ( hits != getCount() && i >= 0 ) {
  1660. if ( line.at( i ) == m_keys.at( m_keys.size()-1 ) )
  1661. hits++;
  1662. if ( hits == getCount() )
  1663. matchColumn = i;
  1664. i--;
  1665. }
  1666. KateViRange r;
  1667. r.endColumn = matchColumn+1;
  1668. r.endLine = cursor.line();
  1669. m_isRepeatedTFcommand = false;
  1670. return r;
  1671. }
  1672. KateViRange KateViNormalMode::motionRepeatlastTF()
  1673. {
  1674. if ( !m_lastTFcommand.isEmpty() ) {
  1675. m_isRepeatedTFcommand = true;
  1676. m_keys = m_lastTFcommand;
  1677. if ( m_keys.at( 0 ) == 'f' ) {
  1678. return motionFindChar();
  1679. }
  1680. else if ( m_keys.at( 0 ) == 'F' ) {
  1681. return motionFindCharBackward();
  1682. }
  1683. else if ( m_keys.at( 0 ) == 't' ) {
  1684. return motionToChar();
  1685. }
  1686. else if ( m_keys.at( 0 ) == 'T' ) {
  1687. return motionToCharBackward();
  1688. }
  1689. }
  1690. // there was no previous t/f command
  1691. KateViRange r;
  1692. r.valid = false;
  1693. return r;
  1694. }
  1695. KateViRange KateViNormalMode::motionRepeatlastTFBackward()
  1696. {
  1697. if ( !m_lastTFcommand.isEmpty() ) {
  1698. m_isRepeatedTFcommand = true;
  1699. m_keys = m_lastTFcommand;
  1700. if ( m_keys.at( 0 ) == 'f' ) {
  1701. return motionFindCharBackward();
  1702. }
  1703. else if ( m_keys.at( 0 ) == 'F' ) {
  1704. return motionFindChar();
  1705. }
  1706. else if ( m_keys.at( 0 ) == 't' ) {
  1707. return motionToCharBackward();
  1708. }
  1709. else if ( m_keys.at( 0 ) == 'T' ) {
  1710. return motionToChar();
  1711. }
  1712. }
  1713. // there was no previous t/f command
  1714. KateViRange r;
  1715. r.valid = false;
  1716. return r;
  1717. }
  1718. // FIXME: should honour the provided count
  1719. KateViRange KateViNormalMode::motionFindPrev()
  1720. {
  1721. QString pattern = m_viInputModeManager->getLastSearchPattern();
  1722. bool backwards = m_viInputModeManager->lastSearchBackwards();
  1723. return findPattern( pattern, !backwards, getCount() );
  1724. }
  1725. KateViRange KateViNormalMode::motionFindNext()
  1726. {
  1727. QString pattern = m_viInputModeManager->getLastSearchPattern();
  1728. bool backwards = m_viInputModeManager->lastSearchBackwards();
  1729. return findPattern( pattern, backwards, getCount() );
  1730. }
  1731. KateViRange KateViNormalMode::motionToLineFirst()
  1732. {
  1733. KateViRange r( getCount()-1, 0, ViMotion::InclusiveMotion );
  1734. m_stickyColumn = -1;
  1735. if ( r.endLine > doc()->lines() - 1 ) {
  1736. r.endLine = doc()->lines() - 1;
  1737. }
  1738. r.jump = true;
  1739. return r;
  1740. }
  1741. KateViRange KateViNormalMode::motionToLineLast()
  1742. {
  1743. KateViRange r( doc()->lines()-1, 0, ViMotion::InclusiveMotion );
  1744. m_stickyColumn = -1;
  1745. // don't use getCount() here, no count and a count of 1 is different here...
  1746. if ( m_count != 0 ) {
  1747. r.endLine = m_count-1;
  1748. }
  1749. if ( r.endLine > doc()->lines() - 1 ) {
  1750. r.endLine = doc()->lines() - 1;
  1751. }
  1752. r.jump = true;
  1753. return r;
  1754. }
  1755. KateViRange KateViNormalMode::motionToScreenColumn()
  1756. {
  1757. m_stickyColumn = -1;
  1758. Cursor c( m_view->cursorPosition() );
  1759. int column = getCount()-1;
  1760. if ( doc()->lineLength( c.line() )-1 < (int)getCount()-1 ) {
  1761. column = doc()->lineLength( c.line() )-1;
  1762. }
  1763. return KateViRange( c.line(), column, ViMotion::ExclusiveMotion );
  1764. }
  1765. KateViRange KateViNormalMode::motionToMark()
  1766. {
  1767. KateViRange r;
  1768. m_stickyColumn = -1;
  1769. QChar reg = m_keys.at( m_keys.size()-1 );
  1770. // ` and ' is the same register (position before jump)
  1771. if ( reg == '`' ) {
  1772. reg = '\'';
  1773. }
  1774. Cursor c = m_view->getViInputModeManager()->getMarkPosition( reg );
  1775. if ( c.isValid() ) {
  1776. r.endLine = c.line();
  1777. r.endColumn = c.column();
  1778. } else {
  1779. error(i18n("Mark not set: %1",m_keys.right( 1 ) ));
  1780. r.valid = false;
  1781. }
  1782. r.jump = true;
  1783. return r;
  1784. }
  1785. KateViRange KateViNormalMode::motionToMarkLine()
  1786. {
  1787. KateViRange r = motionToMark();
  1788. r.endColumn = 0; // FIXME: should be first non-blank on line
  1789. m_stickyColumn = -1;
  1790. r.jump = true;
  1791. return r;
  1792. }
  1793. KateViRange KateViNormalMode::motionToMatchingItem()
  1794. {
  1795. KateViRange r;
  1796. int lines = doc()->lines();
  1797. // If counted, then it's not a motion to matching item anymore,
  1798. // but a motion to the N'th percentage of the document
  1799. if( isCounted() ) {
  1800. int count = getCount();
  1801. if ( count > 100 ) {
  1802. return r;
  1803. }
  1804. r.endLine = qRound(lines * count / 100.0) - 1;
  1805. r.endColumn = 0;
  1806. return r;
  1807. }
  1808. Cursor c( m_view->cursorPosition() );
  1809. r.startColumn = c.column();
  1810. r.startLine = c.line();
  1811. QString l = getLine();
  1812. int n1 = l.indexOf( m_matchItemRegex, c.column() );
  1813. m_stickyColumn = -1;
  1814. if ( n1 < 0 ) {
  1815. r.valid = false;
  1816. return r;
  1817. }
  1818. QRegExp brackets( "[(){}\\[\\]]" );
  1819. // use Kate's built-in matching bracket finder for brackets
  1820. if ( brackets.indexIn ( l, n1 ) == n1 ) {
  1821. // move the cursor to the first bracket
  1822. c.setColumn( n1 + 1 );
  1823. updateCursor( c );
  1824. // find the matching one
  1825. c = m_viewInternal->findMatchingBracket();
  1826. if ( c > m_view->cursorPosition() ) {
  1827. c.setColumn( c.column() - 1 );
  1828. }
  1829. } else {
  1830. // text item we want to find a matching item for
  1831. int n2 = l.indexOf( QRegExp( "\\b|\\s|$" ), n1 );
  1832. QString item = l.mid( n1, n2 - n1 );
  1833. QString matchingItem = m_matchingItems[ item ];
  1834. int toFind = 1;
  1835. int line = c.line();
  1836. int column = n2 - item.length();
  1837. bool reverse = false;
  1838. if ( matchingItem.left( 1 ) == "-" ) {
  1839. matchingItem.remove( 0, 1 ); // remove the '-'
  1840. reverse = true;
  1841. }
  1842. // make sure we don't hit the text item we started the search from
  1843. if ( column == 0 && reverse ) {
  1844. column -= item.length();
  1845. }
  1846. int itemIdx;
  1847. int matchItemIdx;
  1848. while ( toFind > 0 ) {
  1849. if ( reverse ) {
  1850. itemIdx = l.lastIndexOf( item, column - 1 );
  1851. matchItemIdx = l.lastIndexOf( matchingItem, column - 1 );
  1852. if ( itemIdx != -1 && ( matchItemIdx == -1 || itemIdx > matchItemIdx ) ) {
  1853. ++toFind;
  1854. }
  1855. } else {
  1856. itemIdx = l.indexOf( item, column );
  1857. matchItemIdx = l.indexOf( matchingItem, column );
  1858. if ( itemIdx != -1 && ( matchItemIdx == -1 || itemIdx < matchItemIdx ) ) {
  1859. ++toFind;
  1860. }
  1861. }
  1862. if ( matchItemIdx != -1 || itemIdx != -1 ) {
  1863. if ( !reverse ) {
  1864. column = qMin( (unsigned int)itemIdx, (unsigned int)matchItemIdx );
  1865. } else {
  1866. column = qMax( itemIdx, matchItemIdx );
  1867. }
  1868. }
  1869. if ( matchItemIdx != -1 ) { // match on current line
  1870. if ( matchItemIdx == column ) {
  1871. --toFind;
  1872. c.setLine( line );
  1873. c.setColumn( column );
  1874. }
  1875. } else { // no match, advance one line if possible
  1876. ( reverse ) ? --line : ++line;
  1877. column = 0;
  1878. if ( ( !reverse && line >= lines ) || ( reverse && line < 0 ) ) {
  1879. r.valid = false;
  1880. break;
  1881. } else {
  1882. l = getLine( line );
  1883. }
  1884. }
  1885. }
  1886. }
  1887. r.endLine = c.line();
  1888. r.endColumn = c.column();
  1889. r.jump = true;
  1890. return r;
  1891. }
  1892. KateViRange KateViNormalMode::motionToNextBraceBlockStart()
  1893. {
  1894. KateViRange r;
  1895. m_stickyColumn = -1;
  1896. int line = findLineStartingWitchChar( '{', getCount() );
  1897. if ( line == -1 ) {
  1898. r.valid = false;
  1899. return r;
  1900. }
  1901. r.endLine = line;
  1902. r.endColumn = 0;
  1903. r.jump = true;
  1904. return r;
  1905. }
  1906. KateViRange KateViNormalMode::motionToPreviousBraceBlockStart()
  1907. {
  1908. KateViRange r;
  1909. m_stickyColumn = -1;
  1910. int line = findLineStartingWitchChar( '{', getCount(), false );
  1911. if ( line == -1 ) {
  1912. r.valid = false;
  1913. return r;
  1914. }
  1915. r.endLine = line;
  1916. r.endColumn = 0;
  1917. r.jump = true;
  1918. return r;
  1919. }
  1920. KateViRange KateViNormalMode::motionToNextBraceBlockEnd()
  1921. {
  1922. KateViRange r;
  1923. m_stickyColumn = -1;
  1924. int line = findLineStartingWitchChar( '}', getCount() );
  1925. if ( line == -1 ) {
  1926. r.valid = false;
  1927. return r;
  1928. }
  1929. r.endLine = line;
  1930. r.endColumn = 0;
  1931. r.jump = true;
  1932. return r;
  1933. }
  1934. KateViRange KateViNormalMode::motionToPreviousBraceBlockEnd()
  1935. {
  1936. KateViRange r;
  1937. m_stickyColumn = -1;
  1938. int line = findLineStartingWitchChar( '}', getCount(), false );
  1939. if ( line == -1 ) {
  1940. r.valid = false;
  1941. return r;
  1942. }
  1943. r.endLine = line;
  1944. r.endColumn = 0;
  1945. r.jump = true;
  1946. return r;
  1947. }
  1948. KateViRange KateViNormalMode::motionToNextOccurrence()
  1949. {
  1950. QString word = getWordUnderCursor();
  1951. word.prepend("\\b").append("\\b");
  1952. m_viInputModeManager->setLastSearchPattern( word );
  1953. m_viInputModeManager->setLastSearchBackwards( false );
  1954. return findPattern( word, false, getCount() );
  1955. }
  1956. KateViRange KateViNormalMode::motionToPrevOccurrence()
  1957. {
  1958. QString word = getWordUnderCursor();
  1959. word.prepend("\\b").append("\\b");
  1960. m_viInputModeManager->setLastSearchPattern( word );
  1961. m_viInputModeManager->setLastSearchBackwards( true );
  1962. return findPattern( word, true, getCount() );
  1963. }
  1964. KateViRange KateViNormalMode::motionToFirstLineOfWindow() {
  1965. int lines_to_go;
  1966. if (linesDisplayed() <= (unsigned int) m_viewInternal->endLine())
  1967. lines_to_go = m_viewInternal->endLine() - linesDisplayed()- m_view->cursorPosition().line() + 1;
  1968. else
  1969. lines_to_go = - m_view->cursorPosition().line();
  1970. KateViRange r = goLineUpDown(lines_to_go);
  1971. // Finding first non-blank character
  1972. QRegExp nonSpace( "\\S" );
  1973. int c = getLine(r.endLine).indexOf( nonSpace );
  1974. if ( c == -1 )
  1975. c = 0;
  1976. r.endColumn = c;
  1977. return r;
  1978. }
  1979. KateViRange KateViNormalMode::motionToMiddleLineOfWindow() {
  1980. int lines_to_go;
  1981. if (linesDisplayed() <= (unsigned int) m_viewInternal->endLine())
  1982. lines_to_go = m_viewInternal->endLine() - linesDisplayed()/2 - m_view->cursorPosition().line();
  1983. else
  1984. lines_to_go = m_viewInternal->endLine()/2 - m_view->cursorPosition().line();
  1985. KateViRange r = goLineUpDown(lines_to_go);
  1986. // Finding first non-blank character
  1987. QRegExp nonSpace( "\\S" );
  1988. int c = getLine(r.endLine).indexOf( nonSpace );
  1989. if ( c == -1 )
  1990. c = 0;
  1991. r.endColumn = c;
  1992. return r;
  1993. }
  1994. KateViRange KateViNormalMode::motionToLastLineOfWindow() {
  1995. int lines_to_go;
  1996. if (linesDisplayed() <= (unsigned int) m_viewInternal->endLine())
  1997. lines_to_go = m_viewInternal->endLine() - m_view->cursorPosition().line();
  1998. else
  1999. lines_to_go = m_viewInternal->endLine() - m_view->cursorPosition().line();
  2000. KateViRange r = goLineUpDown(lines_to_go);
  2001. // Finding first non-blank character
  2002. QRegExp nonSpace( "\\S" );
  2003. int c = getLine(r.endLine).indexOf( nonSpace );
  2004. if ( c == -1 )
  2005. c = 0;
  2006. r.endColumn = c;
  2007. return r;
  2008. }
  2009. KateViRange KateViNormalMode::motionToNextVisualLine() {
  2010. return goVisualLineUpDown( getCount() );
  2011. }
  2012. KateViRange KateViNormalMode::motionToPrevVisualLine() {
  2013. return goVisualLineUpDown( -getCount() );
  2014. }
  2015. KateViRange KateViNormalMode::motionToBeforeParagraph()
  2016. {
  2017. Cursor c( m_view->cursorPosition() );
  2018. int line = c.line();
  2019. m_stickyColumn = -1;
  2020. for ( unsigned int i = 0; i < getCount(); i++ ) {
  2021. // advance at least one line, but if there are consecutive blank lines
  2022. // skip them all
  2023. do {
  2024. line--;
  2025. } while (line >= 0 && getLine( line+1 ).length() == 0);
  2026. while ( line > 0 && getLine( line ).length() != 0 ) {
  2027. line--;
  2028. }
  2029. }
  2030. if ( line < 0 ) {
  2031. line = 0;
  2032. }
  2033. KateViRange r( line, 0, ViMotion::InclusiveMotion );
  2034. return r;
  2035. }
  2036. KateViRange KateViNormalMode::motionToAfterParagraph()
  2037. {
  2038. Cursor c( m_view->cursorPosition() );
  2039. int line = c.line();
  2040. m_stickyColumn = -1;
  2041. for ( unsigned int i = 0; i < getCount(); i++ ) {
  2042. // advance at least one line, but if there are consecutive blank lines
  2043. // skip them all
  2044. do {
  2045. line++;
  2046. } while (line <= doc()->lines()-1 && getLine( line-1 ).length() == 0);
  2047. while ( line < doc()->lines()-1 && getLine( line ).length() != 0 ) {
  2048. line++;
  2049. }
  2050. }
  2051. if ( line >= doc()->lines() ) {
  2052. line = doc()->lines()-1;
  2053. }
  2054. // if we ended up on the last line, the cursor should be placed on the last column
  2055. int column = (line == doc()->lines()-1) ? qMax( getLine( line ).length()-1, 0 ) : 0;
  2056. KateViRange r( line, column, ViMotion::InclusiveMotion );
  2057. return r;
  2058. }
  2059. ////////////////////////////////////////////////////////////////////////////////
  2060. // TEXT OBJECTS
  2061. ////////////////////////////////////////////////////////////////////////////////
  2062. KateViRange KateViNormalMode::textObjectAWord()
  2063. {
  2064. Cursor c( m_view->cursorPosition() );
  2065. Cursor c1 = findPrevWordStart( c.line(), c.column()+1, true );
  2066. Cursor c2( c );
  2067. for ( unsigned int i = 0; i < getCount(); i++ ) {
  2068. c2 = findNextWordStart( c2.line(), c2.column(), true );
  2069. }
  2070. c2.setColumn( c2.column()-1 ); // don't include the first char of the following word
  2071. KateViRange r( c.line(), c.column(), ViMotion::InclusiveMotion );
  2072. // sanity check
  2073. if ( c1.line() != c2.line() || c1.column() > c2.column() ) {
  2074. r.valid = false;
  2075. } else {
  2076. r.startLine = c1.line();
  2077. r.endLine = c2.line();
  2078. r.startColumn = c1.column();
  2079. r.endColumn = c2.column();
  2080. }
  2081. return r;
  2082. }
  2083. KateViRange KateViNormalMode::textObjectInnerWord()
  2084. {
  2085. Cursor c( m_view->cursorPosition() );
  2086. Cursor c1 = findPrevWordStart( c.line(), c.column()+1, true );
  2087. // need to start search in column-1 because it might be a one-character word
  2088. Cursor c2( c.line(), c.column()-1 );
  2089. for ( unsigned int i = 0; i < getCount(); i++ ) {
  2090. c2 = findWordEnd( c2.line(), c2.column(), true );
  2091. }
  2092. KateViRange r;
  2093. // sanity check
  2094. if ( c1.line() != c2.line() || c1.column() > c2.column() ) {
  2095. r.valid = false;
  2096. } else {
  2097. r.startLine = c1.line();
  2098. r.endLine = c2.line();
  2099. r.startColumn = c1.column();
  2100. r.endColumn = c2.column();
  2101. }
  2102. return r;
  2103. }
  2104. KateViRange KateViNormalMode::textObjectAWORD()
  2105. {
  2106. Cursor c( m_view->cursorPosition() );
  2107. Cursor c1 = findPrevWORDStart( c.line(), c.column()+1, true );
  2108. Cursor c2( c );
  2109. for ( unsigned int i = 0; i < getCount(); i++ ) {
  2110. c2 = findNextWORDStart( c2.line(), c2.column(), true );
  2111. }
  2112. KateViRange r( c.line(), c.column(), ViMotion::ExclusiveMotion );
  2113. // sanity check
  2114. if ( c1.line() != c2.line() || c1.column() > c2.column() ) {
  2115. r.valid = false;
  2116. } else {
  2117. r.startLine = c1.line();
  2118. r.endLine = c2.line();
  2119. r.startColumn = c1.column();
  2120. r.endColumn = c2.column();
  2121. }
  2122. return r;
  2123. }
  2124. KateViRange KateViNormalMode::textObjectInnerWORD()
  2125. {
  2126. Cursor c( m_view->cursorPosition() );
  2127. Cursor c1 = findPrevWORDStart( c.line(), c.column()+1, true );
  2128. Cursor c2( c );
  2129. for ( unsigned int i = 0; i < getCount(); i++ ) {
  2130. c2 = findWORDEnd( c2.line(), c2.column(), true );
  2131. }
  2132. KateViRange r;
  2133. // sanity check
  2134. if ( c1.line() != c2.line() || c1.column() > c2.column() ) {
  2135. r.valid = false;
  2136. } else {
  2137. r.startLine = c1.line();
  2138. r.endLine = c2.line();
  2139. r.startColumn = c1.column();
  2140. r.endColumn = c2.column();
  2141. }
  2142. return r;
  2143. }
  2144. KateViRange KateViNormalMode::textObjectAQuoteDouble()
  2145. {
  2146. return findSurroundingQuotes( '"', false );
  2147. }
  2148. KateViRange KateViNormalMode::textObjectInnerQuoteDouble()
  2149. {
  2150. return findSurroundingQuotes( '"', true );
  2151. }
  2152. KateViRange KateViNormalMode::textObjectAQuoteSingle()
  2153. {
  2154. return findSurroundingQuotes( '\'', false );
  2155. }
  2156. KateViRange KateViNormalMode::textObjectInnerQuoteSingle()
  2157. {
  2158. return findSurroundingQuotes( '\'', true );
  2159. }
  2160. KateViRange KateViNormalMode::textObjectABackQuote()
  2161. {
  2162. return findSurroundingQuotes( '`', false );
  2163. }
  2164. KateViRange KateViNormalMode::textObjectInnerBackQuote()
  2165. {
  2166. return findSurroundingQuotes( '`', true );
  2167. }
  2168. KateViRange KateViNormalMode::textObjectAParen()
  2169. {
  2170. return findSurroundingBrackets( '(', ')', false, '(', ')' );
  2171. }
  2172. KateViRange KateViNormalMode::textObjectInnerParen()
  2173. {
  2174. return findSurroundingBrackets( '(', ')', true, '(', ')');
  2175. }
  2176. KateViRange KateViNormalMode::textObjectABracket()
  2177. {
  2178. return findSurroundingBrackets( '[', ']', false, '[', ']' );
  2179. }
  2180. KateViRange KateViNormalMode::textObjectInnerBracket()
  2181. {
  2182. return findSurroundingBrackets( '[', ']', true, '[', ']' );
  2183. }
  2184. KateViRange KateViNormalMode::textObjectACurlyBracket()
  2185. {
  2186. return findSurroundingBrackets( '{', '}', false, '{', '}' );
  2187. }
  2188. KateViRange KateViNormalMode::textObjectInnerCurlyBracket()
  2189. {
  2190. const KateViRange allBetweenCurlyBrackets = findSurroundingBrackets( '{', '}', true, '{', '}' );
  2191. // Emulate the behaviour of vim, which tries to leave the closing bracket on its own line
  2192. // if it was originally on a line different to that of the opening bracket.
  2193. KateViRange innerCurlyBracket(allBetweenCurlyBrackets);
  2194. if (innerCurlyBracket.startLine != innerCurlyBracket.endLine)
  2195. {
  2196. const bool stuffToDeleteIsAllOnEndLine = innerCurlyBracket.startColumn == doc()->line(innerCurlyBracket.startLine).length() &&
  2197. innerCurlyBracket.endLine == innerCurlyBracket.startLine + 1;
  2198. if (stuffToDeleteIsAllOnEndLine)
  2199. {
  2200. if (innerCurlyBracket.endColumn == -1)
  2201. {
  2202. // Nothing there to select - abort.
  2203. innerCurlyBracket.valid = false;
  2204. return innerCurlyBracket;
  2205. }
  2206. else
  2207. {
  2208. // Shift the beginning of the range to the start of the line containing the closing bracket.
  2209. innerCurlyBracket.startLine++;
  2210. innerCurlyBracket.startColumn = 0;
  2211. }
  2212. }
  2213. else
  2214. {
  2215. // The line containing the end bracket is left alone if the end bracket is preceded by whitespace,
  2216. // else we need to delete everything (i.e. end up with "{}")
  2217. const QString textLeadingClosingBracket = doc()->line(innerCurlyBracket.endLine).mid(0, innerCurlyBracket.endColumn + 1);
  2218. const bool hasStuffToDeleteOnEndLine = (!textLeadingClosingBracket.isEmpty() && !textLeadingClosingBracket.trimmed().isEmpty());
  2219. if (!hasStuffToDeleteOnEndLine)
  2220. {
  2221. // Shrink the endpoint of the range so that it ends at the end of the line above,
  2222. // leaving the closing bracket on its own line.
  2223. innerCurlyBracket.endLine--;
  2224. innerCurlyBracket.endColumn = doc()->line(innerCurlyBracket.endLine).length() - 1;
  2225. }
  2226. }
  2227. }
  2228. return innerCurlyBracket;
  2229. }
  2230. KateViRange KateViNormalMode::textObjectAInequalitySign()
  2231. {
  2232. return findSurroundingBrackets( '<', '>', false, '<', '>' );
  2233. }
  2234. KateViRange KateViNormalMode::textObjectInnerInequalitySign()
  2235. {
  2236. return findSurroundingBrackets( '<', '>', true, '<', '>' );
  2237. }
  2238. KateViRange KateViNormalMode::textObjectAComma()
  2239. {
  2240. return textObjectComma(false);
  2241. }
  2242. KateViRange KateViNormalMode::textObjectInnerComma()
  2243. {
  2244. return textObjectComma(true);
  2245. }
  2246. // add commands
  2247. // when adding commands here, remember to add them to visual mode too (if applicable)
  2248. void KateViNormalMode::initializeCommands()
  2249. {
  2250. ADDCMD("a", commandEnterInsertModeAppend, IS_CHANGE );
  2251. ADDCMD("A", commandEnterInsertModeAppendEOL, IS_CHANGE );
  2252. ADDCMD("i", commandEnterInsertMode, IS_CHANGE );
  2253. ADDCMD("I", commandEnterInsertModeBeforeFirstNonBlankInLine, IS_CHANGE );
  2254. ADDCMD("gi", commandEnterInsertModeLast, IS_CHANGE );
  2255. ADDCMD("v", commandEnterVisualMode, 0 );
  2256. ADDCMD("V", commandEnterVisualLineMode, 0 );
  2257. ADDCMD("<c-v>", commandEnterVisualBlockMode, 0 );
  2258. ADDCMD("gv", commandReselectVisual, 0 );
  2259. ADDCMD("o", commandOpenNewLineUnder, IS_CHANGE );
  2260. ADDCMD("O", commandOpenNewLineOver, IS_CHANGE );
  2261. ADDCMD("J", commandJoinLines, IS_CHANGE );
  2262. ADDCMD("c", commandChange, IS_CHANGE | NEEDS_MOTION );
  2263. ADDCMD("C", commandChangeToEOL, IS_CHANGE );
  2264. ADDCMD("cc", commandChangeLine, IS_CHANGE );
  2265. ADDCMD("s", commandSubstituteChar, IS_CHANGE );
  2266. ADDCMD("S", commandSubstituteLine, IS_CHANGE );
  2267. ADDCMD("dd", commandDeleteLine, IS_CHANGE );
  2268. ADDCMD("d", commandDelete, IS_CHANGE | NEEDS_MOTION );
  2269. ADDCMD("D", commandDeleteToEOL, IS_CHANGE );
  2270. ADDCMD("x", commandDeleteChar, IS_CHANGE );
  2271. ADDCMD("X", commandDeleteCharBackward, IS_CHANGE );
  2272. ADDCMD("gu", commandMakeLowercase, IS_CHANGE | NEEDS_MOTION );
  2273. ADDCMD("guu", commandMakeLowercaseLine, IS_CHANGE );
  2274. ADDCMD("gU", commandMakeUppercase, IS_CHANGE | NEEDS_MOTION );
  2275. ADDCMD("gUU", commandMakeUppercaseLine, IS_CHANGE );
  2276. ADDCMD("y", commandYank, NEEDS_MOTION );
  2277. ADDCMD("yy", commandYankLine, 0 );
  2278. ADDCMD("Y", commandYankToEOL, 0 );
  2279. ADDCMD("p", commandPasteLeaveCursorAtStart, IS_CHANGE );
  2280. ADDCMD("P", commandPasteBeforeLeaveCursorAtStart, IS_CHANGE );
  2281. ADDCMD("gp", commandPasteLeaveCursorAtEnd, IS_CHANGE );
  2282. ADDCMD("gP", commandPasteBeforeLeaveCursorAtEnd, IS_CHANGE );
  2283. ADDCMD("r.", commandReplaceCharacter, IS_CHANGE | REGEX_PATTERN );
  2284. ADDCMD("R", commandEnterReplaceMode, IS_CHANGE );
  2285. ADDCMD(":", commandSwitchToCmdLine, 0 );
  2286. ADDCMD("/", commandSearchForward, 0 );
  2287. ADDCMD("?", commandSearchBackward, 0 );
  2288. ADDCMD("u", commandUndo, 0);
  2289. ADDCMD("<c-r>", commandRedo, 0 );
  2290. ADDCMD("U", commandRedo, 0 );
  2291. ADDCMD("m.", commandSetMark, REGEX_PATTERN );
  2292. ADDCMD(">>", commandIndentLine, IS_CHANGE );
  2293. ADDCMD("<<", commandUnindentLine, IS_CHANGE );
  2294. ADDCMD(">", commandIndentLines, IS_CHANGE | NEEDS_MOTION );
  2295. ADDCMD("<", commandUnindentLines, IS_CHANGE | NEEDS_MOTION );
  2296. ADDCMD("<c-f>", commandScrollPageDown, 0 );
  2297. ADDCMD("<pagedown>", commandScrollPageDown, 0 );
  2298. ADDCMD("<c-b>", commandScrollPageUp, 0 );
  2299. ADDCMD("<pageup>", commandScrollPageUp, 0 );
  2300. ADDCMD("<c-u>", commandScrollHalfPageUp, 0 );
  2301. ADDCMD("<c-d>", commandScrollHalfPageDown, 0 );
  2302. ADDCMD("zz", commandCentreViewOnCursor, 0 );
  2303. ADDCMD("ga", commandPrintCharacterCode, SHOULD_NOT_RESET );
  2304. ADDCMD(".", commandRepeatLastChange, 0 );
  2305. ADDCMD("==", commandAlignLine, IS_CHANGE );
  2306. ADDCMD("=", commandAlignLines, IS_CHANGE | NEEDS_MOTION);
  2307. ADDCMD("~", commandChangeCase, IS_CHANGE );
  2308. ADDCMD("<c-a>", commandAddToNumber, IS_CHANGE );
  2309. ADDCMD("<c-x>", commandSubtractFromNumber, IS_CHANGE );
  2310. ADDCMD("<c-o>", commandGoToPrevJump, 0);
  2311. ADDCMD("<c-i>", commandGoToNextJump, 0);
  2312. ADDCMD("<c-w>h",commandSwitchToLeftView,0);
  2313. ADDCMD("<c-w><c-h>",commandSwitchToLeftView,0);
  2314. ADDCMD("<c-w><left>",commandSwitchToLeftView,0);
  2315. ADDCMD("<c-w>j",commandSwitchToDownView,0);
  2316. ADDCMD("<c-w><c-j>",commandSwitchToDownView,0);
  2317. ADDCMD("<c-w><down>",commandSwitchToDownView,0);
  2318. ADDCMD("<c-w>k",commandSwitchToUpView,0);
  2319. ADDCMD("<c-w><c-k>",commandSwitchToUpView,0);
  2320. ADDCMD("<c-w><up>",commandSwitchToUpView,0);
  2321. ADDCMD("<c-w>l",commandSwitchToRightView,0);
  2322. ADDCMD("<c-w><c-l>",commandSwitchToRightView,0);
  2323. ADDCMD("<c-w><right>",commandSwitchToRightView,0);
  2324. ADDCMD("<c-w>w",commandSwitchToNextView,0);
  2325. ADDCMD("<c-w><c-w>",commandSwitchToNextView,0);
  2326. ADDCMD("<c-w>s", commandSplitHoriz, 0);
  2327. ADDCMD("<c-w>S", commandSplitHoriz, 0);
  2328. ADDCMD("<c-w><c-s>", commandSplitHoriz, 0);
  2329. ADDCMD("<c-w>v", commandSplitVert, 0);
  2330. ADDCMD("<c-w><c-v>", commandSplitVert, 0);
  2331. ADDCMD("gt", commandSwitchToNextTab,0);
  2332. ADDCMD("gT", commandSwitchToPrevTab,0);
  2333. ADDCMD("gqq", commandFormatLine, IS_CHANGE);
  2334. ADDCMD("gq", commandFormatLines, IS_CHANGE | NEEDS_MOTION);
  2335. ADDCMD("zo", commandExpandLocal, 0 );
  2336. ADDCMD("zc", commandCollapseLocal, 0 );
  2337. ADDCMD("za", commandToggleRegionVisibility, 0 );
  2338. ADDCMD("zr", commandExpandAll, 0 );
  2339. ADDCMD("zm", commandCollapseToplevelNodes, 0 );
  2340. // regular motions
  2341. ADDMOTION("h", motionLeft, 0 );
  2342. ADDMOTION("<left>", motionLeft, 0 );
  2343. ADDMOTION("<backspace>", motionLeft, 0 );
  2344. ADDMOTION("j", motionDown, 0 );
  2345. ADDMOTION("<down>", motionDown, 0 );
  2346. ADDMOTION("<enter>", motionDownToFirstNonBlank, 0 );
  2347. ADDMOTION("k", motionUp, 0 );
  2348. ADDMOTION("<up>", motionUp, 0 );
  2349. ADDMOTION("-", motionUpToFirstNonBlank, 0 );
  2350. ADDMOTION("l", motionRight, 0 );
  2351. ADDMOTION("<right>", motionRight, 0 );
  2352. ADDMOTION(" ", motionRight, 0 );
  2353. ADDMOTION("$", motionToEOL, 0 );
  2354. ADDMOTION("<end>", motionToEOL, 0 );
  2355. ADDMOTION("0", motionToColumn0, 0 );
  2356. ADDMOTION("<home>", motionToColumn0, 0 );
  2357. ADDMOTION("^", motionToFirstCharacterOfLine, 0 );
  2358. ADDMOTION("f.", motionFindChar, REGEX_PATTERN );
  2359. ADDMOTION("F.", motionFindCharBackward, REGEX_PATTERN );
  2360. ADDMOTION("t.", motionToChar, REGEX_PATTERN );
  2361. ADDMOTION("T.", motionToCharBackward, REGEX_PATTERN );
  2362. ADDMOTION(";", motionRepeatlastTF, 0 );
  2363. ADDMOTION(",", motionRepeatlastTFBackward, 0 );
  2364. ADDMOTION("n", motionFindNext, 0 );
  2365. ADDMOTION("N", motionFindPrev, 0 );
  2366. ADDMOTION("gg", motionToLineFirst, 0 );
  2367. ADDMOTION("G", motionToLineLast, 0 );
  2368. ADDMOTION("w", motionWordForward, IS_NOT_LINEWISE );
  2369. ADDMOTION("W", motionWORDForward, IS_NOT_LINEWISE );
  2370. ADDMOTION("b", motionWordBackward, 0 );
  2371. ADDMOTION("B", motionWORDBackward, 0 );
  2372. ADDMOTION("e", motionToEndOfWord, 0 );
  2373. ADDMOTION("E", motionToEndOfWORD, 0 );
  2374. ADDMOTION("ge", motionToEndOfPrevWord, 0 );
  2375. ADDMOTION("gE", motionToEndOfPrevWORD, 0 );
  2376. ADDMOTION("|", motionToScreenColumn, 0 );
  2377. ADDMOTION("%", motionToMatchingItem, IS_NOT_LINEWISE );
  2378. ADDMOTION("`[a-zA-Z^><]", motionToMark, REGEX_PATTERN );
  2379. ADDMOTION("'[a-zA-Z^><]", motionToMarkLine, REGEX_PATTERN );
  2380. ADDMOTION("[[", motionToPreviousBraceBlockStart, 0 );
  2381. ADDMOTION("]]", motionToNextBraceBlockStart, 0 );
  2382. ADDMOTION("[]", motionToPreviousBraceBlockEnd, 0 );
  2383. ADDMOTION("][", motionToNextBraceBlockEnd, 0 );
  2384. ADDMOTION("*", motionToNextOccurrence, 0 );
  2385. ADDMOTION("#", motionToPrevOccurrence, 0 );
  2386. ADDMOTION("H", motionToFirstLineOfWindow, 0 );
  2387. ADDMOTION("M", motionToMiddleLineOfWindow, 0 );
  2388. ADDMOTION("L", motionToLastLineOfWindow, 0 );
  2389. ADDMOTION("gj", motionToNextVisualLine, 0 );
  2390. ADDMOTION("gk", motionToPrevVisualLine, 0 );
  2391. ADDMOTION("{", motionToBeforeParagraph, 0 );
  2392. ADDMOTION("}", motionToAfterParagraph, 0 );
  2393. // text objects
  2394. ADDMOTION("iw", textObjectInnerWord, 0 );
  2395. ADDMOTION("aw", textObjectAWord, 0 );
  2396. ADDMOTION("i\"", textObjectInnerQuoteDouble, IS_NOT_LINEWISE );
  2397. ADDMOTION("a\"", textObjectAQuoteDouble, IS_NOT_LINEWISE );
  2398. ADDMOTION("i'", textObjectInnerQuoteSingle, IS_NOT_LINEWISE );
  2399. ADDMOTION("a'", textObjectAQuoteSingle, IS_NOT_LINEWISE );
  2400. ADDMOTION("i`", textObjectInnerBackQuote, IS_NOT_LINEWISE );
  2401. ADDMOTION("a`", textObjectABackQuote, IS_NOT_LINEWISE );
  2402. ADDMOTION("i[()b]", textObjectInnerParen, REGEX_PATTERN | IS_NOT_LINEWISE);
  2403. ADDMOTION("a[()b]", textObjectAParen, REGEX_PATTERN | IS_NOT_LINEWISE);
  2404. ADDMOTION("i[{}B]", textObjectInnerCurlyBracket, REGEX_PATTERN | IS_NOT_LINEWISE);
  2405. ADDMOTION("a[{}B]", textObjectACurlyBracket, REGEX_PATTERN | IS_NOT_LINEWISE);
  2406. ADDMOTION("i[><]", textObjectInnerInequalitySign, REGEX_PATTERN | IS_NOT_LINEWISE);
  2407. ADDMOTION("a[><]", textObjectAInequalitySign, REGEX_PATTERN | IS_NOT_LINEWISE);
  2408. ADDMOTION("i[\\[\\]]", textObjectInnerBracket, REGEX_PATTERN | IS_NOT_LINEWISE);
  2409. ADDMOTION("a[\\[\\]]", textObjectABracket, REGEX_PATTERN | IS_NOT_LINEWISE);
  2410. ADDMOTION("i,", textObjectInnerComma, IS_NOT_LINEWISE );
  2411. ADDMOTION("a,", textObjectAComma, IS_NOT_LINEWISE);
  2412. }
  2413. QRegExp KateViNormalMode::generateMatchingItemRegex()
  2414. {
  2415. QString pattern("\\[|\\]|\\{|\\}|\\(|\\)|");
  2416. QList<QString> keys = m_matchingItems.keys();
  2417. for ( int i = 0; i < keys.size(); i++ ) {
  2418. QString s = m_matchingItems[ keys[ i ] ];
  2419. s = s.replace( QRegExp( "^-" ), QChar() );
  2420. s = s.replace( QRegExp( "\\*" ), "\\*" );
  2421. s = s.replace( QRegExp( "\\+" ), "\\+" );
  2422. s = s.replace( QRegExp( "\\[" ), "\\[" );
  2423. s = s.replace( QRegExp( "\\]" ), "\\]" );
  2424. s = s.replace( QRegExp( "\\(" ), "\\(" );
  2425. s = s.replace( QRegExp( "\\)" ), "\\)" );
  2426. s = s.replace( QRegExp( "\\{" ), "\\{" );
  2427. s = s.replace( QRegExp( "\\}" ), "\\}" );
  2428. pattern.append( s );
  2429. if ( i != keys.size()-1 ) {
  2430. pattern.append( '|' );
  2431. }
  2432. }
  2433. return QRegExp( pattern );
  2434. }
  2435. void KateViNormalMode::addMapping( const QString &from, const QString &to )
  2436. {
  2437. KateGlobal::self()->viInputModeGlobal()->addMapping( NormalMode, from, to );
  2438. }
  2439. const QString KateViNormalMode::getMapping( const QString &from ) const
  2440. {
  2441. return KateGlobal::self()->viInputModeGlobal()->getMapping( NormalMode, from );
  2442. }
  2443. const QStringList KateViNormalMode::getMappings() const
  2444. {
  2445. return KateGlobal::self()->viInputModeGlobal()->getMappings( NormalMode );
  2446. }
  2447. // returns the operation mode that should be used. this is decided by using the following heuristic:
  2448. // 1. if we're in visual block mode, it should be Block
  2449. // 2. if we're in visual line mode OR the range spans several lines, it should be LineWise
  2450. // 3. if neither of these is true, CharWise is returned
  2451. // 4. there are some motion that makes all operator charwise, if we have one of them mode will be CharWise
  2452. OperationMode KateViNormalMode::getOperationMode() const
  2453. {
  2454. OperationMode m = CharWise;
  2455. if ( m_viInputModeManager->getCurrentViMode() == VisualBlockMode ) {
  2456. m = Block;
  2457. } else if ( m_viInputModeManager->getCurrentViMode() == VisualLineMode
  2458. || ( m_commandRange.startLine != m_commandRange.endLine
  2459. && m_viInputModeManager->getCurrentViMode() != VisualMode )) {
  2460. m = LineWise;
  2461. }
  2462. if ( m_commandWithMotion && !m_linewiseCommand )
  2463. m = CharWise;
  2464. return m;
  2465. }
  2466. bool KateViNormalMode::paste(bool leaveCursorAtStart)
  2467. {
  2468. Cursor c( m_view->cursorPosition() );
  2469. Cursor cAfter = c;
  2470. QChar reg = getChosenRegister( m_defaultRegister );
  2471. OperationMode m = getRegisterFlag( reg );
  2472. QString textToInsert = getRegisterContent( reg );
  2473. if ( textToInsert.isNull() ) {
  2474. error(i18n("Nothing in register %1", reg ));
  2475. return false;
  2476. }
  2477. if ( getCount() > 1 ) {
  2478. textToInsert = textToInsert.repeated( getCount() ); // FIXME: does this make sense for blocks?
  2479. }
  2480. if ( m == LineWise ) {
  2481. textToInsert.chop( 1 ); // remove the last \n
  2482. c.setColumn( doc()->lineLength( c.line() ) ); // paste after the current line and ...
  2483. textToInsert.prepend( QChar( '\n' ) ); // ... prepend a \n, so the text starts on a new line
  2484. cAfter.setLine( cAfter.line()+1 );
  2485. cAfter.setColumn( 0 );
  2486. if (!leaveCursorAtStart)
  2487. {
  2488. cAfter.setLine(cAfter.line() + textToInsert.split("\n").length() - 1);
  2489. }
  2490. } else {
  2491. if ( getLine( c.line() ).length() > 0 ) {
  2492. c.setColumn( c.column()+1 );
  2493. }
  2494. cAfter = c;
  2495. if (!leaveCursorAtStart)
  2496. {
  2497. cAfter = cursorPosAtEndOfPaste(c, textToInsert);
  2498. }
  2499. }
  2500. doc()->insertText( c, textToInsert, m == Block );
  2501. updateCursor( cAfter );
  2502. return true;
  2503. }
  2504. bool KateViNormalMode::pasteBefore(bool leaveCursorAtStart)
  2505. {
  2506. Cursor c( m_view->cursorPosition() );
  2507. Cursor cAfter = c;
  2508. QChar reg = getChosenRegister( m_defaultRegister );
  2509. QString textToInsert = getRegisterContent( reg );
  2510. OperationMode m = getRegisterFlag( reg );
  2511. if ( getCount() > 1 ) {
  2512. textToInsert = textToInsert.repeated( getCount() );
  2513. }
  2514. if ( textToInsert.endsWith('\n') ) { // lines
  2515. c.setColumn( 0 );
  2516. cAfter.setColumn( 0 );
  2517. }
  2518. doc()->insertText( c, textToInsert, m == Block );
  2519. if (!leaveCursorAtStart)
  2520. {
  2521. cAfter = cursorPosAtEndOfPaste(c, textToInsert);
  2522. }
  2523. updateCursor( cAfter );
  2524. return true;
  2525. }
  2526. Cursor KateViNormalMode::cursorPosAtEndOfPaste(const Cursor& pasteLocation, const QString& pastedText)
  2527. {
  2528. Cursor cAfter = pasteLocation;
  2529. const QStringList textLines = pastedText.split("\n");
  2530. if (textLines.length() == 1)
  2531. {
  2532. cAfter.setColumn(cAfter.column() + pastedText.length());
  2533. }
  2534. else
  2535. {
  2536. cAfter.setColumn(textLines.last().length() - 0);
  2537. cAfter.setLine(cAfter.line() + textLines.length() - 1);
  2538. }
  2539. return cAfter;
  2540. }
  2541. void KateViNormalMode::joinLines(unsigned int from, unsigned int to) const
  2542. {
  2543. // make sure we don't try to join lines past the document end
  2544. if ( to >= (unsigned int)(doc()->lines()) ) {
  2545. to = doc()->lines()-1;
  2546. }
  2547. // joining one line is a no-op
  2548. if ( from == to ) return;
  2549. doc()->joinLines( from, to );
  2550. }
  2551. void KateViNormalMode::reformatLines(unsigned int from, unsigned int to) const
  2552. {
  2553. joinLines( from, to );
  2554. doc()->wrapText( from, to );
  2555. }
  2556. // Tries to shrinks toShrink so that it fits tightly around rangeToShrinkTo.
  2557. void KateViNormalMode::shrinkRangeAroundCursor(KateViRange& toShrink, const KateViRange& rangeToShrinkTo)
  2558. {
  2559. if (!toShrink.valid || !rangeToShrinkTo.valid)
  2560. {
  2561. return;
  2562. }
  2563. Cursor cursorPos = m_view->cursorPosition();
  2564. if (rangeToShrinkTo.startLine >= cursorPos.line())
  2565. {
  2566. if (rangeToShrinkTo.startLine > cursorPos.line())
  2567. {
  2568. // Does not surround cursor; aborting.
  2569. return;
  2570. }
  2571. Q_ASSERT(rangeToShrinkTo.startLine == cursorPos.line());
  2572. if (rangeToShrinkTo.startColumn > cursorPos.column())
  2573. {
  2574. // Does not surround cursor; aborting.
  2575. return;
  2576. }
  2577. }
  2578. if (rangeToShrinkTo.endLine <= cursorPos.line())
  2579. {
  2580. if (rangeToShrinkTo.endLine < cursorPos.line())
  2581. {
  2582. // Does not surround cursor; aborting.
  2583. return;
  2584. }
  2585. Q_ASSERT(rangeToShrinkTo.endLine == cursorPos.line());
  2586. if (rangeToShrinkTo.endColumn < cursorPos.column())
  2587. {
  2588. // Does not surround cursor; aborting.
  2589. return;
  2590. }
  2591. }
  2592. if (toShrink.startLine <= rangeToShrinkTo.startLine)
  2593. {
  2594. if (toShrink.startLine < rangeToShrinkTo.startLine)
  2595. {
  2596. toShrink.startLine = rangeToShrinkTo.startLine;
  2597. toShrink.startColumn = rangeToShrinkTo.startColumn;
  2598. }
  2599. Q_ASSERT(toShrink.startLine == rangeToShrinkTo.startLine);
  2600. if (toShrink.startColumn < rangeToShrinkTo.startColumn)
  2601. {
  2602. toShrink.startColumn = rangeToShrinkTo.startColumn;
  2603. }
  2604. }
  2605. if (toShrink.endLine >= rangeToShrinkTo.endLine)
  2606. {
  2607. if (toShrink.endLine > rangeToShrinkTo.endLine)
  2608. {
  2609. toShrink.endLine = rangeToShrinkTo.endLine;
  2610. toShrink.endColumn = rangeToShrinkTo.endColumn;
  2611. }
  2612. Q_ASSERT(toShrink.endLine == rangeToShrinkTo.endLine);
  2613. if (toShrink.endColumn > rangeToShrinkTo.endColumn)
  2614. {
  2615. toShrink.endColumn = rangeToShrinkTo.endColumn;
  2616. }
  2617. }
  2618. }
  2619. KateViRange KateViNormalMode::textObjectComma(bool inner)
  2620. {
  2621. // Basic algorithm: look left and right of the cursor for all combinations
  2622. // of enclosing commas and the various types of brackets, and pick the pair
  2623. // closest to the cursor that surrounds the cursor.
  2624. KateViRange r(0, 0, m_view->doc()->lines(), m_view->doc()->line(m_view->doc()->lastLine()).length(), ViMotion::InclusiveMotion);
  2625. shrinkRangeAroundCursor(r, findSurroundingQuotes( ',', inner ));
  2626. shrinkRangeAroundCursor(r, findSurroundingBrackets( '(', ')', inner, '(', ')' ));
  2627. shrinkRangeAroundCursor(r, findSurroundingBrackets( '{', '}', inner, '{', '}' ));
  2628. shrinkRangeAroundCursor(r, findSurroundingBrackets( ',', ')', inner, '(', ')' ));
  2629. shrinkRangeAroundCursor(r, findSurroundingBrackets( ',', ']', inner, '[', ']' ));
  2630. shrinkRangeAroundCursor(r, findSurroundingBrackets( ',', '}', inner, '{', '}' ));
  2631. shrinkRangeAroundCursor(r, findSurroundingBrackets( '(', ',', inner, '(', ')' ));
  2632. shrinkRangeAroundCursor(r, findSurroundingBrackets( '[', ',', inner, '[', ']' ));
  2633. shrinkRangeAroundCursor(r, findSurroundingBrackets( '{', ',', inner, '{', '}' ));
  2634. return r;
  2635. }
  2636. void KateViNormalMode::executeMapping()
  2637. {
  2638. m_mappingKeys.clear();
  2639. const int numberRepeats = m_countTemp == 0 ? 1 : m_countTemp;
  2640. m_countTemp = 1; // Ensure that the first command in the mapping is not repeated.
  2641. m_mappingTimer->stop();
  2642. const QString mappedKeypresses = getMapping(m_fullMappingMatch);
  2643. doc()->editBegin();
  2644. for(int count = 1; count <= numberRepeats; count++)
  2645. {
  2646. m_viInputModeManager->feedKeyPresses(mappedKeypresses);
  2647. }
  2648. doc()->editEnd();
  2649. }