ActiveSearch/SearchAll command and beginnings of ReplaceAll command, coroutine interface change

This commit is contained in:
Krzosa Karol
2026-01-02 09:08:34 +01:00
parent ee1ba86f74
commit bedc2b15e2
12 changed files with 240 additions and 124 deletions

View File

@@ -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:

View File

@@ -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;
} }

View File

@@ -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);
} }

View File

@@ -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;

View File

@@ -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() {

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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 = "");

View File

@@ -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);
}
}

View File

@@ -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;
}; };
}; };

View File

@@ -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);

View File

@@ -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");