FileSystemFilter: Convert to FuzzyMatcher

Fixes: QTCREATORBUG-18960
Change-Id: I7125362e77d7f079eec0cdcc270438cc98ca9407
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
Andre Hartmann
2019-07-14 08:10:50 +02:00
committed by André Hartmann
parent 857b299356
commit 40921421ae
5 changed files with 63 additions and 37 deletions

View File

@@ -122,6 +122,21 @@ QRegularExpression FuzzyMatcher::createRegExp(
return QRegularExpression('(' + plainRegExp + ")|" + keyRegExp); return QRegularExpression('(' + plainRegExp + ")|" + keyRegExp);
} }
/**
\overload
This overload eases the construction of a fuzzy regexp from a given
Qt::CaseSensitivity.
*/
QRegularExpression FuzzyMatcher::createRegExp(const QString &pattern,
Qt::CaseSensitivity caseSensitivity)
{
const CaseSensitivity sensitivity = (caseSensitivity == Qt::CaseSensitive)
? CaseSensitivity::CaseSensitive
: CaseSensitivity::CaseInsensitive;
return createRegExp(pattern, sensitivity);
}
/*! /*!
* \brief Returns a list of matched character positions and their matched lengths for the * \brief Returns a list of matched character positions and their matched lengths for the
* given regular expression \a match. * given regular expression \a match.

View File

@@ -54,5 +54,7 @@ public:
static QRegularExpression createRegExp(const QString &pattern, static QRegularExpression createRegExp(const QString &pattern,
CaseSensitivity caseSensitivity = CaseSensitivity::CaseInsensitive); CaseSensitivity caseSensitivity = CaseSensitivity::CaseInsensitive);
static QRegularExpression createRegExp(const QString &pattern,
Qt::CaseSensitivity caseSensitivity);
static HighlightingPositions highlightingPositions(const QRegularExpressionMatch &match); static HighlightingPositions highlightingPositions(const QRegularExpressionMatch &match);
}; };

View File

@@ -35,30 +35,34 @@
#include <utils/fileutils.h> #include <utils/fileutils.h>
#include <QDir> #include <QDir>
#include <QRegularExpression>
using namespace Core; using namespace Core;
using namespace Core::Internal; using namespace Core::Internal;
namespace { enum class MatchLevel {
Best = 0,
Better,
Good,
Normal,
Number
};
QList<LocatorFilterEntry> *categorize(const QString &entry, const QString &candidate, static MatchLevel matchLevelFor(const QRegularExpressionMatch &match, const QString &matchText)
Qt::CaseSensitivity caseSensitivity,
QList<LocatorFilterEntry> *betterEntries, QList<LocatorFilterEntry> *goodEntries,
int *index)
{ {
const int position = candidate.indexOf(entry, 0, caseSensitivity); const int consecutivePos = match.capturedStart(1);
if (index) if (consecutivePos == 0)
*index = position; return MatchLevel::Best;
if (consecutivePos > 0) {
if (entry.isEmpty() || position == 0) const QChar prevChar = matchText.at(consecutivePos - 1);
return betterEntries; if (prevChar == '_' || prevChar == '.')
if (position >= 0) return MatchLevel::Better;
return goodEntries; }
return nullptr; if (match.capturedStart() == 0)
return MatchLevel::Good;
return MatchLevel::Normal;
} }
} // anynoumous namespace
FileSystemFilter::FileSystemFilter() FileSystemFilter::FileSystemFilter()
{ {
setId("Files in file system"); setId("Files in file system");
@@ -76,8 +80,7 @@ void FileSystemFilter::prepareSearch(const QString &entry)
QList<LocatorFilterEntry> FileSystemFilter::matchesFor(QFutureInterface<LocatorFilterEntry> &future, QList<LocatorFilterEntry> FileSystemFilter::matchesFor(QFutureInterface<LocatorFilterEntry> &future,
const QString &entry) const QString &entry)
{ {
QList<LocatorFilterEntry> goodEntries; QList<LocatorFilterEntry> entries[int(MatchLevel::Number)];
QList<LocatorFilterEntry> betterEntries;
const QFileInfo entryInfo(entry); const QFileInfo entryInfo(entry);
const QString entryFileName = entryInfo.fileName(); const QString entryFileName = entryInfo.fileName();
QString directory = entryInfo.path(); QString directory = entryInfo.path();
@@ -101,19 +104,24 @@ QList<LocatorFilterEntry> FileSystemFilter::matchesFor(QFutureInterface<LocatorF
+ dirInfo.entryList(dirFilter, QDir::Name|QDir::IgnoreCase|QDir::LocaleAware); + dirInfo.entryList(dirFilter, QDir::Name|QDir::IgnoreCase|QDir::LocaleAware);
const QStringList files = dirInfo.entryList(fileFilter, const QStringList files = dirInfo.entryList(fileFilter,
QDir::Name|QDir::IgnoreCase|QDir::LocaleAware); QDir::Name|QDir::IgnoreCase|QDir::LocaleAware);
const QRegularExpression regExp = createRegExp(entryFileName, caseSensitivity_);
if (!regExp.isValid())
return {};
for (const QString &dir : dirs) { for (const QString &dir : dirs) {
if (future.isCanceled()) if (future.isCanceled())
break; break;
int index = -1;
if (QList<LocatorFilterEntry> *category = categorize(entryFileName, dir, caseSensitivity_, const QRegularExpressionMatch match = regExp.match(dir);
&betterEntries, &goodEntries, &index)) { if (match.hasMatch()) {
const MatchLevel level = matchLevelFor(match, dir);
const QString fullPath = dirInfo.filePath(dir); const QString fullPath = dirInfo.filePath(dir);
LocatorFilterEntry filterEntry(this, dir, QVariant()); LocatorFilterEntry filterEntry(this, dir, QVariant());
filterEntry.fileName = fullPath; filterEntry.fileName = fullPath;
if (index >= 0) filterEntry.highlightInfo = highlightInfo(match);
filterEntry.highlightInfo = {index, entryFileName.length()};
category->append(filterEntry); entries[int(level)].append(filterEntry);
} }
} }
// file names can match with +linenumber or :linenumber // file names can match with +linenumber or :linenumber
@@ -122,29 +130,29 @@ QList<LocatorFilterEntry> FileSystemFilter::matchesFor(QFutureInterface<LocatorF
for (const QString &file : files) { for (const QString &file : files) {
if (future.isCanceled()) if (future.isCanceled())
break; break;
int index = -1;
if (QList<LocatorFilterEntry> *category = categorize(fileName, file, caseSensitivity_, const QRegularExpressionMatch match = regExp.match(file);
&betterEntries, &goodEntries, &index)) { if (match.hasMatch()) {
const MatchLevel level = matchLevelFor(match, file);
const QString fullPath = dirInfo.filePath(file); const QString fullPath = dirInfo.filePath(file);
LocatorFilterEntry filterEntry(this, file, QString(fullPath + fp.postfix)); LocatorFilterEntry filterEntry(this, file, QString(fullPath + fp.postfix));
filterEntry.fileName = fullPath; filterEntry.fileName = fullPath;
if (index >= 0) filterEntry.highlightInfo = highlightInfo(match);
filterEntry.highlightInfo = {index, fileName.length()};
category->append(filterEntry); entries[int(level)].append(filterEntry);
} }
} }
betterEntries.append(goodEntries);
// "create and open" functionality // "create and open" functionality
const QString fullFilePath = dirInfo.filePath(fileName); const QString fullFilePath = dirInfo.filePath(fileName);
if (!QFileInfo::exists(fullFilePath) && dirInfo.exists()) { const bool containsWildcard = entry.contains('?') || entry.contains('*');
if (!containsWildcard && !QFileInfo::exists(fullFilePath) && dirInfo.exists()) {
LocatorFilterEntry createAndOpen(this, tr("Create and Open \"%1\"").arg(entry), fullFilePath); LocatorFilterEntry createAndOpen(this, tr("Create and Open \"%1\"").arg(entry), fullFilePath);
createAndOpen.extraInfo = Utils::FilePath::fromString(dirInfo.absolutePath()).shortNativePath(); createAndOpen.extraInfo = Utils::FilePath::fromString(dirInfo.absolutePath()).shortNativePath();
betterEntries.append(createAndOpen); entries[int(MatchLevel::Normal)].append(createAndOpen);
} }
return betterEntries; return std::accumulate(std::begin(entries), std::end(entries), QList<LocatorFilterEntry>());
} }
void FileSystemFilter::accept(LocatorFilterEntry selection, void FileSystemFilter::accept(LocatorFilterEntry selection,

View File

@@ -207,9 +207,9 @@ Qt::CaseSensitivity ILocatorFilter::caseSensitivity(const QString &str)
return str == str.toLower() ? Qt::CaseInsensitive : Qt::CaseSensitive; return str == str.toLower() ? Qt::CaseInsensitive : Qt::CaseSensitive;
} }
QRegularExpression ILocatorFilter::createRegExp(const QString &text) QRegularExpression ILocatorFilter::createRegExp(const QString &text, Qt::CaseSensitivity caseSensitivity)
{ {
return FuzzyMatcher::createRegExp(text); return FuzzyMatcher::createRegExp(text, caseSensitivity);
} }
LocatorFilterEntry::HighlightInfo ILocatorFilter::highlightInfo( LocatorFilterEntry::HighlightInfo ILocatorFilter::highlightInfo(

View File

@@ -145,7 +145,8 @@ public:
bool isEnabled() const; bool isEnabled() const;
static Qt::CaseSensitivity caseSensitivity(const QString &str); static Qt::CaseSensitivity caseSensitivity(const QString &str);
static QRegularExpression createRegExp(const QString &text); static QRegularExpression createRegExp(const QString &text,
Qt::CaseSensitivity caseSensitivity = Qt::CaseInsensitive);
LocatorFilterEntry::HighlightInfo highlightInfo(const QRegularExpressionMatch &match, LocatorFilterEntry::HighlightInfo highlightInfo(const QRegularExpressionMatch &match,
LocatorFilterEntry::HighlightInfo::DataType dataType = LocatorFilterEntry::HighlightInfo::DisplayName); LocatorFilterEntry::HighlightInfo::DataType dataType = LocatorFilterEntry::HighlightInfo::DisplayName);