forked from qt-creator/qt-creator
Rename CamelHumpMatcher -> FuzzyMatcher
Change-Id: Ia8a2eeb985bcdd500b4faf9605e5092a52dad372 Reviewed-by: André Hartmann <aha_1980@gmx.de>
This commit is contained in:
committed by
Orgad Shaneh
parent
fc2bb852fd
commit
e9b4d3a48a
154
src/libs/utils/fuzzymatcher.cpp
Normal file
154
src/libs/utils/fuzzymatcher.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 The Qt Company Ltd.
|
||||
** Copyright (C) 2017 BlackBerry Limited <qt@blackberry.com>
|
||||
** Copyright (C) 2017 Andre Hartmann <aha_1980@gmx.de>
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "fuzzymatcher.h"
|
||||
|
||||
#include <QRegularExpression>
|
||||
#include <QString>
|
||||
|
||||
/**
|
||||
* \brief Creates a regexp that represents a specified wildcard and camel hump pattern,
|
||||
* underscores are not included.
|
||||
*
|
||||
* \param pattern the camel hump pattern
|
||||
* \param caseSensitivity case sensitivity used for camel hump matching
|
||||
* \return the regexp
|
||||
*/
|
||||
QRegularExpression FuzzyMatcher::createRegExp(
|
||||
const QString &pattern, FuzzyMatcher::CaseSensitivity caseSensitivity)
|
||||
{
|
||||
if (pattern.isEmpty())
|
||||
return QRegularExpression();
|
||||
|
||||
/*
|
||||
* This code builds a regular expression in order to more intelligently match
|
||||
* camel-case and underscore names.
|
||||
*
|
||||
* For any but the first letter, the following replacements are made:
|
||||
* A => [a-z0-9_]*A
|
||||
* a => (?:[a-zA-Z0-9]*_)?a
|
||||
*
|
||||
* That means any sequence of lower-case or underscore characters can preceed an
|
||||
* upper-case character. And any sequence of lower-case or upper case characters -
|
||||
* followed by an underscore can preceed a lower-case character.
|
||||
*
|
||||
* Examples: (case sensitive mode)
|
||||
* gAC matches getActionController
|
||||
* gac matches get_action_controller
|
||||
*
|
||||
* It also implements the fully and first-letter-only case sensitivity.
|
||||
*/
|
||||
|
||||
QString keyRegExp;
|
||||
QString plainRegExp;
|
||||
bool first = true;
|
||||
const QChar asterisk = '*';
|
||||
const QChar question = '?';
|
||||
const QLatin1String uppercaseWordFirst("(?<=\\b|[a-z0-9_])");
|
||||
const QLatin1String lowercaseWordFirst("(?<=\\b|[A-Z0-9_])");
|
||||
const QLatin1String uppercaseWordContinuation("[a-z0-9_]*");
|
||||
const QLatin1String lowercaseWordContinuation("(?:[a-zA-Z0-9]*_)?");
|
||||
const QLatin1String upperSnakeWordContinuation("[A-Z0-9]*_");
|
||||
keyRegExp += "(?:";
|
||||
for (const QChar &c : pattern) {
|
||||
if (!c.isLetter()) {
|
||||
if (c == question) {
|
||||
keyRegExp += '.';
|
||||
plainRegExp += '.';
|
||||
} else if (c == asterisk) {
|
||||
keyRegExp += ".*";
|
||||
plainRegExp += ".*";
|
||||
} else {
|
||||
const QString escaped = QRegularExpression::escape(c);
|
||||
keyRegExp += '(' + escaped + ')';
|
||||
plainRegExp += escaped;
|
||||
}
|
||||
} else if (caseSensitivity == CaseSensitivity::CaseInsensitive ||
|
||||
(caseSensitivity == CaseSensitivity::FirstLetterCaseSensitive && !first)) {
|
||||
|
||||
const QString upper = QRegularExpression::escape(c.toUpper());
|
||||
const QString lower = QRegularExpression::escape(c.toLower());
|
||||
keyRegExp += "(?:";
|
||||
keyRegExp += first ? uppercaseWordFirst : uppercaseWordContinuation;
|
||||
keyRegExp += '(' + upper + ')';
|
||||
if (first) {
|
||||
keyRegExp += '|' + lowercaseWordFirst + '(' + lower + ')';
|
||||
} else {
|
||||
keyRegExp += '|' + lowercaseWordContinuation + '(' + lower + ')';
|
||||
keyRegExp += '|' + upperSnakeWordContinuation + '(' + upper + ')';
|
||||
}
|
||||
keyRegExp += ')';
|
||||
plainRegExp += '[' + upper + lower + ']';
|
||||
} else {
|
||||
if (!first) {
|
||||
if (c.isUpper())
|
||||
keyRegExp += uppercaseWordContinuation;
|
||||
else
|
||||
keyRegExp += lowercaseWordContinuation;
|
||||
}
|
||||
const QString escaped = QRegularExpression::escape(c);
|
||||
keyRegExp += escaped;
|
||||
plainRegExp += escaped;
|
||||
}
|
||||
|
||||
first = false;
|
||||
}
|
||||
keyRegExp += ')';
|
||||
|
||||
return QRegularExpression('(' + plainRegExp + ")|" + keyRegExp);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns a list of matched character positions and their matched lengths for the
|
||||
* given regular expression \a match.
|
||||
*
|
||||
* The list is minimized by combining adjacent highlighting positions to a single position.
|
||||
*/
|
||||
FuzzyMatcher::HighlightingPositions FuzzyMatcher::highlightingPositions(
|
||||
const QRegularExpressionMatch &match)
|
||||
{
|
||||
HighlightingPositions result;
|
||||
|
||||
for (int i = 1, size = match.capturedTexts().size(); i < size; ++i) {
|
||||
// skip unused positions, they can appear because upper- and lowercase
|
||||
// checks for one character are done using two capture groups
|
||||
if (match.capturedStart(i) < 0)
|
||||
continue;
|
||||
|
||||
// check for possible highlighting continuation to keep the list minimal
|
||||
if (!result.starts.isEmpty()
|
||||
&& (result.starts.last() + result.lengths.last() == match.capturedStart(i))) {
|
||||
result.lengths.last() += match.capturedLength(i);
|
||||
} else {
|
||||
// no continuation, append as different chunk
|
||||
result.starts.append(match.capturedStart(i));
|
||||
result.lengths.append(match.capturedLength(i));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
Reference in New Issue
Block a user