forked from qt-creator/qt-creator
FakeVim: Add emulation for vim-surround plugin
Change-Id: If450d04dd89a1707ab05806522fbf4cc987d454b Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -128,11 +128,12 @@
|
|||||||
\li \c [count]["x]gr{motion} to replace \c {motion} with the contents of
|
\li \c [count]["x]gr{motion} to replace \c {motion} with the contents of
|
||||||
register \c x.
|
register \c x.
|
||||||
\li ["x]grr to replace the current line.
|
\li ["x]grr to replace the current line.
|
||||||
\l{https://github.com/tommcdo/vim-exchange}{vim-exchange}
|
|
||||||
\endlist
|
\endlist
|
||||||
|
\li \l{https://github.com/tommcdo/vim-exchange}{vim-exchange}
|
||||||
\li \l{https://github.com/vim-scripts/argtextobj.vim}{argtextobj.vim}:
|
\li \l{https://github.com/vim-scripts/argtextobj.vim}{argtextobj.vim}:
|
||||||
Defines the \c ia and \c aa text objects for function parameters.
|
Defines the \c ia and \c aa text objects for function parameters.
|
||||||
\endlist
|
\li \l{https://github.com/tpope/vim-surround}{vim-surround}:
|
||||||
|
Adds mappings for deleting, adding and changing surroundings.
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
\section2 Insert Mode
|
\section2 Insert Mode
|
||||||
|
@@ -4341,6 +4341,76 @@ void FakeVimPlugin::test_vim_arg_text_obj_emulation()
|
|||||||
KEYS("dia", "foo()");
|
KEYS("dia", "foo()");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FakeVimPlugin::test_vim_surround_emulation()
|
||||||
|
{
|
||||||
|
TestData data;
|
||||||
|
setup(&data);
|
||||||
|
data.doCommand("set surround");
|
||||||
|
|
||||||
|
// ys and ds
|
||||||
|
data.setText("abc");
|
||||||
|
KEYS(R"(ysawb)", R"((abc))");
|
||||||
|
KEYS(R"(ysabB)", R"({(abc)})");
|
||||||
|
KEYS(R"(ysaB])", R"([{(abc)}])");
|
||||||
|
KEYS(R"(ysa]>)", R"(<[{(abc)}]>)");
|
||||||
|
KEYS(R"(ysa>")", R"("<[{(abc)}]>")");
|
||||||
|
KEYS(R"(ysa"')", R"('"<[{(abc)}]>"')");
|
||||||
|
KEYS(R"(ds')", R"("<[{(abc)}]>")");
|
||||||
|
KEYS(R"(ds")", R"(<[{(abc)}]>)");
|
||||||
|
KEYS(R"(ds>)", R"([{(abc)}])");
|
||||||
|
KEYS(R"(ds])", R"({(abc)})");
|
||||||
|
KEYS(R"(ds})", R"((abc))");
|
||||||
|
KEYS(R"(ds))", R"(abc)");
|
||||||
|
|
||||||
|
data.setText("abc d|ef ghi");
|
||||||
|
KEYS("ysiWb", "abc (def) ghi");
|
||||||
|
KEYS(".", "abc ((def)) ghi");
|
||||||
|
KEYS("dsb", "abc (def) ghi");
|
||||||
|
KEYS(".", "abc def ghi");
|
||||||
|
KEYS("ysaWb", "abc (def) ghi");
|
||||||
|
KEYS(".", "abc ((def)) ghi");
|
||||||
|
KEYS("dsb", "abc (def) ghi");
|
||||||
|
KEYS(".", "abc def ghi");
|
||||||
|
|
||||||
|
// yss
|
||||||
|
data.setText("\t" "abc");
|
||||||
|
KEYS("yssb", "\t" "(abc)");
|
||||||
|
KEYS(".", "\t" "((abc))");
|
||||||
|
|
||||||
|
// Surround with function
|
||||||
|
data.setText("abc");
|
||||||
|
KEYS("ysiWftest<CR>", "test(abc)");
|
||||||
|
KEYS(".", "test(test(abc))");
|
||||||
|
|
||||||
|
// yS puts text on a new line
|
||||||
|
data.setText("abc");
|
||||||
|
KEYS("ySsB", "{" N
|
||||||
|
"abc" N
|
||||||
|
"}");
|
||||||
|
|
||||||
|
// cs
|
||||||
|
data.setText("(abc)");
|
||||||
|
KEYS(R"(csbB)", R"({abc})");
|
||||||
|
KEYS(R"(csB])", R"([abc])");
|
||||||
|
KEYS(R"(cs]>)", R"(<abc>)");
|
||||||
|
KEYS(R"(cs>")", R"("abc")");
|
||||||
|
KEYS(R"(cs"')", R"('abc')");
|
||||||
|
|
||||||
|
// Visual line mode
|
||||||
|
data.setText("abc" N);
|
||||||
|
KEYS("VSB", "{" N
|
||||||
|
"abc" N
|
||||||
|
"}" N);
|
||||||
|
|
||||||
|
// Visual char mode
|
||||||
|
data.setText("abc");
|
||||||
|
KEYS("vlSB", "{ab}c");
|
||||||
|
|
||||||
|
// Visual block mode
|
||||||
|
data.setText("abc" N "def");
|
||||||
|
KEYS("<C-v>ljSB", "{ab}c" N "{de}f");
|
||||||
|
}
|
||||||
|
|
||||||
void FakeVimPlugin::test_macros()
|
void FakeVimPlugin::test_macros()
|
||||||
{
|
{
|
||||||
TestData data;
|
TestData data;
|
||||||
|
@@ -120,6 +120,7 @@ FakeVimSettings::FakeVimSettings()
|
|||||||
createAction(ConfigEmulateReplaceWithRegister, false, "ReplaceWithRegister");
|
createAction(ConfigEmulateReplaceWithRegister, false, "ReplaceWithRegister");
|
||||||
createAction(ConfigEmulateExchange, false, "exchange");
|
createAction(ConfigEmulateExchange, false, "exchange");
|
||||||
createAction(ConfigEmulateArgTextObj, false, "argtextobj");
|
createAction(ConfigEmulateArgTextObj, false, "argtextobj");
|
||||||
|
createAction(ConfigEmulateSurround, false, "surround");
|
||||||
}
|
}
|
||||||
|
|
||||||
FakeVimSettings::~FakeVimSettings()
|
FakeVimSettings::~FakeVimSettings()
|
||||||
|
@@ -114,6 +114,7 @@ enum FakeVimSettingsCode
|
|||||||
ConfigEmulateReplaceWithRegister,
|
ConfigEmulateReplaceWithRegister,
|
||||||
ConfigEmulateExchange,
|
ConfigEmulateExchange,
|
||||||
ConfigEmulateArgTextObj,
|
ConfigEmulateArgTextObj,
|
||||||
|
ConfigEmulateSurround,
|
||||||
|
|
||||||
ConfigBlinkingCursor
|
ConfigBlinkingCursor
|
||||||
};
|
};
|
||||||
|
@@ -171,6 +171,9 @@ enum SubMode
|
|||||||
ChangeSubMode, // Used for c
|
ChangeSubMode, // Used for c
|
||||||
DeleteSubMode, // Used for d
|
DeleteSubMode, // Used for d
|
||||||
ExchangeSubMode, // Used for cx
|
ExchangeSubMode, // Used for cx
|
||||||
|
DeleteSurroundingSubMode, // Used for ds
|
||||||
|
ChangeSurroundingSubMode, // Used for cs
|
||||||
|
AddSurroundingSubMode, // Used for ys
|
||||||
FilterSubMode, // Used for !
|
FilterSubMode, // Used for !
|
||||||
IndentSubMode, // Used for =
|
IndentSubMode, // Used for =
|
||||||
RegisterSubMode, // Used for "
|
RegisterSubMode, // Used for "
|
||||||
@@ -206,7 +209,9 @@ enum SubSubMode
|
|||||||
ZSubSubMode, // Used for zj, zk
|
ZSubSubMode, // Used for zj, zk
|
||||||
OpenSquareSubSubMode, // Used for [{, {(, [z
|
OpenSquareSubSubMode, // Used for [{, {(, [z
|
||||||
CloseSquareSubSubMode, // Used for ]}, ]), ]z
|
CloseSquareSubSubMode, // Used for ]}, ]), ]z
|
||||||
SearchSubSubMode,
|
SearchSubSubMode, // Used for /, ?
|
||||||
|
SurroundSubSubMode, // Used for cs, ds, ys
|
||||||
|
SurroundWithFunctionSubSubMode, // Used for ys{motion}f
|
||||||
CtrlVUnicodeSubSubMode // Used for Ctrl-v based unicode input
|
CtrlVUnicodeSubSubMode // Used for Ctrl-v based unicode input
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1349,6 +1354,12 @@ QString dotCommandFromSubMode(SubMode submode)
|
|||||||
return QLatin1String("d");
|
return QLatin1String("d");
|
||||||
if (submode == CommentSubMode)
|
if (submode == CommentSubMode)
|
||||||
return QLatin1String("gc");
|
return QLatin1String("gc");
|
||||||
|
if (submode == DeleteSurroundingSubMode)
|
||||||
|
return QLatin1String("ds");
|
||||||
|
if (submode == ChangeSurroundingSubMode)
|
||||||
|
return QLatin1String("c");
|
||||||
|
if (submode == AddSurroundingSubMode)
|
||||||
|
return QLatin1String("y");
|
||||||
if (submode == ExchangeSubMode)
|
if (submode == ExchangeSubMode)
|
||||||
return QLatin1String("cx");
|
return QLatin1String("cx");
|
||||||
if (submode == ReplaceWithRegisterSubMode)
|
if (submode == ReplaceWithRegisterSubMode)
|
||||||
@@ -1836,6 +1847,8 @@ public:
|
|||||||
bool handleCommentSubMode(const Input &);
|
bool handleCommentSubMode(const Input &);
|
||||||
bool handleReplaceWithRegisterSubMode(const Input &);
|
bool handleReplaceWithRegisterSubMode(const Input &);
|
||||||
bool handleExchangeSubMode(const Input &);
|
bool handleExchangeSubMode(const Input &);
|
||||||
|
bool handleDeleteChangeSurroundingSubMode(const Input &);
|
||||||
|
bool handleAddSurroundingSubMode(const Input &);
|
||||||
bool handleFilterSubMode(const Input &);
|
bool handleFilterSubMode(const Input &);
|
||||||
bool handleRegisterSubMode(const Input &);
|
bool handleRegisterSubMode(const Input &);
|
||||||
bool handleShiftSubMode(const Input &);
|
bool handleShiftSubMode(const Input &);
|
||||||
@@ -2101,6 +2114,7 @@ public:
|
|||||||
|| g.submode == ExchangeSubMode
|
|| g.submode == ExchangeSubMode
|
||||||
|| g.submode == CommentSubMode
|
|| g.submode == CommentSubMode
|
||||||
|| g.submode == ReplaceWithRegisterSubMode
|
|| g.submode == ReplaceWithRegisterSubMode
|
||||||
|
|| g.submode == AddSurroundingSubMode
|
||||||
|| g.submode == FilterSubMode
|
|| g.submode == FilterSubMode
|
||||||
|| g.submode == IndentSubMode
|
|| g.submode == IndentSubMode
|
||||||
|| g.submode == ShiftLeftSubMode
|
|| g.submode == ShiftLeftSubMode
|
||||||
@@ -2183,6 +2197,8 @@ public:
|
|||||||
|
|
||||||
void replaceWithRegister(const Range &range);
|
void replaceWithRegister(const Range &range);
|
||||||
|
|
||||||
|
void surroundCurrentRange(const Input &input, const QString &prefix = {});
|
||||||
|
|
||||||
void upCase(const Range &range);
|
void upCase(const Range &range);
|
||||||
|
|
||||||
void downCase(const Range &range);
|
void downCase(const Range &range);
|
||||||
@@ -2423,6 +2439,9 @@ public:
|
|||||||
// If empty, cx{motion} will store the range defined by {motion} here.
|
// If empty, cx{motion} will store the range defined by {motion} here.
|
||||||
// If non-empty, cx{motion} replaces the {motion} with selectText(*exchangeData)
|
// If non-empty, cx{motion} replaces the {motion} with selectText(*exchangeData)
|
||||||
Utils::optional<Range> exchangeRange;
|
Utils::optional<Range> exchangeRange;
|
||||||
|
|
||||||
|
bool surroundUpperCaseS; // True for yS and cS, false otherwise
|
||||||
|
QString surroundFunction; // Used for storing the function name provided to ys{motion}f
|
||||||
} g;
|
} g;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -3613,6 +3632,7 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommandMovement)
|
|||||||
|| g.submode == CommentSubMode
|
|| g.submode == CommentSubMode
|
||||||
|| g.submode == ExchangeSubMode
|
|| g.submode == ExchangeSubMode
|
||||||
|| g.submode == ReplaceWithRegisterSubMode
|
|| g.submode == ReplaceWithRegisterSubMode
|
||||||
|
|| g.submode == AddSurroundingSubMode
|
||||||
|| g.submode == YankSubMode
|
|| g.submode == YankSubMode
|
||||||
|| g.submode == InvertCaseSubMode
|
|| g.submode == InvertCaseSubMode
|
||||||
|| g.submode == DownCaseSubMode
|
|| g.submode == DownCaseSubMode
|
||||||
@@ -3644,6 +3664,15 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommandMovement)
|
|||||||
beginEditBlock();
|
beginEditBlock();
|
||||||
toggleComment(currentRange());
|
toggleComment(currentRange());
|
||||||
endEditBlock();
|
endEditBlock();
|
||||||
|
} else if (g.submode == AddSurroundingSubMode) {
|
||||||
|
g.subsubmode = SurroundSubSubMode;
|
||||||
|
g.dotCommand = dotCommandMovement;
|
||||||
|
|
||||||
|
// We now only know the region that should be surrounded, but not the actual
|
||||||
|
// character that should surround it. We thus do NOT want to finish the
|
||||||
|
// movement yet here, so we return early.
|
||||||
|
// The next character entered will be used by the SurroundSubSubMode.
|
||||||
|
return;
|
||||||
} else if (g.submode == ExchangeSubMode) {
|
} else if (g.submode == ExchangeSubMode) {
|
||||||
exchangeRange(currentRange());
|
exchangeRange(currentRange());
|
||||||
} else if (g.submode == ReplaceWithRegisterSubMode
|
} else if (g.submode == ReplaceWithRegisterSubMode
|
||||||
@@ -3749,6 +3778,8 @@ void FakeVimHandler::Private::clearCurrentMode()
|
|||||||
g.subsubmode = NoSubSubMode;
|
g.subsubmode = NoSubSubMode;
|
||||||
g.movetype = MoveInclusive;
|
g.movetype = MoveInclusive;
|
||||||
g.gflag = false;
|
g.gflag = false;
|
||||||
|
g.surroundUpperCaseS = false;
|
||||||
|
g.surroundFunction.clear();
|
||||||
m_register = '"';
|
m_register = '"';
|
||||||
g.rangemode = RangeCharMode;
|
g.rangemode = RangeCharMode;
|
||||||
g.currentCommand.clear();
|
g.currentCommand.clear();
|
||||||
@@ -3908,6 +3939,11 @@ bool FakeVimHandler::Private::handleCommandSubSubMode(const Input &input)
|
|||||||
.arg(g.semicolonKey));
|
.arg(g.semicolonKey));
|
||||||
}
|
}
|
||||||
} else if (g.subsubmode == TextObjectSubSubMode) {
|
} else if (g.subsubmode == TextObjectSubSubMode) {
|
||||||
|
// vim-surround treats aw and aW the same as iw and iW, respectively
|
||||||
|
if ((input.is('w') || input.is('W'))
|
||||||
|
&& g.submode == AddSurroundingSubMode && g.subsubdata.is('a'))
|
||||||
|
g.subsubdata = Input('i');
|
||||||
|
|
||||||
if (input.is('w'))
|
if (input.is('w'))
|
||||||
selectWordTextObject(g.subsubdata.is('i'));
|
selectWordTextObject(g.subsubdata.is('i'));
|
||||||
else if (input.is('W'))
|
else if (input.is('W'))
|
||||||
@@ -3987,6 +4023,37 @@ bool FakeVimHandler::Private::handleCommandSubSubMode(const Input &input)
|
|||||||
.arg(g.subsubmode == OpenSquareSubSubMode ? '[' : ']')
|
.arg(g.subsubmode == OpenSquareSubSubMode ? '[' : ']')
|
||||||
.arg(input.text()));
|
.arg(input.text()));
|
||||||
}
|
}
|
||||||
|
} else if (g.subsubmode == SurroundWithFunctionSubSubMode) {
|
||||||
|
if (input.isReturn()) {
|
||||||
|
pushUndoState(false);
|
||||||
|
beginEditBlock();
|
||||||
|
|
||||||
|
const QString dotCommand = "ys" + g.dotCommand + "f" + g.surroundFunction + "<CR>";
|
||||||
|
|
||||||
|
surroundCurrentRange(Input(')'), g.surroundFunction);
|
||||||
|
|
||||||
|
g.dotCommand = dotCommand;
|
||||||
|
|
||||||
|
endEditBlock();
|
||||||
|
leaveCurrentMode();
|
||||||
|
} else {
|
||||||
|
g.surroundFunction += input.asChar();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else if (g.subsubmode == SurroundSubSubMode) {
|
||||||
|
if (input.is('f') && g.submode == AddSurroundingSubMode) {
|
||||||
|
g.subsubmode = SurroundWithFunctionSubSubMode;
|
||||||
|
g.commandBuffer.setContents("");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pushUndoState(false);
|
||||||
|
beginEditBlock();
|
||||||
|
|
||||||
|
surroundCurrentRange(input);
|
||||||
|
|
||||||
|
endEditBlock();
|
||||||
|
leaveCurrentMode();
|
||||||
} else {
|
} else {
|
||||||
handled = false;
|
handled = false;
|
||||||
}
|
}
|
||||||
@@ -4306,6 +4373,25 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
|
|||||||
// Exchange submode is "cx", so we need to switch over from ChangeSubMode here
|
// Exchange submode is "cx", so we need to switch over from ChangeSubMode here
|
||||||
g.submode = ExchangeSubMode;
|
g.submode = ExchangeSubMode;
|
||||||
handled = true;
|
handled = true;
|
||||||
|
} else if (g.submode == DeleteSurroundingSubMode
|
||||||
|
|| g.submode == ChangeSurroundingSubMode) {
|
||||||
|
handled = handleDeleteChangeSurroundingSubMode(input);
|
||||||
|
} else if (g.submode == AddSurroundingSubMode) {
|
||||||
|
handled = handleAddSurroundingSubMode(input);
|
||||||
|
} else if (g.submode == ChangeSubMode && (input.is('s') || input.is('S'))
|
||||||
|
&& hasConfig(ConfigEmulateSurround)) {
|
||||||
|
g.submode = ChangeSurroundingSubMode;
|
||||||
|
g.surroundUpperCaseS = input.is('S');
|
||||||
|
handled = true;
|
||||||
|
} else if (g.submode == DeleteSubMode && input.is('s') && hasConfig(ConfigEmulateSurround)) {
|
||||||
|
g.submode = DeleteSurroundingSubMode;
|
||||||
|
handled = true;
|
||||||
|
} else if (g.submode == YankSubMode && (input.is('s') || input.is('S'))
|
||||||
|
&& hasConfig(ConfigEmulateSurround)) {
|
||||||
|
g.submode = AddSurroundingSubMode;
|
||||||
|
g.movetype = MoveInclusive;
|
||||||
|
g.surroundUpperCaseS = input.is('S');
|
||||||
|
handled = true;
|
||||||
} else if (g.submode == ChangeSubMode
|
} else if (g.submode == ChangeSubMode
|
||||||
|| g.submode == DeleteSubMode
|
|| g.submode == DeleteSubMode
|
||||||
|| g.submode == YankSubMode) {
|
|| g.submode == YankSubMode) {
|
||||||
@@ -4640,6 +4726,9 @@ bool FakeVimHandler::Private::handleNoSubMode(const Input &input)
|
|||||||
int repeat = count();
|
int repeat = count();
|
||||||
while (--repeat >= 0)
|
while (--repeat >= 0)
|
||||||
redo();
|
redo();
|
||||||
|
} else if (input.is('S') && isVisualMode() && hasConfig(ConfigEmulateSurround)) {
|
||||||
|
g.submode = AddSurroundingSubMode;
|
||||||
|
g.subsubmode = SurroundSubSubMode;
|
||||||
} else if (input.is('s')) {
|
} else if (input.is('s')) {
|
||||||
handleAs("c%1l");
|
handleAs("c%1l");
|
||||||
} else if (input.is('S')) {
|
} else if (input.is('S')) {
|
||||||
@@ -4891,6 +4980,69 @@ bool FakeVimHandler::Private::handleExchangeSubMode(const Input &input)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FakeVimHandler::Private::handleDeleteChangeSurroundingSubMode(const Input &input)
|
||||||
|
{
|
||||||
|
if (g.submode != ChangeSurroundingSubMode && g.submode != DeleteSurroundingSubMode)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool handled = false;
|
||||||
|
|
||||||
|
if (input.is('(') || input.is(')') || input.is('b')) {
|
||||||
|
handled = selectBlockTextObject(false, '(', ')');
|
||||||
|
} else if (input.is('{') || input.is('}') || input.is('B')) {
|
||||||
|
handled = selectBlockTextObject(false, '{', '}');
|
||||||
|
} else if (input.is('[') || input.is(']')) {
|
||||||
|
handled = selectBlockTextObject(false, '[', ']');
|
||||||
|
} else if (input.is('<') || input.is('>') || input.is('t')) {
|
||||||
|
handled = selectBlockTextObject(false, '<', '>');
|
||||||
|
} else if (input.is('"') || input.is('\'') || input.is('`')) {
|
||||||
|
handled = selectQuotedStringTextObject(false, input.asChar());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handled) {
|
||||||
|
if (g.submode == DeleteSurroundingSubMode) {
|
||||||
|
pushUndoState(false);
|
||||||
|
beginEditBlock();
|
||||||
|
|
||||||
|
// Surround is always one character, so just delete the first and last one
|
||||||
|
transformText(currentRange(), [](const QString &text) {
|
||||||
|
return text.mid(1, text.size() - 2);
|
||||||
|
});
|
||||||
|
|
||||||
|
endEditBlock();
|
||||||
|
clearCurrentMode();
|
||||||
|
|
||||||
|
g.dotCommand = "ds" + input.asChar();
|
||||||
|
} else if (g.submode == ChangeSurroundingSubMode) {
|
||||||
|
g.subsubmode = SurroundSubSubMode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FakeVimHandler::Private::handleAddSurroundingSubMode(const Input &input)
|
||||||
|
{
|
||||||
|
if (!input.is('s'))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
g.subsubmode = SurroundSubSubMode;
|
||||||
|
|
||||||
|
int anc = firstPositionInLine(cursorLine() + 1);
|
||||||
|
const int pos = lastPositionInLine(cursorLine() + 1);
|
||||||
|
|
||||||
|
// Ignore leading spaces
|
||||||
|
while ((characterAt(anc) == " " || characterAt(anc) == "\t") && anc != pos) {
|
||||||
|
anc++;
|
||||||
|
}
|
||||||
|
|
||||||
|
setAnchorAndPosition(anc, pos);
|
||||||
|
|
||||||
|
finishMovement("s");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool FakeVimHandler::Private::handleFilterSubMode(const Input &)
|
bool FakeVimHandler::Private::handleFilterSubMode(const Input &)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -7564,6 +7716,77 @@ void FakeVimHandler::Private::replaceWithRegister(const Range &range)
|
|||||||
replaceText(range, registerContents(m_register));
|
replaceText(range, registerContents(m_register));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FakeVimHandler::Private::surroundCurrentRange(const Input &input, const QString &prefix)
|
||||||
|
{
|
||||||
|
QString dotCommand;
|
||||||
|
if (isVisualMode())
|
||||||
|
dotCommand = visualDotCommand() + "S" + input.asChar();
|
||||||
|
|
||||||
|
const bool wasVisualCharMode = isVisualCharMode();
|
||||||
|
const bool wasVisualLineMode = isVisualLineMode();
|
||||||
|
leaveVisualMode();
|
||||||
|
|
||||||
|
if (dotCommand.isEmpty()) { // i.e. we came from normal mode
|
||||||
|
dotCommand = dotCommandFromSubMode(g.submode) + (g.surroundUpperCaseS ? "S" : "s")
|
||||||
|
+ g.dotCommand + input.asChar();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wasVisualCharMode)
|
||||||
|
setPosition(position() + 1);
|
||||||
|
|
||||||
|
QString newFront, newBack;
|
||||||
|
|
||||||
|
if (input.is('(') || input.is(')') || input.is('b')) {
|
||||||
|
newFront = '(';
|
||||||
|
newBack = ')';
|
||||||
|
} else if (input.is('{') || input.is('}') || input.is('B')) {
|
||||||
|
newFront = '{';
|
||||||
|
newBack = '}';
|
||||||
|
} else if (input.is('[') || input.is(']')) {
|
||||||
|
newFront = '[';
|
||||||
|
newBack = ']';
|
||||||
|
} else if (input.is('<') || input.is('>') || input.is('t')) {
|
||||||
|
newFront = '<';
|
||||||
|
newBack = '>';
|
||||||
|
} else if (input.is('"') || input.is('\'') || input.is('`')) {
|
||||||
|
newFront = input.asChar();
|
||||||
|
newBack = input.asChar();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g.surroundUpperCaseS || wasVisualLineMode) {
|
||||||
|
// yS and cS add a new line before and after the surrounded text
|
||||||
|
newFront += "\n";
|
||||||
|
if (wasVisualLineMode)
|
||||||
|
newBack += "\n";
|
||||||
|
else
|
||||||
|
newBack = "\n" + newBack;
|
||||||
|
} else if (input.is('(') || input.is('{') || input.is('[') || input.is('[')) {
|
||||||
|
// Opening characters add an extra space
|
||||||
|
newFront = newFront + " ";
|
||||||
|
newBack = " " + newBack;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!newFront.isEmpty()) {
|
||||||
|
transformText(currentRange(), [&](QString text) -> QString {
|
||||||
|
if (newFront == QChar())
|
||||||
|
return text.mid(1, text.size() - 2);
|
||||||
|
|
||||||
|
const QString newMiddle = (g.submode == ChangeSurroundingSubMode) ?
|
||||||
|
text.mid(1, text.size() - 2) : text;
|
||||||
|
|
||||||
|
return prefix + newFront + newMiddle + newBack;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// yS, cS and VS also indent the surrounded text
|
||||||
|
if (g.surroundUpperCaseS || wasVisualLineMode)
|
||||||
|
replay("=a" + input.asChar());
|
||||||
|
|
||||||
|
// Indenting has changed the dotCommand, so now set it back to the correct one
|
||||||
|
g.dotCommand = dotCommand;
|
||||||
|
}
|
||||||
|
|
||||||
void FakeVimHandler::Private::replaceText(const Range &range, const QString &str)
|
void FakeVimHandler::Private::replaceText(const Range &range, const QString &str)
|
||||||
{
|
{
|
||||||
transformText(range, [&str](const QString &) { return str; } );
|
transformText(range, [&str](const QString &) { return str; } );
|
||||||
|
@@ -7,7 +7,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>580</width>
|
<width>580</width>
|
||||||
<height>543</height>
|
<height>568</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
@@ -162,6 +162,20 @@
|
|||||||
<string>Plugin Emulation</string>
|
<string>Plugin Emulation</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QCheckBox" name="checkBoxExchange">
|
||||||
|
<property name="text">
|
||||||
|
<string>vim-exchange</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QCheckBox" name="checkBoxArgTextObj">
|
||||||
|
<property name="text">
|
||||||
|
<string>argtextobj.vim</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="1" column="0">
|
||||||
<widget class="QCheckBox" name="checkBoxReplaceWithRegister">
|
<widget class="QCheckBox" name="checkBoxReplaceWithRegister">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@@ -179,17 +193,10 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="4" column="0">
|
||||||
<widget class="QCheckBox" name="checkBoxArgTextObj">
|
<widget class="QCheckBox" name="checkBoxVimSurround">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>argtextobj.vim</string>
|
<string>vim-surround</string>
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="0">
|
|
||||||
<widget class="QCheckBox" name="checkBoxExchange">
|
|
||||||
<property name="text">
|
|
||||||
<string>vim-exchange</string>
|
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@@ -433,6 +433,7 @@ QWidget *FakeVimOptionPage::widget()
|
|||||||
m_group.insert(theFakeVimSetting(ConfigEmulateReplaceWithRegister), m_ui.checkBoxReplaceWithRegister);
|
m_group.insert(theFakeVimSetting(ConfigEmulateReplaceWithRegister), m_ui.checkBoxReplaceWithRegister);
|
||||||
m_group.insert(theFakeVimSetting(ConfigEmulateExchange), m_ui.checkBoxExchange);
|
m_group.insert(theFakeVimSetting(ConfigEmulateExchange), m_ui.checkBoxExchange);
|
||||||
m_group.insert(theFakeVimSetting(ConfigEmulateArgTextObj), m_ui.checkBoxArgTextObj);
|
m_group.insert(theFakeVimSetting(ConfigEmulateArgTextObj), m_ui.checkBoxArgTextObj);
|
||||||
|
m_group.insert(theFakeVimSetting(ConfigEmulateSurround), m_ui.checkBoxVimSurround);
|
||||||
|
|
||||||
connect(m_ui.pushButtonCopyTextEditorSettings, &QAbstractButton::clicked,
|
connect(m_ui.pushButtonCopyTextEditorSettings, &QAbstractButton::clicked,
|
||||||
this, &FakeVimOptionPage::copyTextEditorSettings);
|
this, &FakeVimOptionPage::copyTextEditorSettings);
|
||||||
|
@@ -163,6 +163,7 @@ private slots:
|
|||||||
void test_vim_replace_with_register_emulation();
|
void test_vim_replace_with_register_emulation();
|
||||||
void test_vim_exchange_emulation();
|
void test_vim_exchange_emulation();
|
||||||
void test_vim_arg_text_obj_emulation();
|
void test_vim_arg_text_obj_emulation();
|
||||||
|
void test_vim_surround_emulation();
|
||||||
|
|
||||||
void test_macros();
|
void test_macros();
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user