forked from qt-creator/qt-creator
FakeVim: Add emulation of vim-exchange plugin
Change-Id: I844c9bf11231ab842cee020a0e7a29af8ed209eb Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -118,6 +118,7 @@ FakeVimSettings::FakeVimSettings()
|
||||
// Emulated plugins
|
||||
createAction(ConfigEmulateVimCommentary, false, "commentary");
|
||||
createAction(ConfigEmulateReplaceWithRegister, false, "ReplaceWithRegister");
|
||||
createAction(ConfigEmulateExchange, false, "exchange");
|
||||
}
|
||||
|
||||
FakeVimSettings::~FakeVimSettings()
|
||||
|
||||
@@ -112,6 +112,7 @@ enum FakeVimSettingsCode
|
||||
// Plugin emulation
|
||||
ConfigEmulateVimCommentary,
|
||||
ConfigEmulateReplaceWithRegister,
|
||||
ConfigEmulateExchange,
|
||||
|
||||
ConfigBlinkingCursor
|
||||
};
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user