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
This commit is contained in:
Al Poole 2017-03-30 23:03:19 +01:00 committed by Andy Williams
parent 4e3ff8f702
commit fb8b47c93c
10 changed files with 440 additions and 10 deletions

2
TODO
View File

@ -1,7 +1,7 @@
This project is in heavy development, we are currenty working towards the This project is in heavy development, we are currenty working towards the
"Code aware editor" phase, the following work is still to be done: "Code aware editor" phase, the following work is still to be done:
* Search / replace in project * Replace text (project-wide)
* Code folding * Code folding
* Split pane view (split editor into multiple tabs and split tab to multiple panes) * Split pane view (split editor into multiple tabs and split tab to multiple panes)
* Automatic code indenting / formatting * Automatic code indenting / formatting

View File

@ -29,6 +29,7 @@ screens/edi_screens.h \
edi_filepanel.h \ edi_filepanel.h \
edi_file.h \ edi_file.h \
edi_logpanel.h \ edi_logpanel.h \
edi_searchpanel.h \
edi_consolepanel.h \ edi_consolepanel.h \
mainview/edi_mainview_item.h \ mainview/edi_mainview_item.h \
mainview/edi_mainview.h mainview/edi_mainview.h
@ -47,6 +48,7 @@ screens/edi_settings.c \
edi_filepanel.c \ edi_filepanel.c \
edi_file.c \ edi_file.c \
edi_logpanel.c \ edi_logpanel.c \
edi_searchpanel.c \
edi_consolepanel.c \ edi_consolepanel.c \
mainview/edi_mainview_item.c \ mainview/edi_mainview_item.c \
mainview/edi_mainview.c \ mainview/edi_mainview.c \

View File

@ -6,6 +6,21 @@
static Evas_Object *_parent_obj, *_popup, *_popup_dir, *_edi_file_message_popup; static Evas_Object *_parent_obj, *_popup, *_popup_dir, *_edi_file_message_popup;
static const char *_directory_path; 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 static void
_edi_file_message_close_cb(void *data EINA_UNUSED, _edi_file_message_close_cb(void *data EINA_UNUSED,
Evas_Object *obj EINA_UNUSED, Evas_Object *obj EINA_UNUSED,

View File

@ -22,6 +22,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. * Create a file add dialogue and add it to the parent obj.
* *

View File

@ -45,14 +45,9 @@ _file_listing_empty(Edi_Dir_Data *dir, Elm_Object_Item *parent_it);
static Eina_Bool static Eina_Bool
_file_path_hidden(const char *path, Eina_Bool filter) _file_path_hidden(const char *path, Eina_Bool filter)
{ {
Edi_Build_Provider *provider;
const char *relative; const char *relative;
provider = edi_build_provider_for_project_get(); if (edi_file_path_hidden(path))
if (provider && provider->file_hidden_is(path))
return EINA_TRUE;
if (ecore_file_file_get(path)[0] == '.')
return EINA_TRUE; return EINA_TRUE;
if (!filter || !_filter_set) if (!filter || !_filter_set)

View File

@ -20,6 +20,7 @@
#include "edi_file.h" #include "edi_file.h"
#include "edi_logpanel.h" #include "edi_logpanel.h"
#include "edi_consolepanel.h" #include "edi_consolepanel.h"
#include "edi_searchpanel.h"
#include "mainview/edi_mainview.h" #include "mainview/edi_mainview.h"
#include "screens/edi_screens.h" #include "screens/edi_screens.h"
@ -37,8 +38,8 @@ typedef struct _Edi_Panel_Slide_Effect
#define COPYRIGHT "Copyright © 2014-2015 Andy Williams <andy@andyilliams.me> and various contributors (see AUTHORS)." #define COPYRIGHT "Copyright © 2014-2015 Andy Williams <andy@andyilliams.me> and various contributors (see AUTHORS)."
static Evas_Object *_edi_toolbar, *_edi_leftpanes, *_edi_bottompanes; static Evas_Object *_edi_toolbar, *_edi_leftpanes, *_edi_bottompanes;
static Evas_Object *_edi_logpanel, *_edi_consolepanel, *_edi_testpanel; static Evas_Object *_edi_logpanel, *_edi_consolepanel, *_edi_testpanel, *_edi_searchpanel;
static Elm_Object_Item *_edi_logpanel_item, *_edi_consolepanel_item, *_edi_testpanel_item; static Elm_Object_Item *_edi_logpanel_item, *_edi_consolepanel_item, *_edi_testpanel_item, *_edi_searchpanel_item;
static Elm_Object_Item *_edi_selected_bottompanel; static Elm_Object_Item *_edi_selected_bottompanel;
static Evas_Object *_edi_filepanel, *_edi_filepanel_icon; static Evas_Object *_edi_filepanel, *_edi_filepanel_icon;
@ -105,6 +106,8 @@ _edi_panel_tab_for_index(int index)
return _edi_consolepanel; return _edi_consolepanel;
if (index == 2) if (index == 2)
return _edi_testpanel; return _edi_testpanel;
if (index == 3)
return _edi_searchpanel;
return _edi_logpanel; return _edi_logpanel;
} }
@ -249,7 +252,7 @@ _edi_toggle_panel(void *data, Evas_Object *obj, void *event_info)
if (obj) if (obj)
elm_object_focus_set(obj, EINA_FALSE); elm_object_focus_set(obj, EINA_FALSE);
for (c = 0; c <= 2; c++) for (c = 0; c <= 3; c++)
if (c != index) if (c != index)
evas_object_hide(_edi_panel_tab_for_index(c)); 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); 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 * static Evas_Object *
edi_content_setup(Evas_Object *win, const char *path) 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_logpanel = elm_box_add(win);
_edi_consolepanel = elm_box_add(win); _edi_consolepanel = elm_box_add(win);
_edi_testpanel = elm_box_add(win); _edi_testpanel = elm_box_add(win);
_edi_searchpanel = elm_box_add(win);
// add main content // add main content
content_out = elm_box_add(win); content_out = elm_box_add(win);
@ -387,6 +398,8 @@ edi_content_setup(Evas_Object *win, const char *path)
_edi_toggle_panel, "1"); _edi_toggle_panel, "1");
_edi_testpanel_item = elm_toolbar_item_append(tb, "stock_up", "Tests", _edi_testpanel_item = elm_toolbar_item_append(tb, "stock_up", "Tests",
_edi_toggle_panel, "2"); _edi_toggle_panel, "2");
_edi_searchpanel_item = elm_toolbar_item_append(tb, "stock_up", "Search",
_edi_toggle_panel, "3");
// add lower panel panes // add lower panel panes
logpanels = elm_table_add(logpane); logpanels = elm_table_add(logpane);
@ -407,7 +420,15 @@ edi_content_setup(Evas_Object *win, const char *path)
edi_testpanel_add(_edi_testpanel); edi_testpanel_add(_edi_testpanel);
elm_table_pack(logpanels, _edi_testpanel, 0, 0, 1, 1); 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); elm_object_part_content_set(logpane, "bottom", logpanels);
if (_edi_project_config->gui.bottomopen) if (_edi_project_config->gui.bottomopen)
{ {
elm_panes_content_right_size_set(logpane, _edi_project_config->gui.bottomsize); 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"); elm_toolbar_item_icon_set(_edi_testpanel_item, "stock_down");
_edi_selected_bottompanel = _edi_testpanel_item; _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 else
{ {
elm_toolbar_item_icon_set(_edi_logpanel_item, "stock_down"); elm_toolbar_item_icon_set(_edi_logpanel_item, "stock_down");
@ -733,6 +759,13 @@ _edi_menu_find_cb(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED,
edi_mainview_search(); edi_mainview_search();
} }
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 static void
_edi_menu_findfile_cb(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, _edi_menu_findfile_cb(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED,
void *event_info 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-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, "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_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); 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); elm_menu_item_add(menu, menu_it, "system-run", "Build", _edi_menu_build_cb, NULL);

244
src/bin/edi_searchpanel.c Normal file
View File

@ -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);
}

60
src/bin/edi_searchpanel.h Normal file
View File

@ -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_ */

View File

@ -13,12 +13,15 @@
#include "editor/edi_editor.h" #include "editor/edi_editor.h"
#include "edi_content_provider.h" #include "edi_content_provider.h"
#include "../edi_searchpanel.h"
#include "edi_private.h" #include "edi_private.h"
#include "edi_config.h" #include "edi_config.h"
static Evas_Object *_content_frame, *_current_view, *tb, *_main_win, *_welcome_panel, *_tab_scroller; 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_choose_popup, *_edi_mainview_goto_popup;
static Evas_Object *_edi_mainview_search_project_popup;
static Edi_Path_Options *_edi_mainview_choose_options; static Edi_Path_Options *_edi_mainview_choose_options;
static Eina_List *_edi_mainview_items = NULL; static Eina_List *_edi_mainview_items = NULL;
@ -724,6 +727,66 @@ edi_mainview_goto_popup_show()
elm_object_focus_set(input, EINA_TRUE); 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 void
edi_mainview_add(Evas_Object *parent, Evas_Object *win) edi_mainview_add(Evas_Object *parent, Evas_Object *win)
{ {

View File

@ -177,6 +177,13 @@ void edi_mainview_goto(int line);
*/ */
void edi_mainview_goto_popup_show(); void edi_mainview_goto_popup_show();
/**
* Present a popup that will initiate a project search.
*
* @ingroup Content
*/
void edi_mainview_project_search_popup_show();
/** /**
* @} * @}
* *