diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index 32eb3fad507a274ed3c806359959e9ddaf731b42..205e337d9e74d0d650ba97b2db7aa8ad364829f2 100755 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -142,6 +142,7 @@ enum SubMode ReplaceSubMode, // used for R and r ShiftLeftSubMode, // used for < ShiftRightSubMode, // used for > + TransformSubMode, // used for ~/gu/gU WindowSubMode, // used for Ctrl-w YankSubMode, // used for y ZSubMode, // used for z @@ -157,6 +158,9 @@ enum SubSubMode MarkSubSubMode, // used for m BackTickSubSubMode, // used for ` TickSubSubMode, // used for ' + InvertCaseSubSubMode, // used for ~ + DownCaseSubSubMode, // used for gu + UpCaseSubSubMode, // used for gU }; enum VisualMode @@ -428,8 +432,20 @@ public: int anchor() const { return m_anchor; } int position() const { return m_tc.position(); } + void transformText(const Range &range, void (FakeVimHandler::Private::*transformFunc)(int, QTextCursor *)); + void removeSelectedText(); void removeText(const Range &range); + void removeTransform(int, QTextCursor *); + + void invertCaseSelectedText(); + void invertCaseTransform(int, QTextCursor *); + + void upCaseSelectedText(); + void upCaseTransform(int, QTextCursor *); + + void downCaseSelectedText(); + void downCaseTransform(int, QTextCursor *); QString selectedText() const { return text(Range(position(), anchor())); } QString text(const Range &range) const; @@ -858,6 +874,35 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommand) } else { setPosition(m_savedYankPosition); } + } else if (m_submode == TransformSubMode) { + beginEditBlock(); + if (atEndOfLine()) + moveLeft(); + if (m_rangemode == RangeCharMode) { + if (m_movetype == MoveInclusive) + moveRight(); // correction + if (anchor() >= position()) + m_anchor--; + } + if (m_subsubmode == InvertCaseSubSubMode) { + invertCaseSelectedText(); + if (!dotCommand.isEmpty()) + setDotCommand("~" + dotCommand); + } else if (m_subsubmode == UpCaseSubSubMode) { + upCaseSelectedText(); + if (!dotCommand.isEmpty()) + setDotCommand("gU" + dotCommand); + } else if (m_subsubmode == DownCaseSubSubMode) { + downCaseSelectedText(); + if (!dotCommand.isEmpty()) + setDotCommand("gu" + dotCommand); + } + m_submode = NoSubMode; + m_subsubmode = NoSubSubMode; + setPosition(qMin(anchor(), position())); + if (m_movetype == MoveLineWise) + handleStartOfLine(); + endEditBlock(); } else if (m_submode == ReplaceSubMode) { m_submode = NoSubMode; } else if (m_submode == IndentSubMode) { @@ -1639,7 +1684,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(int key, int unmodified, m_movetype = MoveExclusive; m_subsubmode = FtSubSubMode; m_subsubdata = key; - } else if (key == 'u') { + } else if (!m_gflag && key == 'u') { undo(); } else if (key == control('u')) { int sline = cursorLineOnScreen(); @@ -1743,18 +1788,53 @@ EventResult FakeVimHandler::Private::handleCommandMode(int key, int unmodified, m_submode = ZSubMode; } else if (key == 'Z') { m_submode = CapitalZSubMode; - } else if (key == '~' && !atEndOfLine()) { - beginEditBlock(); - setAnchor(); - moveRight(qMin(count(), rightDist())); - QString str = selectedText(); - removeSelectedText(); - for (int i = str.size(); --i >= 0; ) { - QChar c = str.at(i); - str[i] = c.isUpper() ? c.toLower() : c.toUpper(); + } else if (!m_gflag && key == '~' && !isVisualMode()) { + if (!atEndOfLine()) { + beginEditBlock(); + setAnchor(); + moveRight(qMin(count(), rightDist())); + if (key == '~') { + invertCaseSelectedText(); + setDotCommand("%1~", count()); + } else if (key == 'u') { + downCaseSelectedText(); + setDotCommand("%1gu", count()); + } else if (key == 'U') { + upCaseSelectedText(); + setDotCommand("%1gU", count()); + } + endEditBlock(); } - m_tc.insertText(str); - endEditBlock(); + finishMovement(); + } else if ((m_gflag && key == '~' && !isVisualMode()) + || (m_gflag && key == 'u' && !isVisualMode()) + || (m_gflag && key == 'U' && !isVisualMode())) { + if (atEndOfLine()) + moveLeft(); + setAnchor(); + m_submode = TransformSubMode; + if (key == '~') + m_subsubmode = InvertCaseSubSubMode; + if (key == 'u') + m_subsubmode = DownCaseSubSubMode; + else if (key == 'U') + m_subsubmode = UpCaseSubSubMode; + } else if ((key == '~' && isVisualMode()) + || (m_gflag && key == 'u' && isVisualMode()) + || (m_gflag && key == 'U' && isVisualMode())) { + if (isVisualLineMode()) + m_rangemode = RangeLineMode; + else if (isVisualBlockMode()) + m_rangemode = RangeBlockMode; + leaveVisualMode(); + m_submode = TransformSubMode; + if (key == '~') + m_subsubmode = InvertCaseSubSubMode; + else if (key == 'u') + m_subsubmode = DownCaseSubSubMode; + else if (key == 'U') + m_subsubmode = UpCaseSubSubMode; + finishMovement(); } else if (key == Key_PageDown || key == control('f')) { moveDown(count() * (linesOnScreen() - 2) - cursorLineOnScreen()); scrollToLineInDocument(cursorLineInDocument()); @@ -2844,22 +2924,14 @@ void FakeVimHandler::Private::yankText(const Range &range, int toregister) //qDebug() << "YANKED: " << reg.contents; } -void FakeVimHandler::Private::removeSelectedText() -{ - Range range(anchor(), position()); - range.rangemode = m_rangemode; - removeText(range); -} - -void FakeVimHandler::Private::removeText(const Range &range) +void FakeVimHandler::Private::transformText(const Range &range, void (FakeVimHandler::Private::*transformFunc)(int updateMarksAfter, QTextCursor *tc)) { QTextCursor tc = m_tc; switch (range.rangemode) { case RangeCharMode: { tc.setPosition(range.beginPos, MoveAnchor); tc.setPosition(range.endPos, KeepAnchor); - fixMarks(range.beginPos, tc.selectionStart() - tc.selectionEnd()); - tc.removeSelectedText(); + (this->*transformFunc)(range.beginPos, &tc); return; } case RangeLineMode: { @@ -2882,11 +2954,10 @@ void FakeVimHandler::Private::removeText(const Range &range) } else { tc.movePosition(Right, KeepAnchor, 1); } - fixMarks(range.beginPos, tc.selectionStart() - tc.selectionEnd()); - tc.removeSelectedText(); + (this->*transformFunc)(range.beginPos, &tc); return; } - case RangeBlockAndTailMode: + case RangeBlockAndTailMode: case RangeBlockMode: { int beginLine = lineForPosition(range.beginPos); int endLine = lineForPosition(range.endPos); @@ -2903,9 +2974,7 @@ void FakeVimHandler::Private::removeText(const Range &range) int eCol = qMin(endColumn + 1, block.length() - 1); tc.setPosition(block.position() + bCol, MoveAnchor); tc.setPosition(block.position() + eCol, KeepAnchor); - fixMarks(block.position() + bCol, - tc.selectionStart() - tc.selectionEnd()); - tc.removeSelectedText(); + (this->*transformFunc)(block.position() + bCol, &tc); block = block.previous(); } endEditBlock(); @@ -2913,6 +2982,81 @@ void FakeVimHandler::Private::removeText(const Range &range) } } +void FakeVimHandler::Private::removeSelectedText() +{ + Range range(anchor(), position()); + range.rangemode = m_rangemode; + removeText(range); +} + +void FakeVimHandler::Private::removeText(const Range &range) +{ + transformText(range, &FakeVimHandler::Private::removeTransform); +} + +void FakeVimHandler::Private::removeTransform(int updateMarksAfter, QTextCursor *tc) +{ + fixMarks(updateMarksAfter, tc->selectionStart() - tc->selectionEnd()); + tc->removeSelectedText(); +} + +void FakeVimHandler::Private::downCaseSelectedText() +{ + Range range(anchor(), position()); + range.rangemode = m_rangemode; + transformText(range, &FakeVimHandler::Private::downCaseTransform); +} + +void FakeVimHandler::Private::downCaseTransform(int updateMarksAfter, QTextCursor *tc) +{ + Q_UNUSED(updateMarksAfter); + QString str = tc->selectedText(); + tc->removeSelectedText(); + for (int i = str.size(); --i >= 0; ) { + QChar c = str.at(i); + str[i] = c.toLower(); + } + tc->insertText(str); +} + +void FakeVimHandler::Private::upCaseSelectedText() +{ + Range range(anchor(), position()); + range.rangemode = m_rangemode; + transformText(range, &FakeVimHandler::Private::upCaseTransform); +} + +void FakeVimHandler::Private::upCaseTransform(int updateMarksAfter, QTextCursor *tc) +{ + Q_UNUSED(updateMarksAfter); + QString str = tc->selectedText(); + tc->removeSelectedText(); + for (int i = str.size(); --i >= 0; ) { + QChar c = str.at(i); + str[i] = c.toUpper(); + } + tc->insertText(str); +} + +void FakeVimHandler::Private::invertCaseSelectedText() +{ + Range range(anchor(), position()); + range.rangemode = m_rangemode; + transformText(range, &FakeVimHandler::Private::invertCaseTransform); +} + +void FakeVimHandler::Private::invertCaseTransform(int updateMarksAfter, QTextCursor *tc) +{ + Q_UNUSED(updateMarksAfter); + QString str = tc->selectedText(); + tc->removeSelectedText(); + for (int i = str.size(); --i >= 0; ) { + QChar c = str.at(i); + str[i] = c.isUpper() ? c.toLower() : c.toUpper(); + } + tc->insertText(str); +} + void FakeVimHandler::Private::pasteText(bool afterCursor) { const QString text = m_registers[m_register].contents;