Locator: Add highlighting of the search text

Change-Id: Ia166e9667076e46770a754b626ceb28080139e79
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
Serhii Moroz
2016-08-02 12:04:40 +03:00
parent 4f66adb9a2
commit 6ecb1c4018
22 changed files with 267 additions and 153 deletions

View File

@@ -116,6 +116,7 @@ SplitterColor=ff313131
TextColorDisabled=textDisabled
TextColorError=ffff4040
TextColorHighlight=ffff0000
TextColorHighlightBackground=555500
TextColorLink=textColorLink
TextColorLinkVisited=textColorLinkVisited
TextColorNormal=text

View File

@@ -108,6 +108,7 @@ SplitterColor=ff151515
TextColorDisabled=ff000000
TextColorError=ffff0000
TextColorHighlight=ffa0a0a4
TextColorHighlightBackground=ffef0b
TextColorLink=ff0057ae
TextColorLinkVisited=ff644a9b
TextColorNormal=ff000000

View File

@@ -121,6 +121,7 @@ SplitterColor=splitter
TextColorDisabled=textDisabled
TextColorError=ffff4040
TextColorHighlight=ffff0000
TextColorHighlightBackground=8a7f2c
TextColorLink=textColorLink
TextColorLinkVisited=textColorLinkVisited
TextColorNormal=text

View File

@@ -119,6 +119,7 @@ SplitterColor=splitter
TextColorDisabled=textDisabled
TextColorError=ffff4040
TextColorHighlight=ffff0000
TextColorHighlightBackground=ffef0b
TextColorLink=ff007af4
TextColorLinkVisited=ffa57aff
TextColorNormal=text

View File

@@ -117,6 +117,7 @@ SplitterColor=splitter
TextColorDisabled=textDisabled
TextColorError=ffff4040
TextColorHighlight=ffff0000
TextColorHighlightBackground=ffef0b
TextColorLink=ff007af4
TextColorLinkVisited=ffa57aff
TextColorNormal=text

View File

@@ -116,6 +116,7 @@ public:
TextColorDisabled,
TextColorError,
TextColorHighlight,
TextColorHighlightBackground,
TextColorLink,
TextColorLinkVisited,
TextColorNormal,

View File

@@ -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);
}
}
}

View File

@@ -98,18 +98,18 @@ QList<LocatorFilterEntry> BaseFileFilter::matchesFor(QFutureInterface<LocatorFil
{
QList<LocatorFilterEntry> betterEntries;
QList<LocatorFilterEntry> 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<LocatorFilterEntry> BaseFileFilter::matchesFor(QFutureInterface<LocatorFil
d->m_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<LocatorFilterEntry> BaseFileFilter::matchesFor(QFutureInterface<LocatorFil
QString path = d->m_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);
}

View File

@@ -67,20 +67,27 @@ QList<LocatorFilterEntry> CommandLocator::matchesFor(QFutureInterface<LocatorFil
// Get active, enabled actions matching text, store in list.
// Reference via index in extraInfo.
const QChar ampersand = QLatin1Char('&');
const Qt::CaseSensitivity caseSensitivity_ = caseSensitivity(entry);
const Qt::CaseSensitivity entryCaseSensitivity = caseSensitivity(entry);
const int count = d->commands.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()) {
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);
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)));
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);
}
}
}

View File

@@ -60,16 +60,20 @@ QList<LocatorFilterEntry> ExecuteFilter::matchesFor(QFutureInterface<LocatorFilt
if (!entry.isEmpty()) // avoid empty entry
value.append(LocatorFilterEntry(this, entry, QVariant()));
QList<LocatorFilterEntry> 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;

View File

@@ -64,17 +64,23 @@ void ExternalToolsFilter::refresh(QFutureInterface<void> &)
void ExternalToolsFilter::prepareSearch(const QString &entry)
{
m_results.clear();
Qt::CaseSensitivity useCaseSensitivity = caseSensitivity(entry);
const Qt::CaseSensitivity entryCaseSensitivity = caseSensitivity(entry);
const QMap<QString, ExternalTool *> 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);
}
}

View File

@@ -41,11 +41,16 @@ namespace {
QList<LocatorFilterEntry> *categorize(const QString &entry, const QString &candidate,
Qt::CaseSensitivity caseSensitivity,
QList<LocatorFilterEntry> *betterEntries, QList<LocatorFilterEntry> *goodEntries)
QList<LocatorFilterEntry> *betterEntries, QList<LocatorFilterEntry> *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<LocatorFilterEntry> FileSystemFilter::matchesFor(QFutureInterface<LocatorF
foreach (const QString &dir, dirs) {
if (future.isCanceled())
break;
if (QList<LocatorFilterEntry> *category = categorize(entryFileName, dir, caseSensitivity_, &betterEntries,
&goodEntries)) {
int index = -1;
if (QList<LocatorFilterEntry> *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<LocatorFilterEntry> FileSystemFilter::matchesFor(QFutureInterface<LocatorF
foreach (const QString &file, files) {
if (future.isCanceled())
break;
if (QList<LocatorFilterEntry> *category = categorize(fileName, file, caseSensitivity_, &betterEntries,
&goodEntries)) {
int index = -1;
if (QList<LocatorFilterEntry> *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);
}
}

View File

@@ -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");

View File

@@ -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();

View File

@@ -33,6 +33,8 @@
#include <coreplugin/modemanager.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/fileiconprovider.h>
#include <coreplugin/find/searchresulttreeitemdelegate.h>
#include <coreplugin/find/searchresulttreeitemroles.h>
#include <coreplugin/icontext.h>
#include <coreplugin/mainwindow.h>
#include <utils/algorithm.h>
@@ -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<LocatorFilterEntry> 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<LocatorFilterEntry> &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<LocatorFilterEntry>();
const LocatorFilterEntry entry = m_locatorModel->data(index, ItemDataRoles::ResultItemRole).value<LocatorFilterEntry>();
m_completionList->hide();
m_fileLineEdit->clearFocus();
Q_ASSERT(entry.filter != nullptr);
entry.filter->accept(entry);
}

View File

@@ -55,19 +55,16 @@ OpenDocumentsFilter::OpenDocumentsFilter()
this, &OpenDocumentsFilter::refreshInternally);
}
QList<LocatorFilterEntry> OpenDocumentsFilter::matchesFor(QFutureInterface<LocatorFilterEntry> &future, const QString &entry)
QList<LocatorFilterEntry> OpenDocumentsFilter::matchesFor(QFutureInterface<LocatorFilterEntry> &future,
const QString &entry)
{
QList<LocatorFilterEntry> goodEntries;
QList<LocatorFilterEntry> 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<LocatorFilterEntry> OpenDocumentsFilter::matchesFor(QFutureInterface<Locat
if (fileName.isEmpty())
continue;
QString displayName = editorEntry.displayName;
if (regexp.exactMatch(displayName)) {
LocatorFilterEntry fiEntry(this, displayName, QString(fileName + fp.postfix));
fiEntry.extraInfo = FileUtils::shortNativePath(FileName::fromString(fileName));
fiEntry.fileName = fileName;
QList<LocatorFilterEntry> &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);

View File

@@ -62,18 +62,16 @@ CppCurrentDocumentFilter::CppCurrentDocumentFilter(CppTools::CppModelManager *ma
}
QList<Core::LocatorFilterEntry> CppCurrentDocumentFilter::matchesFor(
QFutureInterface<Core::LocatorFilterEntry> &future, const QString & origEntry)
QFutureInterface<Core::LocatorFilterEntry> &future, const QString & entry)
{
QString entry = trimWildcards(origEntry);
QList<Core::LocatorFilterEntry> goodEntries;
QList<Core::LocatorFilterEntry> 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<Core::LocatorFilterEntry> 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);

View File

@@ -27,6 +27,7 @@
#include "cppmodelmanager.h"
#include <coreplugin/editormanager/editormanager.h>
#include <utils/algorithm.h>
#include <QRegExp>
#include <QStringMatcher>
@@ -66,26 +67,18 @@ void CppLocatorFilter::refresh(QFutureInterface<void> &future)
Q_UNUSED(future)
}
static bool compareLexigraphically(const Core::LocatorFilterEntry &a,
const Core::LocatorFilterEntry &b)
{
return a.displayName < b.displayName;
}
QList<Core::LocatorFilterEntry> CppLocatorFilter::matchesFor(
QFutureInterface<Core::LocatorFilterEntry> &future, const QString &origEntry)
QFutureInterface<Core::LocatorFilterEntry> &future, const QString &entry)
{
QString entry = trimWildcards(origEntry);
QList<Core::LocatorFilterEntry> goodEntries;
QList<Core::LocatorFilterEntry> 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<Core::LocatorFilterEntry> 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<Core::LocatorFilterEntry> 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;

View File

@@ -127,8 +127,12 @@ QList<LocatorFilterEntry> HelpIndexFilter::matchesFor(QFutureInterface<LocatorFi
keywords << unsortedKeywords;
m_keywordCache = allresults;
m_searchTermCache = entry;
foreach (const QString &keyword, keywords)
entries.append(LocatorFilterEntry(this, keyword, QVariant(), m_icon));
foreach (const QString &keyword, keywords) {
const int index = keyword.indexOf(entry, 0, cs);
LocatorFilterEntry filterEntry(this, keyword, QVariant(), m_icon);
filterEntry.highlightInfo = {index, entry.length()};
entries.append(filterEntry);
}
return entries;
}

View File

@@ -129,15 +129,16 @@ RemoteHelpFilter::~RemoteHelpFilter()
{
}
QList<Core::LocatorFilterEntry> RemoteHelpFilter::matchesFor(QFutureInterface<Core::LocatorFilterEntry> &future, const QString &pattern)
QList<Core::LocatorFilterEntry> RemoteHelpFilter::matchesFor(QFutureInterface<Core::LocatorFilterEntry> &future, const QString &entry)
{
QList<Core::LocatorFilterEntry> 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;
}

View File

@@ -54,26 +54,32 @@ QList<Core::LocatorFilterEntry> MacroLocatorFilter::matchesFor(QFutureInterface<
QList<Core::LocatorFilterEntry> goodEntries;
QList<Core::LocatorFilterEntry> betterEntries;
const Qt::CaseSensitivity caseSensitivity_ = caseSensitivity(entry);
const Qt::CaseSensitivity entryCaseSensitivity = caseSensitivity(entry);
const QMap<QString, Macro*> &macros = MacroManager::macros();
QMapIterator<QString, Macro*> it(macros);
while (it.hasNext()) {
it.next();
QString name = it.key();
const QString displayName = it.key();
const QString description = it.value()->description();
QList<Core::LocatorFilterEntry> *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);

View File

@@ -53,24 +53,18 @@ void FunctionFilter::refresh(QFutureInterface<void> &)
{
}
static bool compareLexigraphically(const Core::LocatorFilterEntry &a,
const Core::LocatorFilterEntry &b)
QList<Core::LocatorFilterEntry> FunctionFilter::matchesFor(
QFutureInterface<Core::LocatorFilterEntry> &future,
const QString &entry)
{
return a.displayName < b.displayName;
}
QList<Core::LocatorFilterEntry> FunctionFilter::matchesFor(QFutureInterface<Core::LocatorFilterEntry> &future, const QString &origEntry)
{
QString entry = trimWildcards(origEntry);
QList<Core::LocatorFilterEntry> goodEntries;
QList<Core::LocatorFilterEntry> 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<QString, QList<LocatorData::Entry> > it(m_data->entries());
while (it.hasNext()) {
@@ -83,14 +77,17 @@ QList<Core::LocatorFilterEntry> FunctionFilter::matchesFor(QFutureInterface<Core
foreach (const LocatorData::Entry &info, items) {
if (info.type != LocatorData::Function)
continue;
if ((hasWildcard && regexp.exactMatch(info.symbolName))
|| (!hasWildcard && matcher.indexIn(info.symbolName) != -1)) {
const int index = hasWildcard ? regexp.indexIn(info.symbolName)
: matcher.indexIn(info.symbolName);
if (index >= 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<Core::LocatorFilterEntry> FunctionFilter::matchesFor(QFutureInterface<Core
}
if (goodEntries.size() < 1000)
Utils::sort(goodEntries, compareLexigraphically);
Utils::sort(goodEntries, Core::LocatorFilterEntry::compareLexigraphically);
if (betterEntries.size() < 1000)
Utils::sort(betterEntries, compareLexigraphically);
Utils::sort(betterEntries, Core::LocatorFilterEntry::compareLexigraphically);
betterEntries += goodEntries;
return betterEntries;