mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-10-27 08:37:58 +03:00
Added a new fuzzy matching algorithm, it should be better than the previous version, it's similar to what most editors have (implementation is inspired in the sublime_text fuzzy matcher).
This commit is contained in:
@@ -309,9 +309,11 @@ class EE_API String {
|
||||
*/
|
||||
static bool icontains( const String& haystack, const String& needle );
|
||||
|
||||
static int fuzzyMatch( const std::string& string, const std::string& pattern,
|
||||
static int fuzzyMatchSimple( const std::string& pattern, const std::string& string,
|
||||
bool allowUneven = false, bool permissive = false );
|
||||
|
||||
static int fuzzyMatch( const std::string& pattern, const std::string& string );
|
||||
|
||||
/** Replace all occurrences of the search string with the replacement string. */
|
||||
static void replaceAll( std::string& target, const std::string& that, const std::string& with );
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
// #include <eepp/core/simd.hpp>
|
||||
|
||||
#include <thirdparty/fast_float/include/fast_float/fast_float.h>
|
||||
#define FTS_FUZZY_MATCH_IMPLEMENTATION
|
||||
#include <thirdparty/fts_fuzzy_match/fts_fuzzy_match.h>
|
||||
#include <thirdparty/utf8cpp/utf8.h>
|
||||
|
||||
#include <algorithm>
|
||||
@@ -1133,11 +1135,18 @@ constexpr int tFuzzyMatch( const T* str, const T* ptn, bool allowUneven, bool pe
|
||||
return score - ( permissive ? 0 : strlen( str ) );
|
||||
}
|
||||
|
||||
int String::fuzzyMatch( const std::string& string, const std::string& pattern, bool allowUneven,
|
||||
bool permissive ) {
|
||||
int String::fuzzyMatchSimple( const std::string& pattern, const std::string& string,
|
||||
bool allowUneven, bool permissive ) {
|
||||
return tFuzzyMatch<char>( string.c_str(), pattern.c_str(), allowUneven, permissive );
|
||||
}
|
||||
|
||||
int String::fuzzyMatch( const std::string& pattern, const std::string& string ) {
|
||||
int score = std::numeric_limits<int>::min();
|
||||
uint8_t matches[256];
|
||||
fts::fuzzy_match( pattern.c_str(), string.c_str(), score, matches, sizeof( matches ) );
|
||||
return score;
|
||||
}
|
||||
|
||||
std::vector<Uint8> String::stringToUint8( const std::string& str ) {
|
||||
return std::vector<Uint8>( str.begin(), str.end() );
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ void addHTML() {
|
||||
|
||||
},
|
||||
"",
|
||||
{ "<html", "<![Dd][Oo][Cc][Tt][Yy][Pp][Ee]%s[Hh][Tt][Mm][Ll]>" }
|
||||
{ "^<html", "^<![Dd][Oo][Cc][Tt][Yy][Pp][Ee]%s[Hh][Tt][Mm][Ll]>" }
|
||||
|
||||
} )
|
||||
.setAutoCloseXMLTags( true );
|
||||
|
||||
@@ -33,7 +33,7 @@ void addXML() {
|
||||
|
||||
},
|
||||
"",
|
||||
{ "<%?xml" }
|
||||
{ "^<%?xml" }
|
||||
|
||||
} )
|
||||
.setAutoCloseXMLTags( true );
|
||||
|
||||
+221
@@ -0,0 +1,221 @@
|
||||
// LICENSE
|
||||
//
|
||||
// This software is dual-licensed to the public domain and under the following
|
||||
// license: you are granted a perpetual, irrevocable license to copy, modify,
|
||||
// publish, and distribute this file as you see fit.
|
||||
//
|
||||
// VERSION
|
||||
// 0.2.0 (2017-02-18) Scored matches perform exhaustive search for best score
|
||||
// 0.1.0 (2016-03-28) Initial release
|
||||
//
|
||||
// AUTHOR
|
||||
// Forrest Smith
|
||||
//
|
||||
// NOTES
|
||||
// Compiling
|
||||
// You MUST add '#define FTS_FUZZY_MATCH_IMPLEMENTATION' before including this header in ONE source file to create implementation.
|
||||
//
|
||||
// fuzzy_match_simple(...)
|
||||
// Returns true if each character in pattern is found sequentially within str
|
||||
//
|
||||
// fuzzy_match(...)
|
||||
// Returns true if pattern is found AND calculates a score.
|
||||
// Performs exhaustive search via recursion to find all possible matches and match with highest score.
|
||||
// Scores values have no intrinsic meaning. Possible score range is not normalized and varies with pattern.
|
||||
// Recursion is limited internally (default=10) to prevent degenerate cases (pattern="aaaaaa" str="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
|
||||
// Uses uint8_t for match indices. Therefore patterns are limited to 256 characters.
|
||||
// Score system should be tuned for YOUR use case. Words, sentences, file names, or method names all prefer different tuning.
|
||||
|
||||
|
||||
#ifndef FTS_FUZZY_MATCH_H
|
||||
#define FTS_FUZZY_MATCH_H
|
||||
|
||||
|
||||
#include <cstdint> // uint8_t
|
||||
#include <ctype.h> // ::tolower, ::toupper
|
||||
#include <cstring> // memcpy
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
// Public interface
|
||||
namespace fts {
|
||||
[[maybe_unused]] static bool fuzzy_match_simple(char const * pattern, char const * str);
|
||||
[[maybe_unused]] static bool fuzzy_match(char const * pattern, char const * str, int & outScore);
|
||||
[[maybe_unused]] static bool fuzzy_match(char const * pattern, char const * str, int & outScore, uint8_t * matches, int maxMatches);
|
||||
}
|
||||
|
||||
|
||||
#ifdef FTS_FUZZY_MATCH_IMPLEMENTATION
|
||||
namespace fts {
|
||||
|
||||
// Forward declarations for "private" implementation
|
||||
namespace fuzzy_internal {
|
||||
static bool fuzzy_match_recursive(const char * pattern, const char * str, int & outScore, const char * strBegin,
|
||||
uint8_t const * srcMatches, uint8_t * newMatches, int maxMatches, int nextMatch,
|
||||
int & recursionCount, int recursionLimit);
|
||||
}
|
||||
|
||||
// Public interface
|
||||
static bool fuzzy_match_simple(char const * pattern, char const * str) {
|
||||
while (*pattern != '\0' && *str != '\0') {
|
||||
if (tolower(*pattern) == tolower(*str))
|
||||
++pattern;
|
||||
++str;
|
||||
}
|
||||
|
||||
return *pattern == '\0' ? true : false;
|
||||
}
|
||||
|
||||
static bool fuzzy_match(char const * pattern, char const * str, int & outScore) {
|
||||
|
||||
uint8_t matches[256];
|
||||
return fuzzy_match(pattern, str, outScore, matches, sizeof(matches));
|
||||
}
|
||||
|
||||
static bool fuzzy_match(char const * pattern, char const * str, int & outScore, uint8_t * matches, int maxMatches) {
|
||||
int recursionCount = 0;
|
||||
int recursionLimit = 10;
|
||||
|
||||
return fuzzy_internal::fuzzy_match_recursive(pattern, str, outScore, str, nullptr, matches, maxMatches, 0, recursionCount, recursionLimit);
|
||||
}
|
||||
|
||||
// Private implementation
|
||||
static bool fuzzy_internal::fuzzy_match_recursive(const char * pattern, const char * str, int & outScore,
|
||||
const char * strBegin, uint8_t const * srcMatches, uint8_t * matches, int maxMatches,
|
||||
int nextMatch, int & recursionCount, int recursionLimit)
|
||||
{
|
||||
// Count recursions
|
||||
++recursionCount;
|
||||
if (recursionCount >= recursionLimit)
|
||||
return false;
|
||||
|
||||
// Detect end of strings
|
||||
if (*pattern == '\0' || *str == '\0')
|
||||
return false;
|
||||
|
||||
// Recursion params
|
||||
bool recursiveMatch = false;
|
||||
uint8_t bestRecursiveMatches[256];
|
||||
int bestRecursiveScore = 0;
|
||||
|
||||
// Loop through pattern and str looking for a match
|
||||
bool first_match = true;
|
||||
while (*pattern != '\0' && *str != '\0') {
|
||||
|
||||
// Found match
|
||||
if (tolower(*pattern) == tolower(*str)) {
|
||||
|
||||
// Supplied matches buffer was too short
|
||||
if (nextMatch >= maxMatches)
|
||||
return false;
|
||||
|
||||
// "Copy-on-Write" srcMatches into matches
|
||||
if (first_match && srcMatches) {
|
||||
memcpy(matches, srcMatches, nextMatch);
|
||||
first_match = false;
|
||||
}
|
||||
|
||||
// Recursive call that "skips" this match
|
||||
uint8_t recursiveMatches[256];
|
||||
int recursiveScore;
|
||||
if (fuzzy_match_recursive(pattern, str + 1, recursiveScore, strBegin, matches, recursiveMatches, sizeof(recursiveMatches), nextMatch, recursionCount, recursionLimit)) {
|
||||
|
||||
// Pick best recursive score
|
||||
if (!recursiveMatch || recursiveScore > bestRecursiveScore) {
|
||||
memcpy(bestRecursiveMatches, recursiveMatches, 256);
|
||||
bestRecursiveScore = recursiveScore;
|
||||
}
|
||||
recursiveMatch = true;
|
||||
}
|
||||
|
||||
// Advance
|
||||
matches[nextMatch++] = (uint8_t)(str - strBegin);
|
||||
++pattern;
|
||||
}
|
||||
++str;
|
||||
}
|
||||
|
||||
// Determine if full pattern was matched
|
||||
bool matched = *pattern == '\0' ? true : false;
|
||||
|
||||
// Calculate score
|
||||
if (matched) {
|
||||
const int sequential_bonus = 15; // bonus for adjacent matches
|
||||
const int separator_bonus = 30; // bonus if match occurs after a separator
|
||||
const int camel_bonus = 30; // bonus if match is uppercase and prev is lower
|
||||
const int first_letter_bonus = 15; // bonus if the first letter is matched
|
||||
|
||||
const int leading_letter_penalty = -5; // penalty applied for every letter in str before the first match
|
||||
const int max_leading_letter_penalty = -15; // maximum penalty for leading letters
|
||||
const int unmatched_letter_penalty = -1; // penalty for every letter that doesn't matter
|
||||
|
||||
// Iterate str to end
|
||||
while (*str != '\0')
|
||||
++str;
|
||||
|
||||
// Initialize score
|
||||
outScore = 100;
|
||||
|
||||
// Apply leading letter penalty
|
||||
int penalty = leading_letter_penalty * matches[0];
|
||||
if (penalty < max_leading_letter_penalty)
|
||||
penalty = max_leading_letter_penalty;
|
||||
outScore += penalty;
|
||||
|
||||
// Apply unmatched penalty
|
||||
int unmatched = (int)(str - strBegin) - nextMatch;
|
||||
outScore += unmatched_letter_penalty * unmatched;
|
||||
|
||||
// Apply ordering bonuses
|
||||
for (int i = 0; i < nextMatch; ++i) {
|
||||
uint8_t currIdx = matches[i];
|
||||
|
||||
if (i > 0) {
|
||||
uint8_t prevIdx = matches[i - 1];
|
||||
|
||||
// Sequential
|
||||
if (currIdx == (prevIdx + 1))
|
||||
outScore += sequential_bonus;
|
||||
}
|
||||
|
||||
// Check for bonuses based on neighbor character value
|
||||
if (currIdx > 0) {
|
||||
// Camel case
|
||||
char neighbor = strBegin[currIdx - 1];
|
||||
char curr = strBegin[currIdx];
|
||||
if (::islower(neighbor) && ::isupper(curr))
|
||||
outScore += camel_bonus;
|
||||
|
||||
// Separator
|
||||
bool neighborSeparator = neighbor == '_' || neighbor == ' ';
|
||||
if (neighborSeparator)
|
||||
outScore += separator_bonus;
|
||||
}
|
||||
else {
|
||||
// First letter
|
||||
outScore += first_letter_bonus;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return best result
|
||||
if (recursiveMatch && (!matched || bestRecursiveScore > outScore)) {
|
||||
// Recursive score is better than "this"
|
||||
memcpy(matches, bestRecursiveMatches, maxMatches);
|
||||
outScore = bestRecursiveScore;
|
||||
return true;
|
||||
}
|
||||
else if (matched) {
|
||||
// "this" score is better than recursive
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
// no match
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} // namespace fts
|
||||
|
||||
#endif // FTS_FUZZY_MATCH_IMPLEMENTATION
|
||||
|
||||
#endif // FTS_FUZZY_MATCH_H
|
||||
@@ -66,7 +66,7 @@ void CommandPalette::setCurModel( const std::shared_ptr<CommandPaletteModel>& cu
|
||||
|
||||
std::shared_ptr<CommandPaletteModel>
|
||||
CommandPalette::fuzzyMatch( const std::vector<std::vector<std::string>>& cmdPalette,
|
||||
const std::string& match, const size_t& max ) const {
|
||||
const std::string& pattern, const size_t& max ) const {
|
||||
if ( cmdPalette.empty() )
|
||||
return {};
|
||||
|
||||
@@ -75,9 +75,11 @@ CommandPalette::fuzzyMatch( const std::vector<std::vector<std::string>>& cmdPale
|
||||
std::vector<std::vector<std::string>> ret;
|
||||
|
||||
for ( size_t i = 0; i < cmdPalette.size(); i++ ) {
|
||||
int matchName = String::fuzzyMatch( cmdPalette[i][0], match );
|
||||
int matchKeybind = String::fuzzyMatch( cmdPalette[i][2], match );
|
||||
matchesMap.insert( { std::max( matchName, matchKeybind ), i } );
|
||||
int matchName = String::fuzzyMatch( pattern, cmdPalette[i][0] );
|
||||
int matchKeybind = String::fuzzyMatch( pattern, cmdPalette[i][2] );
|
||||
int matchScore = std::max( matchName, matchKeybind );
|
||||
if ( matchScore > std::numeric_limits<int>::min() )
|
||||
matchesMap.insert( { matchScore, i } );
|
||||
}
|
||||
for ( auto& res : matchesMap ) {
|
||||
if ( ret.size() < max )
|
||||
@@ -86,15 +88,15 @@ CommandPalette::fuzzyMatch( const std::vector<std::vector<std::string>>& cmdPale
|
||||
return CommandPaletteModel::create( 3, ret );
|
||||
}
|
||||
|
||||
void CommandPalette::asyncFuzzyMatch( const std::string& match, const size_t& max,
|
||||
void CommandPalette::asyncFuzzyMatch( const std::string& pattern, const size_t& max,
|
||||
MatchResultCb res ) const {
|
||||
if ( !mCurModel )
|
||||
return;
|
||||
|
||||
mPool->run( [this, match, max, res]() {
|
||||
mPool->run( [this, pattern, max, res]() {
|
||||
const std::vector<std::vector<std::string>>& cmdPalette =
|
||||
mCurModel.get() == mBaseModel.get() ? mCommandPalette : mCommandPaletteEditor;
|
||||
res( fuzzyMatch( cmdPalette, match, max ) );
|
||||
res( fuzzyMatch( cmdPalette, pattern, max ) );
|
||||
} );
|
||||
}
|
||||
|
||||
|
||||
@@ -27,10 +27,10 @@ class CommandPalette {
|
||||
static std::shared_ptr<CommandPaletteModel>
|
||||
asModel( const std::vector<std::string>& commandList, const EE::UI::KeyBindings& keybindings );
|
||||
|
||||
void asyncFuzzyMatch( const std::string& match, const size_t& max, MatchResultCb res ) const;
|
||||
void asyncFuzzyMatch( const std::string& pattern, const size_t& max, MatchResultCb res ) const;
|
||||
|
||||
std::shared_ptr<CommandPaletteModel>
|
||||
fuzzyMatch( const std::vector<std::vector<std::string>>& cmdPalette, const std::string& match,
|
||||
fuzzyMatch( const std::vector<std::vector<std::string>>& cmdPalette, const std::string& pattern,
|
||||
const size_t& max ) const;
|
||||
|
||||
void setCommandPalette( const std::vector<std::string>& commandList,
|
||||
|
||||
@@ -48,19 +48,21 @@ static json getURIAndPositionJSON( UICodeEditor* editor ) {
|
||||
|
||||
static AutoCompletePlugin::SymbolsList
|
||||
fuzzyMatchSymbols( const std::vector<const AutoCompletePlugin::SymbolsList*>& symbolsVec,
|
||||
const std::string& match, const size_t& max ) {
|
||||
const std::string& pattern, const size_t& max ) {
|
||||
AutoCompletePlugin::SymbolsList matches;
|
||||
matches.reserve( max );
|
||||
int score = 0;
|
||||
for ( const auto& symbols : symbolsVec ) {
|
||||
for ( const auto& symbol : *symbols ) {
|
||||
if ( symbol.kind == LSPCompletionItemKind::Snippet ||
|
||||
( score = String::fuzzyMatch( symbol.text, match, false,
|
||||
symbol.kind != LSPCompletionItemKind::Text ) ) >
|
||||
0 ) {
|
||||
( score = String::fuzzyMatch( pattern, symbol.text ) ) >
|
||||
std::numeric_limits<int>::min() ) {
|
||||
if ( std::find( matches.begin(), matches.end(), symbol ) == matches.end() ) {
|
||||
symbol.setScore( score );
|
||||
matches.push_back( symbol );
|
||||
|
||||
if ( matches.size() > max )
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -410,7 +410,7 @@ PluginRequestHandle LSPClientPlugin::processWorkspaceSymbol( const PluginMessage
|
||||
if ( !query.empty() ) {
|
||||
for ( auto& i : info ) {
|
||||
if ( i.score == 0.f )
|
||||
i.score = String::fuzzyMatch( i.name, query );
|
||||
i.score = String::fuzzyMatch( query, i.name );
|
||||
}
|
||||
}
|
||||
mManager->sendResponse( this, PluginMessageType::WorkspaceSymbol,
|
||||
@@ -422,7 +422,7 @@ PluginRequestHandle LSPClientPlugin::processWorkspaceSymbol( const PluginMessage
|
||||
if ( !query.empty() ) {
|
||||
for ( auto& i : info ) {
|
||||
if ( i.score == 0.f )
|
||||
i.score = String::fuzzyMatch( i.name, query );
|
||||
i.score = String::fuzzyMatch( query, i.name );
|
||||
}
|
||||
}
|
||||
mManager->sendResponse( this, PluginMessageType::WorkspaceSymbol,
|
||||
|
||||
@@ -118,9 +118,11 @@ ProjectDirectoryTree::fuzzyMatchTree( const std::vector<std::string>& matches, c
|
||||
std::vector<std::string> names;
|
||||
for ( const auto& match : matches ) {
|
||||
for ( size_t i = 0; i < mNames.size(); i++ ) {
|
||||
int matchName = String::fuzzyMatch( match, mNames[i], true );
|
||||
int matchPath = String::fuzzyMatch( match, mFiles[i], true );
|
||||
matchesMap.insert( { std::max( matchName, matchPath ), i } );
|
||||
int matchName = String::fuzzyMatch( match, mNames[i] );
|
||||
int matchPath = String::fuzzyMatch( match, mFiles[i] );
|
||||
int matchScore = std::max( matchName, matchPath );
|
||||
if ( matchScore > std::numeric_limits<int>::min() )
|
||||
matchesMap.insert( { matchScore, i } );
|
||||
}
|
||||
}
|
||||
for ( auto& res : matchesMap ) {
|
||||
@@ -144,12 +146,14 @@ ProjectDirectoryTree::fuzzyMatchTree( const std::string& match, const size_t& ma
|
||||
std::vector<std::string> files;
|
||||
std::vector<std::string> names;
|
||||
for ( size_t i = 0; i < mNames.size(); i++ ) {
|
||||
int matchName = String::fuzzyMatch( match, mNames[i], true );
|
||||
int matchPath = String::fuzzyMatch( match, mFiles[i], true );
|
||||
matchesMap.insert( { std::max( matchName, matchPath ), i } );
|
||||
int matchName = String::fuzzyMatch( match, mNames[i] );
|
||||
int matchPath = String::fuzzyMatch( match, mFiles[i] );
|
||||
int matchScore = std::max( matchName, matchPath );
|
||||
if ( matchScore > std::numeric_limits<int>::min() )
|
||||
matchesMap.insert( { matchScore, i } );
|
||||
}
|
||||
for ( auto& res : matchesMap ) {
|
||||
if ( names.size() < max ) {
|
||||
if ( names.size() < max && res.first > std::numeric_limits<int>::min() ) {
|
||||
names.emplace_back( mNames[res.second] );
|
||||
files.emplace_back( mFiles[res.second] );
|
||||
} else {
|
||||
@@ -627,7 +631,7 @@ PluginRequestHandle ProjectDirectoryTree::processMessage( const PluginMessage& m
|
||||
std::string closestDataPath;
|
||||
int max{ std::numeric_limits<int>::min() };
|
||||
for ( const auto& paths : tentativePaths ) {
|
||||
int res = String::fuzzyMatch( filePath.c_str(), paths.c_str(), true );
|
||||
int res = String::fuzzyMatch( filePath.c_str(), paths.c_str() );
|
||||
if ( res > max ) {
|
||||
closestDataPath = filePath;
|
||||
max = res;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "universallocator.hpp"
|
||||
#include "ecode.hpp"
|
||||
#include "pathhelper.hpp"
|
||||
#include "settingsmenu.hpp"
|
||||
#include "universallocator.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@@ -94,13 +94,11 @@ LSPSymbolInformationList fuzzyMatchTextDocumentSymbol( const LSPSymbolInformatio
|
||||
std::map<int, LSPSymbolInformation, std::greater<int>> matchesMap;
|
||||
|
||||
for ( const auto& l : list ) {
|
||||
int matchName = String::fuzzyMatch( l.name, query, true );
|
||||
matchesMap.insert( { matchName, l } );
|
||||
int score = String::fuzzyMatch( query, l.name );
|
||||
if ( score > std::numeric_limits<int>::min() )
|
||||
matchesMap.insert( { score, l } );
|
||||
}
|
||||
|
||||
while ( matchesMap.size() > limit )
|
||||
matchesMap.erase( std::prev( matchesMap.end() ) );
|
||||
|
||||
for ( auto& m : matchesMap ) {
|
||||
m.second.score = m.first;
|
||||
nl.emplace_back( std::move( m.second ) );
|
||||
@@ -409,18 +407,21 @@ void UniversalLocator::updateCommandPaletteTable() {
|
||||
mCommandPalette.asyncFuzzyMatch( txt.substr( 1 ).trim(), 10000, [this]( auto res ) {
|
||||
mUISceneNode->runOnMainThread( [this, res] {
|
||||
mLocateTable->setModel( res );
|
||||
mLocateTable->getSelection().set( mLocateTable->getModel()->index( 0 ) );
|
||||
if ( mLocateTable->getModel()->hasChilds() )
|
||||
mLocateTable->getSelection().set( mLocateTable->getModel()->index( 0 ) );
|
||||
mLocateTable->scrollToTop();
|
||||
} );
|
||||
} );
|
||||
#else
|
||||
mLocateTable->setModel( mCommandPalette.fuzzyMatch( txt.substr( 1 ).trim(), 10000 ) );
|
||||
mLocateTable->getSelection().set( mLocateTable->getModel()->index( 0 ) );
|
||||
if ( mLocateTable->getModel()->hasChilds() )
|
||||
mLocateTable->getSelection().set( mLocateTable->getModel()->index( 0 ) );
|
||||
mLocateTable->scrollToTop();
|
||||
#endif
|
||||
} else if ( mCommandPalette.getCurModel() ) {
|
||||
mLocateTable->setModel( mCommandPalette.getCurModel() );
|
||||
mLocateTable->getSelection().set( mLocateTable->getModel()->index( 0 ) );
|
||||
if ( mLocateTable->getModel()->hasChilds() )
|
||||
mLocateTable->getSelection().set( mLocateTable->getModel()->index( 0 ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -715,7 +716,7 @@ void UniversalLocator::showOpenDocuments() {
|
||||
mApp->getStatusBar()->updateState();
|
||||
}
|
||||
|
||||
std::shared_ptr<FileListModel> UniversalLocator::openDocumentsModel( const std::string& match ) {
|
||||
std::shared_ptr<FileListModel> UniversalLocator::openDocumentsModel( const std::string& pattern ) {
|
||||
std::vector<std::string> docs;
|
||||
|
||||
mApp->getSplitter()->forEachDoc( [&docs]( TextDocument& doc ) {
|
||||
@@ -739,15 +740,17 @@ std::shared_ptr<FileListModel> UniversalLocator::openDocumentsModel( const std::
|
||||
files.emplace_back( std::move( doc ) );
|
||||
}
|
||||
|
||||
if ( match.empty() )
|
||||
if ( pattern.empty() )
|
||||
return std::make_shared<FileListModel>( std::move( files ), std::move( names ) );
|
||||
|
||||
std::multimap<int, int, std::greater<int>> matchesMap;
|
||||
|
||||
for ( size_t i = 0; i < names.size(); i++ ) {
|
||||
int matchName = String::fuzzyMatch( names[i], match, true, true );
|
||||
int matchPath = String::fuzzyMatch( files[i], match, true, true );
|
||||
matchesMap.insert( { std::max( matchName, matchPath ), i } );
|
||||
int matchName = String::fuzzyMatch( pattern, names[i] );
|
||||
int matchPath = String::fuzzyMatch( pattern, files[i] );
|
||||
int matchScore = std::max( matchName, matchScore );
|
||||
if ( matchScore > std::numeric_limits<int>::min() )
|
||||
matchesMap.insert( { std::max( matchName, matchPath ), i } );
|
||||
}
|
||||
|
||||
std::vector<std::string> ffiles;
|
||||
@@ -784,7 +787,7 @@ void UniversalLocator::showSwitchBuild() {
|
||||
}
|
||||
|
||||
std::shared_ptr<ItemListOwnerModel<std::string>>
|
||||
UniversalLocator::openBuildModel( const std::string& match ) {
|
||||
UniversalLocator::openBuildModel( const std::string& pattern ) {
|
||||
if ( nullptr == mApp->getProjectBuildManager() )
|
||||
return ItemListOwnerModel<std::string>::create( {} );
|
||||
const auto& builds = mApp->getProjectBuildManager()->getBuilds();
|
||||
@@ -793,8 +796,8 @@ UniversalLocator::openBuildModel( const std::string& match ) {
|
||||
return ItemListOwnerModel<std::string>::create( {} );
|
||||
buildNames.reserve( builds.size() );
|
||||
for ( const auto& build : builds ) {
|
||||
if ( match.empty() ||
|
||||
String::startsWith( String::toLower( build.first ), String::toLower( match ) ) )
|
||||
if ( pattern.empty() ||
|
||||
String::startsWith( String::toLower( build.first ), String::toLower( pattern ) ) )
|
||||
buildNames.push_back( build.first );
|
||||
}
|
||||
std::sort( buildNames.begin(), buildNames.end() );
|
||||
@@ -837,7 +840,7 @@ void UniversalLocator::showSwitchRunTarget() {
|
||||
}
|
||||
|
||||
std::shared_ptr<ItemListOwnerModel<std::string>>
|
||||
UniversalLocator::openBuildTypeModel( const std::string& match ) {
|
||||
UniversalLocator::openBuildTypeModel( const std::string& pattern ) {
|
||||
if ( nullptr == mApp->getProjectBuildManager() )
|
||||
return ItemListOwnerModel<std::string>::create( {} );
|
||||
const auto& builds = mApp->getProjectBuildManager()->getBuilds();
|
||||
@@ -854,8 +857,8 @@ UniversalLocator::openBuildTypeModel( const std::string& match ) {
|
||||
std::vector<std::string> buildTypeNames;
|
||||
buildTypeNames.reserve( buildTypes.size() );
|
||||
for ( const auto& build : buildTypes ) {
|
||||
if ( match.empty() ||
|
||||
String::startsWith( String::toLower( build ), String::toLower( match ) ) )
|
||||
if ( pattern.empty() ||
|
||||
String::startsWith( String::toLower( build ), String::toLower( pattern ) ) )
|
||||
buildTypeNames.push_back( build );
|
||||
}
|
||||
std::sort( buildTypeNames.begin(), buildTypeNames.end() );
|
||||
@@ -863,7 +866,7 @@ UniversalLocator::openBuildTypeModel( const std::string& match ) {
|
||||
}
|
||||
|
||||
std::shared_ptr<ItemListOwnerModel<std::string>>
|
||||
UniversalLocator::openRunTargetModel( const std::string& match ) {
|
||||
UniversalLocator::openRunTargetModel( const std::string& pattern ) {
|
||||
if ( nullptr == mApp->getProjectBuildManager() )
|
||||
return ItemListOwnerModel<std::string>::create( {} );
|
||||
const auto& builds = mApp->getProjectBuildManager()->getBuilds();
|
||||
@@ -879,8 +882,8 @@ UniversalLocator::openRunTargetModel( const std::string& match ) {
|
||||
std::vector<std::string> runTargetNames;
|
||||
runTargetNames.reserve( runs.size() );
|
||||
for ( const auto& run : runs ) {
|
||||
if ( match.empty() ||
|
||||
String::startsWith( String::toLower( run->name ), String::toLower( match ) ) )
|
||||
if ( pattern.empty() ||
|
||||
String::startsWith( String::toLower( run->name ), String::toLower( pattern ) ) )
|
||||
runTargetNames.push_back( run->name );
|
||||
}
|
||||
std::sort( runTargetNames.begin(), runTargetNames.end() );
|
||||
@@ -926,15 +929,15 @@ void UniversalLocator::showSwitchFileType() {
|
||||
}
|
||||
|
||||
std::shared_ptr<ItemListOwnerModel<std::string>>
|
||||
UniversalLocator::openFileTypeModel( const std::string& match ) {
|
||||
UniversalLocator::openFileTypeModel( const std::string& pattern ) {
|
||||
if ( nullptr == mApp->getSplitter()->getCurEditor() )
|
||||
return ItemListOwnerModel<std::string>::create( {} );
|
||||
const auto& defs = SyntaxDefinitionManager::instance()->getDefinitions();
|
||||
std::vector<std::string> fileTypeNames;
|
||||
fileTypeNames.reserve( defs.size() );
|
||||
for ( const auto& def : defs ) {
|
||||
if ( match.empty() || String::startsWith( String::toLower( def.getLanguageName() ),
|
||||
String::toLower( match ) ) )
|
||||
if ( pattern.empty() || String::startsWith( String::toLower( def.getLanguageName() ),
|
||||
String::toLower( pattern ) ) )
|
||||
fileTypeNames.push_back( def.getLanguageName() );
|
||||
}
|
||||
std::sort( fileTypeNames.begin(), fileTypeNames.end() );
|
||||
|
||||
@@ -130,15 +130,18 @@ class UniversalLocator {
|
||||
const LSPSymbolInformationList& list, const std::string& query, const size_t& limit,
|
||||
std::function<void( std::shared_ptr<LSPSymbolInfoModel> )> cb );
|
||||
|
||||
std::shared_ptr<FileListModel> openDocumentsModel( const std::string& match );
|
||||
std::shared_ptr<FileListModel> openDocumentsModel( const std::string& pattern );
|
||||
|
||||
std::shared_ptr<ItemListOwnerModel<std::string>> openBuildModel( const std::string& match );
|
||||
std::shared_ptr<ItemListOwnerModel<std::string>> openBuildModel( const std::string& pattern );
|
||||
|
||||
std::shared_ptr<ItemListOwnerModel<std::string>> openBuildTypeModel( const std::string& match );
|
||||
std::shared_ptr<ItemListOwnerModel<std::string>>
|
||||
openBuildTypeModel( const std::string& pattern );
|
||||
|
||||
std::shared_ptr<ItemListOwnerModel<std::string>> openRunTargetModel( const std::string& match );
|
||||
std::shared_ptr<ItemListOwnerModel<std::string>>
|
||||
openRunTargetModel( const std::string& pattern );
|
||||
|
||||
std::shared_ptr<ItemListOwnerModel<std::string>> openFileTypeModel( const std::string& match );
|
||||
std::shared_ptr<ItemListOwnerModel<std::string>>
|
||||
openFileTypeModel( const std::string& pattern );
|
||||
|
||||
bool findCapability( PluginCapability );
|
||||
|
||||
|
||||
Reference in New Issue
Block a user