diff --git a/elm_code/src/lib/widget/elm_code_widget.c b/elm_code/src/lib/widget/elm_code_widget.c index ee3ca73..8b1a7a2 100644 --- a/elm_code/src/lib/widget/elm_code_widget.c +++ b/elm_code/src/lib/widget/elm_code_widget.c @@ -300,21 +300,26 @@ _elm_code_widget_fill_selection(Elm_Code_Widget *widget, Elm_Code_Line *line, Ev { Elm_Code_Widget_Data *pd; unsigned int x, start, end; + Elm_Code_Widget_Selection_Data *selection; pd = eo_data_scope_get(widget, ELM_CODE_WIDGET_CLASS); - if (!pd->selection) return; - if (pd->selection->start_line > line->number || pd->selection->end_line < line->number) - return; + selection = elm_code_widget_selection_normalized_get(widget); + if (selection->start_line > line->number || selection->end_line < line->number) + { + free(selection); + return; + } - start = pd->selection->start_col; - if (pd->selection->start_line < line->number) + start = selection->start_col; + if (selection->start_line < line->number) start = 1; - end = pd->selection->end_col; - if (pd->selection->end_line > line->number) + end = selection->end_col; + if (selection->end_line > line->number) end = w; + free(selection); for (x = gutter + start - 1; x < gutter + end && x < (unsigned int) w; x++) cells[x].bg = ELM_CODE_WIDGET_COLOR_SELECTION; @@ -947,13 +952,18 @@ static Eina_Bool _elm_code_widget_delete_selection(Elm_Code_Widget *widget) { Elm_Code_Widget_Data *pd; + Elm_Code_Widget_Selection_Data *selection; pd = eo_data_scope_get(widget, ELM_CODE_WIDGET_CLASS); if (!pd->selection) return EINA_FALSE; + selection = elm_code_widget_selection_normalized_get(widget); elm_code_widget_selection_delete(widget); + elm_code_widget_cursor_position_set(widget, selection->start_col, selection->start_line); + free(selection); + return EINA_TRUE; } diff --git a/elm_code/src/lib/widget/elm_code_widget_private.h b/elm_code/src/lib/widget/elm_code_widget_private.h index a1dc7b1..b89973f 100644 --- a/elm_code/src/lib/widget/elm_code_widget_private.h +++ b/elm_code/src/lib/widget/elm_code_widget_private.h @@ -35,6 +35,6 @@ void _elm_code_widget_tooltip_text_set(Evas_Object *widget, const char *text); void _elm_code_widget_tooltip_add(Evas_Object *widget); - +EAPI Elm_Code_Widget_Selection_Data *elm_code_widget_selection_normalized_get(Evas_Object *widget); #endif diff --git a/elm_code/src/lib/widget/elm_code_widget_selection.c b/elm_code/src/lib/widget/elm_code_widget_selection.c index 9774526..dd3ee74 100644 --- a/elm_code/src/lib/widget/elm_code_widget_selection.c +++ b/elm_code/src/lib/widget/elm_code_widget_selection.c @@ -90,6 +90,47 @@ elm_code_widget_selection_end(Evas_Object *widget, eo_do(widget, eo_event_callback_call(ELM_CODE_WIDGET_EVENT_SELECTION_CHANGED, widget)); } +EAPI Elm_Code_Widget_Selection_Data * +elm_code_widget_selection_normalized_get(Evas_Object *widget) +{ + Elm_Code_Widget_Data *pd; + Elm_Code_Widget_Selection_Data *selection; + Eina_Bool reverse; + + pd = eo_data_scope_get(widget, ELM_CODE_WIDGET_CLASS); + selection = _elm_code_widget_selection_new(); + + if (!pd->selection) + { + selection->start_line = selection->end_line = 1; + selection->start_col = selection->end_col = 1; + + return selection; + } + + if (pd->selection->start_line == pd->selection->end_line) + reverse = pd->selection->start_col > pd->selection->end_col; + else + reverse = pd->selection->start_line > pd->selection->end_line; + + if (reverse) + { + selection->start_line = pd->selection->end_line; + selection->start_col = pd->selection->end_col; + selection->end_line = pd->selection->start_line; + selection->end_col = pd->selection->start_col; + } + else + { + selection->start_line = pd->selection->start_line; + selection->start_col = pd->selection->start_col; + selection->end_line = pd->selection->end_line; + selection->end_col = pd->selection->end_col; + } + + return selection; +} + EAPI void elm_code_widget_selection_clear(Evas_Object *widget) { @@ -111,14 +152,13 @@ _elm_code_widget_selection_delete_single(Elm_Code_Widget *widget, Elm_Code_Widge const char *old; unsigned int old_length, start, end, length; char *content; + Elm_Code_Widget_Selection_Data *selection; - if (pd->selection->end_col < pd->selection->start_col) - return; - - line = elm_code_file_line_get(pd->code->file, pd->selection->start_line); + selection = elm_code_widget_selection_normalized_get(widget); + line = elm_code_file_line_get(pd->code->file, selection->start_line); old = elm_code_line_text_get(line, &old_length); - start = elm_code_widget_line_text_position_for_column_get(widget, line, pd->selection->start_col); - end = elm_code_widget_line_text_position_for_column_get(widget, line, pd->selection->end_col); + start = elm_code_widget_line_text_position_for_column_get(widget, line, selection->start_col); + end = elm_code_widget_line_text_position_for_column_get(widget, line, selection->end_col); length = line->length - (end - start + 1); content = malloc(sizeof(char) * length); @@ -127,6 +167,7 @@ _elm_code_widget_selection_delete_single(Elm_Code_Widget *widget, Elm_Code_Widge old_length - (end + 1)); elm_code_line_text_set(line, content, length); free(content); + free(selection); } static void @@ -136,17 +177,19 @@ _elm_code_widget_selection_delete_multi(Elm_Code_Widget *widget, Elm_Code_Widget const char *first, *last; unsigned int last_length, start, end, length, i; char *content; + Elm_Code_Widget_Selection_Data *selection; - if (pd->selection->end_line <= pd->selection->start_line) + if (pd->selection->end_line == pd->selection->start_line) return; - line = elm_code_file_line_get(pd->code->file, pd->selection->start_line); + selection = elm_code_widget_selection_normalized_get(widget); + line = elm_code_file_line_get(pd->code->file, selection->start_line); first = elm_code_line_text_get(line, NULL); - start = elm_code_widget_line_text_position_for_column_get(widget, line, pd->selection->start_col); + start = elm_code_widget_line_text_position_for_column_get(widget, line, selection->start_col); - line = elm_code_file_line_get(pd->code->file, pd->selection->end_line); + line = elm_code_file_line_get(pd->code->file, selection->end_line); last = elm_code_line_text_get(line, &last_length); - end = elm_code_widget_line_text_position_for_column_get(widget, line, pd->selection->end_col); + end = elm_code_widget_line_text_position_for_column_get(widget, line, selection->end_col); length = start + last_length - (end + 1); content = malloc(sizeof(char) * length); @@ -154,12 +197,13 @@ _elm_code_widget_selection_delete_multi(Elm_Code_Widget *widget, Elm_Code_Widget strncpy(content + start, last + end + 1, last_length - (end + 1)); - for (i = line->number; i > pd->selection->start_line; i--) + for (i = line->number; i > selection->start_line; i--) elm_code_file_line_remove(pd->code->file, i); - line = elm_code_file_line_get(pd->code->file, pd->selection->start_line); + line = elm_code_file_line_get(pd->code->file, selection->start_line); elm_code_line_text_set(line, content, length); free(content); + free(selection); } EAPI void @@ -187,10 +231,13 @@ _elm_code_widget_selection_text_single_get(Elm_Code_Widget *widget, Elm_Code_Wid { Elm_Code_Line *line; unsigned int start, end; + Elm_Code_Widget_Selection_Data *selection; - line = elm_code_file_line_get(pd->code->file, pd->selection->start_line); - start = elm_code_widget_line_text_position_for_column_get(widget, line, pd->selection->start_col); - end = elm_code_widget_line_text_position_for_column_get(widget, line, pd->selection->end_col + 1); + selection = elm_code_widget_selection_normalized_get(widget); + line = elm_code_file_line_get(pd->code->file, selection->start_line); + start = elm_code_widget_line_text_position_for_column_get(widget, line, selection->start_col); + end = elm_code_widget_line_text_position_for_column_get(widget, line, selection->end_col + 1); + free(selection); return elm_code_line_text_substr(line, start, end - start); } @@ -204,20 +251,22 @@ _elm_code_widget_selection_text_multi_get(Elm_Code_Widget *widget, Elm_Code_Widg short newline_len; int ret_len; unsigned int row, start, end; + Elm_Code_Widget_Selection_Data *selection; + selection = elm_code_widget_selection_normalized_get(widget); newline = elm_code_file_line_ending_chars_get(pd->code->file, &newline_len); - line = elm_code_file_line_get(pd->code->file, pd->selection->start_line); - start = elm_code_widget_line_text_position_for_column_get(widget, line, pd->selection->start_col); + line = elm_code_file_line_get(pd->code->file, selection->start_line); + start = elm_code_widget_line_text_position_for_column_get(widget, line, selection->start_col); first = elm_code_line_text_substr(line, start, line->length - start + 1); - line = elm_code_file_line_get(pd->code->file, pd->selection->end_line); - end = elm_code_widget_line_text_position_for_column_get(widget, line, pd->selection->end_col + 1); + line = elm_code_file_line_get(pd->code->file, selection->end_line); + end = elm_code_widget_line_text_position_for_column_get(widget, line, selection->end_col + 1); last = elm_code_line_text_substr(line, 0, end); ret_len = strlen(first) + strlen(last) + newline_len; - for (row = pd->selection->start_line + 1; row < pd->selection->end_line; row++) + for (row = pd->selection->start_line + 1; row < selection->end_line; row++) { line = elm_code_file_line_get(pd->code->file, row); ret_len += line->length + newline_len; @@ -229,7 +278,7 @@ _elm_code_widget_selection_text_multi_get(Elm_Code_Widget *widget, Elm_Code_Widg ptr = ret; ptr += strlen(first) + newline_len; - for (row = pd->selection->start_line + 1; row < pd->selection->end_line; row++) + for (row = selection->start_line + 1; row < selection->end_line; row++) { line = elm_code_file_line_get(pd->code->file, row); if (line->modified) @@ -242,6 +291,7 @@ _elm_code_widget_selection_text_multi_get(Elm_Code_Widget *widget, Elm_Code_Widg } snprintf(ptr, strlen(last) + 1, "%s", last); + free(selection); free(first); free(last); return ret; @@ -254,7 +304,7 @@ elm_code_widget_selection_text_get(Evas_Object *widget) pd = eo_data_scope_get(widget, ELM_CODE_WIDGET_CLASS); - if (!pd->selection || pd->selection->end_line < pd->selection->start_line) + if (!pd->selection) return strdup(""); if (pd->selection->start_line == pd->selection->end_line) diff --git a/elm_code/src/tests/widget/elm_code_test_widget_selection.c b/elm_code/src/tests/widget/elm_code_test_widget_selection.c index 53d2f11..7135e4a 100644 --- a/elm_code/src/tests/widget/elm_code_test_widget_selection.c +++ b/elm_code/src/tests/widget/elm_code_test_widget_selection.c @@ -4,6 +4,8 @@ #include "elm_code_suite.h" +#include "elm_code_widget_private.h" + #include "widget/elm_code_widget_selection.h" START_TEST (elm_code_test_widget_selection_set) @@ -30,6 +32,48 @@ START_TEST (elm_code_test_widget_selection_set) } END_TEST +START_TEST (elm_code_test_widget_selection_normalized_get) +{ + Elm_Code *code; + Elm_Code_File *file; + Elm_Code_Widget *widget; + Elm_Code_Widget_Selection_Data *selection; + Evas_Object *win; + + elm_init(1, NULL); + code = elm_code_create(); + file = elm_code_file_new(code); + elm_code_file_line_append(file, "test", 4, NULL); + + win = elm_win_add(NULL, "entry", ELM_WIN_BASIC); + widget = elm_code_widget_add(win, code); + + elm_code_widget_selection_start(widget, 1, 3); + elm_code_widget_selection_end(widget, 1, 2); + selection = elm_code_widget_selection_normalized_get(widget); + + ck_assert_int_eq(selection->start_col, 2); + ck_assert_int_eq(selection->end_col, 3); + elm_code_widget_selection_clear(widget); + free(selection); + + elm_code_file_line_append(file, "another", 7, NULL); + elm_code_widget_selection_start(widget, 2, 2); + elm_code_widget_selection_end(widget, 1, 3); + selection = elm_code_widget_selection_normalized_get(widget); + + ck_assert_int_eq(selection->start_line, 1); + ck_assert_int_eq(selection->start_col, 3); + ck_assert_int_eq(selection->end_line, 2); + ck_assert_int_eq(selection->end_col, 2); + elm_code_widget_selection_clear(widget); + free(selection); + + elm_code_free(code); + elm_shutdown(); +} +END_TEST + START_TEST (elm_code_test_widget_selection_text_get) { Elm_Code *code; @@ -63,6 +107,39 @@ START_TEST (elm_code_test_widget_selection_text_get) } END_TEST +START_TEST (elm_code_test_widget_selection_reverse_text_get) +{ + Elm_Code *code; + Elm_Code_File *file; + Elm_Code_Widget *widget; + Evas_Object *win; + char *selection; + + elm_init(1, NULL); + code = elm_code_create(); + file = elm_code_file_new(code); + elm_code_file_line_append(file, "test", 4, NULL); + + win = elm_win_add(NULL, "entry", ELM_WIN_BASIC); + widget = elm_code_widget_add(win, code); + + ck_assert_str_eq("", elm_code_widget_selection_text_get(widget)); + + elm_code_widget_selection_start(widget, 1, 3); + elm_code_widget_selection_end(widget, 1, 2); + + selection = elm_code_widget_selection_text_get(widget); + ck_assert_str_eq("es", selection); + free(selection); + + elm_code_widget_selection_clear(widget); + ck_assert_str_eq("", elm_code_widget_selection_text_get(widget)); + + elm_code_free(code); + elm_shutdown(); +} +END_TEST + START_TEST (elm_code_test_widget_selection_text_get_twoline) { Elm_Code *code; @@ -92,6 +169,35 @@ START_TEST (elm_code_test_widget_selection_text_get_twoline) } END_TEST +START_TEST (elm_code_test_widget_selection_reverse_text_get_twoline) +{ + Elm_Code *code; + Elm_Code_File *file; + Elm_Code_Widget *widget; + Evas_Object *win; + char *selection; + + elm_init(1, NULL); + code = elm_code_create(); + file = elm_code_file_new(code); + elm_code_file_line_append(file, "test", 4, NULL); + elm_code_file_line_append(file, "test", 4, NULL); + + win = elm_win_add(NULL, "entry", ELM_WIN_BASIC); + widget = elm_code_widget_add(win, code); + + elm_code_widget_selection_start(widget, 2, 2); + elm_code_widget_selection_end(widget, 1, 3); + + selection = elm_code_widget_selection_text_get(widget); + ck_assert_str_eq("st\nte", selection); + free(selection); + + elm_code_free(code); + elm_shutdown(); +} +END_TEST + START_TEST (elm_code_test_widget_selection_text_get_multiline) { Elm_Code *code; @@ -122,6 +228,36 @@ START_TEST (elm_code_test_widget_selection_text_get_multiline) } END_TEST +START_TEST (elm_code_test_widget_selection_reverse_text_get_multiline) +{ + Elm_Code *code; + Elm_Code_File *file; + Elm_Code_Widget *widget; + Evas_Object *win; + char *selection; + + elm_init(1, NULL); + code = elm_code_create(); + file = elm_code_file_new(code); + elm_code_file_line_append(file, "test", 4, NULL); + elm_code_file_line_append(file, "test", 4, NULL); + elm_code_file_line_append(file, "test", 4, NULL); + + win = elm_win_add(NULL, "entry", ELM_WIN_BASIC); + widget = elm_code_widget_add(win, code); + + elm_code_widget_selection_start(widget, 3, 2); + elm_code_widget_selection_end(widget, 1, 3); + + selection = elm_code_widget_selection_text_get(widget); + ck_assert_str_eq("st\ntest\nte", selection); + free(selection); + + elm_code_free(code); + elm_shutdown(); +} +END_TEST + START_TEST (elm_code_test_widget_selection_delete) { Elm_Code *code; @@ -158,6 +294,42 @@ START_TEST (elm_code_test_widget_selection_delete) } END_TEST +START_TEST (elm_code_test_widget_selection_reverse_delete) +{ + Elm_Code *code; + Elm_Code_File *file; + Elm_Code_Line *line; + Elm_Code_Widget *widget; + Evas_Object *win; + const char *text; + unsigned int length; + + elm_init(1, NULL); + code = elm_code_create(); + file = elm_code_file_new(code); + elm_code_file_line_append(file, "text", 4, NULL); + + win = elm_win_add(NULL, "code", ELM_WIN_BASIC); + widget = elm_code_widget_add(win, code); + line = elm_code_file_line_get(file, 1); + text = elm_code_line_text_get(line, &length); + ck_assert_int_eq(4, length); + ck_assert_strn_eq("text", text, length); + + elm_code_widget_selection_start(widget, 1, 3); + elm_code_widget_selection_end(widget, 1, 2); + elm_code_widget_selection_delete(widget); + + line = elm_code_file_line_get(file, 1); + text = elm_code_line_text_get(line, &length); + ck_assert_int_eq(2, length); + ck_assert_strn_eq("tt", text, length); + + elm_code_free(code); + elm_shutdown(); +} +END_TEST + START_TEST (elm_code_test_widget_selection_delete_twoline) { Elm_Code *code; @@ -194,6 +366,42 @@ START_TEST (elm_code_test_widget_selection_delete_twoline) } END_TEST +START_TEST (elm_code_test_widget_selection_reverse_delete_twoline) +{ + Elm_Code *code; + Elm_Code_File *file; + Elm_Code_Line *line; + Elm_Code_Widget *widget; + Evas_Object *win; + const char *text; + + elm_init(1, NULL); + code = elm_code_create(); + file = elm_code_file_new(code); + elm_code_file_line_append(file, "text", 4, NULL); + elm_code_file_line_append(file, "TEXT", 4, NULL); + + win = elm_win_add(NULL, "code", ELM_WIN_BASIC); + widget = elm_code_widget_add(win, code); + line = elm_code_file_line_get(file, 1); + text = elm_code_line_text_get(line, NULL); + ck_assert_str_eq("text", text); + ck_assert_int_eq(2, elm_code_file_lines_get(file)); + + elm_code_widget_selection_start(widget, 2, 2); + elm_code_widget_selection_end(widget, 1, 3); + elm_code_widget_selection_delete(widget); + + line = elm_code_file_line_get(file, 1); + text = elm_code_line_text_get(line, NULL); + ck_assert_str_eq("teXT", text); + ck_assert_int_eq(1, elm_code_file_lines_get(file)); + + elm_code_free(code); + elm_shutdown(); +} +END_TEST + START_TEST (elm_code_test_widget_selection_delete_multiline) { Elm_Code *code; @@ -231,14 +439,57 @@ START_TEST (elm_code_test_widget_selection_delete_multiline) } END_TEST +START_TEST (elm_code_test_widget_selection_reverse_delete_multiline) +{ + Elm_Code *code; + Elm_Code_File *file; + Elm_Code_Line *line; + Elm_Code_Widget *widget; + Evas_Object *win; + const char *text; + + elm_init(1, NULL); + code = elm_code_create(); + file = elm_code_file_new(code); + elm_code_file_line_append(file, "text", 4, NULL); + elm_code_file_line_append(file, "remove", 6, NULL); + elm_code_file_line_append(file, "TEXT", 4, NULL); + + win = elm_win_add(NULL, "code", ELM_WIN_BASIC); + widget = elm_code_widget_add(win, code); + line = elm_code_file_line_get(file, 1); + text = elm_code_line_text_get(line, NULL); + ck_assert_str_eq("text", text); + ck_assert_int_eq(3, elm_code_file_lines_get(file)); + + elm_code_widget_selection_start(widget, 3, 2); + elm_code_widget_selection_end(widget, 1, 3); + elm_code_widget_selection_delete(widget); + + line = elm_code_file_line_get(file, 1); + text = elm_code_line_text_get(line, NULL); + ck_assert_str_eq("teXT", text); + ck_assert_int_eq(1, elm_code_file_lines_get(file)); + + elm_code_free(code); + elm_shutdown(); +} +END_TEST void elm_code_test_widget_selection(TCase *tc) { tcase_add_test(tc, elm_code_test_widget_selection_set); + tcase_add_test(tc, elm_code_test_widget_selection_normalized_get); tcase_add_test(tc, elm_code_test_widget_selection_text_get); + tcase_add_test(tc, elm_code_test_widget_selection_reverse_text_get); tcase_add_test(tc, elm_code_test_widget_selection_text_get_twoline); + tcase_add_test(tc, elm_code_test_widget_selection_reverse_text_get_twoline); tcase_add_test(tc, elm_code_test_widget_selection_text_get_multiline); + tcase_add_test(tc, elm_code_test_widget_selection_reverse_text_get_multiline); tcase_add_test(tc, elm_code_test_widget_selection_delete); + tcase_add_test(tc, elm_code_test_widget_selection_reverse_delete); tcase_add_test(tc, elm_code_test_widget_selection_delete_twoline); + tcase_add_test(tc, elm_code_test_widget_selection_reverse_delete_twoline); tcase_add_test(tc, elm_code_test_widget_selection_delete_multiline); + tcase_add_test(tc, elm_code_test_widget_selection_reverse_delete_multiline); }