diff options
author | Tom Praschan <tom@praschan.de> | 2021-01-30 12:29:14 +0100 |
---|---|---|
committer | Tom Praschan <tom@praschan.de> | 2021-02-10 16:11:50 +0000 |
commit | f83eeb0548e2d57446bdf2a533ce75a9819a53aa (patch) | |
tree | ea65d2ea057b9125ed09a7b300dd7dce4ec12349 | |
parent | 3b1bc1d0534ed2ec65490afa5b3723b2cc8e2d3d (diff) |
FakeVim: Add emulation of vim-exchange plugin
Change-Id: I844c9bf11231ab842cee020a0e7a29af8ed209eb
Reviewed-by: hjk <hjk@qt.io>
-rw-r--r-- | doc/qtcreator/src/editors/creator-only/creator-fakevim.qdoc | 1 | ||||
-rw-r--r-- | src/plugins/fakevim/fakevim_test.cpp | 28 | ||||
-rw-r--r-- | src/plugins/fakevim/fakevimactions.cpp | 1 | ||||
-rw-r--r-- | src/plugins/fakevim/fakevimactions.h | 1 | ||||
-rw-r--r-- | src/plugins/fakevim/fakevimhandler.cpp | 70 | ||||
-rw-r--r-- | src/plugins/fakevim/fakevimoptions.ui | 9 | ||||
-rw-r--r-- | src/plugins/fakevim/fakevimplugin.cpp | 1 | ||||
-rw-r--r-- | src/plugins/fakevim/fakevimplugin.h | 1 |
8 files changed, 111 insertions, 1 deletions
diff --git a/doc/qtcreator/src/editors/creator-only/creator-fakevim.qdoc b/doc/qtcreator/src/editors/creator-only/creator-fakevim.qdoc index 7ac4bea02d0..a35b0f7e19c 100644 --- a/doc/qtcreator/src/editors/creator-only/creator-fakevim.qdoc +++ b/doc/qtcreator/src/editors/creator-only/creator-fakevim.qdoc @@ -128,6 +128,7 @@ \li \c [count]["x]gr{motion} to replace \c {motion} with the contents of register \c x. \li ["x]grr to replace the current line. + \l{https://github.com/tommcdo/vim-exchange}{vim-exchange} \endlist \endlist diff --git a/src/plugins/fakevim/fakevim_test.cpp b/src/plugins/fakevim/fakevim_test.cpp index 14f8d7dd315..a5bf90cf563 100644 --- a/src/plugins/fakevim/fakevim_test.cpp +++ b/src/plugins/fakevim/fakevim_test.cpp @@ -4289,6 +4289,34 @@ void FakeVimPlugin::test_vim_replace_with_register_emulation() KEYS("v4lgr", "abc abci"); } +void FakeVimPlugin::test_vim_exchange_emulation() +{ + TestData data; + setup(&data); + data.doCommand("set exchange"); + + // Simple exchange + data.setText("abc def"); + KEYS("cxiw", "abc def"); + KEYS("W", "abc " X "def"); + KEYS(".", "def abc"); + + // Clearing pending exchange + data.setText("abc def ghi"); + KEYS("cxiw", "abc def ghi"); + KEYS("cxc", "abc def ghi"); + KEYS("W", "abc " X "def ghi"); + KEYS("cxiw", "abc def" X " ghi"); + KEYS("W", "abc def " X "ghi"); + KEYS(".", "abc ghi def"); + + // Exchange line + data.setText("abc" N "def"); + KEYS("cxx", "abc" N "def"); + KEYS("j", "abc" N "def"); + KEYS(".", "def" N "abc"); +} + void FakeVimPlugin::test_macros() { TestData data; diff --git a/src/plugins/fakevim/fakevimactions.cpp b/src/plugins/fakevim/fakevimactions.cpp index c32ca25a57b..51377387833 100644 --- a/src/plugins/fakevim/fakevimactions.cpp +++ b/src/plugins/fakevim/fakevimactions.cpp @@ -118,6 +118,7 @@ FakeVimSettings::FakeVimSettings() // Emulated plugins createAction(ConfigEmulateVimCommentary, false, "commentary"); createAction(ConfigEmulateReplaceWithRegister, false, "ReplaceWithRegister"); + createAction(ConfigEmulateExchange, false, "exchange"); } FakeVimSettings::~FakeVimSettings() diff --git a/src/plugins/fakevim/fakevimactions.h b/src/plugins/fakevim/fakevimactions.h index 828ad5204d3..b1de54a60e4 100644 --- a/src/plugins/fakevim/fakevimactions.h +++ b/src/plugins/fakevim/fakevimactions.h @@ -112,6 +112,7 @@ enum FakeVimSettingsCode // Plugin emulation ConfigEmulateVimCommentary, ConfigEmulateReplaceWithRegister, + ConfigEmulateExchange, ConfigBlinkingCursor }; diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index fe3f2262e51..5c393a714c4 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -168,6 +168,7 @@ enum SubMode NoSubMode, ChangeSubMode, // Used for c DeleteSubMode, // Used for d + ExchangeSubMode, // Used for cx FilterSubMode, // Used for ! IndentSubMode, // Used for = RegisterSubMode, // Used for " @@ -1346,6 +1347,8 @@ QString dotCommandFromSubMode(SubMode submode) return QLatin1String("d"); if (submode == CommentSubMode) return QLatin1String("gc"); + if (submode == ExchangeSubMode) + return QLatin1String("cx"); if (submode == ReplaceWithRegisterSubMode) return QLatin1String("gr"); if (submode == InvertCaseSubMode) @@ -1830,6 +1833,7 @@ public: bool handleReplaceSubMode(const Input &); bool handleCommentSubMode(const Input &); bool handleReplaceWithRegisterSubMode(const Input &); + bool handleExchangeSubMode(const Input &); bool handleFilterSubMode(const Input &); bool handleRegisterSubMode(const Input &); bool handleShiftSubMode(const Input &); @@ -2092,6 +2096,7 @@ public: bool isOperatorPending() const { return g.submode == ChangeSubMode || g.submode == DeleteSubMode + || g.submode == ExchangeSubMode || g.submode == CommentSubMode || g.submode == ReplaceWithRegisterSubMode || g.submode == FilterSubMode @@ -2171,6 +2176,8 @@ public: void toggleComment(const Range &range); + void exchangeRange(const Range &range); + void replaceWithRegister(const Range &range); void upCase(const Range &range); @@ -2409,6 +2416,10 @@ public: QString recorded; int currentRegister = 0; int lastExecutedRegister = 0; + + // If empty, cx{motion} will store the range defined by {motion} here. + // If non-empty, cx{motion} replaces the {motion} with selectText(*exchangeData) + std::optional<Range> exchangeRange; } g; }; @@ -3597,6 +3608,7 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommandMovement) if (g.submode == ChangeSubMode || g.submode == DeleteSubMode || g.submode == CommentSubMode + || g.submode == ExchangeSubMode || g.submode == ReplaceWithRegisterSubMode || g.submode == YankSubMode || g.submode == InvertCaseSubMode @@ -3629,6 +3641,8 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommandMovement) beginEditBlock(); toggleComment(currentRange()); endEditBlock(); + } else if (g.submode == ExchangeSubMode) { + exchangeRange(currentRange()); } else if (g.submode == ReplaceWithRegisterSubMode && hasConfig(ConfigEmulateReplaceWithRegister)) { pushUndoState(false); @@ -4281,6 +4295,12 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input) handled = handleCommandSubSubMode(input); } else if (g.submode == NoSubMode) { handled = handleNoSubMode(input); + } else if (g.submode == ExchangeSubMode) { + handled = handleExchangeSubMode(input); + } else if (g.submode == ChangeSubMode && input.is('x') && hasConfig(ConfigEmulateExchange)) { + // Exchange submode is "cx", so we need to switch over from ChangeSubMode here + g.submode = ExchangeSubMode; + handled = true; } else if (g.submode == ChangeSubMode || g.submode == DeleteSubMode || g.submode == YankSubMode) { @@ -4842,6 +4862,30 @@ bool FakeVimHandler::Private::handleReplaceWithRegisterSubMode(const Input &inpu return true; } +bool FakeVimHandler::Private::handleExchangeSubMode(const Input &input) +{ + if (input.is('c')) { // cxc + g.exchangeRange.reset(); + g.submode = NoSubMode; + return true; + } + + if (input.is('x')) { // cxx + setAnchorAndPosition(firstPositionInLine(cursorLine() + 1), + lastPositionInLine(cursorLine() + 1) + 1); + + setDotCommand("cxx"); + + finishMovement(); + + g.submode = NoSubMode; + + return true; + } + + return false; +} + bool FakeVimHandler::Private::handleFilterSubMode(const Input &) { return false; @@ -7484,6 +7528,32 @@ void FakeVimHandler::Private::toggleComment(const Range &range) }); } +void FakeVimHandler::Private::exchangeRange(const Range &range) +{ + if (g.exchangeRange) { + pushUndoState(false); + beginEditBlock(); + + Range leftRange = *g.exchangeRange; + Range rightRange = range; + if (leftRange.beginPos > rightRange.beginPos) + std::swap(leftRange, rightRange); + + // First replace the right range, then left one + // If we did it the other way around, we would invalidate the positions + // of the right range + const QString rightText = selectText(rightRange); + replaceText(rightRange, selectText(leftRange)); + replaceText(leftRange, rightText); + + g.exchangeRange.reset(); + + endEditBlock(); + } else { + g.exchangeRange = range; + } +} + void FakeVimHandler::Private::replaceWithRegister(const Range &range) { replaceText(range, registerContents(m_register)); diff --git a/src/plugins/fakevim/fakevimoptions.ui b/src/plugins/fakevim/fakevimoptions.ui index d8e26e2c509..c7d2d2e688a 100644 --- a/src/plugins/fakevim/fakevimoptions.ui +++ b/src/plugins/fakevim/fakevimoptions.ui @@ -165,7 +165,7 @@ <item row="0" column="0"> <widget class="QCheckBox" name="checkBoxVimCommentary"> <property name="text"> - <string>Vim-commentary</string> + <string>vim-commentary</string> </property> <property name="checked"> <bool>false</bool> @@ -179,6 +179,13 @@ </property> </widget> </item> + <item row="2" column="0"> + <widget class="QCheckBox" name="checkBoxExchange"> + <property name="text"> + <string>vim-exchange</string> + </property> + </widget> + </item> </layout> </widget> </item> diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index e11310d7de6..a2f34d268bd 100644 --- a/src/plugins/fakevim/fakevimplugin.cpp +++ b/src/plugins/fakevim/fakevimplugin.cpp @@ -431,6 +431,7 @@ QWidget *FakeVimOptionPage::widget() m_group.insert(theFakeVimSetting(ConfigEmulateVimCommentary), m_ui.checkBoxVimCommentary); m_group.insert(theFakeVimSetting(ConfigEmulateReplaceWithRegister), m_ui.checkBoxReplaceWithRegister); + m_group.insert(theFakeVimSetting(ConfigEmulateExchange), m_ui.checkBoxExchange); connect(m_ui.pushButtonCopyTextEditorSettings, &QAbstractButton::clicked, this, &FakeVimOptionPage::copyTextEditorSettings); diff --git a/src/plugins/fakevim/fakevimplugin.h b/src/plugins/fakevim/fakevimplugin.h index ad5d64fb2fb..37950c37d40 100644 --- a/src/plugins/fakevim/fakevimplugin.h +++ b/src/plugins/fakevim/fakevimplugin.h @@ -161,6 +161,7 @@ private slots: void test_vim_commentary_emulation(); void test_vim_commentary_file_names(); void test_vim_replace_with_register_emulation(); + void test_vim_exchange_emulation(); void test_macros(); |