diff options
author | Lukas Holecek <hluk@email.cz> | 2014-11-20 19:57:16 +0100 |
---|---|---|
committer | hjk <hjk121@nokiamail.com> | 2014-11-25 10:32:12 +0100 |
commit | 577fcd97d4f0ae6dd944d1587b2c4ed0ac2c66c9 (patch) | |
tree | 894c662299aa21fadfa345743cd67f5403b6a680 /src/plugins | |
parent | e8aecca215fdc5c01507e06e0a26e09eab6b4655 (diff) |
FakeVim: Select and modify paragraph object
Change-Id: Ib528fa2914bfcb17caed114d7da2d201079b0725
Reviewed-by: hjk <hjk121@nokiamail.com>
Diffstat (limited to 'src/plugins')
-rw-r--r-- | src/plugins/fakevim/fakevim_test.cpp | 426 | ||||
-rw-r--r-- | src/plugins/fakevim/fakevimhandler.cpp | 134 | ||||
-rw-r--r-- | src/plugins/fakevim/fakevimplugin.h | 14 |
3 files changed, 558 insertions, 16 deletions
diff --git a/src/plugins/fakevim/fakevim_test.cpp b/src/plugins/fakevim/fakevim_test.cpp index e012b04969a..cd1ed10b1f8 100644 --- a/src/plugins/fakevim/fakevim_test.cpp +++ b/src/plugins/fakevim/fakevim_test.cpp @@ -1573,6 +1573,432 @@ void FakeVimPlugin::test_vim_block_selection_insert() "a" X "bXYZc" N " XYZ" N "deXYZf" N + ); +} + +void FakeVimPlugin::test_vim_delete_inner_paragraph() +{ + TestData data; + setup(&data); + + data.setText( + "abc" N + "def" N + "" N + "" N + "ghi" N + "" N + "jkl" N + ); + + KEYS("dip", + X "" N + "" N + "ghi" N + "" N + "jkl" N + ); + KEYS("dip", + X "ghi" N + "" N + "jkl" N + ); + KEYS("2dip", + X "jkl" N + ); +} + +void FakeVimPlugin::test_vim_delete_a_paragraph() +{ + TestData data; + setup(&data); + + data.setText( + "abc" N + "def" N + "" N + "" N + "ghi" N + "" N + "jkl" N + ); + + KEYS("dap", + X "ghi" N + "" N + "jkl" N + ); + KEYS("dap", + X "jkl" N + ); + KEYS("u", + X "ghi" N + "" N + "jkl" N + ); + + data.setText( + "abc" N + "" N + "" N + "def" + ); + KEYS("Gdap", + X "abc" + ); +} + +void FakeVimPlugin::test_vim_change_inner_paragraph() +{ + TestData data; + setup(&data); + + data.setText( + "abc" N + "def" N + "" N + "" N + "ghi" N + "" N + "jkl" N + ); + + KEYS("cipXXX<ESC>", + "XX" X "X" N + "" N + "" N + "ghi" N + "" N + "jkl" N + ); + KEYS("3j" "cipYYY<ESC>", + "XXX" N + "" N + "" N + "YY" X "Y" N + "" N + "jkl" N + ); +} + +void FakeVimPlugin::test_vim_change_a_paragraph() +{ + TestData data; + setup(&data); + + data.setText( + "abc" N + "def" N + "" N + "" N + "ghi" N + "" N + "jkl" N + ); + + KEYS("4j" "capXXX<ESC>", + "abc" N + "def" N + "" N + "" N + "XX" X "X" N + "jkl" N + ); + KEYS("gg" "capYYY<ESC>", + "YY" X "Y" N + "XXX" N + "jkl" N + ); + + data.setText( + "abc" N + "" N + "" N + "def" + ); + KEYS("GcapXXX<ESC>", + "abc" N + "XX" X "X" + ); +} + +void FakeVimPlugin::test_vim_select_inner_paragraph() +{ + TestData data; + setup(&data); + + data.setText( + "" N + X "abc" N + "def" N + "" N + "ghi" + ); + KEYS("vip" "r-", + "" N + X "---" N + "---" N + "" N + "ghi" + ); + + data.setText( + "" N + X "abc" N + "def" N + "" N + "ghi" + ); + KEYS("vip" ":s/^/-<CR>", + "" N + "-abc" N + X "-def" N + "" N + "ghi" + ); + + data.setText( + "" N + X "abc" N + "def" N + "" N + "ghi" + ); + KEYS("v2ip" ":s/^/-<CR>", + "" N + "-abc" N + "-def" N + X "-" N + "ghi" + ); + + data.setText( + "" N + X "abc" N + "def" N + "" N + "ghi" + ); + KEYS("Vj" "ip" ":s/^/-<CR>", + "" N + "-abc" N + "-def" N + X "-" N + "ghi" + ); + + data.setText( + "" N + X "abc" N + "def" N + "" N + "ghi" + ); + KEYS("vj" "ip" ":s/^/-<CR>", + "" N + "-abc" N + "-def" N + "-" N + "ghi" + ); + + data.setText( + "" N + X "abc" N + "def" N + "ghi" N + "" N + "jkl" + ); + KEYS("vj" "ip" ":s/^/-<CR>", + "" N + "-abc" N + "-def" N + "-ghi" N + "" N + "jkl" + ); + + data.setText( + "" N + X "abc" N + "def" N + "" N + "ghi" + ); + KEYS("vip" "r-", + "" N + X "---" N + "---" N + "" N + "ghi" + ); + + data.setText( + "abc" N + "" N + "def" + ); + KEYS("G" "vip" "r-", + "abc" N + "" N + "---" + ); + + data.setText( + "" N + "" N + "ghi" + ); + KEYS("vip" ":s/^/-<CR>", + "-" N + "-" N + "ghi" + ); + + data.setText( + "" N + "ghi" + ); + KEYS("vip" "ip" ":s/^/-<CR>", + "-" N + X "-ghi" + ); + + data.setText( + "abc" N + "" N + "" + ); + KEYS("j" "vip" ":s/^/-<CR>", + "abc" N + "-" N + "-" + ); + + // Don't move anchor if it's on different line. + data.setText( + "" N + "abc" N + X "def" N + "ghi" N + "" N + "jkl" + ); + KEYS("vj" "ip" ":s/^/-<CR>", + "" N + "abc" N + "-def" N + "-ghi" N + X "-" N + "jkl" + ); + + // Don't change selection mode if anchor is on different line. + data.setText( + "" N + "abc" N + X "def" N + "ghi" N + "" N + "jkl" + ); + KEYS("vj" "2ip" "r-", + "" N + "abc" N + X "---" N + "---" N + "" N + "-kl" + ); + KEYS("gv" ":s/^/X<CR>", + "" N + "abc" N + "X---" N + "X---" N + "X" N + X "X-kl" + ); + + data.setText( + "" N + "abc" N + X "def" N + "ghi" N + "" N + "jkl" + ); + KEYS("<C-V>j" "2ip" "r-", + "" N + "abc" N + X "-ef" N + "-hi" N + "" N + "-kl" + ); + KEYS("gv" "IX<ESC>", + "" N + "abc" N + "X-ef" N + "X-hi" N + "X" N + "X-kl" + ); +} + +void FakeVimPlugin::test_vim_select_a_paragraph() +{ + TestData data; + setup(&data); + + data.setText( + "abc" N + "def" N + "" N + "ghi" + ); + KEYS("vap" ":s/^/-<CR>", + "-abc" N + "-def" N + "-" N + "ghi" + ); + + data.setText( + "" N + "abc" N + "def" N + "" N + "ghi" + ); + KEYS("vap" ":s/^/-<CR>", + "-" N + "-abc" N + "-def" N + "" N + "ghi" + ); + + data.setText( + "abc" N + "def" N + "" + ); + KEYS("j" "vap" ":s/^/-<CR>", + "-abc" N + "-def" N + "-" + ); + + data.setText( + "" N + "abc" N + "def" + ); + KEYS("j" "vap" ":s/^/-<CR>", + "-" N + "-abc" N + "-def" ); } diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index 7376a2166cc..ec00465840b 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -1776,6 +1776,7 @@ public: int lineNumber(const QTextBlock &block) const; int columnAt(int pos) const; + int blockNumberAt(int pos) const; QTextBlock blockAt(int pos) const; QTextBlock nextLine(const QTextBlock &block) const; // following line (respects wrapped parts) QTextBlock previousLine(const QTextBlock &block) const; // previous line (respects wrapped parts) @@ -1916,8 +1917,9 @@ public: QTextCursor m_cursor; bool m_cursorNeedsUpdate; - bool moveToPreviousParagraph(int count) { return moveToNextParagraph(-count); } - bool moveToNextParagraph(int count); + bool moveToPreviousParagraph(int count = 1) { return moveToNextParagraph(-count); } + bool moveToNextParagraph(int count = 1); + void moveToParagraphStartOrEnd(int direction = 1); bool handleFfTt(const QString &key, bool repeats = false); @@ -3197,7 +3199,6 @@ bool FakeVimHandler::Private::moveToNextParagraph(int count) { const bool forward = count > 0; int repeat = forward ? count : -count; - int pos = position(); QTextBlock block = this->block(); if (block.isValid() && block.length() == 1) @@ -3209,23 +3210,39 @@ bool FakeVimHandler::Private::moveToNextParagraph(int count) break; while (block.isValid() && block.length() == 1) block = forward ? block.next() : block.previous(); + if (!block.isValid()) + break; } } - if (repeat == 0) - setPosition(block.position()); - else if (repeat == 1) - setPosition(forward ? lastPositionInDocument() : 0); - else + if (!block.isValid()) + --repeat; + + if (repeat > 0) return false; - recordJump(pos); - setTargetColumn(); - g.movetype = MoveExclusive; + if (block.isValid()) + setPosition(block.position()); + else + setPosition(forward ? lastPositionInDocument() : 0); return true; } +void FakeVimHandler::Private::moveToParagraphStartOrEnd(int direction) +{ + bool emptyLine = atEmptyLine(); + int oldPos = -1; + + while (atEmptyLine() == emptyLine && oldPos != position()) { + oldPos = position(); + moveDown(direction); + } + + if (oldPos != position()) + moveUp(direction); +} + void FakeVimHandler::Private::moveToEndOfLine() { // Additionally select (in visual mode) or apply current command on hidden lines following @@ -3836,10 +3853,16 @@ bool FakeVimHandler::Private::handleMovement(const Input &input) moveRight(qMin(column, rightDist() - 1)); m_targetColumn = column; m_visualTargetColumn = column; - } else if (input.is('}')) { - handled = moveToNextParagraph(count); - } else if (input.is('{')) { - handled = moveToPreviousParagraph(count); + } else if (input.is('{') || input.is('}')) { + const int oldPosition = position(); + handled = input.is('}') + ? moveToNextParagraph(count) + : moveToPreviousParagraph(count); + if (handled) { + recordJump(oldPosition); + setTargetColumn(); + g.movetype = MoveExclusive; + } } else if (input.isReturn()) { moveToStartOfLine(); moveDown(); @@ -7333,6 +7356,11 @@ int FakeVimHandler::Private::columnAt(int pos) const return pos - blockAt(pos).position(); } +int FakeVimHandler::Private::blockNumberAt(int pos) const +{ + return blockAt(pos).blockNumber(); +} + QTextBlock FakeVimHandler::Private::blockAt(int pos) const { return document()->findBlock(pos); @@ -8044,7 +8072,81 @@ void FakeVimHandler::Private::selectSentenceTextObject(bool inner) void FakeVimHandler::Private::selectParagraphTextObject(bool inner) { - Q_UNUSED(inner); + const QTextCursor oldCursor = m_cursor; + const VisualMode oldVisualMode = g.visualMode; + + const int anchorBlock = blockNumberAt(anchor()); + const int positionBlock = blockNumberAt(position()); + const bool setupAnchor = anchorBlock == positionBlock; + int repeat = count(); + + // If anchor and position are in the same block, + // start line selection at beginning of current paragraph. + if (setupAnchor) { + moveToParagraphStartOrEnd(-1); + setAnchor(); + + if (!isVisualLineMode() && isVisualMode()) + toggleVisualMode(VisualLineMode); + } + + const bool forward = anchor() <= position(); + const int d = forward ? 1 : -1; + + bool startsAtParagraph = !atEmptyLine(position()); + + moveToParagraphStartOrEnd(d); + + // If selection already changed, decreate count. + if ((setupAnchor && g.submode != NoSubMode) + || oldVisualMode != g.visualMode + || m_cursor != oldCursor) + { + --repeat; + if (!inner) { + moveDown(d); + moveToParagraphStartOrEnd(d); + startsAtParagraph = !startsAtParagraph; + } + } + + if (repeat > 0) { + bool isCountEven = repeat % 2 == 0; + bool endsOnParagraph = + inner ? isCountEven == startsAtParagraph : startsAtParagraph; + + if (inner) { + repeat = repeat / 2; + if (!isCountEven || endsOnParagraph) + ++repeat; + } else { + if (endsOnParagraph) + ++repeat; + } + + if (!moveToNextParagraph(d * repeat)) { + m_cursor = oldCursor; + g.visualMode = oldVisualMode; + return; + } + + if (endsOnParagraph && atEmptyLine()) + moveUp(d); + else + moveToParagraphStartOrEnd(d); + } + + if (!inner && setupAnchor && !atEmptyLine() && !atEmptyLine(anchor())) { + // If position cannot select empty lines, try to select them with anchor. + setAnchorAndPosition(position(), anchor()); + moveToNextParagraph(-d); + moveToParagraphStartOrEnd(-d); + setAnchorAndPosition(position(), anchor()); + } + + recordJump(oldCursor.position()); + setTargetColumn(); + g.movetype = MoveLineWise; } bool FakeVimHandler::Private::selectBlockTextObject(bool inner, diff --git a/src/plugins/fakevim/fakevimplugin.h b/src/plugins/fakevim/fakevimplugin.h index b8cd0d246a2..620cf6b7d0a 100644 --- a/src/plugins/fakevim/fakevimplugin.h +++ b/src/plugins/fakevim/fakevimplugin.h @@ -61,23 +61,37 @@ private: #ifdef WITH_TESTS private slots: void cleanup(); + void test_vim_movement(); + void test_vim_target_column_normal(); void test_vim_target_column_visual_char(); void test_vim_target_column_visual_block(); void test_vim_target_column_visual_line(); void test_vim_target_column_insert(); void test_vim_target_column_replace(); + void test_vim_insert(); void test_vim_fFtT(); void test_vim_transform_numbers(); void test_vim_delete(); + void test_vim_delete_inner_word(); void test_vim_delete_a_word(); void test_vim_change_a_word(); + void test_vim_change_replace(); + void test_vim_block_selection(); void test_vim_block_selection_insert(); + + void test_vim_delete_inner_paragraph(); + void test_vim_delete_a_paragraph(); + void test_vim_change_inner_paragraph(); + void test_vim_change_a_paragraph(); + void test_vim_select_inner_paragraph(); + void test_vim_select_a_paragraph(); + void test_vim_repeat(); void test_vim_search(); void test_vim_indent(); |