Optimizing search, buggy BlockArena on emscripten, cleanup MergeSort, address sanitizer, compile web on linux

This commit is contained in:
Krzosa Karol
2025-12-30 11:59:20 +01:00
parent a57ebb49be
commit b140d9c3f1
15 changed files with 92 additions and 142 deletions

View File

@@ -3,10 +3,12 @@
mkdir build mkdir build
cd build cd build
FLAGS="-nostdlib++ -fno-exceptions -fdiagnostics-absolute-paths -g -Wno-writable-strings -I../src -DDEBUG_BUILD=1" FLAGS="-Wall -Wno-missing-braces -Wno-writable-strings -nostdlib++ -fsanitize=address -fno-exceptions -fdiagnostics-absolute-paths -g -Wno-writable-strings -I../src -DDEBUG_BUILD=1"
# clang -o metaprogram $FLAGS ../src/metaprogram/metaprogram.cpp # clang -o metaprogram $FLAGS ../src/metaprogram/metaprogram.cpp
# ./metaprogram # ./metaprogram
I="-I../src/external/SDL/include -I../src/external/lua/src -I../src/external/glad" I="-I../src/external/SDL/include -I../src/external/lua/src -I../src/external/glad"
clang -o te $FLAGS ../src/text_editor/text_editor.cpp $I -lSDL3 -lm -lbacktrace clang -o te $FLAGS ../src/text_editor/text_editor.cpp $I -lSDL3 -lm -lbacktrace
cp te ../data/te cp te ../data/te
# -v -Wl,--verbose

View File

@@ -6,10 +6,4 @@ set flags=-Wall -Wno-missing-braces -Wno-writable-strings -nostdlib++ -fno-excep
set dbg=-g -DDEBUG_BUILD=1 -gsource-map set dbg=-g -DDEBUG_BUILD=1 -gsource-map
set rel=-O3 -DDEBUG_BUILD=0 set rel=-O3 -DDEBUG_BUILD=0
mkdir build
cd build
clang ../src/metaprogram/metaprogram.cpp -o metaprogram.exe %flags% -g -DDEBUG_BUILD=1 -I../src
metaprogram.exe
cd ..
emcc -o text_editor.html --shell-file=data/shell.html %flags% %incs% %wasmflags% %dbg% -lm -lSDL3 src/text_editor/text_editor.cpp emcc -o text_editor.html --shell-file=data/shell.html %flags% %incs% %wasmflags% %dbg% -lm -lSDL3 src/text_editor/text_editor.cpp

View File

@@ -1,8 +1,9 @@
#!/usr/bin/bash #!/usr/bin/bash
mkdir build incs="-Isrc/external/SDL/include -Isrc/external/lua/src -Isrc/external/glad -Lsrc/external/SDL/build_web -Isrc"
cd build wasmflags="-sALLOW_MEMORY_GROWTH=1 -sMAXIMUM_MEMORY=1gb -msimd128 -sTOTAL_STACK=5MB -sINITIAL_MEMORY=256mb -sUSE_WEBGL2 -sFULL_ES3=1 -sUSE_SDL=3 -sASYNCIFY -sASSERTIONS=2"
flags="-Wall -Wno-missing-braces -Wno-writable-strings -nostdlib++ -fno-exceptions -fdiagnostics-absolute-paths"
dbg="-g -DDEBUG_BUILD=1 -gsource-map"
rel="-O3 -DDEBUG_BUILD=0"
echo todo emcc -o text_editor.html --shell-file=data/shell.html $flags $incs $wasmflags $dbg -lm -lSDL3 src/text_editor/text_editor.cpp
cd ..

View File

@@ -20,6 +20,8 @@ Debug session:
- Should highlight main buffer when clicking on status? - Should highlight main buffer when clicking on status?
- Report errorf - use coroutine dialogs - Report errorf - use coroutine dialogs
- Replace in render layer also - Replace in render layer also
- BlockAllocator something is not working there which only showed after executing OpenCode on many files
- Some bad allocating happening in Clipboard for sure
New UI Session New UI Session
- Move CommandWindow hooks to hooks - Move CommandWindow hooks to hooks

View File

@@ -268,7 +268,7 @@ void AddBlock(BlockArena *arena, size_t size = MiB(1)) {
if (arena->allocator.proc == NULL) { if (arena->allocator.proc == NULL) {
arena->allocator = GetSystemAllocator(); arena->allocator = GetSystemAllocator();
} }
BlockArenaNode *new_block = (BlockArenaNode *)AllocSize(arena->allocator, block_size + sizeof(BlockArenaNode) + 16); BlockArenaNode *new_block = (BlockArenaNode *)AllocSize(arena->allocator, block_size + sizeof(BlockArenaNode));
Assert(GetAlignOffset((size_t)new_block->start, DEFAULT_ALIGNMENT) == 0); Assert(GetAlignOffset((size_t)new_block->start, DEFAULT_ALIGNMENT) == 0);
arena->start = new_block->start; arena->start = new_block->start;
new_block->end = arena->end = new_block->start + block_size; new_block->end = arena->end = new_block->start + block_size;
@@ -294,9 +294,7 @@ API void Release(BlockArena *arena) {
next = it->next; next = it->next;
Dealloc(arena->allocator, it); Dealloc(arena->allocator, it);
} }
bool safe = arena->when_unwinding_make_sure_to_keep_last_block_alive;
MemoryZero(arena, sizeof(BlockArena)); MemoryZero(arena, sizeof(BlockArena));
arena->when_unwinding_make_sure_to_keep_last_block_alive = safe;
} }
API void Unwind(BlockArena *arena, U8 *pos) { API void Unwind(BlockArena *arena, U8 *pos) {
@@ -306,17 +304,12 @@ API void Unwind(BlockArena *arena, U8 *pos) {
if ((pos >= it->start) && (pos <= it->end)) { if ((pos >= it->start) && (pos <= it->end)) {
contains = true; contains = true;
break; break;
} else {
bool keep = arena->when_unwinding_make_sure_to_keep_last_block_alive && arena->blocks->next == NULL;
if (keep) {
pos = arena->blocks->start;
} else { } else {
arena->blocks = arena->blocks->next; arena->blocks = arena->blocks->next;
Dealloc(arena->allocator, it); Dealloc(arena->allocator, it);
} }
} }
} Assert(contains || pos == NULL);
Assert(contains || pos == NULL || (arena->when_unwinding_make_sure_to_keep_last_block_alive && pos == arena->blocks->start));
arena->start = pos; arena->start = pos;
arena->end = arena->blocks ? arena->blocks->end : NULL; arena->end = arena->blocks ? arena->blocks->end : NULL;
} }
@@ -332,8 +325,11 @@ API void *BlockArenaAllocatorProc(void *object, int kind, void *p, size_t size)
return NULL; return NULL;
} }
#if OS_WASM
API void InitScratch() {
}
#else
thread_local VirtualArena ScratchArenas[4]; thread_local VirtualArena ScratchArenas[4];
API void InitScratch() { API void InitScratch() {
for (int i = 0; i < 4; i += 1) { for (int i = 0; i < 4; i += 1) {
InitArena(&ScratchArenas[i]); InitArena(&ScratchArenas[i]);
@@ -362,6 +358,7 @@ API VirtualArena *GetScratchEx(VirtualArena **conflicts, int conflict_count) {
Assert(unoccupied); Assert(unoccupied);
return unoccupied; return unoccupied;
} }
#endif
void RunArenaTest() { void RunArenaTest() {
Allocator memory_tracking_allocator = GetTrackingAllocator(); Allocator memory_tracking_allocator = GetTrackingAllocator();
@@ -380,7 +377,6 @@ void RunArenaTest() {
{ {
BlockArena arena = {}; BlockArena arena = {};
U8 *start = arena.start;
arena.allocator = memory_tracking_allocator; arena.allocator = memory_tracking_allocator;
int *vals = (int *)PushSize(&arena, sizeof(int) * 32); int *vals = (int *)PushSize(&arena, sizeof(int) * 32);
for (int i = 0; i < 32; i += 1) vals[i] = i; for (int i = 0; i < 32; i += 1) vals[i] = i;
@@ -402,7 +398,7 @@ void RunArenaTest() {
U8 *p = arena.start; U8 *p = arena.start;
U8 *a = (U8 *)PushSize(&arena, KiB(32)); U8 *a = (U8 *)PushSize(&arena, KiB(32));
U8 *b = (U8 *)PushSize(&arena, KiB(1000)); PushSize(&arena, KiB(1000));
Assert(arena.blocks); Assert(arena.blocks);
Assert(arena.blocks->next); Assert(arena.blocks->next);
Assert(arena.blocks->next->next == NULL); Assert(arena.blocks->next->next == NULL);
@@ -418,7 +414,7 @@ void RunArenaTest() {
{ {
BlockArena arena = {}; BlockArena arena = {};
arena.allocator = memory_tracking_allocator; arena.allocator = memory_tracking_allocator;
U8 *a = (U8 *)PushSize(&arena, KiB(2000)); PushSize(&arena, KiB(2000));
Assert((size_t)(arena.blocks[0].end - arena.blocks[0].start) == KiB(2000)); Assert((size_t)(arena.blocks[0].end - arena.blocks[0].start) == KiB(2000));
Release(&arena); Release(&arena);
Assert(MemoryTrackingRecord.len == 0); Assert(MemoryTrackingRecord.len == 0);
@@ -427,15 +423,14 @@ void RunArenaTest() {
{ {
BlockArena arena = {}; BlockArena arena = {};
arena.allocator = memory_tracking_allocator; arena.allocator = memory_tracking_allocator;
arena.when_unwinding_make_sure_to_keep_last_block_alive = true;
PushSize(&arena, KiB(2000)); PushSize(&arena, KiB(2000));
Unwind(&arena, 0); Unwind(&arena, 0);
Assert(MemoryTrackingRecord.len == 1); Assert(MemoryTrackingRecord.len == 0);
PushSize(&arena, MiB(1)); PushSize(&arena, MiB(1));
PushSize(&arena, MiB(3)); PushSize(&arena, MiB(3));
Assert(MemoryTrackingRecord.len == 2); Assert(MemoryTrackingRecord.len == 2);
Unwind(&arena, 0); Unwind(&arena, 0);
Assert(MemoryTrackingRecord.len == 1); Assert(MemoryTrackingRecord.len == 0);
Release(&arena); Release(&arena);
Assert(MemoryTrackingRecord.len == 0); Assert(MemoryTrackingRecord.len == 0);
} }

View File

@@ -51,7 +51,6 @@ struct BlockArena {
U8 *end; U8 *end;
BlockArenaNode *blocks; BlockArenaNode *blocks;
Allocator allocator; Allocator allocator;
bool when_unwinding_make_sure_to_keep_last_block_alive;
operator Allocator() { return {BlockArenaAllocatorProc, this}; } operator Allocator() { return {BlockArenaAllocatorProc, this}; }
}; };
@@ -96,9 +95,24 @@ API void Release(VirtualArena *arena);
/////////////////////////////// ///////////////////////////////
// Scratch // Scratch
#if OS_WASM
struct Scratch {
BlockArena arena = {};
Scratch() {}
Scratch(BlockArena *conflict) {}
Scratch(BlockArena *c1, BlockArena *c2) {}
Scratch(Allocator conflict) {}
Scratch(Allocator c1, Allocator c2) {}
~Scratch() { Release(&arena); }
operator BlockArena *() { return &arena; }
operator Allocator() { return arena; }
private: // @Note: Disable copy constructors, cause its error prone
Scratch(Scratch &arena);
Scratch(Scratch &arena, Scratch &a2);
};
#else
extern thread_local VirtualArena ScratchArenas[4]; extern thread_local VirtualArena ScratchArenas[4];
API VirtualArena *GetScratchEx(VirtualArena **conflicts, int conflict_count); API VirtualArena *GetScratchEx(VirtualArena **conflicts, int conflict_count);
struct Scratch { struct Scratch {
VirtualArena *arena; VirtualArena *arena;
U64 p; U64 p;
@@ -131,6 +145,7 @@ struct Scratch {
Scratch(Scratch &arena); Scratch(Scratch &arena);
Scratch(Scratch &arena, Scratch &a2); Scratch(Scratch &arena, Scratch &a2);
}; };
#endif
const int PAGE_SIZE = 4096; const int PAGE_SIZE = 4096;
const int DEFAULT_ALIGNMENT = sizeof(void *); const int DEFAULT_ALIGNMENT = sizeof(void *);

View File

@@ -408,6 +408,7 @@ API bool IsValid(Process *process) {
int res = poll(&p, 1, 0); int res = poll(&p, 1, 0);
if (res > 0) { if (res > 0) {
pid_t result = waitpid(plat->pid, &status, 0); pid_t result = waitpid(plat->pid, &status, 0);
Assert(result != -1);
process->exit_code = WEXITSTATUS(status); process->exit_code = WEXITSTATUS(status);
return false; return false;
} }
@@ -1104,9 +1105,9 @@ API void Advance(FileIter *it) {
const char *dir_char_ending = it->is_directory ? "/" : ""; const char *dir_char_ending = it->is_directory ? "/" : "";
const char *separator = it->path.data[it->path.len - 1] == '/' ? "" : "/"; const char *separator = it->path.data[it->path.len - 1] == '/' ? "" : "/";
it->relative_path = Format(it->allocator, "%.*s%s%s%s", FmtString(it->path), separator, file->d_name, dir_char_ending); it->relative_path = Format(it->allocator, "%S%s%s%s", it->path, separator, file->d_name, dir_char_ending);
it->absolute_path = GetAbsolutePath(it->allocator, it->relative_path); it->absolute_path = GetAbsolutePath(it->allocator, it->relative_path);
if (it->is_directory) it->absolute_path = Format(it->allocator, "%.*s/", FmtString(it->absolute_path)); if (it->is_directory) it->absolute_path = Format(it->allocator, "%S/", it->absolute_path);
it->is_valid = true; it->is_valid = true;
return; return;
} }

View File

@@ -539,8 +539,8 @@ static void mco_dealloc(void *ptr, size_t size, void *allocator_data) {
#define _MCO_USE_TSAN #define _MCO_USE_TSAN
#endif #endif
#ifdef _MCO_USE_ASAN #ifdef _MCO_USE_ASAN
void __sanitizer_start_switch_fiber(void **fake_stack_save, const void *bottom, size_t size); extern "C" void __sanitizer_start_switch_fiber(void **fake_stack_save, const void *bottom, size_t size);
void __sanitizer_finish_switch_fiber(void *fake_stack_save, const void **bottom_old, size_t *size_old); extern "C" void __sanitizer_finish_switch_fiber(void *fake_stack_save, const void **bottom_old, size_t *size_old);
#endif #endif
#ifdef _MCO_USE_TSAN #ifdef _MCO_USE_TSAN
void *__tsan_get_current_fiber(void); void *__tsan_get_current_fiber(void);

View File

@@ -712,43 +712,52 @@ API void RawAppendf(Buffer *buffer, const char *fmt, ...) {
// multicursor // multicursor
/////////////////////////////// ///////////////////////////////
void MergeSort(int64_t Count, Caret *First, Caret *Temp) { inline bool MergeSortCompare(Caret *EntryA, Caret *EntryB) {
bool result = EntryA->range.min > EntryB->range.min;
return result;
}
inline bool MergeSortCompare(Edit *EntryA, Edit *EntryB) {
bool result = EntryA->range.min > EntryB->range.min;
return result;
}
template<class T>
void MergeSort(int64_t Count, T *First, T *Temp) {
ProfileFunction(); ProfileFunction();
// SortKey = range.min // SortKey = range.min
if (Count == 1) { if (Count == 1) {
// NOTE(casey): No work to do. // NOTE(casey): No work to do.
} else if (Count == 2) { } else if (Count == 2) {
Caret *EntryA = First; T *EntryA = First;
Caret *EntryB = First + 1; T *EntryB = First + 1;
if (EntryA->range.min > EntryB->range.min) { if (MergeSortCompare(EntryA, EntryB)) {
Swap(EntryA, EntryB); Swap(EntryA, EntryB);
} }
} else { } else {
int64_t Half0 = Count / 2; Int Half0 = Count / 2;
int64_t Half1 = Count - Half0; Int Half1 = Count - Half0;
Assert(Half0 >= 1); Assert(Half0 >= 1);
Assert(Half1 >= 1); Assert(Half1 >= 1);
Caret *InHalf0 = First; T *InHalf0 = First;
Caret *InHalf1 = First + Half0; T *InHalf1 = First + Half0;
Caret *End = First + Count; T *End = First + Count;
MergeSort(Half0, InHalf0, Temp); MergeSort(Half0, InHalf0, Temp);
MergeSort(Half1, InHalf1, Temp); MergeSort(Half1, InHalf1, Temp);
Caret *ReadHalf0 = InHalf0; T *ReadHalf0 = InHalf0;
Caret *ReadHalf1 = InHalf1; T *ReadHalf1 = InHalf1;
Caret *Out = Temp; T *Out = Temp;
for (int64_t Index = 0; for (Int Index = 0; Index < Count; ++Index) {
Index < Count;
++Index) {
if (ReadHalf0 == InHalf1) { if (ReadHalf0 == InHalf1) {
*Out++ = *ReadHalf1++; *Out++ = *ReadHalf1++;
} else if (ReadHalf1 == End) { } else if (ReadHalf1 == End) {
*Out++ = *ReadHalf0++; *Out++ = *ReadHalf0++;
} else if (ReadHalf0->range.min < ReadHalf1->range.min) { } else if (!MergeSortCompare(ReadHalf0, ReadHalf1)) {
*Out++ = *ReadHalf0++; *Out++ = *ReadHalf0++;
} else { } else {
*Out++ = *ReadHalf1++; *Out++ = *ReadHalf1++;
@@ -759,64 +768,7 @@ void MergeSort(int64_t Count, Caret *First, Caret *Temp) {
Assert(ReadHalf1 == End); Assert(ReadHalf1 == End);
// TODO(casey): Not really necessary if we ping-pong // TODO(casey): Not really necessary if we ping-pong
for (int64_t Index = 0; for (Int Index = 0; Index < Count; ++Index) {
Index < Count;
++Index) {
First[Index] = Temp[Index];
}
}
}
void MergeSort(int64_t Count, Edit *First, Edit *Temp) {
ProfileFunction();
// SortKey = range.min
if (Count == 1) {
// NOTE(casey): No work to do.
} else if (Count == 2) {
Edit *EntryA = First;
Edit *EntryB = First + 1;
if (EntryA->range.min > EntryB->range.min) {
Swap(EntryA, EntryB);
}
} else {
int64_t Half0 = Count / 2;
int64_t Half1 = Count - Half0;
Assert(Half0 >= 1);
Assert(Half1 >= 1);
Edit *InHalf0 = First;
Edit *InHalf1 = First + Half0;
Edit *End = First + Count;
MergeSort(Half0, InHalf0, Temp);
MergeSort(Half1, InHalf1, Temp);
Edit *ReadHalf0 = InHalf0;
Edit *ReadHalf1 = InHalf1;
Edit *Out = Temp;
for (int64_t Index = 0;
Index < Count;
++Index) {
if (ReadHalf0 == InHalf1) {
*Out++ = *ReadHalf1++;
} else if (ReadHalf1 == End) {
*Out++ = *ReadHalf0++;
} else if (ReadHalf0->range.min < ReadHalf1->range.min) {
*Out++ = *ReadHalf0++;
} else {
*Out++ = *ReadHalf1++;
}
}
Assert(Out == (Temp + Count));
Assert(ReadHalf0 == InHalf1);
Assert(ReadHalf1 == End);
// TODO(casey): Not really necessary if we ping-pong
for (int64_t Index = 0;
Index < Count;
++Index) {
First[Index] = Temp[Index]; First[Index] = Temp[Index];
} }
} }

View File

@@ -48,8 +48,8 @@ struct Buffer {
}; };
struct FuzzyPair { struct FuzzyPair {
Int index; int32_t index;
Int rating; int32_t rating;
}; };
enum { enum {
@@ -130,8 +130,6 @@ API Int GetLineIndent(Buffer *buffer, Int line);
API Int GetIndentAtPos(Buffer *buffer, Int pos); API Int GetIndentAtPos(Buffer *buffer, Int pos);
API Range GetIndentRangeAtPos(Buffer *buffer, Int pos); API Range GetIndentRangeAtPos(Buffer *buffer, Int pos);
API Int FuzzyRate(String16 string, String16 with);
API Array<FuzzyPair> FuzzySearchLines(Allocator allocator, Buffer *buffer, Int line_min, Int line_max, String16 needle);
API Int FindRangeByPos(Array<Range> *ranges, Int pos); API Int FindRangeByPos(Array<Range> *ranges, Int pos);
// These don't handle history, just raw operations on buffer memory // These don't handle history, just raw operations on buffer memory

View File

@@ -669,7 +669,6 @@ String Coro_OpenCodeDir;
void Coro_OpenCode(mco_coro *co) { void Coro_OpenCode(mco_coro *co) {
Array<String> dirs = {CoCurr->arena}; Array<String> dirs = {CoCurr->arena};
Add(&dirs, Coro_OpenCodeDir); Add(&dirs, Coro_OpenCodeDir);
int i = 0;
for (int diri = 0; diri < dirs.len; diri += 1) { for (int diri = 0; diri < dirs.len; diri += 1) {
for (FileIter it = IterateFiles(CoCurr->arena, dirs[diri]); IsValid(it); Advance(&it)) { for (FileIter it = IterateFiles(CoCurr->arena, dirs[diri]); IsValid(it); Advance(&it)) {
bool match = false; bool match = false;

View File

@@ -134,7 +134,6 @@ Trigger *ParseKeyChord(Lexer *lex) {
Trigger *left = ParseKeyAtom(lex); Trigger *left = ParseKeyAtom(lex);
EatWhitespace(lex); EatWhitespace(lex);
while (IsAlphanumeric(At(lex))) { while (IsAlphanumeric(At(lex))) {
int op = At(lex);
left = TriggerBinary(lex, left, ParseKeyChord(lex), ' '); left = TriggerBinary(lex, left, ParseKeyChord(lex), ' ');
EatWhitespace(lex); EatWhitespace(lex);
} }

View File

@@ -294,7 +294,7 @@ void DrawWindow(Window *window, Event &event) {
} }
// darken the inactive windows // darken the inactive windows
if (!is_active) { if (!is_active && !active_layed_out_doc) {
ProfileScope(DarkenInactiveRect); ProfileScope(DarkenInactiveRect);
SetScissor(screen_rect); SetScissor(screen_rect);
DrawRect(window->total_rect, ColorInactiveWindow); DrawRect(window->total_rect, ColorInactiveWindow);

View File

@@ -27,13 +27,13 @@ void CommandWindowLayout(Rect2I *rect, Int wx, Int wy) {
n->document_rect = n->total_rect = CutBottom(rect, barsize); n->document_rect = n->total_rect = CutBottom(rect, barsize);
} }
Int FuzzyRate(String16 string, String16 with) { int32_t FuzzyRate(String16 string, String16 with) {
ProfileFunction(); ProfileFunction();
if (with.len == 0) return 0; if (with.len == 0) return 0;
Int points = 0; int32_t points = 0;
Int consecutive = 0; int32_t consecutive = 0;
Int with_i = 0; int32_t with_i = 0;
for (Int i = 0; i < string.len; i++) { for (int32_t i = 0; i < string.len; i++) {
if (ToLowerCase(string.data[i]) == ToLowerCase(with[with_i])) { if (ToLowerCase(string.data[i]) == ToLowerCase(with[with_i])) {
consecutive += 1; consecutive += 1;
with_i += 1; with_i += 1;
@@ -49,33 +49,25 @@ Int FuzzyRate(String16 string, String16 with) {
return points; return points;
} }
inline bool MergeSortCompare(FuzzyPair *a, FuzzyPair *b) {
bool result = a->rating > b->rating;
return result;
}
Array<FuzzyPair> FuzzySearchLines(Allocator allocator, Buffer *buffer, Int line_min, Int line_max, String16 needle) { Array<FuzzyPair> FuzzySearchLines(Allocator allocator, Buffer *buffer, Int line_min, Int line_max, String16 needle) {
ProfileFunction(); ProfileFunction();
if (line_min < 0 || line_min >= buffer->line_starts.len) return {}; if (line_min < 0 || line_min >= buffer->line_starts.len) return {};
if (line_max < 0 || line_min > buffer->line_starts.len) return {}; if (line_max < 0 || line_min > buffer->line_starts.len) return {};
Array<FuzzyPair> ratings = {allocator}; Array<FuzzyPair> ratings = {allocator};
Reserve(&ratings, line_max - line_min + 4);
for (Int i = line_min; i < line_max; i += 1) { for (Int i = line_min; i < line_max; i += 1) {
String16 s = GetLineStringWithoutNL(buffer, i); String16 s = GetLineStringWithoutNL(buffer, i);
Int idx = 0; int32_t rating = FuzzyRate(s, needle);
if (Seek(s, u" || ", &idx)) { Add(&ratings, {(int32_t)i, rating});
s.len = idx;
}
s = Trim(s);
Int rating = FuzzyRate(s, needle);
Add(&ratings, {i, rating});
}
// bubble sort
for (Int i = 0; i < ratings.len - 1; i++) {
for (Int j = 0; j < ratings.len - 1; j++) {
if (ratings[j].rating > ratings[j + 1].rating) {
FuzzyPair temp = ratings[j];
ratings[j] = ratings[j + 1];
ratings[j + 1] = temp;
}
}
} }
Array<FuzzyPair> temp = Copy(allocator, ratings);
MergeSort(ratings.len, ratings.data, temp.data);
return ratings; return ratings;
} }

View File

@@ -97,7 +97,7 @@ void StatusWindowUpdate() {
String16 string_to_replace = GetString(title.buffer, replace_range); String16 string_to_replace = GetString(title.buffer, replace_range);
if (string_to_replace != string) { if (string_to_replace != string) {
SelectRange(title.view, replace_range); SelectRange(title.view, replace_range);
Array<Edit> edits = ReplaceEx(scratch, title.view, string); ReplaceEx(scratch, title.view, string);
} }
SelectRange(title.view, MakeRange(0)); SelectRange(title.view, MakeRange(0));