diff --git a/src/bin/edi_consolepanel.c b/src/bin/edi_consolepanel.c index a228890..fd5a312 100644 --- a/src/bin/edi_consolepanel.c +++ b/src/bin/edi_consolepanel.c @@ -6,12 +6,17 @@ #include #include +#include +#include +#include #include "edi_consolepanel.h" +#include "edi_mainview.h" #include "edi_private.h" static Evas_Object *_console_box; +static const char *_current_dir = NULL; static const char *_edi_consolepanel_icon_for_line(const char *line) { @@ -25,18 +30,87 @@ static const char *_edi_consolepanel_icon_for_line(const char *line) return NULL; } +static Eina_Bool _startswith_location(const char *line) +{ + regex_t regex; + int ret; + + regcomp(®ex, "^[^/].*:[0-9]*:[0-9]* ", 0); + ret = !regexec(®ex, line, 0, NULL, 0); + + regfree(®ex); + return ret; +} + +static void _edi_consolepanel_clicked_cb(void *data, Evas *e EINA_UNUSED, + Evas_Object *obj EINA_UNUSED, Evas_Event_Mouse_Down *ev) +{ + Edi_Path_Options *options; + + if (strstr(data, edi_project_get()) != data) + return; + + options = edi_path_options_create(data); + edi_mainview_open(options); +} + +static void _edi_consolepanel_parse_directory(const char *line) +{ + const char *pos; + + pos = strstr(line, "Entering directory '"); + if (pos) + { + if (_current_dir) + eina_stringshare_del(_current_dir); + + _current_dir = eina_stringshare_add_length(pos + 20, strlen(pos) - 21); + } +} + static void _edi_consolepanel_append_line_type(const char *line, Eina_Bool err) { Evas_Object *txt, *icon, *box; - const char *type = NULL; + const char *buf, *pos, *file, *path, *type = NULL, *cursor = NULL; + int length; txt = elm_label_add(_console_box); + if (err) evas_object_color_set(txt, 255, 63, 63, 255); else evas_object_color_set(txt, 255, 255, 255, 255); - elm_object_text_set(txt, line); + if (_startswith_location(line)) + { + cursor = ELM_CURSOR_HAND1; + elm_object_cursor_set(txt, cursor); + elm_object_cursor_theme_search_enabled_set(txt, EINA_TRUE); + + pos = strstr(line, " "); + length = strlen(line) - strlen(pos); + file = eina_stringshare_add_length(line, length); + + buf = malloc(sizeof(char) * (strlen(line) + 8)); + snprintf(buf, strlen(line) + 8, "%s%s/n", file, pos); + elm_object_text_set(txt, buf); + + length = strlen(_current_dir) + strlen(file) + 2; + path = malloc(sizeof(char) * length); + snprintf(path, length, "%s/%s\n", _current_dir, file); + + evas_object_event_callback_add(txt, EVAS_CALLBACK_MOUSE_DOWN, + _edi_consolepanel_clicked_cb, eina_stringshare_add(path)); + + free(path); + free(buf); + } + else + { + _edi_consolepanel_parse_directory(line); + elm_object_text_set(txt, line); + } + evas_object_size_hint_weight_set(txt, EVAS_HINT_EXPAND, 0.0); evas_object_size_hint_align_set(txt, 0.0, EVAS_HINT_FILL); evas_object_show(txt); @@ -48,7 +122,14 @@ static void _edi_consolepanel_append_line_type(const char *line, Eina_Bool err) evas_object_size_hint_min_set(icon, 14, 14); evas_object_size_hint_max_set(icon, 14, 14); if (type) - elm_icon_standard_set(icon, type); + { + elm_icon_standard_set(icon, type); + if (cursor) + { + elm_object_cursor_set(icon, cursor); + elm_object_cursor_theme_search_enabled_set(icon, EINA_TRUE); + } + } evas_object_show(icon); box = elm_box_add(_console_box); diff --git a/src/bin/edi_consolepanel.h b/src/bin/edi_consolepanel.h index 0a9ba61..bd51a8b 100644 --- a/src/bin/edi_consolepanel.h +++ b/src/bin/edi_consolepanel.h @@ -3,6 +3,8 @@ #include +#include "Edi.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/src/bin/edi_main.c b/src/bin/edi_main.c index 3f7974e..ee27d4a 100644 --- a/src/bin/edi_main.c +++ b/src/bin/edi_main.c @@ -36,15 +36,20 @@ _edi_exit(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info static void _edi_file_open_cb(const char *path, const char *type, Eina_Bool newwin) { + Edi_Path_Options *options; + + options = edi_path_options_create(path); + options->type = type; + if (type == NULL) INF("Opening %s", path); else INF("Opening %s as %s", path, type); if (newwin) - edi_mainview_open_window_path(path, type); + edi_mainview_open_window(options); else - edi_mainview_open_path(path, type); + edi_mainview_open(options); } static void @@ -159,7 +164,7 @@ _tb_new_create_cb(void *data, path = edi_project_file_path_get(name); fclose(fopen(path, "w")); - edi_mainview_open_path(path, NULL); + edi_mainview_open_path(path); evas_object_del(_edi_new_popup); free((char*)path); diff --git a/src/bin/edi_mainview.c b/src/bin/edi_mainview.c index 4104215..fde5b8e 100644 --- a/src/bin/edi_mainview.c +++ b/src/bin/edi_mainview.c @@ -15,7 +15,7 @@ static Evas_Object *nf, *tb, *_main_win; static Evas_Object *_edi_mainview_choose_popup; -static const char *_edi_mainview_choose_path; +static Edi_Path_Options *_edi_mainview_choose_options; static Eina_List *_edi_mainview_items = NULL; @@ -152,20 +152,23 @@ _edi_mainview_content_create(const char *path, const char *type, Evas_Object *pa } static void -_edi_mainview_item_tab_add(const char *path, const char *type) +_edi_mainview_item_tab_add(Edi_Path_Options *options) { Evas_Object *content; Elm_Object_Item *it, *tab; Edi_Mainview_Item *item; - content = _edi_mainview_content_create(path, type, nf); + content = _edi_mainview_content_create(options->path, options->type, nf); + if (options->line) + edi_mainview_goto(options->line); + it = elm_naviframe_item_simple_push(nf, content); elm_naviframe_item_style_set(it, "overlap"); - tab = elm_toolbar_item_append(tb, NULL, basename(path), _promote, it); + tab = elm_toolbar_item_append(tb, NULL, basename(options->path), _promote, it); elm_toolbar_item_selected_set(tab, EINA_TRUE); - item = _edi_mainview_item_add(path, tab, it, NULL); + item = _edi_mainview_item_add(options->path, tab, it, NULL); elm_object_item_data_set(it, item); } @@ -195,20 +198,20 @@ _edi_mainview_win_title_get(const char *path) } static void -_edi_mainview_item_win_add(const char *path, const char *type) +_edi_mainview_item_win_add(Edi_Path_Options *options) { Evas_Object *win, *content; Edi_Mainview_Item *item; - win = elm_win_util_standard_add("mainview", _edi_mainview_win_title_get(path)); + win = elm_win_util_standard_add("mainview", _edi_mainview_win_title_get(options->path)); if (!win) return; elm_win_focus_highlight_enabled_set(win, EINA_TRUE); evas_object_smart_callback_add(win, "delete,request", _edi_mainview_win_exit, NULL); - item = _edi_mainview_item_add(path, NULL, NULL, win); + item = _edi_mainview_item_add(options->path, NULL, NULL, win); evas_object_data_set(win, "edi_mainview_item", item); - content = _edi_mainview_content_create(path, type, win); + content = _edi_mainview_content_create(options->path, options->type, win); elm_win_resize_object_add(win, content); evas_object_resize(win, 380, 260); @@ -221,8 +224,9 @@ _edi_mainview_choose_type_tab_cb(void *data, void *event_info EINA_UNUSED) { evas_object_del(_edi_mainview_choose_popup); - edi_mainview_open_path(_edi_mainview_choose_path, (const char *) data); + _edi_mainview_choose_options->type = (const char *) data; + edi_mainview_open(_edi_mainview_choose_options); } static void @@ -231,7 +235,9 @@ _edi_mainview_choose_type_win_cb(void *data, void *event_info EINA_UNUSED) { evas_object_del(_edi_mainview_choose_popup); - edi_mainview_open_window_path(_edi_mainview_choose_path, (const char *) data); + + _edi_mainview_choose_options->type = (const char *) data; + edi_mainview_open_window(_edi_mainview_choose_options); } @@ -244,13 +250,13 @@ _edi_mainview_choose_type_close_cb(void *data EINA_UNUSED, } static void -_edi_mainview_choose_type(Evas_Object *parent, const char *path, void *cb) +_edi_mainview_choose_type(Evas_Object *parent, Edi_Path_Options *options, void *cb) { Evas_Object *popup, *cancel, *icon; popup = elm_popup_add(_main_win); _edi_mainview_choose_popup = popup; - _edi_mainview_choose_path = path; + _edi_mainview_choose_options = options; // popup title elm_object_part_text_set(popup, "title,text", @@ -278,75 +284,101 @@ _edi_mainview_choose_type(Evas_Object *parent, const char *path, void *cb) static void _edi_mainview_tab_stat_done(void *data, Eio_File *handler EINA_UNUSED, const Eina_Stat *stat) { - const char *path, *mime; + Edi_Path_Options *options; + const char *mime; - path = data; + options = data; if (S_ISREG(stat->mode)) { - mime = efreet_mime_type_get(path); + mime = efreet_mime_type_get(options->path); if (!strcasecmp(mime, "text/plain") || !strcasecmp(mime, "application/x-shellscript")) - _edi_mainview_item_tab_add(path, "text"); + options->type = "text"; else if (!strcasecmp(mime, "text/x-chdr") || !strcasecmp(mime, "text/x-csrc")) - _edi_mainview_item_tab_add(path, "text"); // TODO make a code view + options->type = "text"; // TODO make a code view else if (!strncasecmp(mime, "image/", 6)) - _edi_mainview_item_tab_add(path, "image"); + options->type = "image"; else - _edi_mainview_choose_type(nf, path, _edi_mainview_choose_type_tab_cb); + { + _edi_mainview_choose_type(nf, options, _edi_mainview_choose_type_tab_cb); + return; + } } - eina_stringshare_del(path); + _edi_mainview_item_tab_add(options); } static void _edi_mainview_win_stat_done(void *data, Eio_File *handler EINA_UNUSED, const Eina_Stat *stat) { - const char *path, *mime; + Edi_Path_Options *options; + const char *mime; - path = data; + options = data; if (S_ISREG(stat->mode)) { - mime = efreet_mime_type_get(path); + mime = efreet_mime_type_get(options->path); if (!strcasecmp(mime, "text/plain") || !strcasecmp(mime, "application/x-shellscript")) - _edi_mainview_item_win_add(path, "text"); + options->type = "text"; else if (!strcasecmp(mime, "text/x-chdr") || !strcasecmp(mime, "text/x-csrc")) - _edi_mainview_item_win_add(path, "text"); // TODO make a code view + options->type = "text"; // TODO make a code view else if (!strncasecmp(mime, "image/", 6)) - _edi_mainview_item_win_add(path, "image"); + options->type = "image"; else - _edi_mainview_choose_type(nf, path, _edi_mainview_choose_type_win_cb); + { + _edi_mainview_choose_type(nf, options, _edi_mainview_choose_type_win_cb); + return; + } } - eina_stringshare_del(path); + _edi_mainview_item_win_add(options); } EAPI void -edi_mainview_open_path(const char *path, const char *type) +edi_mainview_open_path(const char *path) { + Edi_Path_Options *options; Edi_Mainview_Item *it; - path = eina_stringshare_add(path); it = _get_item_for_path(path); if (it) { edi_mainview_item_select(it); - eina_stringshare_del(path); return; } - if (type == NULL) + options = edi_path_options_create(path); + + eio_file_direct_stat(path, _edi_mainview_tab_stat_done, dummy, options); +} + +EAPI void +edi_mainview_open(Edi_Path_Options *options) +{ + Edi_Mainview_Item *it; + + it = _get_item_for_path(options->path); + if (it) { - eio_file_direct_stat(path, _edi_mainview_tab_stat_done, dummy, - eina_stringshare_add(path)); + edi_mainview_item_select(it); + if (options->line) + edi_mainview_goto(options->line); + return; + } + + if (options->type == NULL) + { + eio_file_direct_stat(options->path, _edi_mainview_tab_stat_done, dummy, options); } else { - _edi_mainview_item_tab_add(path, type); + _edi_mainview_item_tab_add(options); } } EAPI void -edi_mainview_open_window_path(const char *path, const char *type) +edi_mainview_open_window_path(const char *path) { + Edi_Path_Options *options; Edi_Mainview_Item *it; it = _get_item_for_path(path); @@ -359,14 +391,33 @@ edi_mainview_open_window_path(const char *path, const char *type) free(it); } - if (type == NULL) + options = edi_path_options_create(path); + + eio_file_direct_stat(path, _edi_mainview_win_stat_done, dummy, options); +} + +EAPI void +edi_mainview_open_window(Edi_Path_Options *options) +{ + Edi_Mainview_Item *it; + + it = _get_item_for_path(options->path); + if (it) { - eio_file_direct_stat(path, _edi_mainview_win_stat_done, dummy, - eina_stringshare_add(path)); + edi_mainview_item_select(it); + elm_naviframe_item_pop(nf); + elm_object_item_del(elm_toolbar_selected_item_get(tb)); + _edi_mainview_items = eina_list_remove(_edi_mainview_items, it); + free(it); + } + + if (options->type == NULL) + { + eio_file_direct_stat(options->path, _edi_mainview_win_stat_done, dummy, options); } else { - _edi_mainview_item_win_add(path, type); + _edi_mainview_item_win_add(options); } } @@ -391,7 +442,7 @@ edi_mainview_new_window() if (!item) return; - edi_mainview_open_window_path(item->path, NULL); + edi_mainview_open_window_path(item->path); } EAPI void diff --git a/src/bin/edi_mainview.h b/src/bin/edi_mainview.h index 2169d93..c96a925 100644 --- a/src/bin/edi_mainview.h +++ b/src/bin/edi_mainview.h @@ -4,6 +4,8 @@ #include #include +#include "Edi.h" + #ifdef __cplusplus extern "C" { #endif @@ -12,18 +14,12 @@ extern "C" { * @file * @brief These routines are used for managing the main area of the Edi interface. */ - - /** - * @typedef Edi_Mainview_Item - * An item being displayed in the mainview. - */ -typedef struct _Edi_Mainview_Item Edi_Mainview_Item; /** * @struct _Edi_Mainview_Item * An item being displayed in the mainview. */ -struct _Edi_Mainview_Item +typedef struct _Edi_Mainview_Item { const char *path; /**< The path of the file in this mainview item */ @@ -34,7 +30,7 @@ struct _Edi_Mainview_Item /* Private */ /* Add new members here. */ -}; +} Edi_Mainview_Item; /** * @brief UI management functions. @@ -74,11 +70,19 @@ EAPI void edi_mainview_add(Evas_Object *parent, Evas_Object *win); * Supported types are "text" and "image". * * @param path The absolute path of the file to open. - * @param type The requested type to use when opening the file or NULL for auto-detect * * @ingroup Content */ -EAPI void edi_mainview_open_path(const char *path, const char *type); +EAPI void edi_mainview_open_path(const char *path); + +/** + * Open the file described in the provided options - path and location etc. + * + * @param path The path and options of the file to open. + * + * @ingroup Content + */ +EAPI void edi_mainview_open(Edi_Path_Options *options); /** * Open the file at path for editing in a new window using the type specified. @@ -86,11 +90,20 @@ EAPI void edi_mainview_open_path(const char *path, const char *type); * If the path is already open it will be moved to a new window. * * @param path The absolute path of the file to open. - * @param type The requested type to use when opening the file or NULL for auto-detect * * @ingroup Content */ -EAPI void edi_mainview_open_window_path(const char *path, const char *type); +EAPI void edi_mainview_open_window_path(const char *path); + +/** + * Open the file described in the provided options in a new window - path and location etc. + * + * @param path The path and options of the file to open. + * + * @ingroup Content + */ +EAPI void edi_mainview_open_window(Edi_Path_Options *options); + /** * Save the current file. diff --git a/src/lib/Edi.h b/src/lib/Edi.h index 529bf0a..c533995 100644 --- a/src/lib/Edi.h +++ b/src/lib/Edi.h @@ -34,6 +34,7 @@ extern "C" { #endif #include +#include /** * @file diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 9942201..39bb0d0 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -14,6 +14,7 @@ includes_HEADERS = Edi.h includesdir = $(includedir)/edi-@VMAJ@ libedi_la_SOURCES = \ +edi_path.c \ edi_builder.c \ edi.c libedi_la_LIBADD = @EFL_LIBS@ -lm diff --git a/src/lib/edi_path.c b/src/lib/edi_path.c new file mode 100644 index 0000000..3f84398 --- /dev/null +++ b/src/lib/edi_path.c @@ -0,0 +1,45 @@ +#ifdef HAVE_CONFIG +# include "config.h" +#endif + +#include "Edi.h" +#include "edi_path.h" + +#include "edi_private.h" + +EAPI Edi_Path_Options * +edi_path_options_create(const char *input) +{ + Edi_Path_Options *ret; + const char *path, *pos1, *pos2; + int line = 0, col = 0; + + path = input; + ret = calloc(1, sizeof(Edi_Path_Options)); + + pos1 = strstr(path, ":"); + if (pos1) + { + path = eina_stringshare_add_length(path, strlen(path) - strlen(pos1)); + pos1++; + pos2 = strstr(pos1, ":"); + if (pos2) + { + line = atoi(eina_stringshare_add_length(pos1, strlen(pos1) - strlen(pos2))); + + col = atoi(pos2 + 1); + } + else + { + line = atoi(pos1); + } + } + + ret->path = path; + ret->line = line; + ret->character = col; + + return ret; +} + + diff --git a/src/lib/edi_path.h b/src/lib/edi_path.h new file mode 100644 index 0000000..41b3b5f --- /dev/null +++ b/src/lib/edi_path.h @@ -0,0 +1,51 @@ +#ifndef EDI_PATH_H_ +# define EDI_PATH_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file + * @brief These routines are used for Edi path handling. + */ + +typedef struct _Edi_Path_Options +{ + const char *path; + const char *type; + int line, character; +} Edi_Path_Options; + +/** + * @brief Path options + * @defgroup Options + * + * @{ + * + * Manipulation of various path options. + * + */ + +/** + * Create an options based on parsing a string input. + * String will be of the format [:[:]] + * + * @param input The string formatted to have a path with optional line and character parameters + * If only one of line or character is provided it's assumed to be the line number. + * + * @return A newly allocated options struct. + * + * @ingroup Options + */ +EAPI Edi_Path_Options *edi_path_options_create(const char *input); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* EDI_PATH_H_ */ diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am index 097c8be..d18854e 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -4,6 +4,7 @@ if EFL_HAVE_TESTS check_PROGRAMS = edi_suite edi_suite_SOURCES = \ +edi_test_path.c \ edi_test_console.c \ edi_suite.c diff --git a/src/tests/edi_suite.c b/src/tests/edi_suite.c index f38e422..b168ba7 100644 --- a/src/tests/edi_suite.c +++ b/src/tests/edi_suite.c @@ -14,7 +14,8 @@ static const struct { void (*build)(TCase *tc); } tests[] = { { "basic", edi_test_basic }, - { "console", edi_test_console } + { "console", edi_test_console }, + { "path", edi_test_path } }; START_TEST(edi_initialization) diff --git a/src/tests/edi_suite.h b/src/tests/edi_suite.h index 48a1da7..bdc17f2 100644 --- a/src/tests/edi_suite.h +++ b/src/tests/edi_suite.h @@ -7,5 +7,6 @@ void edi_test_basic(TCase *tc); void edi_test_console(TCase *tc); +void edi_test_path(TCase *tc); #endif /* _EDI_SUITE_H */ diff --git a/src/tests/edi_test_console.c b/src/tests/edi_test_console.c index 8824c29..23fb389 100644 --- a/src/tests/edi_test_console.c +++ b/src/tests/edi_test_console.c @@ -15,8 +15,19 @@ START_TEST (edi_console_icons) } END_TEST +START_TEST (edi_console_parse) +{ + ck_assert(_startswith_location("test:1:1 error")); + ck_assert(!_startswith_location("test:56-3 false")); + ck_assert(!_startswith_location("test:1:1nospace")); + ck_assert(!_startswith_location("test:a:b testing")); + ck_assert(!_startswith_location("/test:1:1 absolute")); +} +END_TEST + void edi_test_console(TCase *tc) { tcase_add_test(tc, edi_console_icons); + tcase_add_test(tc, edi_console_parse); } diff --git a/src/tests/edi_test_path.c b/src/tests/edi_test_path.c new file mode 100644 index 0000000..ba39beb --- /dev/null +++ b/src/tests/edi_test_path.c @@ -0,0 +1,36 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "edi_suite.h" + +START_TEST (edi_path_parse_plain_options) +{ + Edi_Path_Options *options; + + options = edi_path_options_create("test"); + + ck_assert_str_eq(options->path, "test"); + ck_assert(options->line == 0); + ck_assert(options->character == 0); +} +END_TEST + +START_TEST (edi_path_parse_line_options) +{ + Edi_Path_Options *options; + + options = edi_path_options_create("test:5:5"); + + ck_assert_str_eq(options->path, "test"); + ck_assert(options->line == 5); + ck_assert(options->character == 5); +} +END_TEST + +void edi_test_path(TCase *tc) +{ + tcase_add_test(tc, edi_path_parse_plain_options); + tcase_add_test(tc, edi_path_parse_line_options); +} +