ActiveSearch/SearchAll command and beginnings of ReplaceAll command, coroutine interface change
This commit is contained in:
@@ -2,10 +2,12 @@
|
|||||||
! From a user (novice) point of view, how does it look like?
|
! From a user (novice) point of view, how does it look like?
|
||||||
|
|
||||||
- Make a fuzzy command !> grep and fuzzy over it??? (doesn't seem very useful for grep)
|
- Make a fuzzy command !> grep and fuzzy over it??? (doesn't seem very useful for grep)
|
||||||
|
- Make the equivalent of SearchProject but for cmds like !@git grep -n "@>"
|
||||||
- Add Bool variable
|
- Add Bool variable
|
||||||
|
|
||||||
- Initialize all keybindings at the start and refer using global variables?
|
- Initialize all keybindings at the start and refer using global variables?
|
||||||
- RegisterCommand should_appear_in_listing variable
|
- RegisterCommand should_appear_in_listing variable
|
||||||
|
- RegisterCommand docs
|
||||||
- Maybe one list for all variables including the commands etc?
|
- Maybe one list for all variables including the commands etc?
|
||||||
|
|
||||||
Use session 3:
|
Use session 3:
|
||||||
|
|||||||
@@ -162,10 +162,10 @@ inline size_t WrapAroundPowerOf2(size_t x, size_t pow2) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint64_t HashBytes(void *data, unsigned size) {
|
inline uint64_t HashBytes(void *data, int64_t size) {
|
||||||
uint8_t *data8 = (uint8_t *)data;
|
uint8_t *data8 = (uint8_t *)data;
|
||||||
uint64_t hash = (uint64_t)14695981039346656037ULL;
|
uint64_t hash = (uint64_t)14695981039346656037ULL;
|
||||||
for (unsigned i = 0; i < size; i++) {
|
for (int64_t i = 0; i < size; i++) {
|
||||||
hash = hash ^ (uint64_t)(data8[i]);
|
hash = hash ^ (uint64_t)(data8[i]);
|
||||||
hash = hash * (uint64_t)1099511628211ULL;
|
hash = hash * (uint64_t)1099511628211ULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -152,6 +152,9 @@ void Test(mco_coro *co) {
|
|||||||
void InitTests() {
|
void InitTests() {
|
||||||
WaitForEvents = false;
|
WaitForEvents = false;
|
||||||
TestDir = Format(TestArena, "%S/test_env", GetExeDir(TestArena));
|
TestDir = Format(TestArena, "%S/test_env", GetExeDir(TestArena));
|
||||||
|
|
||||||
|
CoRemove("Test");
|
||||||
CoData *data = CoAdd(Test);
|
CoData *data = CoAdd(Test);
|
||||||
data->dont_wait_until_resolved = true;
|
data->dont_wait_until_resolved = true;
|
||||||
|
CoResume(data);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1385,7 +1385,7 @@ String GetUniqueBufferName(String working_dir, String prepend_name, String exten
|
|||||||
void InitBuffers() {
|
void InitBuffers() {
|
||||||
Allocator sys_allocator = GetSystemAllocator();
|
Allocator sys_allocator = GetSystemAllocator();
|
||||||
Scratch scratch;
|
Scratch scratch;
|
||||||
Buffer *null_buffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkDir, "console"));
|
Buffer *null_buffer = CreateBuffer(sys_allocator, GetUniqueBufferName(WorkDir, "logs", ""));
|
||||||
null_buffer->special = true;
|
null_buffer->special = true;
|
||||||
View *null_view = CreateView(null_buffer->id);
|
View *null_view = CreateView(null_buffer->id);
|
||||||
null_view->special = true;
|
null_view->special = true;
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ String GetMainDir() {
|
|||||||
return GetDir(main.buffer);
|
return GetDir(main.buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JumpTempBuffer(BSet *set, String buffer_name = "") {
|
void JumpTempBuffer(BSet *set, String buffer_name) {
|
||||||
if (buffer_name.len == 0) {
|
if (buffer_name.len == 0) {
|
||||||
buffer_name = GetUniqueBufferName(GetDir(set->buffer), "temp");
|
buffer_name = GetUniqueBufferName(GetDir(set->buffer), "temp");
|
||||||
}
|
}
|
||||||
@@ -730,8 +730,10 @@ void Coro_OpenCode(mco_coro *co) {
|
|||||||
|
|
||||||
void OpenCode(String dir) {
|
void OpenCode(String dir) {
|
||||||
Coro_OpenCodeDir = dir;
|
Coro_OpenCodeDir = dir;
|
||||||
|
CoRemove("Coro_OpenCode");
|
||||||
CoData *data = CoAdd(Coro_OpenCode);
|
CoData *data = CoAdd(Coro_OpenCode);
|
||||||
data->dont_wait_until_resolved = true;
|
data->dont_wait_until_resolved = true;
|
||||||
|
CoResume(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMD_OpenCode() {
|
void CMD_OpenCode() {
|
||||||
@@ -790,8 +792,11 @@ void Coro_Rename(mco_coro *co) {
|
|||||||
buffer->name = Intern(&GlobalInternTable, string);
|
buffer->name = Intern(&GlobalInternTable, string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMD_Rename() {
|
void CMD_Rename() {
|
||||||
CoAdd(Coro_Rename);
|
CoRemove("Coro_Rename");
|
||||||
|
CoData *data = CoAdd(Coro_Rename);
|
||||||
|
CoResume(data);
|
||||||
} RegisterCommand(CMD_Rename, "");
|
} RegisterCommand(CMD_Rename, "");
|
||||||
|
|
||||||
String Coro_YesNoCancel(mco_coro *co, BSet main, String question) {
|
String Coro_YesNoCancel(mco_coro *co, BSet main, String question) {
|
||||||
@@ -865,7 +870,10 @@ void Coro_Close(mco_coro *co) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CMD_Close() {
|
void CMD_Close() {
|
||||||
CoAdd(Coro_Close);
|
CoRemove("Coro_Close");
|
||||||
|
CoData *data = CoAdd(Coro_Close);
|
||||||
|
CoResume(data);
|
||||||
|
|
||||||
} RegisterCommand(CMD_Close, "ctrl-w");
|
} RegisterCommand(CMD_Close, "ctrl-w");
|
||||||
|
|
||||||
// Considerations with coroutines:
|
// Considerations with coroutines:
|
||||||
@@ -910,15 +918,23 @@ void Coro_Quit(mco_coro *co) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CMD_Quit() {
|
void CMD_Quit() {
|
||||||
CoAdd(Coro_Quit);
|
CoRemove("Coro_Quit");
|
||||||
|
CoData *data = CoAdd(Coro_Quit);
|
||||||
|
CoResume(data);
|
||||||
} RegisterCommand(CMD_Quit, "");
|
} RegisterCommand(CMD_Quit, "");
|
||||||
|
|
||||||
|
void CMD_QuitWithoutSaving() {
|
||||||
|
AppIsRunning = false;
|
||||||
|
} RegisterCommand(CMD_QuitWithoutSaving, "");
|
||||||
|
|
||||||
void Coro_CloseAll(mco_coro *co) {
|
void Coro_CloseAll(mco_coro *co) {
|
||||||
Coro_CloseAllEx(co);
|
Coro_CloseAllEx(co);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMD_CloseAll() {
|
void CMD_CloseAll() {
|
||||||
CoAdd(Coro_CloseAll);
|
CoRemove("Coro_CloseAll");
|
||||||
|
CoData *data = CoAdd(Coro_CloseAll);
|
||||||
|
CoResume(data);
|
||||||
} RegisterCommand(CMD_CloseAll, "");
|
} RegisterCommand(CMD_CloseAll, "");
|
||||||
|
|
||||||
void CMD_JumpPrev() {
|
void CMD_JumpPrev() {
|
||||||
|
|||||||
@@ -19,9 +19,7 @@ void CoRemove(String name) {
|
|||||||
|
|
||||||
#define CoAdd(x) CoAddEx(x, #x)
|
#define CoAdd(x) CoAddEx(x, #x)
|
||||||
CoData *CoAddEx(CoroutineProc *proc, String name) {
|
CoData *CoAddEx(CoroutineProc *proc, String name) {
|
||||||
CoRemove(name);
|
|
||||||
mco_desc desc = mco_desc_init(proc, 0);
|
mco_desc desc = mco_desc_init(proc, 0);
|
||||||
|
|
||||||
mco_coro *coro = NULL;
|
mco_coro *coro = NULL;
|
||||||
mco_result ok = mco_create(&coro, &desc);
|
mco_result ok = mco_create(&coro, &desc);
|
||||||
if (ok != MCO_SUCCESS) {
|
if (ok != MCO_SUCCESS) {
|
||||||
@@ -30,12 +28,15 @@ CoData *CoAddEx(CoroutineProc *proc, String name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Add(&ActiveCoroutines, {coro, name});
|
Add(&ActiveCoroutines, {coro, name});
|
||||||
|
return GetLast(ActiveCoroutines);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoResume(CoData *dat) {
|
||||||
CoData *prev_curr = CoCurr;
|
CoData *prev_curr = CoCurr;
|
||||||
CoCurr = GetLast(ActiveCoroutines);
|
CoCurr = dat;
|
||||||
ok = mco_resume(coro);
|
mco_result ok = mco_resume(dat->co);
|
||||||
Assert(ok == MCO_SUCCESS);
|
Assert(ok == MCO_SUCCESS);
|
||||||
CoCurr = prev_curr;
|
CoCurr = prev_curr;
|
||||||
return GetLast(ActiveCoroutines);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoUpdate(Event *event) {
|
void CoUpdate(Event *event) {
|
||||||
|
|||||||
@@ -915,8 +915,10 @@ int main(int argc, char **argv)
|
|||||||
ReportConsolef("WorkDir = %S", WorkDir);
|
ReportConsolef("WorkDir = %S", WorkDir);
|
||||||
if (Testing) InitTests();
|
if (Testing) InitTests();
|
||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
|
CoRemove("Windows_SetupVCVarsall");
|
||||||
CoData *co_data = CoAdd(Windows_SetupVCVarsall);
|
CoData *co_data = CoAdd(Windows_SetupVCVarsall);
|
||||||
co_data->dont_wait_until_resolved = true;
|
co_data->dont_wait_until_resolved = true;
|
||||||
|
CoResume(co_data);
|
||||||
#endif
|
#endif
|
||||||
#if OS_WASM
|
#if OS_WASM
|
||||||
emscripten_set_main_loop(MainLoop, 0, 1);
|
emscripten_set_main_loop(MainLoop, 0, 1);
|
||||||
|
|||||||
@@ -197,3 +197,4 @@ ResolvedOpen ResolveOpen(Allocator scratch, String path, String meta);
|
|||||||
void CenterView(WindowID window);
|
void CenterView(WindowID window);
|
||||||
void TrimWhitespace(Buffer *buffer, bool trim_lines_with_caret = false);
|
void TrimWhitespace(Buffer *buffer, bool trim_lines_with_caret = false);
|
||||||
void ApplyFormattingTool(Buffer *buffer, String tool);
|
void ApplyFormattingTool(Buffer *buffer, String tool);
|
||||||
|
void JumpTempBuffer(BSet *set, String buffer_name = "");
|
||||||
@@ -174,8 +174,7 @@ Caret FindNext(Buffer *buffer, String16 needle, Caret caret) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Array<Caret> FindAll(Allocator allocator, Buffer *buffer, String16 needle) {
|
void FindAllEx(Array<Caret> *n, Buffer *buffer, String16 needle) {
|
||||||
Array<Caret> result = {allocator};
|
|
||||||
String16 string = GetString(buffer);
|
String16 string = GetString(buffer);
|
||||||
String16 start = string;
|
String16 start = string;
|
||||||
SeekFlag flag = SearchCaseSensitive ? SeekFlag_None : SeekFlag_IgnoreCase;
|
SeekFlag flag = SearchCaseSensitive ? SeekFlag_None : SeekFlag_IgnoreCase;
|
||||||
@@ -187,12 +186,17 @@ Array<Caret> FindAll(Allocator allocator, Buffer *buffer, String16 needle) {
|
|||||||
if (Seek(string, needle, &index, flag)) {
|
if (Seek(string, needle, &index, flag)) {
|
||||||
Int back = index + (Int)(string.data - start.data);
|
Int back = index + (Int)(string.data - start.data);
|
||||||
Int front = back + needle.len;
|
Int front = back + needle.len;
|
||||||
Add(&result, MakeCaret(front, back));
|
Add(n, MakeCaret(front, back));
|
||||||
string = Skip(string, index + needle.len);
|
string = Skip(string, index + needle.len);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Array<Caret> FindAll(Allocator allocator, Buffer *buffer, String16 needle) {
|
||||||
|
Array<Caret> result = {allocator};
|
||||||
|
FindAllEx(&result, buffer, needle);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,23 +223,6 @@ void Find(View *seek_view, String16 needle, bool forward = true) {
|
|||||||
IF_DEBUG(AssertRanges(seek_view->carets));
|
IF_DEBUG(AssertRanges(seek_view->carets));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SelectAll(View *view, String16 needle) {
|
|
||||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
|
||||||
String16 string_buffer = GetString(buffer);
|
|
||||||
|
|
||||||
for (Int pos = 0;;) {
|
|
||||||
Int index = 0;
|
|
||||||
String16 medium = Skip(string_buffer, pos);
|
|
||||||
if (!Seek(medium, needle, &index)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Add(&view->carets, MakeCaret(pos + index + needle.len, pos + index));
|
|
||||||
pos += needle.len;
|
|
||||||
}
|
|
||||||
MergeCarets(buffer, &view->carets);
|
|
||||||
}
|
|
||||||
|
|
||||||
Caret MoveCaret(Buffer *buffer, Caret it, int direction, bool ctrl = false, bool shift = false) {
|
Caret MoveCaret(Buffer *buffer, Caret it, int direction, bool ctrl = false, bool shift = false) {
|
||||||
Int front = GetFront(it);
|
Int front = GetFront(it);
|
||||||
Int range_size = GetSize(it.range);
|
Int range_size = GetSize(it.range);
|
||||||
@@ -638,3 +625,16 @@ void EncloseScope(View *view) {
|
|||||||
it.range.max = Clamp(buffer, it.range.max - 1);
|
it.range.max = Clamp(buffer, it.range.max - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SelectAllOccurences(View *view, String16 needle) {
|
||||||
|
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||||
|
Scratch scratch;
|
||||||
|
Array<Caret> all = FindAll(scratch, buffer, needle);
|
||||||
|
if (all.len > 0) {
|
||||||
|
view->carets.len = 0;
|
||||||
|
For (all) {
|
||||||
|
Add(&view->carets, it);
|
||||||
|
}
|
||||||
|
MergeCarets(buffer, &view->carets);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,9 +5,16 @@ typedef void Function();
|
|||||||
struct FunctionData { String name; Function *function; };
|
struct FunctionData { String name; Function *function; };
|
||||||
struct CommandData { String name; String binding; Function *function; struct Trigger *trigger; };
|
struct CommandData { String name; String binding; Function *function; struct Trigger *trigger; };
|
||||||
|
|
||||||
|
enum ViewKind {
|
||||||
|
ViewKind_Normal,
|
||||||
|
ViewKind_FuzzySearch,
|
||||||
|
ViewKind_ActiveSearch,
|
||||||
|
};
|
||||||
|
|
||||||
struct View {
|
struct View {
|
||||||
ViewID id;
|
ViewID id;
|
||||||
BufferID active_buffer;
|
BufferID active_buffer;
|
||||||
|
ViewKind kind;
|
||||||
Vec2I scroll;
|
Vec2I scroll;
|
||||||
Array<Caret> carets;
|
Array<Caret> carets;
|
||||||
|
|
||||||
@@ -17,11 +24,10 @@ struct View {
|
|||||||
|
|
||||||
String hook_cmd;
|
String hook_cmd;
|
||||||
Array<CommandData> hooks;
|
Array<CommandData> hooks;
|
||||||
String16 prev_search_line;
|
uint64_t prev_search_line_hash;
|
||||||
struct {
|
struct {
|
||||||
unsigned close : 1;
|
unsigned close : 1;
|
||||||
unsigned special : 1;
|
unsigned special : 1;
|
||||||
unsigned fuzzy : 1;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,74 +1,3 @@
|
|||||||
int32_t FuzzyRate(String16 string, String16 with) {
|
|
||||||
ProfileFunction();
|
|
||||||
if (with.len == 0) return 0;
|
|
||||||
int32_t points = 0;
|
|
||||||
int32_t consecutive = 0;
|
|
||||||
int32_t with_i = 0;
|
|
||||||
for (int32_t i = 0; i < string.len; i++) {
|
|
||||||
if (ToLowerCase(string.data[i]) == ToLowerCase(with[with_i])) {
|
|
||||||
consecutive += 1;
|
|
||||||
with_i += 1;
|
|
||||||
} else {
|
|
||||||
with_i = 0;
|
|
||||||
points += consecutive * consecutive;
|
|
||||||
consecutive = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (with_i >= with.len) with_i = 0;
|
|
||||||
}
|
|
||||||
points += consecutive * consecutive;
|
|
||||||
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) {
|
|
||||||
ProfileFunction();
|
|
||||||
if (line_min < 0 || line_min >= buffer->line_starts.len) return {};
|
|
||||||
if (line_max < 0 || line_min > buffer->line_starts.len) return {};
|
|
||||||
Array<FuzzyPair> ratings = {allocator};
|
|
||||||
Reserve(&ratings, line_max - line_min + 4);
|
|
||||||
for (Int i = line_min; i < line_max; i += 1) {
|
|
||||||
String16 s = GetLineStringWithoutNL(buffer, i);
|
|
||||||
int32_t rating = FuzzyRate(s, needle);
|
|
||||||
Add(&ratings, {(int32_t)i, rating});
|
|
||||||
}
|
|
||||||
Array<FuzzyPair> temp = Copy(allocator, ratings);
|
|
||||||
MergeSort(ratings.len, ratings.data, temp.data);
|
|
||||||
return ratings;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FuzzySearchViewUpdate() {
|
|
||||||
ProfileFunction();
|
|
||||||
BSet active = GetBSet(ActiveWindowID);
|
|
||||||
if (active.view->fuzzy) {
|
|
||||||
Scratch scratch;
|
|
||||||
String16 line_string = GetLineStringWithoutNL(active.buffer, 0);
|
|
||||||
if (active.view->prev_search_line != line_string) {
|
|
||||||
active.view->prev_search_line = line_string;
|
|
||||||
Array<FuzzyPair> ratings = FuzzySearchLines(scratch, active.buffer, 1, active.buffer->line_starts.len, line_string);
|
|
||||||
|
|
||||||
Buffer *scratch_buff = CreateScratchBuffer(scratch, active.buffer->cap);
|
|
||||||
RawAppend(scratch_buff, line_string);
|
|
||||||
For(IterateInReverse(&ratings)) {
|
|
||||||
String16 s = GetLineStringWithoutNL(active.buffer, it.index);
|
|
||||||
if (s.len == 0) continue;
|
|
||||||
RawAppend(scratch_buff, u"\n");
|
|
||||||
RawAppend(scratch_buff, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
Caret caret = active.view->carets[0];
|
|
||||||
SaveCaretHistoryBeforeBeginEdit(active.buffer, active.view->carets);
|
|
||||||
SelectEntireBuffer(active.view);
|
|
||||||
Replace(active.view, GetString(scratch_buff));
|
|
||||||
active.view->carets[0] = caret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CMD_ShowCommands() {
|
void CMD_ShowCommands() {
|
||||||
if (ActiveWindowID == CommandWindowID && LastExecutedManualCommand == CMD_ShowCommands) {
|
if (ActiveWindowID == CommandWindowID && LastExecutedManualCommand == CMD_ShowCommands) {
|
||||||
NextActiveWindowID = LastActiveLayoutWindowID;
|
NextActiveWindowID = LastActiveLayoutWindowID;
|
||||||
@@ -140,6 +69,12 @@ void OpenCommand(BSet active) {
|
|||||||
line = ClampTop(1ll, active.buffer->line_starts.len - 1ll);
|
line = ClampTop(1ll, active.buffer->line_starts.len - 1ll);
|
||||||
}
|
}
|
||||||
string = GetLineStringWithoutNL(active.buffer, line);
|
string = GetLineStringWithoutNL(active.buffer, line);
|
||||||
|
|
||||||
|
Int idx = 0;
|
||||||
|
String16 delim = u"|::|";
|
||||||
|
if (Seek(string, delim, &idx, SeekFlag_None)) {
|
||||||
|
string = Skip(string, idx + delim.len);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Open(string);
|
Open(string);
|
||||||
@@ -162,8 +97,170 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t FuzzyRate(String16 string, String16 with) {
|
||||||
|
ProfileFunction();
|
||||||
|
if (with.len == 0) return 0;
|
||||||
|
int32_t points = 0;
|
||||||
|
int32_t consecutive = 0;
|
||||||
|
int32_t with_i = 0;
|
||||||
|
for (int32_t i = 0; i < string.len; i++) {
|
||||||
|
if (ToLowerCase(string.data[i]) == ToLowerCase(with[with_i])) {
|
||||||
|
consecutive += 1;
|
||||||
|
with_i += 1;
|
||||||
|
} else {
|
||||||
|
with_i = 0;
|
||||||
|
points += consecutive * consecutive;
|
||||||
|
consecutive = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (with_i >= with.len) with_i = 0;
|
||||||
|
}
|
||||||
|
points += consecutive * consecutive;
|
||||||
|
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) {
|
||||||
|
ProfileFunction();
|
||||||
|
if (line_min < 0 || line_min >= buffer->line_starts.len) return {};
|
||||||
|
if (line_max < 0 || line_min > buffer->line_starts.len) return {};
|
||||||
|
Array<FuzzyPair> ratings = {allocator};
|
||||||
|
Reserve(&ratings, line_max - line_min + 4);
|
||||||
|
for (Int i = line_min; i < line_max; i += 1) {
|
||||||
|
String16 s = GetLineStringWithoutNL(buffer, i);
|
||||||
|
|
||||||
|
Int idx = 0;
|
||||||
|
String16 delim = u"|::|";
|
||||||
|
if (Seek(s, delim, &idx, SeekFlag_None)) {
|
||||||
|
s = GetPrefix(s, idx);
|
||||||
|
}
|
||||||
|
s = Trim(s);
|
||||||
|
|
||||||
|
int32_t rating = FuzzyRate(s, needle);
|
||||||
|
Add(&ratings, {(int32_t)i, rating});
|
||||||
|
}
|
||||||
|
Array<FuzzyPair> temp = Copy(allocator, ratings);
|
||||||
|
MergeSort(ratings.len, ratings.data, temp.data);
|
||||||
|
return ratings;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SearchProjectParams {
|
||||||
|
String16 needle;
|
||||||
|
BufferID buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
void Coro_SearchProject(mco_coro *co) {
|
||||||
|
SearchProjectParams *param = (SearchProjectParams *)CoCurr->user_ctx;
|
||||||
|
For (Buffers) {
|
||||||
|
if (it->special || it->is_dir || it->temp || it->dont_try_to_save_in_bulk_ops) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Scratch scratch;
|
||||||
|
Array<Caret> occurences = FindAll(scratch, it, param->needle);
|
||||||
|
Buffer *out_buffer = GetBuffer(param->buffer);
|
||||||
|
ForItem (caret, occurences) {
|
||||||
|
Int pos = caret.range.min;
|
||||||
|
Int line = PosToLine(it, pos);
|
||||||
|
String16 line_string = GetLineStringWithoutNL(it, line);
|
||||||
|
String line_string8 = ToString(scratch, line_string);
|
||||||
|
RawAppendf(out_buffer, "%-150S |::| %S:%lld\n", line_string8, it->name, (long long)line + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CoYield(co);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMD_ReplaceAll() {
|
||||||
|
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||||
|
String16 string = FetchLoadWord(main.view);
|
||||||
|
Scratch scratch;
|
||||||
|
Array<String16> parts = Split(scratch, string, u"@>");
|
||||||
|
if (parts.len != 2) {
|
||||||
|
ReportErrorf("Invalid ReplaceAll pattern");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String16 needle = parts[0];
|
||||||
|
String16 replace = parts[1];
|
||||||
|
ForItem (buffer, Buffers) {
|
||||||
|
if (buffer->special || buffer->is_dir || buffer->temp || buffer->dont_try_to_save_in_bulk_ops) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
View *view = OpenBufferView(buffer->name);
|
||||||
|
SelectAllOccurences(view, needle);
|
||||||
|
Replace(view, replace);
|
||||||
|
}
|
||||||
|
} RegisterCommand(CMD_ReplaceAll, "");
|
||||||
|
|
||||||
|
void FuzzySearchViewUpdate() {
|
||||||
|
ProfileFunction();
|
||||||
|
BSet active = GetBSet(ActiveWindowID);
|
||||||
|
if (active.view->kind == ViewKind_ActiveSearch) {
|
||||||
|
Scratch scratch;
|
||||||
|
String16 line_string = GetLineStringWithoutNL(active.buffer, 0);
|
||||||
|
uint64_t hash = HashBytes(line_string.data, line_string.len * sizeof(char16_t));
|
||||||
|
if (active.view->prev_search_line_hash != hash) {
|
||||||
|
active.view->prev_search_line_hash = hash;
|
||||||
|
if (line_string.len > 0) {
|
||||||
|
// @todo: do we reintroduce history here?
|
||||||
|
SelectEntireBuffer(active.view);
|
||||||
|
Replace(active.view, line_string);
|
||||||
|
Append(active.view, "\n", false);
|
||||||
|
|
||||||
|
CoRemove("Coro_SearchProject");
|
||||||
|
CoData *dat = CoAdd(Coro_SearchProject);
|
||||||
|
SearchProjectParams *param = AllocType(dat->arena, SearchProjectParams);
|
||||||
|
param->needle = Copy16(dat->arena, line_string);
|
||||||
|
param->buffer = active.buffer->id;
|
||||||
|
dat->user_ctx = param;
|
||||||
|
dat->dont_wait_until_resolved = true;
|
||||||
|
CoResume(dat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (active.view->kind == ViewKind_FuzzySearch) {
|
||||||
|
Scratch scratch;
|
||||||
|
String16 line_string = GetLineStringWithoutNL(active.buffer, 0);
|
||||||
|
uint64_t hash = HashBytes(line_string.data, line_string.len * sizeof(char16_t));
|
||||||
|
if (active.view->prev_search_line_hash != hash) {
|
||||||
|
active.view->prev_search_line_hash = hash;
|
||||||
|
Array<FuzzyPair> ratings = FuzzySearchLines(scratch, active.buffer, 1, active.buffer->line_starts.len, line_string);
|
||||||
|
|
||||||
|
Buffer *scratch_buff = CreateScratchBuffer(scratch, active.buffer->cap);
|
||||||
|
RawAppend(scratch_buff, line_string);
|
||||||
|
For(IterateInReverse(&ratings)) {
|
||||||
|
String16 s = GetLineStringWithoutNL(active.buffer, it.index);
|
||||||
|
if (s.len == 0) continue;
|
||||||
|
RawAppend(scratch_buff, u"\n");
|
||||||
|
RawAppend(scratch_buff, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
Caret caret = active.view->carets[0];
|
||||||
|
SaveCaretHistoryBeforeBeginEdit(active.buffer, active.view->carets);
|
||||||
|
SelectEntireBuffer(active.view);
|
||||||
|
Replace(active.view, GetString(scratch_buff));
|
||||||
|
active.view->carets[0] = caret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMD_SearchProject() {
|
||||||
|
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||||
|
JumpTempBuffer(&main);
|
||||||
|
NextActiveWindowID = main.window->id;
|
||||||
|
main.view->kind = ViewKind_ActiveSearch;
|
||||||
|
AddHook(&main.view->hooks, "Open", "ctrl-q | enter", CMD_CommandWindowOpen);
|
||||||
|
main.buffer->no_history = true;
|
||||||
|
} RegisterCommand(CMD_SearchProject, "ctrl-shift-f");
|
||||||
|
|
||||||
void SetFuzzy(View *view) {
|
void SetFuzzy(View *view) {
|
||||||
view->fuzzy = true;
|
view->kind = ViewKind_FuzzySearch;
|
||||||
AddHook(&view->hooks, "Open", "ctrl-q | enter", CMD_CommandWindowOpen);
|
AddHook(&view->hooks, "Open", "ctrl-q | enter", CMD_CommandWindowOpen);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,6 +269,7 @@ void CommandWindowInit() {
|
|||||||
CommandWindowID = window->id;
|
CommandWindowID = window->id;
|
||||||
Buffer *buffer = CreateBuffer(SysAllocator, GetUniqueBufferName(WorkDir, "command_bar"));
|
Buffer *buffer = CreateBuffer(SysAllocator, GetUniqueBufferName(WorkDir, "command_bar"));
|
||||||
buffer->special = true;
|
buffer->special = true;
|
||||||
|
buffer->no_history = true;
|
||||||
View *view = CreateView(buffer->id);
|
View *view = CreateView(buffer->id);
|
||||||
view->special = true;
|
view->special = true;
|
||||||
SetFuzzy(view);
|
SetFuzzy(view);
|
||||||
|
|||||||
@@ -39,24 +39,11 @@ void CMD_SearchPrev() {
|
|||||||
SearchWindowFindNext(false);
|
SearchWindowFindNext(false);
|
||||||
} RegisterCommand(CMD_SearchPrev, "shift-f3");
|
} RegisterCommand(CMD_SearchPrev, "shift-f3");
|
||||||
|
|
||||||
void SearchAll() {
|
void CMD_SearchAll() {
|
||||||
Scratch scratch;
|
|
||||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||||
BSet set = GetBSet(SearchWindowID);
|
BSet set = GetBSet(SearchWindowID);
|
||||||
String16 needle = GetString(set.buffer, GetRange(set.buffer));
|
String16 needle = GetString(set.buffer, GetRange(set.buffer));
|
||||||
Array<Caret> all = FindAll(scratch, main.buffer, needle);
|
SelectAllOccurences(main.view, needle);
|
||||||
if (all.len > 0) {
|
|
||||||
main.view->carets.len = 0;
|
|
||||||
For (all) {
|
|
||||||
Add(&main.view->carets, it);
|
|
||||||
}
|
|
||||||
MergeCarets(main.buffer, &main.view->carets);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CMD_SearchAll() {
|
|
||||||
SearchAll();
|
|
||||||
BSet set = GetBSet(SearchWindowID);
|
|
||||||
set.window->visible = false;
|
set.window->visible = false;
|
||||||
} RegisterCommand(CMD_SearchAll, "alt-f3");
|
} RegisterCommand(CMD_SearchAll, "alt-f3");
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user