diff --git a/src/bin/edi_file.c b/src/bin/edi_file.c index fe7ada0..f9e960d 100644 --- a/src/bin/edi_file.c +++ b/src/bin/edi_file.c @@ -17,3 +17,104 @@ edi_file_path_hidden(const char *path) return EINA_FALSE; } +void +edi_file_text_replace(const char *path, const char *search, const char *replace) +{ + char *map, *tempfilepath, *found; + FILE *tempfile; + Eina_File *f; + unsigned long long len, idx; + unsigned int slen; + + f = eina_file_open(path, EINA_FALSE); + if (!f) return; + + map = eina_file_map_all(f, EINA_FILE_POPULATE); + if (!map) + { + eina_file_close(f); + return; + } + + len = eina_file_size_get(f); + if (!len) + { + eina_file_close(f); + return; + } + + tempfilepath = malloc(strlen(path)) + 5; + sprintf(tempfilepath, "/tmp/%s.tmp", ecore_file_file_get(path)); + + tempfile = fopen(tempfilepath, "wb"); + if (!tempfile) goto done; + + idx = 0; + + found = strstr(&map[idx], search); + if (!found) + { + fclose(tempfile); + unlink(tempfilepath); + goto done; + } + + slen = strlen(search); + + while (idx < len) + { + if (!found || &map[idx] < found) + { + fprintf(tempfile, "%c", map[idx]); + idx++; + } + else + { + fprintf(tempfile, "%s", replace); + idx += slen; + found = strstr(&map[idx], search); + } + } + + fclose(tempfile); + ecore_file_mv(tempfilepath, path); +done: + eina_file_map_free(f, map); + eina_file_close(f); +} + +static void +_edi_file_text_replace_all(const char *directory, const char *search, const char *replace) +{ + char *path, *file; + Eina_List *files; + + files = ecore_file_ls(directory); + + EINA_LIST_FREE(files, file) + { + path = edi_path_append(directory, file); + if (!edi_file_path_hidden(path)) + { + if (ecore_file_is_dir(path)) + { + _edi_file_text_replace_all(path, search, replace); + } + else + { + edi_file_text_replace(path, search, replace); + } + } + free(path); + free(file); + } + + if (files) + eina_list_free(files); +} + +void +edi_file_text_replace_all(const char *search, const char *replace) +{ + _edi_file_text_replace_all(edi_project_get(), search, replace); +} diff --git a/src/bin/edi_file.h b/src/bin/edi_file.h index 2c0e587..f3fffd9 100644 --- a/src/bin/edi_file.h +++ b/src/bin/edi_file.h @@ -31,6 +31,27 @@ extern "C" { Eina_Bool edi_file_path_hidden(const char *path); +/** + * Replace all occurences of text within whole project. + * + * @param search The text to be replaced. + * @param replace The text that will replace. + * + * @ingroup Lookup + */ +void edi_file_text_replace_all(const char *search, const char *replace); + +/** + * Replace all occurences of text within given file. + * + * @param path The path of the file to replace all occurences of the text. + * @param search The text to be replaced. + * @param replace The text that will replace. + * + * @ingroup Lookup + */ +void edi_file_text_replace(const char *path, const char *search, const char *replace); + /** * @} */ diff --git a/src/bin/edi_main.c b/src/bin/edi_main.c index 62dedfa..f7d8da5 100644 --- a/src/bin/edi_main.c +++ b/src/bin/edi_main.c @@ -926,6 +926,13 @@ _edi_menu_find_project_cb(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, edi_mainview_project_search_popup_show(); } +static void +_edi_menu_find_replace_project_cb(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, + void *event_info EINA_UNUSED) +{ + edi_mainview_project_replace_popup_show(); +} + static void _edi_menu_findfile_cb(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) @@ -1137,6 +1144,7 @@ _edi_menu_setup(Evas_Object *win) elm_menu_item_add(menu, menu_it, "go-jump", _("Goto Line ..."), _edi_menu_goto_cb, NULL); elm_menu_item_separator_add(menu, menu_it); elm_menu_item_add(menu, menu_it, "edit-find", _("Find in project ..."), _edi_menu_find_project_cb, NULL); + elm_menu_item_add(menu, menu_it, "edit-find-replace", _("Replace in project ..."), _edi_menu_find_replace_project_cb, NULL); menu_it = elm_menu_item_add(menu, NULL, NULL, _("View"), NULL, NULL); elm_menu_item_add(menu, menu_it, "window-new", _("New Window"), _edi_menu_view_open_window_cb, NULL); diff --git a/src/bin/mainview/edi_mainview.c b/src/bin/mainview/edi_mainview.c index ca04ada..010055b 100644 --- a/src/bin/mainview/edi_mainview.c +++ b/src/bin/mainview/edi_mainview.c @@ -14,7 +14,8 @@ #include "editor/edi_editor.h" #include "edi_content_provider.h" -#include "../edi_searchpanel.h" +#include "edi_searchpanel.h" +#include "edi_file.h" #include "edi_private.h" #include "edi_config.h" @@ -465,6 +466,35 @@ edi_mainview_goto_popup_show() edi_mainview_panel_goto_popup_show(_current_panel); } +static void +_edi_mainview_popup_message_close_cb(void *data EINA_UNUSED, + Evas_Object *obj EINA_UNUSED, + void *event_info EINA_UNUSED) +{ + Evas_Object *popup = data; + + evas_object_del(popup); +} + +static void +_edi_mainview_popup_message_open(const char *message) +{ + Evas_Object *popup, *button; + + popup = elm_popup_add(_main_win); + elm_object_part_text_set(popup, "title,text", + message); + + button = elm_button_add(popup); + + elm_object_text_set(button, _("OK")); + elm_object_part_content_set(popup, "button1", button); + evas_object_smart_callback_add(button, "clicked", + _edi_mainview_popup_message_close_cb, popup); + + evas_object_show(popup); +} + static void _edi_mainview_project_search_popup_cancel_cb(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, @@ -482,7 +512,11 @@ _edi_mainview_project_search_cb(void *data, char *text; text_markup = elm_object_text_get((Evas_Object *) data); - if (!text_markup || !text_markup[0]) return; + if (!text_markup || !text_markup[0]) + { + _edi_mainview_popup_message_open(_("Please enter a valid search term.")); + return; + } text = elm_entry_markup_to_utf8(text_markup); @@ -517,6 +551,7 @@ edi_mainview_project_search_popup_show(void) _("Search for (whole project)")); box = elm_box_add(popup); + evas_object_show(box); sep = elm_separator_add(box); elm_separator_horizontal_set(sep, EINA_TRUE); evas_object_show(sep); @@ -565,6 +600,127 @@ edi_mainview_project_search_popup_show(void) evas_object_show(popup); elm_object_focus_set(input, EINA_TRUE); } + +static void +_edi_mainview_project_replace_cb(void *data, + Evas_Object *obj, + void *event_info EINA_UNUSED) +{ + const char *search_markup, *replace_markup; + char *search, *replace; + + search_markup = elm_object_text_get(evas_object_data_get(obj, "search")); + if (!search_markup || !search_markup[0]) + { + _edi_mainview_popup_message_open(_("Please enter a valid search string.")); + return; + } + + replace_markup = elm_object_text_get(data); + if (!replace_markup || !replace_markup[0]) + { + _edi_mainview_popup_message_open(_("Please enter a valid replace string.")); + return; + } + + if (!strcmp(replace_markup, search_markup)) + { + _edi_mainview_popup_message_open(_("Strings cannot match.")); + return; + } + + search = elm_entry_markup_to_utf8(search_markup); + replace = elm_entry_markup_to_utf8(replace_markup); + + edi_file_text_replace_all(search, replace); + + free(search); + free(replace); + + evas_object_del(_edi_mainview_search_project_popup); +} + +void +edi_mainview_project_replace_popup_show(void) +{ + Evas_Object *popup, *table, *box, *label, *sep, *search, *replace, *button; + + popup = elm_popup_add(_main_win); + _edi_mainview_search_project_popup = popup; + elm_object_part_text_set(popup, "title,text", _("Search & Replace")); + + box = elm_box_add(popup); + elm_object_content_set(popup, box); + + sep = elm_separator_add(box); + elm_separator_horizontal_set(sep, EINA_TRUE); + evas_object_show(sep); + elm_box_pack_end(box, sep); + + label = elm_label_add(box); + elm_object_text_set(label, _("Replace all occurences of text within the whole project.")); + evas_object_show(label); + elm_box_pack_end(box, label); + + sep = elm_separator_add(box); + elm_separator_horizontal_set(sep, EINA_TRUE); + evas_object_show(sep); + elm_box_pack_end(box, sep); + + table = elm_table_add(box); + evas_object_size_hint_weight_set(table, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(table, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_show(table); + + label = elm_label_add(table); + elm_object_text_set(label, _("Search: ")); + evas_object_show(label); + elm_table_pack(table, label, 0, 0, 1, 1); + + search = elm_entry_add(table); + elm_entry_single_line_set(search, EINA_TRUE); + elm_entry_scrollable_set(search, EINA_TRUE); + evas_object_size_hint_weight_set(search, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(search, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_show(search); + elm_table_pack(table, search, 1, 0, 1, 1); + + label = elm_label_add(table); + elm_object_text_set(label, _("Replace: ")); + evas_object_show(label); + elm_table_pack(table, label, 0, 1, 1, 1); + + replace = elm_entry_add(table); + elm_entry_single_line_set(replace, EINA_TRUE); + elm_entry_scrollable_set(replace, EINA_TRUE); + evas_object_size_hint_weight_set(replace, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(replace, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_show(replace); + elm_table_pack(table, replace, 1, 1, 1, 1); + + elm_box_pack_end(box, table); + + sep = elm_separator_add(box); + elm_separator_horizontal_set(sep, EINA_TRUE); + evas_object_show(sep); + elm_box_pack_end(box, sep); + + button = elm_button_add(popup); + elm_object_text_set(button, _("Cancel")); + elm_object_part_content_set(popup, "button1", button); + evas_object_smart_callback_add(button, "clicked", + _edi_mainview_project_search_popup_cancel_cb, NULL); + + button = elm_button_add(popup); + evas_object_data_set(button, "search", search); + elm_object_text_set(button, _("Replace")); + elm_object_part_content_set(popup, "button2", button); + evas_object_smart_callback_add(button, "clicked", + _edi_mainview_project_replace_cb, replace); + + evas_object_show(popup); +} + void edi_mainview_panel_remove(Edi_Mainview_Panel *panel) { diff --git a/src/bin/mainview/edi_mainview.h b/src/bin/mainview/edi_mainview.h index ce9fd39..4a317c1 100644 --- a/src/bin/mainview/edi_mainview.h +++ b/src/bin/mainview/edi_mainview.h @@ -237,6 +237,14 @@ void edi_mainview_goto_popup_show(); */ void edi_mainview_project_search_popup_show(); + +/** + * Present a popup to initiate a project-wide search and replace. + * + * @ingroup Content + */ +void edi_mainview_project_replace_popup_show(); + /** * @} *