ajwillia-ms pushed a commit to branch master.

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

commit fb8b47c93cec745c938d212ee2cc615946b940fb
Author: Al Poole <nets...@gmail.com>
Date:   Thu Mar 30 23:03:19 2017 +0100

    Edi -> Search Project - Add initial support for search in project.
    
    Summary: Almost there.
    
    Reviewers: ajwillia.ms
    
    Reviewed By: ajwillia.ms
    
    Differential Revision: https://phab.enlightenment.org/D4752
---
 TODO                            |   2 +-
 src/bin/Makefile.am             |   2 +
 src/bin/edi_file.c              |  15 +++
 src/bin/edi_file.h              |   9 ++
 src/bin/edi_filepanel.c         |   7 +-
 src/bin/edi_main.c              |  41 ++++++-
 src/bin/edi_searchpanel.c       | 244 ++++++++++++++++++++++++++++++++++++++++
 src/bin/edi_searchpanel.h       |  60 ++++++++++
 src/bin/mainview/edi_mainview.c |  63 +++++++++++
 src/bin/mainview/edi_mainview.h |   7 ++
 10 files changed, 440 insertions(+), 10 deletions(-)

diff --git a/TODO b/TODO
index fb4797c..4596c69 100644
--- a/TODO
+++ b/TODO
@@ -1,7 +1,7 @@
 This project is in heavy development, we are currenty working towards the
 "Code aware editor" phase, the following work is still to be done:
 
-* Search / replace in project
+* Replace text (project-wide)
 * Code folding
 * Split pane view (split editor into multiple tabs and split tab to multiple 
panes)
 * Automatic code indenting / formatting
diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am
index cdcedb0..baf0183 100644
--- a/src/bin/Makefile.am
+++ b/src/bin/Makefile.am
@@ -29,6 +29,7 @@ screens/edi_screens.h \
 edi_filepanel.h \
 edi_file.h \
 edi_logpanel.h \
+edi_searchpanel.h \
 edi_consolepanel.h \
 mainview/edi_mainview_item.h \
 mainview/edi_mainview.h
@@ -47,6 +48,7 @@ screens/edi_settings.c \
 edi_filepanel.c \
 edi_file.c \
 edi_logpanel.c \
+edi_searchpanel.c \
 edi_consolepanel.c \
 mainview/edi_mainview_item.c \
 mainview/edi_mainview.c \
diff --git a/src/bin/edi_file.c b/src/bin/edi_file.c
index 0ac22b9..1a06d8b 100644
--- a/src/bin/edi_file.c
+++ b/src/bin/edi_file.c
@@ -6,6 +6,21 @@
 static Evas_Object *_parent_obj, *_popup, *_popup_dir, 
*_edi_file_message_popup;
 static const char *_directory_path;
 
+Eina_Bool
+edi_file_path_hidden(const char *path)
+{
+   Edi_Build_Provider *provider;
+
+   provider = edi_build_provider_for_project_get();
+   if (provider && provider->file_hidden_is(path))
+     return EINA_TRUE;
+
+   if (ecore_file_file_get(path)[0] == '.')
+     return EINA_TRUE;
+
+   return EINA_FALSE;
+}
+
 static void
 _edi_file_message_close_cb(void *data EINA_UNUSED,
                      Evas_Object *obj EINA_UNUSED,
diff --git a/src/bin/edi_file.h b/src/bin/edi_file.h
index cc1e3e5..233c8b3 100644
--- a/src/bin/edi_file.h
+++ b/src/bin/edi_file.h
@@ -23,6 +23,15 @@ extern "C" {
  */
 
 /**
+ * Check the path is not hidden according to project rules.
+ * 
+ * @param path The file path to check.
+ * @ingroup Lookup
+ */
+
+Eina_Bool edi_file_path_hidden(const char *path);
+
+/**
  * Create a file add dialogue and add it to the parent obj.
  *
  * @param parent The object into which the UI will load.
diff --git a/src/bin/edi_filepanel.c b/src/bin/edi_filepanel.c
index e9ef1a5..3fad056 100644
--- a/src/bin/edi_filepanel.c
+++ b/src/bin/edi_filepanel.c
@@ -45,14 +45,9 @@ _file_listing_empty(Edi_Dir_Data *dir, Elm_Object_Item 
*parent_it);
 static Eina_Bool
 _file_path_hidden(const char *path, Eina_Bool filter)
 {
-   Edi_Build_Provider *provider;
    const char *relative;
 
-   provider = edi_build_provider_for_project_get();
-   if (provider && provider->file_hidden_is(path))
-     return EINA_TRUE;
-
-   if (ecore_file_file_get(path)[0] == '.')
+   if (edi_file_path_hidden(path))
      return EINA_TRUE;
 
    if (!filter || !_filter_set)
diff --git a/src/bin/edi_main.c b/src/bin/edi_main.c
index efa477a..ebd557a 100644
--- a/src/bin/edi_main.c
+++ b/src/bin/edi_main.c
@@ -20,6 +20,7 @@
 #include "edi_file.h"
 #include "edi_logpanel.h"
 #include "edi_consolepanel.h"
+#include "edi_searchpanel.h"
 #include "mainview/edi_mainview.h"
 #include "screens/edi_screens.h"
 
@@ -37,8 +38,8 @@ typedef struct _Edi_Panel_Slide_Effect
 #define COPYRIGHT "Copyright © 2014-2015 Andy Williams <a...@andyilliams.me> 
and various contributors (see AUTHORS)."
 
 static Evas_Object *_edi_toolbar, *_edi_leftpanes, *_edi_bottompanes;
-static Evas_Object *_edi_logpanel, *_edi_consolepanel, *_edi_testpanel;
-static Elm_Object_Item *_edi_logpanel_item, *_edi_consolepanel_item, 
*_edi_testpanel_item;
+static Evas_Object *_edi_logpanel, *_edi_consolepanel, *_edi_testpanel, 
*_edi_searchpanel;
+static Elm_Object_Item *_edi_logpanel_item, *_edi_consolepanel_item, 
*_edi_testpanel_item, *_edi_searchpanel_item;
 static Elm_Object_Item *_edi_selected_bottompanel;
 static Evas_Object *_edi_filepanel, *_edi_filepanel_icon;
 
@@ -105,6 +106,8 @@ _edi_panel_tab_for_index(int index)
      return _edi_consolepanel;
    if (index == 2)
      return _edi_testpanel;
+   if (index == 3)
+     return _edi_searchpanel;
 
    return _edi_logpanel;
 }
@@ -249,7 +252,7 @@ _edi_toggle_panel(void *data, Evas_Object *obj, void 
*event_info)
    if (obj)
      elm_object_focus_set(obj, EINA_FALSE);
 
-   for (c = 0; c <= 2; c++)
+   for (c = 0; c <= 3; c++)
      if (c != index)
        evas_object_hide(_edi_panel_tab_for_index(c));
 
@@ -299,6 +302,13 @@ edi_testpanel_show()
      elm_toolbar_item_selected_set(_edi_testpanel_item, EINA_TRUE);
 }
 
+void
+edi_searchpanel_show()
+{
+   if (_edi_selected_bottompanel != _edi_searchpanel_item)
+     elm_toolbar_item_selected_set(_edi_searchpanel_item, EINA_TRUE);
+}
+
 static Evas_Object *
 edi_content_setup(Evas_Object *win, const char *path)
 {
@@ -317,6 +327,7 @@ edi_content_setup(Evas_Object *win, const char *path)
    _edi_logpanel = elm_box_add(win);
    _edi_consolepanel = elm_box_add(win);
    _edi_testpanel = elm_box_add(win);
+   _edi_searchpanel = elm_box_add(win);
 
    // add main content
    content_out = elm_box_add(win);
@@ -387,6 +398,8 @@ edi_content_setup(Evas_Object *win, const char *path)
                                                     _edi_toggle_panel, "1");
    _edi_testpanel_item = elm_toolbar_item_append(tb, "stock_up", "Tests",
                                                  _edi_toggle_panel, "2");
+   _edi_searchpanel_item = elm_toolbar_item_append(tb, "stock_up", "Search",
+                                                 _edi_toggle_panel, "3");
 
    // add lower panel panes
    logpanels = elm_table_add(logpane);
@@ -407,7 +420,15 @@ edi_content_setup(Evas_Object *win, const char *path)
 
    edi_testpanel_add(_edi_testpanel);
    elm_table_pack(logpanels, _edi_testpanel, 0, 0, 1, 1);
+
+   evas_object_size_hint_weight_set(_edi_searchpanel, EVAS_HINT_EXPAND, 
EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(_edi_searchpanel, EVAS_HINT_FILL, 
EVAS_HINT_FILL);
+
+   edi_searchpanel_add(_edi_searchpanel);
+   elm_table_pack(logpanels, _edi_searchpanel, 0, 0, 1, 1);
+
    elm_object_part_content_set(logpane, "bottom", logpanels);
+
    if (_edi_project_config->gui.bottomopen)
      {
         elm_panes_content_right_size_set(logpane, 
_edi_project_config->gui.bottomsize);
@@ -421,6 +442,11 @@ edi_content_setup(Evas_Object *win, const char *path)
              elm_toolbar_item_icon_set(_edi_testpanel_item, "stock_down");
              _edi_selected_bottompanel = _edi_testpanel_item;
           }
+        else if (_edi_project_config->gui.bottomtab == 3)
+          {
+             elm_toolbar_item_icon_set(_edi_searchpanel_item, "stock_down");
+             _edi_selected_bottompanel = _edi_searchpanel_item;
+          }
         else
           {
              elm_toolbar_item_icon_set(_edi_logpanel_item, "stock_down");
@@ -734,6 +760,13 @@ _edi_menu_find_cb(void *data EINA_UNUSED, Evas_Object *obj 
EINA_UNUSED,
 }
 
 static void
+_edi_menu_find_project_cb(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED,
+                      void *event_info EINA_UNUSED)
+{
+   edi_mainview_project_search_popup_show();
+}
+
+static void
 _edi_menu_findfile_cb(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED,
                       void *event_info EINA_UNUSED)
 {
@@ -821,6 +854,8 @@ _edi_menu_setup(Evas_Object *win)
    elm_menu_item_add(menu, menu_it, "edit-find-replace", "Find & Replace", 
_edi_menu_find_cb, NULL);
    elm_menu_item_add(menu, menu_it, "edit-find", "Find file", 
_edi_menu_findfile_cb, NULL);
    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);
 
    menu_it = elm_menu_item_add(menu, NULL, NULL, "Build", NULL, NULL);
    elm_menu_item_add(menu, menu_it, "system-run", "Build", _edi_menu_build_cb, 
NULL);
diff --git a/src/bin/edi_searchpanel.c b/src/bin/edi_searchpanel.c
new file mode 100644
index 0000000..cb6843f
--- /dev/null
+++ b/src/bin/edi_searchpanel.c
@@ -0,0 +1,244 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <Eo.h>
+#include <Eina.h>
+#include <Elementary.h>
+
+#include <string.h>
+#include "edi_file.h"
+#include "edi_searchpanel.h"
+#include "edi_config.h"
+#include "mainview/edi_mainview.h"
+
+#include "edi_private.h"
+
+static Evas_Object *_info_widget;
+static Elm_Code *_elm_code;
+
+static Ecore_Thread *_search_thread = NULL;
+static Eina_Bool _searching = EINA_FALSE;
+static char *_search_text = NULL;
+
+static void
+_edi_searchpanel_line_cb(void *data EINA_UNUSED, const Efl_Event *event)
+{
+   Elm_Code_Line *line;
+
+   line = (Elm_Code_Line *)event->info;
+
+   if (line->data)
+     line->status = ELM_CODE_STATUS_TYPE_ERROR;
+}
+
+static Eina_Bool
+_edi_searchpanel_config_changed_cb(void *data EINA_UNUSED, int type 
EINA_UNUSED, void *event EINA_UNUSED)
+{
+   elm_code_widget_font_set(_info_widget, _edi_project_config->font.name, 
_edi_project_config->font.size);
+
+   return ECORE_CALLBACK_RENEW;
+}
+
+static void
+_edi_searchpanel_line_clicked_cb(void *data EINA_UNUSED, const Efl_Event 
*event)
+{
+   Elm_Code_Line *line;
+   const char *content;
+   unsigned int length;
+   char *filename, *filename_end;
+   char *line_start, *line_end;
+   Eina_Bool success = EINA_FALSE;
+
+   filename_end = line_start = line_end = NULL;
+
+   line = (Elm_Code_Line *)event->info;
+   if (!line) return;
+   content = elm_code_line_text_get(line, &length);
+   if (!content) return;
+
+   filename = strdup(content);
+   if (!filename) return;
+
+   filename_end = strchr(filename, ':');
+   if (filename_end)
+     line_start = filename_end + 1;
+   if (line_start)
+     line_end = strchr(line_start, ' ');
+   if (line_end)
+     {
+        *filename_end = '\0';
+        *line_end = '\0';
+        success = EINA_TRUE;
+     }
+
+   if (success)
+     {
+        edi_mainview_open_path(filename);
+        edi_mainview_goto(atoi(line_start));
+     }
+   
+   free(filename);
+}
+
+void _edi_searchpanel_project_search_file(const char *filename)
+{
+   Elm_Code *code;
+   Elm_Code_File *code_file; 
+   Eina_List *item;
+   Elm_Code_Line *line;
+   unsigned int len;
+   const char *text;
+   char *tmp;
+   static char buf[1024];
+   static char data[1024];
+
+   code = elm_code_create();
+   code_file = elm_code_file_open(code, filename);
+
+   EINA_LIST_FOREACH(code->file->lines, item, line)
+     {
+        int found = elm_code_line_text_strpos(line, _search_text, 0);
+        if (found != ELM_CODE_TEXT_NOT_FOUND) 
+          {
+             text = elm_code_line_text_get(line, &len);
+             if (text)
+               {
+                  if (line->length >= sizeof(data))
+                    len = sizeof(data);
+                  else
+                    len = line->length + 1;
+                  snprintf(data, len, "%s", text);
+                  snprintf(buf, sizeof(buf), "%s:%d -> %s", filename, 
line->number, data);
+                  tmp = strdup(buf);
+                  ecore_thread_feedback(_search_thread, tmp);
+               }
+          }
+     }
+
+    elm_code_file_close(code_file);
+}
+
+Eina_Bool
+_file_ignore(const char *filename)
+{
+   if ((eina_str_has_extension(filename, ".png")   ||
+        eina_str_has_extension(filename, ".PNG")   ||
+        eina_str_has_extension(filename, ".jpg")   ||
+        eina_str_has_extension(filename, ".jpeg")  ||
+        eina_str_has_extension(filename, ".JPG")   ||
+        eina_str_has_extension(filename, ".JPEG" ) ||
+        eina_str_has_extension(filename, ".bmp")   ||
+        eina_str_has_extension(filename, ".eet")   ||
+        eina_str_has_extension(filename, ".edj")
+       ))
+     return EINA_TRUE;
+
+   return EINA_FALSE;
+}
+
+void
+_edi_searchpanel_project_search(const char *directory)
+{
+   Eina_List *files, *item;
+   char *file;
+   char *path;
+
+   files = ecore_file_ls(directory);
+
+   EINA_LIST_FOREACH(files, item, file)
+     {
+        if (_file_ignore(file)) continue;
+
+        path = edi_path_append(directory, file);
+        if (!edi_file_path_hidden(path))
+          {
+             if (ecore_file_is_dir(path))
+               _edi_searchpanel_project_search(path);
+             else
+               _edi_searchpanel_project_search_file(path);
+          }
+
+        free (path);
+        if (ecore_thread_check(_search_thread)) return;
+     }
+}
+
+static void
+_search_feedback_cb(void *data EINA_UNUSED, Ecore_Thread *thread EINA_UNUSED, 
void *msg)
+{
+   char *text = msg;
+
+   elm_code_file_line_append(_elm_code->file, text, strlen(text), NULL);
+   free(text);
+}
+
+static void
+_search_end_cb(void *data EINA_UNUSED, Ecore_Thread *thread EINA_UNUSED)
+{
+   _search_thread = NULL;
+   _searching = EINA_FALSE;
+}
+
+static void
+_search_cancel_cb(void *data EINA_UNUSED, Ecore_Thread *thread EINA_UNUSED)
+{
+   while ((ecore_thread_wait(_search_thread, 0.1)) != EINA_TRUE);
+   _searching = EINA_FALSE;
+}
+
+static void
+_search_begin_cb(void *data, Ecore_Thread *thread EINA_UNUSED)
+{
+   const char *path = data;
+
+   _searching = EINA_TRUE;
+
+   _edi_searchpanel_project_search(path);
+
+   if (ecore_thread_check(_search_thread)) return;
+}
+
+void edi_searchpanel_find(const char *text)
+{
+   const char *path;
+
+   if (!text || strlen(text) == 0) return;
+
+   if (_searching) _search_cancel_cb(NULL, _search_thread);
+
+   if (_search_text) free(_search_text);
+   _search_text = strdup(text);
+
+   path = edi_project_get();
+
+   elm_code_file_clear(_elm_code->file);
+
+   edi_searchpanel_show();
+
+   _search_thread = ecore_thread_feedback_run(_search_begin_cb, 
_search_feedback_cb,
+                                      _search_end_cb, _search_cancel_cb,
+                                      path, EINA_FALSE);
+}
+
+void edi_searchpanel_add(Evas_Object *parent)
+{
+   Elm_Code_Widget *widget;
+   Elm_Code *code;
+   code = elm_code_create();
+   widget = elm_code_widget_add(parent, code);
+   elm_obj_code_widget_font_set(widget, _edi_project_config->font.name, 
_edi_project_config->font.size);
+   elm_obj_code_widget_gravity_set(widget, 0.0, 1.0);
+   efl_event_callback_add(widget, &ELM_CODE_EVENT_LINE_LOAD_DONE, 
_edi_searchpanel_line_cb, NULL);
+   efl_event_callback_add(widget, ELM_OBJ_CODE_WIDGET_EVENT_LINE_CLICKED, 
_edi_searchpanel_line_clicked_cb, NULL);
+   evas_object_size_hint_weight_set(widget, EVAS_HINT_EXPAND, 
EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(widget, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   evas_object_show(widget);
+
+   _elm_code = code;
+   _info_widget = widget;
+
+   elm_box_pack_end(parent, widget);
+   ecore_event_handler_add(EDI_EVENT_CONFIG_CHANGED, 
_edi_searchpanel_config_changed_cb, NULL);
+}
+
diff --git a/src/bin/edi_searchpanel.h b/src/bin/edi_searchpanel.h
new file mode 100644
index 0000000..144a04d
--- /dev/null
+++ b/src/bin/edi_searchpanel.h
@@ -0,0 +1,60 @@
+#ifndef EDI_SEARCHPANEL_H_
+# define EDI_SEARCHPANEL_H_
+
+#include <Elementary.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file
+ * @brief These routines are used for managing the Edi search panel.
+ */
+
+/**
+ * @brief UI management functions.
+ * @defgroup UI
+ *
+ * @{
+ *
+ * Initialisation and management of the search panel UI
+ *
+ */
+
+/**
+ * Show the Edi searchpanel - animating on to screen if required.
+ *
+ * @ingroup UI
+ */
+void edi_searchpanel_show();
+
+/**
+ * Initialize a new Edi searchpanel and add it to the parent panel.
+ *
+ * @param parent The panel into which the panel will be loaded.
+ *
+ * @ingroup UI
+ */
+void edi_searchpanel_add(Evas_Object *parent);
+
+/**
+ * Search in project for text and print results to the panel.
+ * 
+ * @param text The search string to use when parsing project files.
+ *
+ * @ingroup UI
+ */
+void edi_searchpanel_find(const char *text);
+
+/**
+ * @}
+ */
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EDI_LOGPANEL_H_ */
diff --git a/src/bin/mainview/edi_mainview.c b/src/bin/mainview/edi_mainview.c
index 2d8f641..173c500 100644
--- a/src/bin/mainview/edi_mainview.c
+++ b/src/bin/mainview/edi_mainview.c
@@ -13,12 +13,15 @@
 
 #include "editor/edi_editor.h"
 #include "edi_content_provider.h"
+#include "../edi_searchpanel.h"
 
 #include "edi_private.h"
 #include "edi_config.h"
 
 static Evas_Object *_content_frame, *_current_view, *tb, *_main_win, 
*_welcome_panel, *_tab_scroller;
 static Evas_Object *_edi_mainview_choose_popup, *_edi_mainview_goto_popup;
+static Evas_Object *_edi_mainview_search_project_popup;
+
 static Edi_Path_Options *_edi_mainview_choose_options;
 
 static Eina_List *_edi_mainview_items = NULL;
@@ -724,6 +727,66 @@ edi_mainview_goto_popup_show()
    elm_object_focus_set(input, EINA_TRUE);
 }
 
+static void
+_edi_mainview_project_search_popup_cancel_cb(void *data EINA_UNUSED,
+                                   Evas_Object *obj EINA_UNUSED,
+                                   void *event_info EINA_UNUSED)
+{
+   evas_object_del(_edi_mainview_search_project_popup);
+}
+
+static void
+_edi_mainview_project_search_cb(void *data,
+                             Evas_Object *obj EINA_UNUSED,
+                             void *event_info EINA_UNUSED)
+{
+   const char *text;
+
+   text = elm_entry_entry_get((Evas_Object *) data);
+   if (!text || strlen(text) == 0) return;
+
+   edi_searchpanel_find(text);
+   evas_object_del(_edi_mainview_search_project_popup);
+}
+
+void
+edi_mainview_project_search_popup_show(void)
+{
+   Evas_Object *popup, *box, *input, *button;
+
+   popup = elm_popup_add(_main_win);
+   _edi_mainview_search_project_popup = popup;
+   elm_object_part_text_set(popup, "title,text",
+                            "Search for");
+
+   box = elm_box_add(popup);
+   elm_box_horizontal_set(box, EINA_FALSE);
+   elm_object_content_set(popup, box);
+
+   input = elm_entry_add(box);
+   elm_entry_single_line_set(input, EINA_TRUE);
+   evas_object_event_callback_add(input, EVAS_CALLBACK_KEY_UP, 
_edi_mainview_goto_popup_key_up_cb, NULL);
+   evas_object_size_hint_weight_set(input, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   evas_object_size_hint_align_set(input, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   evas_object_show(input);
+   elm_box_pack_end(box, input);
+
+   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);
+   elm_object_text_set(button, "search");
+   elm_object_part_content_set(popup, "button2", button);
+   evas_object_smart_callback_add(button, "clicked",
+                                       _edi_mainview_project_search_cb, input);
+
+   evas_object_show(popup);
+   elm_object_focus_set(input, EINA_TRUE);
+}
+
 void
 edi_mainview_add(Evas_Object *parent, Evas_Object *win)
 {
diff --git a/src/bin/mainview/edi_mainview.h b/src/bin/mainview/edi_mainview.h
index d1580fe..3262f46 100644
--- a/src/bin/mainview/edi_mainview.h
+++ b/src/bin/mainview/edi_mainview.h
@@ -178,6 +178,13 @@ void edi_mainview_goto(int line);
 void edi_mainview_goto_popup_show();
 
 /**
+ * Present a popup that will initiate a project search.
+ *
+ * @ingroup Content
+ */
+void edi_mainview_project_search_popup_show();
+
+/**
  * @}
  *
  *

-- 


Reply via email to