diff --git a/src/plugins/fakevim/fakevim_test.cpp b/src/plugins/fakevim/fakevim_test.cpp index 88973a5200e..81eee1973f0 100644 --- a/src/plugins/fakevim/fakevim_test.cpp +++ b/src/plugins/fakevim/fakevim_test.cpp @@ -3006,6 +3006,18 @@ void FakeVimPlugin::test_vim_substitute() COMMAND("undo | s/[bcef]//g", "a d"); COMMAND("undo | s/\\w//g", " "); COMMAND("undo | s/f\\|$/-/g", "abc de-"); + + // modifiers + data.setText("abC dEfGh"); + COMMAND("s/b...E/\\u&", "aBC dEfGh"); + COMMAND("undo | s/b...E/\\U&/g", "aBC DEfGh"); + COMMAND("undo | s/C..E/\\l&/g", "abc dEfGh"); + COMMAND("undo | s/b...E/\\L&/g", "abc defGh"); + + COMMAND("undo | s/\\(b...E\\)/\\u\\1/g", "aBC dEfGh"); + COMMAND("undo | s/\\(b...E\\)/\\U\\1/g", "aBC DEfGh"); + COMMAND("undo | s/\\(C..E\\)/\\l\\1/g", "abc dEfGh"); + COMMAND("undo | s/\\(b...E\\)/\\L\\1/g", "abc defGh"); } void FakeVimPlugin::test_vim_ex_commandbuffer_paste() diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index ea0be66d54a..e4147e55806 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -700,6 +700,47 @@ static char backslashed(char t) return t; } +enum class Modifier {NONE,UPPERCASE,LOWERCASE}; + +static QString applyReplacementLetterCases(QString repl, + Modifier &toggledModifier, + Modifier &nextCharacterModifier) +{ + if (toggledModifier == Modifier::UPPERCASE) + repl = repl.toUpper(); + else if (toggledModifier == Modifier::LOWERCASE) + repl = repl.toLower(); + + if (nextCharacterModifier == Modifier::UPPERCASE) { + repl.replace(0, 1, repl.at(0).toUpper()); + nextCharacterModifier = Modifier::NONE; + } else if (nextCharacterModifier == Modifier::LOWERCASE) { + repl.replace(0, 1, repl.at(0).toLower()); + nextCharacterModifier = Modifier::NONE; + } + return repl; +} + +static QChar applyReplacementLetterCases(QChar repl, + Modifier &toggledModifier, + Modifier &nextCharacterModifier) +{ + if (nextCharacterModifier == Modifier::UPPERCASE){ + nextCharacterModifier = Modifier::NONE; + return repl.toUpper(); + } + else if (nextCharacterModifier == Modifier::LOWERCASE) { + nextCharacterModifier = Modifier::NONE; + return repl.toLower(); + } + else if (toggledModifier == Modifier::UPPERCASE) + return repl.toUpper(); + else if (toggledModifier == Modifier::LOWERCASE) + return repl.toLower(); + else + return repl; +} + static bool substituteText(QString *text, const QRegularExpression &pattern, const QString &replacement, @@ -729,14 +770,31 @@ static bool substituteText(QString *text, QString matched = text->mid(pos, match.captured(0).size()); QString repl; bool escape = false; + Modifier toggledModifier = Modifier::NONE; + Modifier nextCharacterModifier = Modifier::NONE; // insert captured texts for (int i = 0; i < replacement.size(); ++i) { const QChar &c = replacement[i]; if (escape) { escape = false; if (c.isDigit()) { - if (c.digitValue() <= match.lastCapturedIndex()) - repl += match.captured(c.digitValue()); + if (c.digitValue() <= match.lastCapturedIndex()) { + repl += applyReplacementLetterCases(match.captured(c.digitValue()), + toggledModifier, + nextCharacterModifier); + + } + } else if (c == 'u') { + nextCharacterModifier = Modifier::UPPERCASE; + } else if (c == 'l') { + nextCharacterModifier = Modifier::LOWERCASE; + } else if (c == 'U') { + toggledModifier = Modifier::UPPERCASE; + } else if (c == 'L') { + toggledModifier = Modifier::LOWERCASE; + } else if (c == 'e' || c == 'E') { + nextCharacterModifier = Modifier::NONE; + toggledModifier = Modifier::NONE; } else { repl += backslashed(c.unicode()); } @@ -744,9 +802,11 @@ static bool substituteText(QString *text, if (c == '\\') escape = true; else if (c == '&') - repl += match.captured(0); + repl += applyReplacementLetterCases(match.captured(0), + toggledModifier, + nextCharacterModifier); else - repl += c; + repl += applyReplacementLetterCases(c, toggledModifier, nextCharacterModifier); } } text->replace(pos, matched.size(), repl);