summaryrefslogtreecommitdiff
path: root/src/plugins/fakevim/fakevimhandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/fakevim/fakevimhandler.cpp')
-rw-r--r--src/plugins/fakevim/fakevimhandler.cpp103
1 files changed, 79 insertions, 24 deletions
diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp
index 0612b73fce..8d247ccda0 100644
--- a/src/plugins/fakevim/fakevimhandler.cpp
+++ b/src/plugins/fakevim/fakevimhandler.cpp
@@ -623,10 +623,22 @@ static bool substituteText(QString *text, QRegExp &pattern, const QString &repla
{
bool substituted = false;
int pos = 0;
+ int right = -1;
while (true) {
pos = pattern.indexIn(*text, pos, QRegExp::CaretAtZero);
if (pos == -1)
break;
+
+ // ensure that substitution is advancing towards end of line
+ if (right == text->size() - pos) {
+ ++pos;
+ if (pos == text->size())
+ break;
+ continue;
+ }
+
+ right = text->size() - pos;
+
substituted = true;
QString matched = text->mid(pos, pattern.cap(0).size());
QString repl;
@@ -652,7 +664,7 @@ static bool substituteText(QString *text, QRegExp &pattern, const QString &repla
}
}
text->replace(pos, matched.size(), repl);
- pos += qMax(1, repl.size());
+ pos += (repl.isEmpty() && matched.isEmpty()) ? 1 : repl.size();
if (pos >= text->size() || !global)
break;
@@ -693,6 +705,33 @@ static void setClipboardData(const QString &content, RangeMode mode,
clipboard->setMimeData(data, clipboardMode);
}
+static QByteArray toLocalEncoding(const QString &text)
+{
+ return HostOsInfo::isWindowsHost() ? QString(text).replace(_("\n"), _("\r\n")).toLocal8Bit()
+ : text.toLocal8Bit();
+}
+
+static QString fromLocalEncoding(const QByteArray &data)
+{
+ return HostOsInfo::isWindowsHost() ? QString::fromLocal8Bit(data).replace(_("\n"), _("\r\n"))
+ : QString::fromLocal8Bit(data);
+}
+
+static QString getProcessOutput(const QString &command, const QString &input)
+{
+ QProcess proc;
+ proc.start(command);
+ proc.waitForStarted();
+ proc.write(toLocalEncoding(input));
+ proc.closeWriteChannel();
+
+ // FIXME: Process should be interruptable by user.
+ // Solution is to create a QObject for each process and emit finished state.
+ proc.waitForFinished();
+
+ return fromLocalEncoding(proc.readAllStandardOutput());
+}
+
static const QMap<QString, int> &vimKeyNames()
{
static QMap<QString, int> k;
@@ -804,6 +843,11 @@ QString Range::toString() const
.arg(rangemode);
}
+bool Range::isValid() const
+{
+ return beginPos >= 0 && endPos >= 0;
+}
+
QDebug operator<<(QDebug ts, const Range &range)
{
return ts << '[' << range.beginPos << ',' << range.endPos << ']';
@@ -5038,9 +5082,6 @@ bool FakeVimHandler::Private::parseExCommmand(QString *line, ExCommand *cmd)
if (line->isEmpty())
return false;
- // remove leading colons and spaces
- line->remove(QRegExp(_("^\\s*(:+\\s*)*")));
-
// parse range first
if (!parseLineRange(line, cmd))
return false;
@@ -5093,6 +5134,15 @@ bool FakeVimHandler::Private::parseExCommmand(QString *line, ExCommand *cmd)
bool FakeVimHandler::Private::parseLineRange(QString *line, ExCommand *cmd)
{
+ // remove leading colons and spaces
+ line->remove(QRegExp(_("^\\s*(:+\\s*)*")));
+
+ // special case ':!...' (use invalid range)
+ if (line->startsWith(QLatin1Char('!'))) {
+ cmd->range = Range();
+ return true;
+ }
+
// FIXME: that seems to be different for %w and %s
if (line->startsWith(QLatin1Char('%')))
line->replace(0, 1, _("1,$"));
@@ -5655,22 +5705,15 @@ bool FakeVimHandler::Private::handleExBangCommand(const ExCommand &cmd) // :!
if (!cmd.cmd.isEmpty() || !cmd.hasBang)
return false;
- setCurrentRange(cmd.range);
- int targetPosition = firstPositionInLine(lineForPosition(cmd.range.beginPos));
- QString command = QString(cmd.cmd.mid(1) + QLatin1Char(' ') + cmd.args).trimmed();
- QString text = selectText(cmd.range);
- QProcess proc;
- proc.start(command);
- proc.waitForStarted();
- if (HostOsInfo::isWindowsHost())
- text.replace(_("\n"), _("\r\n"));
- proc.write(text.toUtf8());
- proc.closeWriteChannel();
- proc.waitForFinished();
- QString result = QString::fromUtf8(proc.readAllStandardOutput());
- if (text.isEmpty()) {
- emit q->extraInformationChanged(result);
- } else {
+ bool replaceText = cmd.range.isValid();
+ const QString command = QString(cmd.cmd.mid(1) + QLatin1Char(' ') + cmd.args).trimmed();
+ const QString input = replaceText ? selectText(cmd.range) : QString();
+
+ const QString result = getProcessOutput(command, input);
+
+ if (replaceText) {
+ setCurrentRange(cmd.range);
+ int targetPosition = firstPositionInLine(lineForPosition(cmd.range.beginPos));
beginEditBlock();
removeText(currentRange());
insertText(result);
@@ -5679,8 +5722,11 @@ bool FakeVimHandler::Private::handleExBangCommand(const ExCommand &cmd) // :!
leaveVisualMode();
//qDebug() << "FILTER: " << command;
showMessage(MessageInfo, FakeVimHandler::tr("%n lines filtered.", 0,
- text.count(QLatin1Char('\n'))));
+ input.count(QLatin1Char('\n'))));
+ } else if (!result.isEmpty()) {
+ emit q->extraInformationChanged(result);
}
+
return true;
}
@@ -6478,10 +6524,19 @@ void FakeVimHandler::Private::scrollToLine(int line)
EDITOR(setTextCursor(tc2));
EDITOR(ensureCursorVisible());
+ int offset = 0;
const QTextBlock block = document()->findBlockByLineNumber(line);
- const QTextLine textLine = block.isValid()
- ? block.layout()->lineAt(line - block.firstLineNumber()) : QTextLine();
- tc2.setPosition(block.position() + (textLine.isValid() ? textLine.textStart() : 0));
+ if (block.isValid()) {
+ const int blockLineCount = block.layout()->lineCount();
+ const int lineInBlock = line - block.firstLineNumber();
+ if (0 <= lineInBlock && lineInBlock < blockLineCount) {
+ QTextLine textLine = block.layout()->lineAt(lineInBlock);
+ offset = textLine.textStart();
+ } else {
+// QTC_CHECK(false);
+ }
+ }
+ tc2.setPosition(block.position() + offset);
EDITOR(setTextCursor(tc2));
EDITOR(ensureCursorVisible());