From 7e7460ad33fc5732c55a90c19bb702e2d438f217 Mon Sep 17 00:00:00 2001 From: Lukas Holecek Date: Sun, 22 Jul 2012 14:30:56 +0200 Subject: [PATCH] fakevim: Added support for smartcase searching Change-Id: I85a83aff0886282a6eac2dc9cc4662087c3b0b95 Reviewed-by: hjk --- src/plugins/fakevim/fakevimactions.cpp | 7 + src/plugins/fakevim/fakevimactions.h | 1 + src/plugins/fakevim/fakevimhandler.cpp | 239 ++++++++++++------------- src/plugins/fakevim/fakevimoptions.ui | 11 +- src/plugins/fakevim/fakevimplugin.cpp | 3 + 5 files changed, 139 insertions(+), 122 deletions(-) diff --git a/src/plugins/fakevim/fakevimactions.cpp b/src/plugins/fakevim/fakevimactions.cpp index f62d0d3c4e2..59a6dfb035d 100644 --- a/src/plugins/fakevim/fakevimactions.cpp +++ b/src/plugins/fakevim/fakevimactions.cpp @@ -211,6 +211,13 @@ FakeVimSettings *theFakeVimSettings() instance->insertItem(ConfigUseCoreSearch, item, _("usecoresearch"), _("ucs")); + item = new SavedAction(instance); + item->setDefaultValue(false); + item->setValue(false); + item->setSettingsKey(group, _("SmartCase")); item->setCheckable(true); + item->setCheckable(true); + instance->insertItem(ConfigSmartCase, item, _("smartcase"), _("scs")); + item = new SavedAction(instance); item->setDefaultValue(_("indent,eol,start")); item->setSettingsKey(group, _("Backspace")); diff --git a/src/plugins/fakevim/fakevimactions.h b/src/plugins/fakevim/fakevimactions.h index 5eb622da6b2..d52bf98cdf1 100644 --- a/src/plugins/fakevim/fakevimactions.h +++ b/src/plugins/fakevim/fakevimactions.h @@ -55,6 +55,7 @@ enum FakeVimSettingsCode ConfigSmartIndent, ConfigIncSearch, ConfigUseCoreSearch, + ConfigSmartCase, // indent allow backspacing over autoindent // eol allow backspacing over line breaks (join lines) diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index ef23b65d965..3b989ba8611 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -290,6 +290,122 @@ struct SearchData bool highlightCursor; }; +static QRegExp vimPatternToQtPattern(QString needle, bool smartcase) +{ + /* 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 + */ + bool ignorecase = smartcase && !needle.contains(QRegExp("[A-Z]")); + QString pattern; + pattern.reserve(2 * needle.size()); + + 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; + } + + 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); +} + Range::Range() : beginPos(-1), endPos(-1), rangemode(RangeCharMode) @@ -3377,7 +3493,7 @@ bool FakeVimHandler::Private::handleExSubstituteCommand(const ExCommand &cmd) needle.replace('$', '\n'); needle.replace("\\\n", "\\$"); - pattern.setPattern(needle); + pattern = vimPatternToQtPattern(needle, hasConfig(ConfigSmartCase)); m_lastSubstituteFlags = flags; m_lastSubstitutePattern = pattern; @@ -3916,123 +4032,6 @@ bool FakeVimHandler::Private::handleExPluginCommand(const ExCommand &cmd) return handled; } -static QRegExp vimPatternToQtPattern(QString needle) -{ - /* 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()); - - 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; - } - - 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) { int level = 1; @@ -4074,7 +4073,7 @@ void FakeVimHandler::Private::search(const SearchData &sd) if (!sd.forward) flags |= QTextDocument::FindBackward; - QRegExp needleExp = vimPatternToQtPattern(sd.needle); + QRegExp needleExp = vimPatternToQtPattern(sd.needle, hasConfig(ConfigSmartCase)); const int oldLine = cursorLine() - cursorLineOnScreen(); @@ -4135,7 +4134,7 @@ void FakeVimHandler::Private::highlightMatches(const QString &needle) QTextCursor tc = cursor(); tc.movePosition(StartOfDocument, MoveAnchor); - QRegExp needleExp = vimPatternToQtPattern(needle); + QRegExp needleExp = vimPatternToQtPattern(needle, hasConfig(ConfigSmartCase)); if (!needleExp.isValid()) { QString error = needleExp.errorString(); showRedMessage( diff --git a/src/plugins/fakevim/fakevimoptions.ui b/src/plugins/fakevim/fakevimoptions.ui index 0bb312d247b..ff324ce7c80 100644 --- a/src/plugins/fakevim/fakevimoptions.ui +++ b/src/plugins/fakevim/fakevimoptions.ui @@ -59,6 +59,13 @@ + + + + Use smartcase + + + @@ -66,7 +73,7 @@ - + Show position of text marks @@ -80,7 +87,7 @@ - + Pass key sequences like Ctrl-S to Qt Creator core instead of interpreting them in FakeVim. This gives easier access to Qt Creator core functionality at the price of losing some features of FakeVim. diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index 5e07f126cde..e4a1e470f59 100644 --- a/src/plugins/fakevim/fakevimplugin.cpp +++ b/src/plugins/fakevim/fakevimplugin.cpp @@ -245,6 +245,8 @@ QWidget *FakeVimOptionPage::createPage(QWidget *parent) m_ui.checkBoxIncSearch); m_group.insert(theFakeVimSetting(ConfigUseCoreSearch), m_ui.checkBoxUseCoreSearch); + m_group.insert(theFakeVimSetting(ConfigSmartCase), + m_ui.checkBoxSmartCase); connect(m_ui.pushButtonCopyTextEditorSettings, SIGNAL(clicked()), SLOT(copyTextEditorSettings())); @@ -266,6 +268,7 @@ QWidget *FakeVimOptionPage::createPage(QWidget *parent) << sep << m_ui.checkBoxIncSearch->text() << sep << m_ui.checkBoxStartOfLine->text() << sep << m_ui.checkBoxUseCoreSearch->text() + << sep << m_ui.checkBoxSmartCase->text() << sep << m_ui.checkBoxShowMarks->text() << sep << m_ui.checkBoxPassControlKey->text() << sep << m_ui.labelShiftWidth->text()