diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index 6d06fde11bbabf38da0edffaff9e1bdae0bb743b..fd457b87e153b3dd22665d4f2a7f6ccef2f7bd8d 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -1030,6 +1030,9 @@ public: QList<QTextEdit::ExtraSelection> m_searchSelections; QTextCursor m_searchCursor; QString m_oldNeedle; + QString m_lastSubstituteFlags; + QRegExp m_lastSubstitutePattern; + QString m_lastSubstituteReplacement; bool handleExCommandHelper(const ExCommand &cmd); // Returns success. bool handleExPluginCommand(const ExCommand &cmd); // Handled by plugin? @@ -2062,6 +2065,8 @@ EventResult FakeVimHandler::Private::handleCommandMode1(const Input &input) handleFfTt(m_semicolonKey); m_subsubmode = NoSubSubMode; finishMovement(); + } else if (input.is('&')) { + handleExCommand(m_gflag ? "%s//~/&" : "s"); } else if (input.is(':')) { enterExMode(); g.commandHistory.restart(); @@ -3267,84 +3272,124 @@ void FakeVimHandler::Private::handleCommand(const QString &cmd) bool FakeVimHandler::Private::handleExSubstituteCommand(const ExCommand &cmd) // :substitute { - QString line = cmd.cmd + ' ' + cmd.args; - line = line.trimmed(); - if (line.startsWith(_("substitute"))) - line = line.mid(10); - else if (line.startsWith('s') && line.size() > 1 - && !isalpha(line.at(1).unicode())) - line = line.mid(1); - else - return false; - - // we have /{pattern}/{string}/[flags] now - if (line.isEmpty()) - return false; - const QChar separator = line.at(0); - int pos1 = -1; - int pos2 = -1; - int i; - for (i = 1; i < line.size(); ++i) { - if (line.at(i) == separator && line.at(i - 1) != '\\') { - pos1 = i; - break; + QString flags; + QRegExp pattern; + QString replacement; + int count = 0; + + if (cmd.cmd.startsWith("&&")) { + flags = cmd.cmd.mid(2); + if (flags.isEmpty()) + flags = m_lastSubstituteFlags; + pattern = m_lastSubstitutePattern; + replacement = m_lastSubstituteReplacement; + count = cmd.args.section(QLatin1Char(' '), 1, 1).toInt(); + } else if (cmd.cmd.startsWith("&")) { + flags = cmd.cmd.mid(1); + if (flags.isEmpty()) + flags = m_lastSubstituteFlags; + pattern = m_lastSubstitutePattern; + replacement = m_lastSubstituteReplacement; + count = cmd.args.section(QLatin1Char(' '), 1, 1).toInt(); + } else if (cmd.matches("s", "substitute")) { + flags = m_lastSubstituteFlags; + if (flags.isEmpty()) + flags = m_lastSubstituteFlags; + pattern = m_lastSubstitutePattern; + replacement = m_lastSubstituteReplacement; + count = cmd.args.section(QLatin1Char(' '), 2, 2).toInt(); + } else { + QString line = cmd.cmd + ' ' + cmd.args; + line = line.trimmed(); + if (line.startsWith(_("substitute"))) + line = line.mid(10); + else if (line.startsWith('s') && line.size() > 1 + && !isalpha(line.at(1).unicode())) + line = line.mid(1); + else + return false; + // we have /{pattern}/{string}/[flags] now + if (line.isEmpty()) + return false; + const QChar separator = line.at(0); + int pos1 = -1; + int pos2 = -1; + int i; + for (i = 1; i < line.size(); ++i) { + if (line.at(i) == separator && line.at(i - 1) != '\\') { + pos1 = i; + break; + } } - } - if (pos1 == -1) - return false; - for (++i; i < line.size(); ++i) { - if (line.at(i) == separator && line.at(i - 1) != '\\') { - pos2 = i; - break; + if (pos1 == -1) + return false; + for (++i; i < line.size(); ++i) { + if (line.at(i) == separator && line.at(i - 1) != '\\') { + pos2 = i; + break; + } } + if (pos2 == -1) + pos2 = line.size(); + + QString needle = line.mid(1, pos1 - 1); + replacement = line.mid(pos1 + 1, pos2 - pos1 - 1); + flags = line.mid(pos2 + 1); + + needle.replace('$', '\n'); + needle.replace("\\\n", "\\$"); + pattern.setPattern(needle); + + m_lastSubstituteFlags = flags; + m_lastSubstitutePattern = pattern; + m_lastSubstituteReplacement = replacement; } - if (pos2 == -1) - pos2 = line.size(); - QString needle = line.mid(1, pos1 - 1); - const QString replacement = line.mid(pos1 + 1, pos2 - pos1 - 1); - QString flags = line.mid(pos2 + 1); + if (count == 0) + count = 1; - needle.replace('$', '\n'); - needle.replace("\\\n", "\\$"); - QRegExp pattern(needle); if (flags.contains('i')) pattern.setCaseSensitivity(Qt::CaseInsensitive); - const bool global = flags.contains('g'); - const Range range = cmd.range.endPos == 0 ? rangeFromCurrentLine() : cmd.range; - const int beginLine = lineForPosition(range.beginPos); - const int endLine = lineForPosition(range.endPos); + beginEditBlock(); - for (int line = endLine; line >= beginLine; --line) { - QString origText = lineContents(line); - QString text = origText; - int pos = 0; - while (true) { - pos = pattern.indexIn(text, pos, QRegExp::CaretAtZero); - if (pos == -1) - break; - if (pattern.cap(0).isEmpty()) - break; - QStringList caps = pattern.capturedTexts(); - QString matched = text.mid(pos, caps.at(0).size()); - QString repl = replacement; - for (int i = 1; i < caps.size(); ++i) - repl.replace("\\" + QString::number(i), caps.at(i)); - for (int i = 0; i < repl.size(); ++i) { - if (repl.at(i) == '&' && (i == 0 || repl.at(i - 1) != '\\')) { - repl.replace(i, 1, caps.at(0)); - i += caps.at(0).size(); + const bool global = flags.contains('g'); + for (int a = 0; a != count; ++a) { + const Range range = cmd.range.endPos == 0 ? rangeFromCurrentLine() : cmd.range; + const int beginLine = lineForPosition(range.beginPos); + const int endLine = lineForPosition(range.endPos); + for (int line = endLine; line >= beginLine; --line) { + QString origText = lineContents(line); + QString text = origText; + int pos = 0; + while (true) { + pos = pattern.indexIn(text, pos, QRegExp::CaretAtZero); + if (pos == -1) + break; + if (pattern.cap(0).isEmpty()) + break; + QStringList caps = pattern.capturedTexts(); + QString matched = text.mid(pos, caps.at(0).size()); + QString repl = replacement; + for (int i = 1; i < caps.size(); ++i) + repl.replace("\\" + QString::number(i), caps.at(i)); + for (int i = 0; i < repl.size(); ++i) { + if (repl.at(i) == '&' && (i == 0 || repl.at(i - 1) != '\\')) { + repl.replace(i, 1, caps.at(0)); + i += caps.at(0).size(); + } } + repl.replace("\\&", "&"); + text = text.left(pos) + repl + text.mid(pos + matched.size()); + pos += repl.size(); + if (!global) + break; } - repl.replace("\\&", "&"); - text = text.left(pos) + repl + text.mid(pos + matched.size()); - pos += repl.size(); - if (!global) - break; + if (text != origText) + setLineContents(line, text); } - if (text != origText) - setLineContents(line, text); } + moveToStartOfLine(); + setTargetColumn(); endEditBlock(); return true; }