Locator: Add camel hump locator filter for C++, QML, and files

* Use the CamelHumpMatcher in the C++, QML, and files filters
* Supports matching against UpperCamelCase, lowerCamelCase
  and snake_case strings
* Supports highlighting of matched characters

Task-number: QTCREATORBUG-3111
Started-by: David Kaspar <dkaspar@blackberry.com>
Change-Id: If6220191432ef965bde3c8dbe4a10d89e222ba6f
Reviewed-by: Orgad Shaneh <orgads@gmail.com>
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
Andre Hartmann
2017-07-24 20:55:47 +02:00
committed by André Hartmann
parent 2fb54abd03
commit 632f2a7709
14 changed files with 279 additions and 100 deletions

View File

@@ -30,9 +30,9 @@
#include <coreplugin/idocument.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/ieditor.h>
#include <utils/camelhumpmatcher.h>
#include <QRegExp>
#include <QStringMatcher>
#include <QRegularExpression>
using namespace CppTools::Internal;
using namespace CPlusPlus;
@@ -66,12 +66,12 @@ QList<Core::LocatorFilterEntry> CppCurrentDocumentFilter::matchesFor(
{
QList<Core::LocatorFilterEntry> goodEntries;
QList<Core::LocatorFilterEntry> betterEntries;
const Qt::CaseSensitivity cs = caseSensitivity(entry);
QStringMatcher matcher(entry, cs);
QRegExp regexp(entry, cs, QRegExp::Wildcard);
const QRegularExpression regexp = containsWildcard(entry)
? createWildcardRegExp(entry) : CamelHumpMatcher::createCamelHumpRegExp(entry);
if (!regexp.isValid())
return goodEntries;
bool hasWildcard = containsWildcard(entry);
foreach (IndexItem::Ptr info, itemsOfCurrentDocument()) {
if (future.isCanceled())
@@ -83,29 +83,30 @@ QList<Core::LocatorFilterEntry> CppCurrentDocumentFilter::matchesFor(
else if (info->type() == IndexItem::Function)
matchString += info->symbolType();
int index = hasWildcard ? regexp.indexIn(matchString) : matcher.indexIn(matchString);
if (index >= 0) {
const bool betterMatch = index == 0;
QRegularExpressionMatch match = regexp.match(matchString);
if (match.hasMatch()) {
const bool betterMatch = match.capturedStart() == 0;
QVariant id = qVariantFromValue(info);
QString name = matchString;
QString extraInfo = info->symbolScope();
if (info->type() == IndexItem::Function) {
if (info->unqualifiedNameAndScope(matchString, &name, &extraInfo)) {
name += info->symbolType();
index = hasWildcard ? regexp.indexIn(name) : matcher.indexIn(name);
match = regexp.match(name);
}
}
Core::LocatorFilterEntry filterEntry(this, name, id, info->icon());
filterEntry.extraInfo = extraInfo;
if (index < 0) {
index = hasWildcard ? regexp.indexIn(extraInfo) : matcher.indexIn(extraInfo);
if (!match.hasMatch()) {
match = regexp.match(extraInfo);
filterEntry.highlightInfo.dataType = Core::LocatorFilterEntry::HighlightInfo::ExtraInfo;
}
if (index >= 0) {
filterEntry.highlightInfo.startIndex = index;
filterEntry.highlightInfo.length = hasWildcard ? regexp.matchedLength() : entry.length();
}
const CamelHumpMatcher::HighlightingPositions positions =
CamelHumpMatcher::highlightingPositions(match);
filterEntry.highlightInfo.starts = positions.starts;
filterEntry.highlightInfo.lengths = positions.lengths;
if (betterMatch)
betterEntries.append(filterEntry);
else

View File

@@ -28,9 +28,9 @@
#include <coreplugin/editormanager/editormanager.h>
#include <utils/algorithm.h>
#include <utils/camelhumpmatcher.h>
#include <QRegExp>
#include <QStringMatcher>
#include <QRegularExpression>
#include <algorithm>
@@ -72,34 +72,37 @@ QList<Core::LocatorFilterEntry> CppLocatorFilter::matchesFor(
{
QList<Core::LocatorFilterEntry> goodEntries;
QList<Core::LocatorFilterEntry> betterEntries;
const Qt::CaseSensitivity cs = caseSensitivity(entry);
QStringMatcher matcher(entry, cs);
QRegExp regexp(entry, cs, QRegExp::Wildcard);
if (!regexp.isValid())
return goodEntries;
bool hasWildcard = containsWildcard(entry);
QList<Core::LocatorFilterEntry> bestEntries;
const Qt::CaseSensitivity caseSensitivityForPrefix = caseSensitivity(entry);
bool hasColonColon = entry.contains(QLatin1String("::"));
const IndexItem::ItemType wanted = matchTypes();
const QRegularExpression regexp = containsWildcard(entry)
? createWildcardRegExp(entry) : CamelHumpMatcher::createCamelHumpRegExp(entry);
if (!regexp.isValid())
return goodEntries;
m_data->filterAllFiles([&](const IndexItem::Ptr &info) -> IndexItem::VisitorResult {
if (future.isCanceled())
return IndexItem::Break;
if (info->type() & wanted) {
const QString matchString = hasColonColon ? info->scopedSymbolName() : info->symbolName();
int index = hasWildcard ? regexp.indexIn(matchString) : matcher.indexIn(matchString);
if (index >= 0) {
const bool betterMatch = index == 0;
QString matchString = hasColonColon ? info->scopedSymbolName() : info->symbolName();
QRegularExpressionMatch match = regexp.match(matchString);
if (match.hasMatch()) {
Core::LocatorFilterEntry filterEntry = filterEntryFromIndexItem(info);
if (matchString != filterEntry.displayName) {
index = hasWildcard ? regexp.indexIn(filterEntry.displayName)
: matcher.indexIn(filterEntry.displayName);
}
// Highlight the matched characters, therefore it may be necessary
// to update the match if the displayName is different from matchString
if (matchString != filterEntry.displayName)
match = regexp.match(filterEntry.displayName);
const CamelHumpMatcher::HighlightingPositions positions =
CamelHumpMatcher::highlightingPositions(match);
filterEntry.highlightInfo.starts = positions.starts;
filterEntry.highlightInfo.lengths = positions.lengths;
if (index >= 0)
filterEntry.highlightInfo = {index, (hasWildcard ? regexp.matchedLength() : entry.length())};
if (betterMatch)
if (matchString.startsWith(entry, caseSensitivityForPrefix))
bestEntries.append(filterEntry);
else if (matchString.contains(entry, caseSensitivityForPrefix))
betterEntries.append(filterEntry);
else
goodEntries.append(filterEntry);
@@ -116,9 +119,12 @@ QList<Core::LocatorFilterEntry> CppLocatorFilter::matchesFor(
Utils::sort(goodEntries, Core::LocatorFilterEntry::compareLexigraphically);
if (betterEntries.size() < 1000)
Utils::sort(betterEntries, Core::LocatorFilterEntry::compareLexigraphically);
if (bestEntries.size() < 1000)
Utils::sort(bestEntries, Core::LocatorFilterEntry::compareLexigraphically);
betterEntries += goodEntries;
return betterEntries;
bestEntries += betterEntries;
bestEntries += goodEntries;
return bestEntries;
}
void CppLocatorFilter::accept(Core::LocatorFilterEntry selection,

View File

@@ -190,6 +190,16 @@ void CppToolsPlugin::test_cpplocatorfilters_CppLocatorFilter_data()
<< ResultData(_("myFunction(bool, int)"), _("<anonymous namespace> (file1.cpp)"))
);
QTest::newRow("CppFunctionsFilter-Sorting")
<< testFile
<< cppFunctionsFilter
<< _("pos")
<< (QList<ResultData>()
<< ResultData(_("positiveNumber()"), testFileShort)
<< ResultData(_("getPosition()"), testFileShort)
<< ResultData(_("pointOfService()"), testFileShort)
);
QTest::newRow("CppFunctionsFilter-WithNamespacePrefix")
<< testFile
<< cppFunctionsFilter
@@ -280,6 +290,9 @@ void CppToolsPlugin::test_cpplocatorfilters_CppCurrentDocumentFilter()
QList<ResultData> expectedResults = QList<ResultData>()
<< ResultData(_("int myVariable"), _(""))
<< ResultData(_("myFunction(bool, int)"), _(""))
<< ResultData(_("pointOfService()"), _(""))
<< ResultData(_("getPosition()"), _(""))
<< ResultData(_("positiveNumber()"), _(""))
<< ResultData(_("MyEnum"), _(""))
<< ResultData(_("int V1"), _("MyEnum"))
<< ResultData(_("int V2"), _("MyEnum"))