forked from qt-creator/qt-creator
fakevim: Emulate Vim regexp more precisely
Change-Id: Ia951f6e10d0e8d19e8d7d4b2a696eb9277ce6201 Reviewed-by: hjk <qthjk@ovi.com>
This commit is contained in:
@@ -3916,22 +3916,121 @@ bool FakeVimHandler::Private::handleExPluginCommand(const ExCommand &cmd)
|
||||
return handled;
|
||||
}
|
||||
|
||||
static QRegExp vimPatternToQtPattern(QString needle, QTextDocument::FindFlags *flags)
|
||||
static QRegExp vimPatternToQtPattern(QString needle)
|
||||
{
|
||||
// FIXME: Rough mapping of a common case.
|
||||
if (needle.startsWith(_("\\<")) && needle.endsWith(_("\\>")))
|
||||
(*flags) |= QTextDocument::FindWholeWords;
|
||||
needle.remove(_("\\<")); // start of word
|
||||
needle.remove(_("\\>")); // end of word
|
||||
/* Trasformations (Vim regexp -> QRegExp):
|
||||
* \a -> [A-Za-z]
|
||||
* \A -> [^A-Za-z]
|
||||
* \h -> [A-Za-z_]
|
||||
* \H -> [^A-Za-z_]
|
||||
* \l -> [a-z]
|
||||
* \L -> [^a-z]
|
||||
* \o -> [0-7]
|
||||
* \O -> [^0-7]
|
||||
* \u -> [A-Z]
|
||||
* \U -> [^A-Z]
|
||||
* \x -> [0-9A-Fa-f]
|
||||
* \X -> [^0-9A-Fa-f]
|
||||
*
|
||||
* \< -> \b
|
||||
* \> -> \b
|
||||
* [] -> \[\]
|
||||
* \= -> ?
|
||||
*
|
||||
* (...) <-> \(...\)
|
||||
* {...} <-> \{...\}
|
||||
* | <-> \|
|
||||
* ? <-> \?
|
||||
* + <-> \+
|
||||
* \{...} -> {...}
|
||||
*
|
||||
* \c - set ignorecase for rest
|
||||
* \C - set noignorecase for rest
|
||||
*/
|
||||
// TODO: Set initial value and handle smartcase option.
|
||||
bool ignorecase = false;
|
||||
QString pattern;
|
||||
pattern.reserve(2 * needle.size());
|
||||
|
||||
// QRegExp's | and \| have the opposite meaning of vim's.
|
||||
QString dummy(QLatin1Char(1));
|
||||
needle.replace(_("\\|"), dummy);
|
||||
needle.replace(_("|"), _("\\|"));
|
||||
needle.replace(dummy, _("|"));
|
||||
bool escape = false;
|
||||
bool brace = false;
|
||||
bool curly = false;
|
||||
foreach (const QChar &c, needle) {
|
||||
if (brace) {
|
||||
brace = false;
|
||||
if (c == ']') {
|
||||
pattern.append(_("\\[\\]"));
|
||||
continue;
|
||||
} else {
|
||||
pattern.append('[');
|
||||
}
|
||||
}
|
||||
if (QString("(){}+|?").indexOf(c) != -1) {
|
||||
if (c == '{') {
|
||||
curly = escape;
|
||||
} else if (c == '}' && curly) {
|
||||
curly = false;
|
||||
escape = true;
|
||||
}
|
||||
|
||||
//qDebug() << "NEEDLE " << needle << needle;
|
||||
return QRegExp(needle);
|
||||
if (escape)
|
||||
escape = false;
|
||||
else
|
||||
pattern.append('\\');
|
||||
pattern.append(c);
|
||||
} else if (escape) {
|
||||
// escape expression
|
||||
escape = false;
|
||||
if (c == '<' || c == '>')
|
||||
pattern.append(_("\\b"));
|
||||
else if (c == 'a')
|
||||
pattern.append(_("[a-zA-Z]"));
|
||||
else if (c == 'A')
|
||||
pattern.append(_("[^a-zA-Z]"));
|
||||
else if (c == 'h')
|
||||
pattern.append(_("[A-Za-z_]"));
|
||||
else if (c == 'H')
|
||||
pattern.append(_("[^A-Za-z_]"));
|
||||
else if (c == 'c' || c == 'C')
|
||||
ignorecase = (c == 'c');
|
||||
else if (c == 'l')
|
||||
pattern.append(_("[a-z]"));
|
||||
else if (c == 'L')
|
||||
pattern.append(_("[^a-z]"));
|
||||
else if (c == 'o')
|
||||
pattern.append(_("[0-7]"));
|
||||
else if (c == 'O')
|
||||
pattern.append(_("[^0-7]"));
|
||||
else if (c == 'u')
|
||||
pattern.append(_("[A-Z]"));
|
||||
else if (c == 'U')
|
||||
pattern.append(_("[^A-Z]"));
|
||||
else if (c == 'x')
|
||||
pattern.append(_("[0-9A-Fa-f]"));
|
||||
else if (c == 'X')
|
||||
pattern.append(_("[^0-9A-Fa-f]"));
|
||||
else if (c == '=')
|
||||
pattern.append(_("?"));
|
||||
else
|
||||
pattern.append('\\' + c);
|
||||
} else {
|
||||
// unescaped expression
|
||||
if (c == '\\')
|
||||
escape = true;
|
||||
else if (c == '[')
|
||||
brace = true;
|
||||
else if (c.isLetter() && ignorecase)
|
||||
pattern.append('[' + c.toLower() + c.toUpper() + ']');
|
||||
else
|
||||
pattern.append(c);
|
||||
}
|
||||
}
|
||||
if (escape)
|
||||
pattern.append('\\');
|
||||
else if (brace)
|
||||
pattern.append('[');
|
||||
|
||||
return QRegExp(pattern);
|
||||
}
|
||||
|
||||
void FakeVimHandler::Private::searchBalanced(bool forward, QChar needle, QChar other)
|
||||
@@ -3975,7 +4074,7 @@ void FakeVimHandler::Private::search(const SearchData &sd)
|
||||
if (!sd.forward)
|
||||
flags |= QTextDocument::FindBackward;
|
||||
|
||||
QRegExp needleExp = vimPatternToQtPattern(sd.needle, &flags);
|
||||
QRegExp needleExp = vimPatternToQtPattern(sd.needle);
|
||||
|
||||
const int oldLine = cursorLine() - cursorLineOnScreen();
|
||||
|
||||
@@ -4036,10 +4135,16 @@ void FakeVimHandler::Private::highlightMatches(const QString &needle)
|
||||
QTextCursor tc = cursor();
|
||||
tc.movePosition(StartOfDocument, MoveAnchor);
|
||||
|
||||
QTextDocument::FindFlags flags = QTextDocument::FindCaseSensitively;
|
||||
QRegExp needleExp = vimPatternToQtPattern(needle, &flags);
|
||||
QRegExp needleExp = vimPatternToQtPattern(needle);
|
||||
if (!needleExp.isValid()) {
|
||||
QString error = needleExp.errorString();
|
||||
showRedMessage(
|
||||
FakeVimHandler::tr("Invalid regular expression: %1").arg(error));
|
||||
return;
|
||||
}
|
||||
|
||||
while (!tc.atEnd()) {
|
||||
tc = tc.document()->find(needleExp, tc.position(), flags);
|
||||
tc = tc.document()->find(needleExp, tc.position());
|
||||
if (tc.isNull())
|
||||
break;
|
||||
if (!tc.hasSelection())
|
||||
|
||||
Reference in New Issue
Block a user