netstar pushed a commit to branch master.

http://git.enlightenment.org/tools/edi.git/commit/?id=c826dee557ba7c9202418373500af471308a749a

commit c826dee557ba7c9202418373500af471308a749a
Author: Al Poole <nets...@gmail.com>
Date:   Thu Sep 28 01:23:18 2017 +0100

    search: Add project-wide search and replace feature.
---
 src/bin/edi_file.c              | 101 +++++++++++++++++++++++++
 src/bin/edi_file.h              |  21 ++++++
 src/bin/edi_main.c              |   8 ++
 src/bin/mainview/edi_mainview.c | 160 +++++++++++++++++++++++++++++++++++++++-
 src/bin/mainview/edi_mainview.h |   8 ++
 5 files changed, 296 insertions(+), 2 deletions(-)

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
@@ -32,6 +32,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
@@ -927,6 +927,13 @@ _edi_menu_find_project_cb(void *data EINA_UNUSED, 
Evas_Object *obj EINA_UNUSED,
 }
 
 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"
@@ -466,6 +467,35 @@ edi_mainview_goto_popup_show()
 }
 
 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,
                                    void *event_info 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 &amp; 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();
+
 /**
  * @}
  *

-- 


Reply via email to