Search case sensitive and word boundary

This commit is contained in:
Krzosa Karol
2025-12-27 15:54:10 +01:00
parent b6f3a1ebec
commit e4b84dde90
7 changed files with 110 additions and 32 deletions

View File

@@ -206,26 +206,54 @@ API String NormalizePath(Allocator allocator, String s) {
API bool Seek(String string, String find, int64_t *index_out, SeekFlag flags) {
bool ignore_case = flags & SeekFlag_IgnoreCase ? true : false;
bool result = false;
bool result = false;
if (flags & SeekFlag_MatchFindLast) {
for (int64_t i = string.len; i != 0; i--) {
int64_t index = i - 1;
String substring = GetSlice(string, index, index + find.len);
int64_t index = i - 1;
String substring = GetSlice(string, index, index + find.len);
if (AreEqual(substring, find, ignore_case)) {
if (index_out)
*index_out = index;
result = true;
break;
bool ok_boundary = true;
if (flags & SeekFlag_WordBoundary) {
String left = GetSlice(string, i - 1, i);
String right = GetSlice(string, i + find.len, i + find.len + 1);
if (left.len != 0 && !IsNonWord(left.data[0])) {
ok_boundary = false;
}
if (right.len != 0 && !IsNonWord(right.data[0])) {
ok_boundary = false;
}
}
if (ok_boundary) {
if (index_out) {
*index_out = index;
}
result = true;
break;
}
}
}
} else {
for (int64_t i = 0; i < string.len; i++) {
String substring = GetSlice(string, i, i + find.len);
if (AreEqual(substring, find, ignore_case)) {
if (index_out)
*index_out = i;
result = true;
break;
bool ok_boundary = true;
if (flags & SeekFlag_WordBoundary) {
String left = GetSlice(string, i - 1, i);
String right = GetSlice(string, i + find.len, i + find.len + 1);
if (left.len != 0 && !IsNonWord(left.data[0])) {
ok_boundary = false;
}
if (right.len != 0 && !IsNonWord(right.data[0])) {
ok_boundary = false;
}
}
if (ok_boundary) {
if (index_out) {
*index_out = i;
}
result = true;
break;
}
}
}
}

View File

@@ -97,6 +97,7 @@ enum {
SeekFlag_None = 0,
SeekFlag_IgnoreCase = 1,
SeekFlag_MatchFindLast = 2,
SeekFlag_WordBoundary = 4,
};
API bool Seek(String string, String find, int64_t *index_out = NULL, SeekFlag flags = SeekFlag_None);

View File

@@ -216,26 +216,54 @@ API String16 NormalizePath(Allocator allocator, String16 s) {
API bool Seek(String16 string, String16 find, int64_t *index_out, SeekFlag flags) {
bool ignore_case = flags & SeekFlag_IgnoreCase ? true : false;
bool result = false;
bool result = false;
if (flags & SeekFlag_MatchFindLast) {
for (int64_t i = string.len; i != 0; i--) {
int64_t index = i - 1;
String16 substring = GetSlice(string, index, index + find.len);
int64_t index = i - 1;
String16 substring = GetSlice(string, index, index + find.len);
if (AreEqual(substring, find, ignore_case)) {
if (index_out)
*index_out = index;
result = true;
break;
bool ok_boundary = true;
if (flags & SeekFlag_WordBoundary) {
String16 left = GetSlice(string, i - 1, i);
String16 right = GetSlice(string, i + find.len, i + find.len + 1);
if (left.len != 0 && !IsNonWord(left.data[0])) {
ok_boundary = false;
}
if (right.len != 0 && !IsNonWord(right.data[0])) {
ok_boundary = false;
}
}
if (ok_boundary) {
if (index_out) {
*index_out = index;
}
result = true;
break;
}
}
}
} else {
for (int64_t i = 0; i < string.len; i++) {
String16 substring = GetSlice(string, i, i + find.len);
if (AreEqual(substring, find, ignore_case)) {
if (index_out)
*index_out = i;
result = true;
break;
bool ok_boundary = true;
if (flags & SeekFlag_WordBoundary) {
String16 left = GetSlice(string, i - 1, i);
String16 right = GetSlice(string, i + find.len, i + find.len + 1);
if (left.len != 0 && !IsNonWord(left.data[0])) {
ok_boundary = false;
}
if (right.len != 0 && !IsNonWord(right.data[0])) {
ok_boundary = false;
}
}
if (ok_boundary) {
if (index_out) {
*index_out = i;
}
result = true;
break;
}
}
}
}

View File

@@ -6,6 +6,8 @@ bool Testing = false;
bool AppIsRunning = true;
bool WaitForEvents = true;
bool RunGCThisFrame;
bool SearchCaseSensitive = false;
bool SearchWordBoundary = false;
WindowID WindowIDs;
ViewID ViewIDs;

View File

@@ -124,16 +124,20 @@ void IdentedNewLine(View *view) {
}
Caret FindPrev(Buffer *buffer, String16 needle, Caret caret) {
Int pos = GetFront(caret);
Int pos = GetFront(caret);
String16 medium = GetString(buffer, {0, pos});
SeekFlag flag = SearchCaseSensitive ? SeekFlag_None : SeekFlag_IgnoreCase;
if (SearchWordBoundary) {
flag |= SeekFlag_WordBoundary;
}
Caret result = caret;
Int index = 0;
if (Seek(medium, needle, &index, SeekFlag_MatchFindLast)) {
if (Seek(medium, needle, &index, flag | SeekFlag_MatchFindLast)) {
result = MakeCaret(index, index + needle.len);
} else {
medium = GetString(buffer);
if (Seek(medium, needle, &index, SeekFlag_MatchFindLast)) {
if (Seek(medium, needle, &index, flag | SeekFlag_MatchFindLast)) {
result = MakeCaret(index, index + needle.len);
}
}
@@ -142,16 +146,20 @@ Caret FindPrev(Buffer *buffer, String16 needle, Caret caret) {
}
Caret FindNext(Buffer *buffer, String16 needle, Caret caret) {
Int pos = GetMax(caret);
Int pos = GetMax(caret);
String16 medium = GetString(buffer, {pos, INT64_MAX});
SeekFlag flag = SearchCaseSensitive ? SeekFlag_None : SeekFlag_IgnoreCase;
if (SearchWordBoundary) {
flag |= SeekFlag_WordBoundary;
}
Caret result = caret;
Int index = 0;
if (Seek(medium, needle, &index)) {
if (Seek(medium, needle, &index, flag)) {
result = MakeCaret(pos + index + needle.len, pos + index);
} else {
medium = GetString(buffer);
if (Seek(medium, needle, &index)) {
if (Seek(medium, needle, &index, flag)) {
result = MakeCaret(index + needle.len, index);
}
}
@@ -163,9 +171,13 @@ Array<Caret> FindAll(Allocator allocator, Buffer *buffer, String16 needle) {
Array<Caret> result = {allocator};
String16 string = GetString(buffer);
String16 start = string;
SeekFlag flag = SearchCaseSensitive ? SeekFlag_None : SeekFlag_IgnoreCase;
if (SearchWordBoundary) {
flag |= SeekFlag_WordBoundary;
}
for (;;) {
Int index = 0;
if (Seek(string, needle, &index)) {
if (Seek(string, needle, &index, flag)) {
Int back = index + (Int)(string.data - start.data);
Int front = back + needle.len;
Add(&result, MakeCaret(front, back));

View File

@@ -100,7 +100,6 @@ void Command_SearchAll() {
set.window->visible = false;
} RegisterCommand(Command_SearchAll, "alt-f3");
void Command_SearchAllInSearch() {
if (ActiveWindowID != SearchWindowID) {
return;
@@ -110,6 +109,13 @@ void Command_SearchAllInSearch() {
set.window->visible = false;
} RegisterCommand(Command_SearchAllInSearch, "alt-enter");
void Command_ToggleCaseSensitiveSearch() {
SearchCaseSensitive = !SearchCaseSensitive;
} RegisterCommand(Command_ToggleCaseSensitiveSearch, "alt-c");
void Command_ToggleSearchWordBoundary() {
SearchWordBoundary = !SearchWordBoundary;
} RegisterCommand(Command_ToggleSearchWordBoundary, "alt-w");
void SearchWindowUpdate() {
BSet active = GetBSet(ActiveWindowID);

View File

@@ -81,10 +81,11 @@ void StatusWindowUpdate() {
Array<Edit> edits = ReplaceEx(scratch, title.view, u" |");
}
// replace data up to separator with filename and stuff
const char *reopen = main.buffer->changed_on_disk ? " :Reopen" : "";
String s = Format(scratch, "# %S:%lld:%lld%s", main.buffer->name, (long long)xy.line + 1ll, (long long)xy.col + 1ll, reopen);
const char *case_sens = SearchCaseSensitive ? " C" : "";
const char *word_bound = SearchWordBoundary ? " W" : "";
String s = Format(scratch, "# %S:%lld:%lld%s%s", main.buffer->name, (long long)xy.line + 1ll, (long long)xy.col + 1ll, case_sens, word_bound, reopen);
For (ActiveProcesses) {
if (it.view_id == main.view->id.id) {
s = Format(scratch, "%S %lld :KillProcess", s, (long long)it.id);