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(); + +/** * @} * * --