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:
parent
04888b8f10
commit
ac99191487
3 changed files with 106 additions and 47 deletions
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue