Let's open files that are reported on the console.

Adding support to open at a specific line when
opening files or switching tabs.
This commit is contained in:
Andy Williams 2014-03-16 16:01:35 +00:00
parent a3a4f5fce6
commit c3185b2225
14 changed files with 361 additions and 61 deletions

View File

@ -6,12 +6,17 @@
#include <Eina.h>
#include <Ecore.h>
#include <Elementary.h>
#include <Elementary_Cursor.h>
#include <regex.h>
#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(&regex, "^[^/].*:[0-9]*:[0-9]* ", 0);
ret = !regexec(&regex, line, 0, NULL, 0);
regfree(&regex);
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, "<b>%s</b>%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);

View File

@ -3,6 +3,8 @@
#include <Elementary.h>
#include "Edi.h"
#ifdef __cplusplus
extern "C" {
#endif

View File

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

View File

@ -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

View File

@ -4,6 +4,8 @@
#include <Elementary.h>
#include <Evas.h>
#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.

View File

@ -34,6 +34,7 @@ extern "C" {
#endif
#include <edi_builder.h>
#include <edi_path.h>
/**
* @file

View File

@ -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

45
src/lib/edi_path.c Normal file
View File

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

51
src/lib/edi_path.h Normal file
View File

@ -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 <path>[:<line>[:<character>]]
*
* @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_ */

View File

@ -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

View File

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

View File

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

View File

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

36
src/tests/edi_test_path.c Normal file
View File

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