1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 19:48:20 +02:00

Sort updated autocomplete results

This commit is contained in:
Simon Lübeß 2021-12-20 13:35:58 +01:00
parent 04888b8f10
commit ac99191487
3 changed files with 106 additions and 47 deletions

View file

@ -383,6 +383,7 @@ namespace IDE.ui
public String mDocumentation; public String mDocumentation;
public Image mIcon; public Image mIcon;
public List<uint8> mMatchIndices; public List<uint8> mMatchIndices;
public int32 mScore;
public float Y public float Y
{ {
@ -423,7 +424,20 @@ namespace IDE.ui
index = @c.NextIndex; index = @c.NextIndex;
} }
} }
public void SetMatches(Span<uint8> matchIndices)
{
mMatchIndices?.Clear();
if (!matchIndices.IsEmpty)
{
if(mMatchIndices == null)
mMatchIndices = new:(mAutoCompleteListWidget.mAlloc) List<uint8>(matchIndices.Length);
mMatchIndices.AddRange(matchIndices);
}
}
} }
class Content : Widget class Content : Widget
@ -635,14 +649,13 @@ namespace IDE.ui
if (!documentation.IsEmpty) if (!documentation.IsEmpty)
entryWidget.mDocumentation = new:mAlloc String(documentation); entryWidget.mDocumentation = new:mAlloc String(documentation);
entryWidget.mIcon = icon; entryWidget.mIcon = icon;
// TODO(FUZZY): There may be a better way
if (matchIndices != null && !matchIndices.IsEmpty) entryWidget.SetMatches(matchIndices);
entryWidget.mMatchIndices = new:mAlloc List<uint8>(matchIndices.GetEnumerator());
UpdateEntry(entryWidget, mEntryList.Count); UpdateEntry(entryWidget, mEntryList.Count);
mEntryList.Add(entryWidget); mEntryList.Add(entryWidget);
//mScrollContent.AddWidget(entryWidget); //mScrollContent.AddWidget(entryWidget);
} }
public void EnsureSelectionVisible() public void EnsureSelectionVisible()
{ {
@ -1599,22 +1612,50 @@ namespace IDE.ui
// IDEHelper/third_party/FtsFuzzyMatch.h // IDEHelper/third_party/FtsFuzzyMatch.h
[CallingConvention(.Stdcall), CLink] [CallingConvention(.Stdcall), CLink]
static extern bool fts_fuzzy_match(char8* pattern, char8* str, ref int outScore, uint8* matches, int maxMatches); static extern bool fts_fuzzy_match(char8* pattern, char8* str, ref int32 outScore, uint8* matches, int maxMatches);
bool DoesFilterMatch(String entry, String filter) /// Checks whether the given entry matches the filter and updates its score and match indices accordingly.
bool UpdateFilterMatch(AutoCompleteListWidget.EntryWidget entry, String filter)
{ {
if (filter.Length == 0) if (filter.Length == 0)
return true; return true;
if (filter.Length > entry.Length) if (filter.Length > entry.mEntryDisplay.Length)
return false; return false;
int score = 0; int32 score = 0;
uint8[256] matches = ?; uint8[256] matches = ?;
return fts_fuzzy_match(filter.CStr(), entry.CStr(), ref score, &matches, matches.Count); if (!fts_fuzzy_match(filter.CStr(), entry.mEntryDisplay.CStr(), ref score, &matches, matches.Count))
{
entry.SetMatches(Span<uint8>(null, 0));
entry.mScore = score;
return false;
}
// Should be the amount of Unicode-codepoints in filter though it' probably faster to do it this way
int matchesLength = 0;
for (uint8 i = 0;; i++)
{
uint8 matchIndex = matches[i];
if ((matchIndex == 0 && i != 0) || i == uint8.MaxValue)
{
matchesLength = i;
break;
}
}
entry.SetMatches(Span<uint8>(&matches, matchesLength));
entry.mScore = score;
return true;
} }
[LinkName("_stricmp")]
static extern int32 stricmp(char8* lhs, char8* rhs);
void UpdateData(String selectString, bool changedAfterInfo) void UpdateData(String selectString, bool changedAfterInfo)
{ {
if ((mInsertEndIdx != -1) && (mInsertEndIdx < mInsertStartIdx)) if ((mInsertEndIdx != -1) && (mInsertEndIdx < mInsertStartIdx))
@ -1671,10 +1712,9 @@ namespace IDE.ui
{ {
var entry = mAutoCompleteListWidget.mFullEntryList[i]; var entry = mAutoCompleteListWidget.mFullEntryList[i];
if (DoesFilterMatch(entry.mEntryDisplay, curString)) if (UpdateFilterMatch(entry, curString))
{ {
mAutoCompleteListWidget.mEntryList.Add(entry); mAutoCompleteListWidget.mEntryList.Add(entry);
mAutoCompleteListWidget.UpdateEntry(entry, visibleCount);
visibleCount++; visibleCount++;
} }
else else
@ -1683,6 +1723,22 @@ namespace IDE.ui
} }
} }
// sort entries because the scores probably have changed
mAutoCompleteListWidget.mEntryList.Sort(scope (left, right) =>
{
if (left.mScore > right.mScore)
return -1;
else if (left.mScore < right.mScore)
return 1;
else
return ((stricmp(left.mEntryDisplay.CStr(), right.mEntryDisplay.CStr()) < 0) ? -1 : 1);
});
for (int i < mAutoCompleteListWidget.mEntryList.Count)
{
mAutoCompleteListWidget.UpdateEntry(mAutoCompleteListWidget.mEntryList[i], i);
}
if ((visibleCount == 0) && (mInvokeSrcPositions == null)) if ((visibleCount == 0) && (mInvokeSrcPositions == null))
{ {
mPopulating = false; mPopulating = false;

View file

@ -28,19 +28,16 @@ AutoCompleteBase::~AutoCompleteBase()
Clear(); Clear();
} }
AutoCompleteEntry* AutoCompleteBase::AddEntry(AutoCompleteEntry& entry, const StringImpl& filter) inline void UpdateEntryMatchindices(uint8* matches, AutoCompleteEntry& entry)
{ {
uint8 matches[256];
if (!DoesFilterMatch(entry.mDisplay, filter.c_str(), entry.mScore, matches, 256) || (entry.mNamePrefixCount < 0))
return NULL;
if (matches[0] != UINT8_MAX) if (matches[0] != UINT8_MAX)
{ {
// Count entries in matches
// Note: entry.mMatchesLength should be the amount of unicode-codepoints in the filter
for (uint8 i = 0;; i++) for (uint8 i = 0;; i++)
{ {
uint8 matchIndex = matches[i]; uint8 matchIndex = matches[i];
if ((matchIndex == 0 && i != 0) || i == UINT8_MAX) if ((matchIndex == 0 && i != 0) || i == UINT8_MAX)
{ {
entry.mMatchesLength = i; entry.mMatchesLength = i;
@ -48,15 +45,33 @@ AutoCompleteEntry* AutoCompleteBase::AddEntry(AutoCompleteEntry& entry, const St
} }
} }
if (entry.mMatches != nullptr) //assert(entry.mMatches != nullptr);
delete entry.mMatches;
entry.mMatches = new uint8[entry.mMatchesLength]; entry.mMatches = matches;
memcpy(entry.mMatches, matches, entry.mMatchesLength);
} }
else
{
entry.mMatches = nullptr;
entry.mMatchesLength = 0;
}
}
return AddEntry(entry); AutoCompleteEntry* AutoCompleteBase::AddEntry(AutoCompleteEntry& entry, const StringImpl& filter)
{
uint8 matches[256];
if (!DoesFilterMatch(entry.mDisplay, filter.c_str(), entry.mScore, matches, 256) || (entry.mNamePrefixCount < 0))
return NULL;
UpdateEntryMatchindices(matches, entry);
auto result = AddEntry(entry);
// Reset matches because the array will be invalid after return
entry.mMatches = nullptr;
entry.mMatchesLength = 0;
return result;
} }
AutoCompleteEntry* AutoCompleteBase::AddEntry(AutoCompleteEntry& entry, const char* filter) AutoCompleteEntry* AutoCompleteBase::AddEntry(AutoCompleteEntry& entry, const char* filter)
@ -66,28 +81,15 @@ AutoCompleteEntry* AutoCompleteBase::AddEntry(AutoCompleteEntry& entry, const ch
if (!DoesFilterMatch(entry.mDisplay, filter, entry.mScore, matches, 256) || (entry.mNamePrefixCount < 0)) if (!DoesFilterMatch(entry.mDisplay, filter, entry.mScore, matches, 256) || (entry.mNamePrefixCount < 0))
return NULL; return NULL;
if (matches[0] != UINT8_MAX) UpdateEntryMatchindices(matches, entry);
{
for (uint8 i = 0;; i++)
{
uint8 matchIndex = matches[i];
if ((matchIndex == 0 && i != 0) || i == UINT8_MAX) auto result = AddEntry(entry);
{
entry.mMatchesLength = i;
break;
}
}
if (entry.mMatches != nullptr) // Reset matches because the array will be invalid after return
delete entry.mMatches; entry.mMatches = nullptr;
entry.mMatchesLength = 0;
entry.mMatches = new uint8[entry.mMatchesLength]; return result;
memcpy(entry.mMatches, matches, entry.mMatchesLength);
}
return AddEntry(entry);
} }
AutoCompleteEntry* AutoCompleteBase::AddEntry(const AutoCompleteEntry& entry) AutoCompleteEntry* AutoCompleteBase::AddEntry(const AutoCompleteEntry& entry)
@ -140,9 +142,6 @@ bool AutoCompleteBase::DoesFilterMatch(const char* entry, const char* filter, in
if (filterLen > entryLen) if (filterLen > entryLen)
{ {
// Kinda dirty
matches[0] = UINT8_MAX;
matches[1] = 0;
return false; return false;
} }

View file

@ -8007,8 +8007,12 @@ void BfCompiler::GenerateAutocompleteInfo()
{ {
entries.Add(&entry); entries.Add(&entry);
} }
std::sort(entries.begin(), entries.end(), [](AutoCompleteEntry* lhs, AutoCompleteEntry* rhs) std::sort(entries.begin(), entries.end(), [](AutoCompleteEntry* lhs, AutoCompleteEntry* rhs)
{ {
if (lhs->mScore == rhs->mScore)
return stricmp(lhs->mDisplay, rhs->mDisplay) < 0;
return lhs->mScore > rhs->mScore; return lhs->mScore > rhs->mScore;
}); });