forked from qt-creator/qt-creator
FileSystemFilter: Convert to FuzzyMatcher
Fixes: QTCREATORBUG-18960 Change-Id: I7125362e77d7f079eec0cdcc270438cc98ca9407 Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
committed by
André Hartmann
parent
857b299356
commit
40921421ae
@@ -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.
|
||||||
|
@@ -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);
|
||||||
};
|
};
|
||||||
|
@@ -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,
|
||||||
|
@@ -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(
|
||||||
|
@@ -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);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user