From: Olaf Wintermann Date: Sat, 31 Jan 2026 17:20:31 +0000 (+0100) Subject: implement case insensitive and backwards search X-Git-Url: https://uap-core.de/gitweb/?a=commitdiff_plain;h=ba44c29735d8cd5dcc1aba26a24d080e1f856dbf;p=note.git implement case insensitive and backwards search --- diff --git a/application/application.c b/application/application.c index 29ef4ad..d8736a4 100644 --- a/application/application.c +++ b/application/application.c @@ -178,11 +178,9 @@ void action_note_delete(UiEvent *event, void *data) { } void action_find(UiEvent *event, void *data) { - ui_set_state(event->obj->ctx, APP_STATE_NOTE_FIND); - ui_unset_state(event->obj->ctx, APP_STATE_NOTE_REPLACE); + window_show_searchbar(event->window, FALSE); } void action_replace(UiEvent *event, void *data) { - ui_set_state(event->obj->ctx, APP_STATE_NOTE_FIND); - ui_set_state(event->obj->ctx, APP_STATE_NOTE_REPLACE); + window_show_searchbar(event->window, TRUE); } diff --git a/application/application.h b/application/application.h index 2957a2e..8dedf35 100644 --- a/application/application.h +++ b/application/application.h @@ -66,6 +66,8 @@ typedef struct MainWindow { UIWIDGET textview; UIWIDGET attachments; + UIWIDGET searchbar_textfield; + /* * is the note list visible (splitpane child 0) */ diff --git a/application/note.c b/application/note.c index a2a506f..3781a45 100644 --- a/application/note.c +++ b/application/note.c @@ -266,7 +266,7 @@ void note_insert_image(NoteModel *note, const char *filepath) { void note_update_title(NotebookModel *notebook, Note *note) { NoteModel *m = note->model; - int index = notebookmode_get_note_index(notebook, note); + int index = notebookmodel_get_note_index(notebook, note); if(index < 0 && !m->new_note) { return; } @@ -316,3 +316,109 @@ Attachment* note_get_attachment(Resource *note, const char *path) { } return NULL; } + + +/* ----------------------------- Search/Replace ---------------------------- */ + +cxstring text_search_strcasestr(cxstring haystack, cxstring needle) { + if(needle.length == 0) { + return haystack; + } + + for(size_t i=0;i needle.length) { + str2.length = needle.length; + } + if(!cx_strcasecmp(str2, needle)) { + return str; + } + } + return (cxstring){NULL,0}; +} + +int text_search( + cxstring text, + cxstring search, + int pos, + bool backwards, + bool case_sensitive, + bool regex, + int *result_begin, + int *result_end) +{ + cxstring result = (cxstring){NULL,0}; + if(!backwards) { + cxstring subtext = cx_strsubs(text, pos); + if(!regex) { + result = case_sensitive ? cx_strstr(subtext, search) : text_search_strcasestr(subtext, search); + } else { + // regex search + // TODO + } + } else { + // use text_search in forward-mode as long as result_end < pos + int begin, end; + int prev_begin = -1; + int prev_end = 0; + cxstring subtext = text; + while(text_search(subtext, search, prev_end, FALSE, case_sensitive, regex, &begin, &end)) { + if(end > pos) { + break; + } + prev_begin = begin; + prev_end = end; + } + if(prev_begin >= 0) { + result = cx_strn(text.ptr + prev_begin, prev_end-prev_begin); + } + } + if(result.ptr) { + *result_begin = (int)(result.ptr - text.ptr); + *result_end = *result_begin + search.length; + return 1; + } + return 0; +} + +static int get_search_start_pos(NoteModel *note) { + int pos = note->text->position(note->text); + int sel_begin, sel_end; + note->text->selection(note->text, &sel_begin, &sel_end); + if(sel_end >= 0) { + pos = sel_end; + } + return pos; +} + +static void note_search(NoteModel *note, bool backwards) { + cxstring searchstr = cx_str(ui_get(note->search)); + if(searchstr.length == 0) { + return; + } + + cxstring text = cx_str(ui_get(note->text)); + int pos = get_search_start_pos(note); + + bool cs = (bool)ui_get(note->search_cs); + bool regex = (bool)ui_get(note->search_regex); + + int begin, end; + if(text_search(text, searchstr, pos, backwards, regex, cs, &begin, &end)) { + note->text->setposition(note->text, end); + note->text->setselection(note->text, begin, end); + } +} + +void note_search_next(NoteModel *note) { + note_search(note, FALSE); +} + +void note_search_prev(NoteModel *note) { + note_search(note, TRUE); +} + +void note_replace(NoteModel *note) { + +} diff --git a/application/note.h b/application/note.h index 9486647..f7be359 100644 --- a/application/note.h +++ b/application/note.h @@ -70,6 +70,22 @@ void note_destroy(const CxAllocator *a, Note *note); Attachment* note_get_attachment(Resource *note, const char *path); +cxstring text_search_strcasestr(cxstring haystack, cxstring needle); + +int text_search( + cxstring text, + cxstring search, + int pos, + bool backwards, + bool case_sensitive, + bool regex, + int *result_begin, + int *result_end); + +void note_search_next(NoteModel *note); +void note_search_prev(NoteModel *note); +void note_replace(NoteModel *note); + #ifdef __cplusplus } #endif diff --git a/application/notebook.c b/application/notebook.c index 37a9e9f..6cf0d8b 100644 --- a/application/notebook.c +++ b/application/notebook.c @@ -296,7 +296,7 @@ void notebookmodel_add2navstack(NotebookModel *model) { */ } -int notebookmode_get_note_index(NotebookModel *model, Note *note) { +int notebookmodel_get_note_index(NotebookModel *model, Note *note) { CxList *list = model->notes->data; size_t index = cxListFind(list, note); return cxListIndexValid(list, index) ? index : -1; diff --git a/application/notebook.h b/application/notebook.h index 89ea350..21a2937 100644 --- a/application/notebook.h +++ b/application/notebook.h @@ -56,7 +56,7 @@ void notebookmodel_delete_note(NotebookModel *model); void notebookmodel_add2navstack(NotebookModel *model); -int notebookmode_get_note_index(NotebookModel *model, Note *note); +int notebookmodel_get_note_index(NotebookModel *model, Note *note); #ifdef __cplusplus diff --git a/application/window.c b/application/window.c index 61a693f..4811571 100644 --- a/application/window.c +++ b/application/window.c @@ -120,9 +120,9 @@ void window_create() { ui_grid(obj, .margin = 4, .columnspacing = 4, .rowspacing = 4, .def_hfill = TRUE, .def_vfill = TRUE, .visibility_states = UI_GROUPS(APP_STATE_NOTE_FIND)) { ui_rlabel(obj, .label = "Find"); - ui_textfield(obj, .hexpand = TRUE, .onactivate = ui_searchbar_next, .varname = "search"); - ui_button(obj, .label = "Previous"); - ui_button(obj, .label = "Next", .onclick = ui_searchbar_next); + wdata->searchbar_textfield = ui_textfield(obj, .hexpand = TRUE, .onactivate = action_searchbar_next, .varname = "search"); + ui_button(obj, .label = "Previous", .onclick = action_searchbar_prev); + ui_button(obj, .label = "Next", .onclick = action_searchbar_next); ui_checkbox(obj, .label = "Case Sensitive", .varname = "search_cs"); ui_checkbox(obj, .label = "Regex", .varname = "search_regex"); ui_button(obj, .icon = "window-close", .onclick = action_searchbar_close); @@ -295,6 +295,17 @@ void window_store_groups_updated(NoteStore *store, MainWindow *window) { update_sublists(window->obj->ctx, window->notebooks); } +void window_show_searchbar(MainWindow *window, UiBool replace) { + UiContext *ctx = window->obj->ctx; + ui_set_state(ctx, APP_STATE_NOTE_FIND); + if(replace) { + ui_set_state(ctx, APP_STATE_NOTE_REPLACE); + } else { + ui_unset_state(ctx, APP_STATE_NOTE_REPLACE); + } + ui_textfield_focus(window->searchbar_textfield); +} + typedef struct NotebookCreatedResult { MainWindow *window; @@ -564,26 +575,16 @@ void action_searchbar_close(UiEvent *event, void *userdata) { ui_unset_state(event->obj->ctx, APP_STATE_NOTE_REPLACE); } -void ui_searchbar_next(UiEvent *event, void *userdata) { +void action_searchbar_next(UiEvent *event, void *userdata) { NoteModel *note = notemodel_current(event->obj); - if(!note) { - return; - } - - cxstring searchstr = cx_str(ui_get(note->search)); - if(searchstr.length == 0) { - return; + if(note) { + note_search_next(note); } - - cxstring text = cx_str(ui_get(note->text)); - int pos = note->text->position(note->text); - cxstring subtext = cx_strsubs(text, pos); - - cxstring result = cx_strstr(subtext, searchstr); - if(result.ptr) { - size_t result_pos = result.ptr - text.ptr; - size_t result_end = result_pos + searchstr.length; - note->text->setposition(note->text, result_end); - note->text->setselection(note->text, (int)result_pos, (int)result_end); +} + +void action_searchbar_prev(UiEvent *event, void *userdata) { + NoteModel *note = notemodel_current(event->obj); + if(note) { + note_search_prev(note); } } diff --git a/application/window.h b/application/window.h index c65d25f..fe1e1ee 100644 --- a/application/window.h +++ b/application/window.h @@ -69,6 +69,8 @@ void* window_notelist_getvalue(void *data, int col); // note store listener funcs void window_store_groups_updated(NoteStore *store, MainWindow *window); +void window_show_searchbar(MainWindow *window, UiBool replace); + void action_notebook_add(UiEvent *event, void *userdata); void action_notebook_config(UiEvent *event, void *userdata); @@ -88,7 +90,8 @@ void action_textnote_insertlist(UiEvent *event, void *userdata); void action_textnote_insertimg(UiEvent *event, void *userdata); void action_searchbar_close(UiEvent *event, void *userdata); -void ui_searchbar_next(UiEvent *event, void *userdata); +void action_searchbar_next(UiEvent *event, void *userdata); +void action_searchbar_prev(UiEvent *event, void *userdata);