From 6ecb1c401851dd1f4e5582ad491a6871710abeb7 Mon Sep 17 00:00:00 2001 From: Serhii Moroz Date: Tue, 2 Aug 2016 12:04:40 +0300 Subject: [PATCH] Locator: Add highlighting of the search text Change-Id: Ia166e9667076e46770a754b626ceb28080139e79 Reviewed-by: Eike Ziller --- share/qtcreator/themes/dark.creatortheme | 1 + share/qtcreator/themes/default.creatortheme | 1 + share/qtcreator/themes/flat-dark.creatortheme | 1 + .../qtcreator/themes/flat-light.creatortheme | 1 + share/qtcreator/themes/flat.creatortheme | 1 + src/libs/utils/theme/theme.h | 1 + .../cmakelocatorfilter.cpp | 10 +++-- .../coreplugin/locator/basefilefilter.cpp | 45 ++++++++++++------- .../coreplugin/locator/commandlocator.cpp | 27 ++++++----- .../coreplugin/locator/executefilter.cpp | 18 +++++--- .../locator/externaltoolsfilter.cpp | 14 ++++-- .../coreplugin/locator/filesystemfilter.cpp | 27 ++++++++--- .../coreplugin/locator/ilocatorfilter.cpp | 21 +++------ .../coreplugin/locator/ilocatorfilter.h | 27 ++++++++++- .../coreplugin/locator/locatorwidget.cpp | 42 ++++++++++++++--- .../locator/opendocumentsfilter.cpp | 28 ++++++------ .../cpptools/cppcurrentdocumentfilter.cpp | 34 ++++++++------ src/plugins/cpptools/cpplocatorfilter.cpp | 41 +++++++++-------- src/plugins/help/helpindexfilter.cpp | 8 +++- src/plugins/help/remotehelpfilter.cpp | 9 ++-- src/plugins/macros/macrolocatorfilter.cpp | 30 ++++++++----- .../qmljstools/qmljsfunctionfilter.cpp | 33 +++++++------- 22 files changed, 267 insertions(+), 153 deletions(-) diff --git a/share/qtcreator/themes/dark.creatortheme b/share/qtcreator/themes/dark.creatortheme index 41fd0579c1e..006daa501c2 100644 --- a/share/qtcreator/themes/dark.creatortheme +++ b/share/qtcreator/themes/dark.creatortheme @@ -116,6 +116,7 @@ SplitterColor=ff313131 TextColorDisabled=textDisabled TextColorError=ffff4040 TextColorHighlight=ffff0000 +TextColorHighlightBackground=555500 TextColorLink=textColorLink TextColorLinkVisited=textColorLinkVisited TextColorNormal=text diff --git a/share/qtcreator/themes/default.creatortheme b/share/qtcreator/themes/default.creatortheme index 819d3d00ad7..4be1514bb25 100644 --- a/share/qtcreator/themes/default.creatortheme +++ b/share/qtcreator/themes/default.creatortheme @@ -108,6 +108,7 @@ SplitterColor=ff151515 TextColorDisabled=ff000000 TextColorError=ffff0000 TextColorHighlight=ffa0a0a4 +TextColorHighlightBackground=ffef0b TextColorLink=ff0057ae TextColorLinkVisited=ff644a9b TextColorNormal=ff000000 diff --git a/share/qtcreator/themes/flat-dark.creatortheme b/share/qtcreator/themes/flat-dark.creatortheme index ada2668622c..24c3f573190 100644 --- a/share/qtcreator/themes/flat-dark.creatortheme +++ b/share/qtcreator/themes/flat-dark.creatortheme @@ -121,6 +121,7 @@ SplitterColor=splitter TextColorDisabled=textDisabled TextColorError=ffff4040 TextColorHighlight=ffff0000 +TextColorHighlightBackground=8a7f2c TextColorLink=textColorLink TextColorLinkVisited=textColorLinkVisited TextColorNormal=text diff --git a/share/qtcreator/themes/flat-light.creatortheme b/share/qtcreator/themes/flat-light.creatortheme index fb2a0b5c37b..4460fd72d1e 100644 --- a/share/qtcreator/themes/flat-light.creatortheme +++ b/share/qtcreator/themes/flat-light.creatortheme @@ -119,6 +119,7 @@ SplitterColor=splitter TextColorDisabled=textDisabled TextColorError=ffff4040 TextColorHighlight=ffff0000 +TextColorHighlightBackground=ffef0b TextColorLink=ff007af4 TextColorLinkVisited=ffa57aff TextColorNormal=text diff --git a/share/qtcreator/themes/flat.creatortheme b/share/qtcreator/themes/flat.creatortheme index faea39f266c..e98999056ac 100644 --- a/share/qtcreator/themes/flat.creatortheme +++ b/share/qtcreator/themes/flat.creatortheme @@ -117,6 +117,7 @@ SplitterColor=splitter TextColorDisabled=textDisabled TextColorError=ffff4040 TextColorHighlight=ffff0000 +TextColorHighlightBackground=ffef0b TextColorLink=ff007af4 TextColorLinkVisited=ffa57aff TextColorNormal=text diff --git a/src/libs/utils/theme/theme.h b/src/libs/utils/theme/theme.h index 7179d0d4525..ea69e2fae76 100644 --- a/src/libs/utils/theme/theme.h +++ b/src/libs/utils/theme/theme.h @@ -116,6 +116,7 @@ public: TextColorDisabled, TextColorError, TextColorHighlight, + TextColorHighlightBackground, TextColorLink, TextColorLinkVisited, TextColorNormal, diff --git a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp index 11b7696baeb..124ec906b1f 100644 --- a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp @@ -65,10 +65,12 @@ void CMakeLocatorFilter::prepareSearch(const QString &entry) if (!cmakeProject) continue; foreach (const QString &title, cmakeProject->buildTargetTitles()) { - if (title.contains(entry)) { - Core::LocatorFilterEntry entry(this, title, cmakeProject->projectFilePath().toString()); - entry.extraInfo = FileUtils::shortNativePath(cmakeProject->projectFilePath()); - m_result.append(entry); + const int index = title.indexOf(entry); + if (index >= 0) { + Core::LocatorFilterEntry filterEntry(this, title, cmakeProject->projectFilePath().toString()); + filterEntry.extraInfo = FileUtils::shortNativePath(cmakeProject->projectFilePath()); + filterEntry.highlightInfo = {index, entry.length()}; + m_result.append(filterEntry); } } } diff --git a/src/plugins/coreplugin/locator/basefilefilter.cpp b/src/plugins/coreplugin/locator/basefilefilter.cpp index 7562a76d766..df624793ddf 100644 --- a/src/plugins/coreplugin/locator/basefilefilter.cpp +++ b/src/plugins/coreplugin/locator/basefilefilter.cpp @@ -98,18 +98,18 @@ QList BaseFileFilter::matchesFor(QFutureInterface betterEntries; QList goodEntries; - const QString trimmed = trimWildcards(QDir::fromNativeSeparators(origEntry)); - const EditorManager::FilePathInfo fp = EditorManager::splitLineAndColumnNumber(trimmed); - QStringMatcher matcher(fp.filePath, Qt::CaseInsensitive); - const QChar asterisk = QLatin1Char('*'); - QRegExp regexp(asterisk + fp.filePath+ asterisk, Qt::CaseInsensitive, QRegExp::Wildcard); + const QString entry = QDir::fromNativeSeparators(origEntry); + const EditorManager::FilePathInfo fp = EditorManager::splitLineAndColumnNumber(entry); + const Qt::CaseSensitivity cs = caseSensitivity(fp.filePath); + QStringMatcher matcher(fp.filePath, cs); + QRegExp regexp(fp.filePath, cs, QRegExp::Wildcard); if (!regexp.isValid()) { d->m_current.clear(); // free memory return betterEntries; } const QChar pathSeparator(QLatin1Char('/')); const bool hasPathSeparator = fp.filePath.contains(pathSeparator); - const bool hasWildcard = fp.filePath.contains(asterisk) || fp.filePath.contains(QLatin1Char('?')); + const bool hasWildcard = containsWildcard(fp.filePath); const bool containsPreviousEntry = !d->m_current.previousEntry.isEmpty() && fp.filePath.contains(d->m_current.previousEntry); const bool pathSeparatorAdded = !d->m_current.previousEntry.contains(pathSeparator) @@ -124,7 +124,6 @@ QList BaseFileFilter::matchesFor(QFutureInterfacem_current.previousResultPaths.clear(); d->m_current.previousResultNames.clear(); d->m_current.previousEntry = fp.filePath; - const Qt::CaseSensitivity caseSensitivityForPrefix = caseSensitivity(fp.filePath); d->m_current.iterator->toFront(); bool canceled = false; while (d->m_current.iterator->hasNext()) { @@ -137,16 +136,32 @@ QList BaseFileFilter::matchesFor(QFutureInterfacem_current.iterator->filePath(); QString name = d->m_current.iterator->fileName(); QString matchText = hasPathSeparator ? path : name; - if ((hasWildcard && regexp.exactMatch(matchText)) - || (!hasWildcard && matcher.indexIn(matchText) != -1)) { + int index = hasWildcard ? regexp.indexIn(matchText) : matcher.indexIn(matchText); + + if (index >= 0) { QFileInfo fi(path); - LocatorFilterEntry entry(this, fi.fileName(), QString(path + fp.postfix)); - entry.extraInfo = FileUtils::shortNativePath(FileName(fi)); - entry.fileName = path; - if (matchText.startsWith(fp.filePath, caseSensitivityForPrefix)) - betterEntries.append(entry); + LocatorFilterEntry filterEntry(this, fi.fileName(), QString(path + fp.postfix)); + filterEntry.fileName = path; + filterEntry.extraInfo = FileUtils::shortNativePath(FileName(fi)); + + LocatorFilterEntry::HighlightInfo::DataType hDataType = LocatorFilterEntry::HighlightInfo::DisplayName; + int length = hasWildcard ? regexp.matchedLength() : fp.filePath.length(); + const bool betterMatch = index == 0; + if (hasPathSeparator) { + const int indexCandidate = index + filterEntry.extraInfo.length() - path.length(); + const int cutOff = indexCandidate < 0 ? -indexCandidate : 0; + index = qMax(indexCandidate, 0); + length = qMax(length - cutOff, 1); + hDataType = LocatorFilterEntry::HighlightInfo::ExtraInfo; + } + + if (index >= 0) + filterEntry.highlightInfo = LocatorFilterEntry::HighlightInfo(index, length, hDataType); + + if (betterMatch) + betterEntries.append(filterEntry); else - goodEntries.append(entry); + goodEntries.append(filterEntry); d->m_current.previousResultPaths.append(path); d->m_current.previousResultNames.append(name); } diff --git a/src/plugins/coreplugin/locator/commandlocator.cpp b/src/plugins/coreplugin/locator/commandlocator.cpp index 37d1fe2739b..14e57ad0178 100644 --- a/src/plugins/coreplugin/locator/commandlocator.cpp +++ b/src/plugins/coreplugin/locator/commandlocator.cpp @@ -67,20 +67,27 @@ QList CommandLocator::matchesFor(QFutureInterfacecommands.size(); for (int i = 0; i < count; i++) { if (future.isCanceled()) break; - if (d->commands.at(i)->isActive()) { - if (QAction *action = d->commands.at(i)->action()) - if (action->isEnabled()) { - QString text = action->text(); - text.remove(ampersand); - if (text.startsWith(entry, caseSensitivity_)) - betterEntries.append(LocatorFilterEntry(this, text, QVariant(i))); - else if (text.contains(entry, caseSensitivity_)) - goodEntries.append(LocatorFilterEntry(this, text, QVariant(i))); + if (!d->commands.at(i)->isActive()) + continue; + + QAction *action = d->commands.at(i)->action(); + if (action && action->isEnabled()) { + QString text = action->text(); + text.remove(ampersand); + const int index = text.indexOf(entry, 0, entryCaseSensitivity); + if (index >= 0) { + LocatorFilterEntry filterEntry(this, text, QVariant(i)); + filterEntry.highlightInfo = {index, entry.length()}; + + if (index == 0) + betterEntries.append(filterEntry); + else + goodEntries.append(filterEntry); } } } diff --git a/src/plugins/coreplugin/locator/executefilter.cpp b/src/plugins/coreplugin/locator/executefilter.cpp index ce0636fe6b7..d46550a5698 100644 --- a/src/plugins/coreplugin/locator/executefilter.cpp +++ b/src/plugins/coreplugin/locator/executefilter.cpp @@ -60,16 +60,20 @@ QList ExecuteFilter::matchesFor(QFutureInterface others; - const Qt::CaseSensitivity caseSensitivityForPrefix = caseSensitivity(entry); - foreach (const QString &i, m_commandHistory) { + const Qt::CaseSensitivity entryCaseSensitivity = caseSensitivity(entry); + foreach (const QString &cmd, m_commandHistory) { if (future.isCanceled()) break; - if (i == entry) // avoid repeated entry + if (cmd == entry) // avoid repeated entry continue; - if (i.startsWith(entry, caseSensitivityForPrefix)) - value.append(LocatorFilterEntry(this, i, QVariant())); - else - others.append(LocatorFilterEntry(this, i, QVariant())); + LocatorFilterEntry filterEntry(this, cmd, QVariant()); + const int index = cmd.indexOf(entry, 0, entryCaseSensitivity); + if (index >= 0) { + filterEntry.highlightInfo = {index, entry.length()}; + value.append(filterEntry); + } else { + others.append(filterEntry); + } } value.append(others); return value; diff --git a/src/plugins/coreplugin/locator/externaltoolsfilter.cpp b/src/plugins/coreplugin/locator/externaltoolsfilter.cpp index 69dfe6c6702..7307473168b 100644 --- a/src/plugins/coreplugin/locator/externaltoolsfilter.cpp +++ b/src/plugins/coreplugin/locator/externaltoolsfilter.cpp @@ -64,17 +64,23 @@ void ExternalToolsFilter::refresh(QFutureInterface &) void ExternalToolsFilter::prepareSearch(const QString &entry) { m_results.clear(); - - Qt::CaseSensitivity useCaseSensitivity = caseSensitivity(entry); + const Qt::CaseSensitivity entryCaseSensitivity = caseSensitivity(entry); const QMap externalToolsById = ExternalToolManager::toolsById(); auto end = externalToolsById.cend(); for (auto it = externalToolsById.cbegin(); it != end; ++it) { ExternalTool *tool = *it; - if (tool->description().contains(entry, useCaseSensitivity) || - tool->displayName().contains(entry, useCaseSensitivity)) { + int index = tool->displayName().indexOf(entry, 0, entryCaseSensitivity); + LocatorFilterEntry::HighlightInfo::DataType hDataType = LocatorFilterEntry::HighlightInfo::DisplayName; + if (index < 0) { + index = tool->description().indexOf(entry, 0, entryCaseSensitivity); + hDataType = LocatorFilterEntry::HighlightInfo::ExtraInfo; + } + + if (index >= 0) { LocatorFilterEntry filterEntry(this, tool->displayName(), QVariant::fromValue(tool)); filterEntry.extraInfo = tool->description(); + filterEntry.highlightInfo = LocatorFilterEntry::HighlightInfo(index, entry.length(), hDataType); m_results.append(filterEntry); } } diff --git a/src/plugins/coreplugin/locator/filesystemfilter.cpp b/src/plugins/coreplugin/locator/filesystemfilter.cpp index fcfb0415b2b..14014cda2e7 100644 --- a/src/plugins/coreplugin/locator/filesystemfilter.cpp +++ b/src/plugins/coreplugin/locator/filesystemfilter.cpp @@ -41,11 +41,16 @@ namespace { QList *categorize(const QString &entry, const QString &candidate, Qt::CaseSensitivity caseSensitivity, - QList *betterEntries, QList *goodEntries) + QList *betterEntries, QList *goodEntries, + int *index) { - if (entry.isEmpty() || candidate.startsWith(entry, caseSensitivity)) + const int position = candidate.indexOf(entry, 0, caseSensitivity); + if (index) + *index = position; + + if (entry.isEmpty() || position == 0) return betterEntries; - else if (candidate.contains(entry, caseSensitivity)) + else if (position >= 0) return goodEntries; return 0; } @@ -99,11 +104,15 @@ QList FileSystemFilter::matchesFor(QFutureInterface *category = categorize(entryFileName, dir, caseSensitivity_, &betterEntries, - &goodEntries)) { + int index = -1; + if (QList *category = categorize(entryFileName, dir, caseSensitivity_, + &betterEntries, &goodEntries, &index)) { const QString fullPath = dirInfo.filePath(dir); LocatorFilterEntry filterEntry(this, dir, QVariant()); filterEntry.fileName = fullPath; + if (index >= 0) + filterEntry.highlightInfo = {index, entryFileName.length()}; + category->append(filterEntry); } } @@ -113,11 +122,15 @@ QList FileSystemFilter::matchesFor(QFutureInterface *category = categorize(fileName, file, caseSensitivity_, &betterEntries, - &goodEntries)) { + int index = -1; + if (QList *category = categorize(fileName, file, caseSensitivity_, + &betterEntries, &goodEntries, &index)) { const QString fullPath = dirInfo.filePath(file); LocatorFilterEntry filterEntry(this, file, QString(fullPath + fp.postfix)); filterEntry.fileName = fullPath; + if (index >= 0) + filterEntry.highlightInfo = {index, fileName.length()}; + category->append(filterEntry); } } diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index aabc2d43baf..ea1ca929bf8 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -118,27 +118,16 @@ bool ILocatorFilter::openConfigDialog(QWidget *parent, bool &needsRefresh) return false; } -QString ILocatorFilter::trimWildcards(const QString &str) -{ - if (str.isEmpty()) - return str; - int first = 0, last = str.size() - 1; - const QChar asterisk = QLatin1Char('*'); - const QChar question = QLatin1Char('?'); - while (first < str.size() && (str.at(first) == asterisk || str.at(first) == question)) - ++first; - while (last >= 0 && (str.at(last) == asterisk || str.at(last) == question)) - --last; - if (first > last) - return QString(); - return str.mid(first, last - first + 1); -} - Qt::CaseSensitivity ILocatorFilter::caseSensitivity(const QString &str) { return str == str.toLower() ? Qt::CaseInsensitive : Qt::CaseSensitive; } +bool ILocatorFilter::containsWildcard(const QString &str) +{ + return str.contains(QLatin1Char('*')) || str.contains(QLatin1Char('?')); +} + QString ILocatorFilter::msgConfigureDialogTitle() { return tr("Filter Configuration"); diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.h b/src/plugins/coreplugin/locator/ilocatorfilter.h index c50bdf22177..bb2fa000014 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.h +++ b/src/plugins/coreplugin/locator/ilocatorfilter.h @@ -37,6 +37,23 @@ class ILocatorFilter; struct LocatorFilterEntry { + struct HighlightInfo { + enum DataType { + DisplayName, + ExtraInfo + }; + + HighlightInfo(int startIndex, int length, DataType type = DataType::DisplayName) + : startIndex(startIndex) + , length(length) + , dataType(type) + {} + + int startIndex; + int length; + DataType dataType; + }; + LocatorFilterEntry() = default; LocatorFilterEntry(ILocatorFilter *fromFilter, const QString &name, const QVariant &data, @@ -67,6 +84,14 @@ struct LocatorFilterEntry QString fileName; /* internal */ bool fileIconResolved = false; + /* highlighting support */ + HighlightInfo highlightInfo{0, 0}; + + static bool compareLexigraphically(const Core::LocatorFilterEntry &lhs, + const Core::LocatorFilterEntry &rhs) + { + return lhs.displayName < rhs.displayName; + } }; class CORE_EXPORT ILocatorFilter : public QObject @@ -134,8 +159,8 @@ public: /* Returns whether the filter should be enabled and used in menus. */ bool isEnabled() const; - static QString trimWildcards(const QString &str); static Qt::CaseSensitivity caseSensitivity(const QString &str); + static bool containsWildcard(const QString &str); static QString msgConfigureDialogTitle(); static QString msgPrefixLabel(); diff --git a/src/plugins/coreplugin/locator/locatorwidget.cpp b/src/plugins/coreplugin/locator/locatorwidget.cpp index 8169cff3c04..e85bdf30df2 100644 --- a/src/plugins/coreplugin/locator/locatorwidget.cpp +++ b/src/plugins/coreplugin/locator/locatorwidget.cpp @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include #include #include @@ -69,8 +71,16 @@ namespace Internal { class LocatorModel : public QAbstractListModel { public: + + enum Columns { + DisplayNameColumn, + ExtraInfoColumn, + ColumnCount + }; + LocatorModel(QObject *parent = 0) : QAbstractListModel(parent) + , mBackgroundColor(Utils::creatorTheme()->color(Utils::Theme::TextColorHighlightBackground).name()) {} void clear(); @@ -83,6 +93,7 @@ public: private: mutable QList mEntries; bool hasExtraInfo = false; + QColor mBackgroundColor; }; class CompletionList : public QTreeView @@ -144,7 +155,7 @@ int LocatorModel::columnCount(const QModelIndex &parent) const { if (parent.isValid()) return 0; - return hasExtraInfo ? 2 : 1; + return hasExtraInfo ? ColumnCount : 1; } QVariant LocatorModel::data(const QModelIndex &index, int role) const @@ -154,9 +165,9 @@ QVariant LocatorModel::data(const QModelIndex &index, int role) const switch (role) { case Qt::DisplayRole: - if (index.column() == 0) + if (index.column() == DisplayNameColumn) return mEntries.at(index.row()).displayName; - else if (index.column() == 1) + else if (index.column() == ExtraInfoColumn) return mEntries.at(index.row()).extraInfo; break; case Qt::ToolTipRole: @@ -167,7 +178,8 @@ QVariant LocatorModel::data(const QModelIndex &index, int role) const + QLatin1String("\n\n") + mEntries.at(index.row()).extraInfo); break; case Qt::DecorationRole: - if (index.column() == 0) { + case ItemDataRoles::ResultIconRole: + if (index.column() == DisplayNameColumn) { LocatorFilterEntry &entry = mEntries[index.row()]; if (!entry.fileIconResolved && !entry.fileName.isEmpty() && entry.displayIcon.isNull()) { entry.fileIconResolved = true; @@ -177,11 +189,25 @@ QVariant LocatorModel::data(const QModelIndex &index, int role) const } break; case Qt::ForegroundRole: - if (index.column() == 1) + if (index.column() == ExtraInfoColumn) return QColor(Qt::darkGray); break; - case Qt::UserRole: + case ItemDataRoles::ResultItemRole: return qVariantFromValue(mEntries.at(index.row())); + case ItemDataRoles::ResultBeginColumnNumberRole: + case ItemDataRoles::SearchTermLengthRole: { + LocatorFilterEntry &entry = mEntries[index.row()]; + const int highlightColumn = entry.highlightInfo.dataType == LocatorFilterEntry::HighlightInfo::DisplayName + ? DisplayNameColumn + : ExtraInfoColumn; + if (highlightColumn == index.column()) { + const bool startIndexRole = role == ItemDataRoles::ResultBeginColumnNumberRole; + return startIndexRole ? entry.highlightInfo.startIndex : entry.highlightInfo.length; + } + break; + } + case ItemDataRoles::ResultHighlightBackgroundColor: + return mBackgroundColor; } return QVariant(); @@ -202,6 +228,7 @@ void LocatorModel::addEntries(const QList &entries) CompletionList::CompletionList(QWidget *parent) : QTreeView(parent) { + setItemDelegate(new SearchResultTreeItemDelegate(0, this)); setRootIsDecorated(false); setUniformRowHeights(true); header()->hide(); @@ -611,9 +638,10 @@ void LocatorWidget::acceptCurrentEntry() const QModelIndex index = m_completionList->currentIndex(); if (!index.isValid()) return; - const LocatorFilterEntry entry = m_locatorModel->data(index, Qt::UserRole).value(); + const LocatorFilterEntry entry = m_locatorModel->data(index, ItemDataRoles::ResultItemRole).value(); m_completionList->hide(); m_fileLineEdit->clearFocus(); + Q_ASSERT(entry.filter != nullptr); entry.filter->accept(entry); } diff --git a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp index 73c3c2dc40a..d6bfcab4ef3 100644 --- a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp +++ b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp @@ -55,19 +55,16 @@ OpenDocumentsFilter::OpenDocumentsFilter() this, &OpenDocumentsFilter::refreshInternally); } -QList OpenDocumentsFilter::matchesFor(QFutureInterface &future, const QString &entry) +QList OpenDocumentsFilter::matchesFor(QFutureInterface &future, + const QString &entry) { QList goodEntries; QList betterEntries; const EditorManager::FilePathInfo fp = EditorManager::splitLineAndColumnNumber(entry); - const QChar asterisk = QLatin1Char('*'); - QString pattern = QString(asterisk); - pattern += fp.filePath; - pattern += asterisk; - QRegExp regexp(pattern, Qt::CaseInsensitive, QRegExp::Wildcard); + QRegExp regexp(fp.filePath, caseSensitivity(fp.filePath), QRegExp::Wildcard); if (!regexp.isValid()) return goodEntries; - const Qt::CaseSensitivity caseSensitivityForPrefix = caseSensitivity(fp.filePath); + foreach (const Entry &editorEntry, editors()) { if (future.isCanceled()) break; @@ -75,13 +72,16 @@ QList OpenDocumentsFilter::matchesFor(QFutureInterface &category = displayName.startsWith(fp.filePath, caseSensitivityForPrefix) - ? betterEntries : goodEntries; - category.append(fiEntry); + const int index = regexp.indexIn(displayName); + if (index >= 0) { + LocatorFilterEntry filterEntry(this, displayName, QString(fileName + fp.postfix)); + filterEntry.extraInfo = FileUtils::shortNativePath(FileName::fromString(fileName)); + filterEntry.fileName = fileName; + filterEntry.highlightInfo = {index, regexp.matchedLength()}; + if (index == 0) + betterEntries.append(filterEntry); + else + goodEntries.append(filterEntry); } } betterEntries.append(goodEntries); diff --git a/src/plugins/cpptools/cppcurrentdocumentfilter.cpp b/src/plugins/cpptools/cppcurrentdocumentfilter.cpp index 964720e7a93..537dcc6da87 100644 --- a/src/plugins/cpptools/cppcurrentdocumentfilter.cpp +++ b/src/plugins/cpptools/cppcurrentdocumentfilter.cpp @@ -62,18 +62,16 @@ CppCurrentDocumentFilter::CppCurrentDocumentFilter(CppTools::CppModelManager *ma } QList CppCurrentDocumentFilter::matchesFor( - QFutureInterface &future, const QString & origEntry) + QFutureInterface &future, const QString & entry) { - QString entry = trimWildcards(origEntry); QList goodEntries; QList betterEntries; - QStringMatcher matcher(entry, Qt::CaseInsensitive); - const QChar asterisk = QLatin1Char('*'); - QRegExp regexp(asterisk + entry + asterisk, Qt::CaseInsensitive, QRegExp::Wildcard); + const Qt::CaseSensitivity cs = caseSensitivity(entry); + QStringMatcher matcher(entry, cs); + QRegExp regexp(entry, cs, QRegExp::Wildcard); if (!regexp.isValid()) return goodEntries; - bool hasWildcard = (entry.contains(asterisk) || entry.contains(QLatin1Char('?'))); - const Qt::CaseSensitivity caseSensitivityForPrefix = caseSensitivity(entry); + bool hasWildcard = containsWildcard(entry); foreach (IndexItem::Ptr info, itemsOfCurrentDocument()) { if (future.isCanceled()) @@ -85,20 +83,30 @@ QList CppCurrentDocumentFilter::matchesFor( else if (info->type() == IndexItem::Function) matchString += info->symbolType(); - if ((hasWildcard && regexp.exactMatch(matchString)) - || (!hasWildcard && matcher.indexIn(matchString) != -1)) - { + int index = hasWildcard ? regexp.indexIn(matchString) : matcher.indexIn(matchString); + if (index >= 0) { + const bool betterMatch = index == 0; QVariant id = qVariantFromValue(info); QString name = matchString; QString extraInfo = info->symbolScope(); if (info->type() == IndexItem::Function) { - if (info->unqualifiedNameAndScope(matchString, &name, &extraInfo)) + if (info->unqualifiedNameAndScope(matchString, &name, &extraInfo)) { name += info->symbolType(); + index = hasWildcard ? regexp.indexIn(name) : matcher.indexIn(name); + } } + Core::LocatorFilterEntry filterEntry(this, name, id, info->icon()); filterEntry.extraInfo = extraInfo; - - if (matchString.startsWith(entry, caseSensitivityForPrefix)) + if (index < 0) { + index = hasWildcard ? regexp.indexIn(extraInfo) : matcher.indexIn(extraInfo); + filterEntry.highlightInfo.dataType = Core::LocatorFilterEntry::HighlightInfo::ExtraInfo; + } + if (index >= 0) { + filterEntry.highlightInfo.startIndex = index; + filterEntry.highlightInfo.length = hasWildcard ? regexp.matchedLength() : entry.length(); + } + if (betterMatch) betterEntries.append(filterEntry); else goodEntries.append(filterEntry); diff --git a/src/plugins/cpptools/cpplocatorfilter.cpp b/src/plugins/cpptools/cpplocatorfilter.cpp index e18a1a4c57a..084c4d5479d 100644 --- a/src/plugins/cpptools/cpplocatorfilter.cpp +++ b/src/plugins/cpptools/cpplocatorfilter.cpp @@ -27,6 +27,7 @@ #include "cppmodelmanager.h" #include +#include #include #include @@ -66,26 +67,18 @@ void CppLocatorFilter::refresh(QFutureInterface &future) Q_UNUSED(future) } -static bool compareLexigraphically(const Core::LocatorFilterEntry &a, - const Core::LocatorFilterEntry &b) -{ - return a.displayName < b.displayName; -} - QList CppLocatorFilter::matchesFor( - QFutureInterface &future, const QString &origEntry) + QFutureInterface &future, const QString &entry) { - QString entry = trimWildcards(origEntry); QList goodEntries; QList betterEntries; - const QChar asterisk = QLatin1Char('*'); - QStringMatcher matcher(entry, Qt::CaseInsensitive); - QRegExp regexp(asterisk + entry+ asterisk, Qt::CaseInsensitive, QRegExp::Wildcard); + const Qt::CaseSensitivity cs = caseSensitivity(entry); + QStringMatcher matcher(entry, cs); + QRegExp regexp(entry, cs, QRegExp::Wildcard); if (!regexp.isValid()) return goodEntries; - bool hasWildcard = (entry.contains(asterisk) || entry.contains(QLatin1Char('?'))); + bool hasWildcard = containsWildcard(entry); bool hasColonColon = entry.contains(QLatin1String("::")); - const Qt::CaseSensitivity caseSensitivityForPrefix = caseSensitivity(entry); const IndexItem::ItemType wanted = matchTypes(); m_data->filterAllFiles([&](const IndexItem::Ptr &info) -> IndexItem::VisitorResult { @@ -93,10 +86,20 @@ QList CppLocatorFilter::matchesFor( return IndexItem::Break; if (info->type() & wanted) { const QString matchString = hasColonColon ? info->scopedSymbolName() : info->symbolName(); - if ((hasWildcard && regexp.exactMatch(matchString)) || - (!hasWildcard && matcher.indexIn(matchString) != -1)) { - const Core::LocatorFilterEntry filterEntry = filterEntryFromIndexItem(info); - if (matchString.startsWith(entry, caseSensitivityForPrefix)) + int index = hasWildcard ? regexp.indexIn(matchString) : matcher.indexIn(matchString); + if (index >= 0) { + const bool betterMatch = index == 0; + Core::LocatorFilterEntry filterEntry = filterEntryFromIndexItem(info); + + if (matchString != filterEntry.displayName) { + index = hasWildcard ? regexp.indexIn(filterEntry.displayName) + : matcher.indexIn(filterEntry.displayName); + } + + if (index >= 0) + filterEntry.highlightInfo = {index, (hasWildcard ? regexp.matchedLength() : entry.length())}; + + if (betterMatch) betterEntries.append(filterEntry); else goodEntries.append(filterEntry); @@ -110,9 +113,9 @@ QList CppLocatorFilter::matchesFor( }); if (goodEntries.size() < 1000) - std::stable_sort(goodEntries.begin(), goodEntries.end(), compareLexigraphically); + Utils::sort(goodEntries, Core::LocatorFilterEntry::compareLexigraphically); if (betterEntries.size() < 1000) - std::stable_sort(betterEntries.begin(), betterEntries.end(), compareLexigraphically); + Utils::sort(betterEntries, Core::LocatorFilterEntry::compareLexigraphically); betterEntries += goodEntries; return betterEntries; diff --git a/src/plugins/help/helpindexfilter.cpp b/src/plugins/help/helpindexfilter.cpp index 8f12c34fb4d..61bf3d76b31 100644 --- a/src/plugins/help/helpindexfilter.cpp +++ b/src/plugins/help/helpindexfilter.cpp @@ -127,8 +127,12 @@ QList HelpIndexFilter::matchesFor(QFutureInterface RemoteHelpFilter::matchesFor(QFutureInterface &future, const QString &pattern) +QList RemoteHelpFilter::matchesFor(QFutureInterface &future, const QString &entry) { QList entries; foreach (const QString &url, remoteUrls()) { if (future.isCanceled()) break; - - entries.append(Core::LocatorFilterEntry(this, url.arg(pattern), QVariant(), - m_icon)); + const QString name = url.arg(entry); + Core::LocatorFilterEntry filterEntry(this, name, QVariant(), m_icon); + filterEntry.highlightInfo = {name.lastIndexOf(entry), entry.length()}; + entries.append(filterEntry); } return entries; } diff --git a/src/plugins/macros/macrolocatorfilter.cpp b/src/plugins/macros/macrolocatorfilter.cpp index 7f210f4178f..a631eafd546 100644 --- a/src/plugins/macros/macrolocatorfilter.cpp +++ b/src/plugins/macros/macrolocatorfilter.cpp @@ -54,26 +54,32 @@ QList MacroLocatorFilter::matchesFor(QFutureInterface< QList goodEntries; QList betterEntries; - const Qt::CaseSensitivity caseSensitivity_ = caseSensitivity(entry); + const Qt::CaseSensitivity entryCaseSensitivity = caseSensitivity(entry); const QMap ¯os = MacroManager::macros(); QMapIterator it(macros); while (it.hasNext()) { it.next(); - QString name = it.key(); + const QString displayName = it.key(); + const QString description = it.value()->description(); - QList *category = 0; - if (name.startsWith(entry, caseSensitivity_)) - category = &betterEntries; - else if (name.contains(entry, caseSensitivity_)) - category = &goodEntries; + int index = displayName.indexOf(entry, 0, entryCaseSensitivity); + Core::LocatorFilterEntry::HighlightInfo::DataType hDataType = Core::LocatorFilterEntry::HighlightInfo::DisplayName; + if (index < 0) { + index = description.indexOf(entry, 0, entryCaseSensitivity); + hDataType = Core::LocatorFilterEntry::HighlightInfo::ExtraInfo; + } - if (category) { - QVariant id; - Core::LocatorFilterEntry entry(this, it.key(), id, m_icon); - entry.extraInfo = it.value()->description(); - category->append(entry); + if (index >= 0) { + Core::LocatorFilterEntry filterEntry(this, displayName, QVariant(), m_icon); + filterEntry.extraInfo = description; + filterEntry.highlightInfo = Core::LocatorFilterEntry::HighlightInfo(index, entry.length(), hDataType); + + if (index == 0) + betterEntries.append(filterEntry); + else + goodEntries.append(filterEntry); } } betterEntries.append(goodEntries); diff --git a/src/plugins/qmljstools/qmljsfunctionfilter.cpp b/src/plugins/qmljstools/qmljsfunctionfilter.cpp index d7c5979fd77..036ba1a314d 100644 --- a/src/plugins/qmljstools/qmljsfunctionfilter.cpp +++ b/src/plugins/qmljstools/qmljsfunctionfilter.cpp @@ -53,24 +53,18 @@ void FunctionFilter::refresh(QFutureInterface &) { } -static bool compareLexigraphically(const Core::LocatorFilterEntry &a, - const Core::LocatorFilterEntry &b) +QList FunctionFilter::matchesFor( + QFutureInterface &future, + const QString &entry) { - return a.displayName < b.displayName; -} - -QList FunctionFilter::matchesFor(QFutureInterface &future, const QString &origEntry) -{ - QString entry = trimWildcards(origEntry); QList goodEntries; QList betterEntries; - const QChar asterisk = QLatin1Char('*'); - QStringMatcher matcher(entry, Qt::CaseInsensitive); - QRegExp regexp(asterisk + entry+ asterisk, Qt::CaseInsensitive, QRegExp::Wildcard); + const Qt::CaseSensitivity cs = caseSensitivity(entry); + QStringMatcher matcher(entry, cs); + QRegExp regexp(entry, cs, QRegExp::Wildcard); if (!regexp.isValid()) return goodEntries; - bool hasWildcard = (entry.contains(asterisk) || entry.contains(QLatin1Char('?'))); - const Qt::CaseSensitivity caseSensitivityForPrefix = caseSensitivity(entry); + bool hasWildcard = containsWildcard(entry); QHashIterator > it(m_data->entries()); while (it.hasNext()) { @@ -83,14 +77,17 @@ QList FunctionFilter::matchesFor(QFutureInterface= 0) { QVariant id = qVariantFromValue(info); Core::LocatorFilterEntry filterEntry(this, info.displayName, id/*, info.icon*/); filterEntry.extraInfo = info.extraInfo; + const int length = hasWildcard ? regexp.matchedLength() : entry.length(); + filterEntry.highlightInfo = {index, length}; - if (info.symbolName.startsWith(entry, caseSensitivityForPrefix)) + if (index == 0) betterEntries.append(filterEntry); else goodEntries.append(filterEntry); @@ -99,9 +96,9 @@ QList FunctionFilter::matchesFor(QFutureInterface