FakeVim: Add emulation of vim-exchange plugin

Change-Id: I844c9bf11231ab842cee020a0e7a29af8ed209eb
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Tom Praschan
2021-01-30 12:29:14 +01:00
parent 3b1bc1d053
commit f83eeb0548
8 changed files with 111 additions and 1 deletions

View File

@@ -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

View File

@@ -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;

View File

@@ -118,6 +118,7 @@ FakeVimSettings::FakeVimSettings()
// Emulated plugins
createAction(ConfigEmulateVimCommentary, false, "commentary");
createAction(ConfigEmulateReplaceWithRegister, false, "ReplaceWithRegister");
createAction(ConfigEmulateExchange, false, "exchange");
}
FakeVimSettings::~FakeVimSettings()

View File

@@ -112,6 +112,7 @@ enum FakeVimSettingsCode
// Plugin emulation
ConfigEmulateVimCommentary,
ConfigEmulateReplaceWithRegister,
ConfigEmulateExchange,
ConfigBlinkingCursor
};

View File

@@ -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));

View File

@@ -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>

View File

@@ -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);

View File

@@ -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();