From 4aee312774df7446eecc9bcfd15ce98ea568f815 Mon Sep 17 00:00:00 2001 From: YeongJong Lee Date: Thu, 2 Feb 2017 18:07:02 +0000 Subject: [PATCH] elm_code: add support for redo Summary: now, elm_code support redo. shortcut is + Test Plan: 1. elementary_test - Code Editor 2. Check that undo and redo are work correctly. Reviewers: ajwillia.ms Reviewed By: ajwillia.ms Subscribers: cedric, jpeg Differential Revision: https://phab.enlightenment.org/D4642 --- src/lib/elementary/elm_code_widget.c | 19 +++-- src/lib/elementary/elm_code_widget.eo | 3 + src/lib/elementary/elm_code_widget_undo.c | 84 ++++++++++++++++++----- 3 files changed, 81 insertions(+), 25 deletions(-) diff --git a/src/lib/elementary/elm_code_widget.c b/src/lib/elementary/elm_code_widget.c index 199d19aa3f..349551b5a6 100644 --- a/src/lib/elementary/elm_code_widget.c +++ b/src/lib/elementary/elm_code_widget.c @@ -1249,7 +1249,7 @@ _elm_code_widget_change_selection_add(Evas_Object *widget) change = _elm_code_widget_change_create(selection->start_col, selection->start_line, - selection->end_col + 1, + selection->end_col, selection->end_line, selection_text, strlen(selection_text), @@ -1360,8 +1360,8 @@ _elm_code_widget_newline(Elm_Code_Widget *widget) Elm_Code *code; Elm_Code_Line *line; Elm_Code_Widget_Change_Info *change; - unsigned int row, col, position, oldlen, width, indent; - char *oldtext, *leading; + unsigned int row, col, position, oldlen, width, indent, textlen; + char *oldtext, *leading, *text; _elm_code_widget_change_selection_add(widget); elm_code_widget_selection_delete(widget); @@ -1394,9 +1394,14 @@ _elm_code_widget_newline(Elm_Code_Widget *widget) efl_event_callback_legacy_call(widget, ELM_OBJ_CODE_WIDGET_EVENT_CHANGED_USER, NULL); free(leading); - change = _elm_code_widget_change_create(width + 1, row, indent - 1, row + 1, "\n", 1, EINA_TRUE); + textlen = strlen(leading) + 2; + text = malloc(sizeof(char) * textlen); + snprintf(text, textlen, "\n%s", leading); + + change = _elm_code_widget_change_create(width + 1, row, indent - 1, row + 1, text, strlen(text), EINA_TRUE); _elm_code_widget_undo_change_add(widget, change); _elm_code_widget_change_free(change); + free(text); } static void @@ -1479,7 +1484,7 @@ _elm_code_widget_backspace(Elm_Code_Widget *widget) efl_event_callback_legacy_call(widget, ELM_OBJ_CODE_WIDGET_EVENT_CHANGED_USER, NULL); - change = _elm_code_widget_change_create(start_col, row, end_col, row, text, char_width, EINA_FALSE); + change = _elm_code_widget_change_create(start_col, row, end_col - 1, row, text, char_width, EINA_FALSE); _elm_code_widget_undo_change_add(widget, change); _elm_code_widget_change_free(change); } @@ -1524,7 +1529,7 @@ _elm_code_widget_delete(Elm_Code_Widget *widget) elm_obj_code_widget_cursor_position_set(widget, row, start_col); efl_event_callback_legacy_call(widget, ELM_OBJ_CODE_WIDGET_EVENT_CHANGED_USER, NULL); - change = _elm_code_widget_change_create(start_col, row, col, row, text, char_width, EINA_FALSE); + change = _elm_code_widget_change_create(start_col, row, col - 1, row, text, char_width, EINA_FALSE); _elm_code_widget_undo_change_add(widget, change); _elm_code_widget_change_free(change); } @@ -1545,6 +1550,8 @@ _elm_code_widget_control_key_down_cb(Elm_Code_Widget *widget, const char *key) elm_code_widget_selection_paste(widget); else if (!strcmp("x", key)) elm_code_widget_selection_cut(widget); + else if (!strcmp("y", key)) + elm_code_widget_redo(widget); else if (!strcmp("z", key)) elm_code_widget_undo(widget); } diff --git a/src/lib/elementary/elm_code_widget.eo b/src/lib/elementary/elm_code_widget.eo index f6bf6f48a4..49a2ad81ba 100644 --- a/src/lib/elementary/elm_code_widget.eo +++ b/src/lib/elementary/elm_code_widget.eo @@ -275,6 +275,9 @@ class Elm.Code_Widget (Elm.Layout, Elm.Interface.Atspi.Text) undo { [[Undo last action]] } + redo { + [[Redo last action]] + } } implements { class.constructor; diff --git a/src/lib/elementary/elm_code_widget_undo.c b/src/lib/elementary/elm_code_widget_undo.c index ed0b8f2f01..5da08d1a6b 100644 --- a/src/lib/elementary/elm_code_widget_undo.c +++ b/src/lib/elementary/elm_code_widget_undo.c @@ -6,6 +6,25 @@ #include "elm_code_widget_private.h" +static void +_elm_code_widget_undo_prev_clear(Evas_Object *widget) +{ + Elm_Code_Widget_Data *pd; + Elm_Code_Widget_Change_Info *info; + Eina_List *list; + + pd = efl_data_scope_get(widget, ELM_CODE_WIDGET_CLASS); + if (!pd->undo_stack_ptr) + return; + + for (list = eina_list_prev(pd->undo_stack_ptr); list; list = eina_list_prev(list)) + { + info = eina_list_data_get(list); + free(info->content); + free(info); + } +} + Elm_Code_Widget_Change_Info * _elm_code_widget_undo_info_copy(Elm_Code_Widget_Change_Info *info) { @@ -13,8 +32,7 @@ _elm_code_widget_undo_info_copy(Elm_Code_Widget_Change_Info *info) copy = calloc(1, sizeof(*info)); memcpy(copy, info, sizeof(*info)); - copy->content = malloc(sizeof(char) * (info->length + 1)); - strncpy(copy->content, info->content, info->length); + copy->content = strndup(info->content, info->length); return copy; } @@ -29,6 +47,8 @@ _elm_code_widget_undo_change_add(Evas_Object *widget, info_copy = _elm_code_widget_undo_info_copy(info); pd = efl_data_scope_get(widget, ELM_CODE_WIDGET_CLASS); + _elm_code_widget_undo_prev_clear(widget); + pd->undo_stack_ptr = eina_list_prepend(pd->undo_stack_ptr, info_copy); pd->undo_stack = pd->undo_stack_ptr; } @@ -38,8 +58,9 @@ _elm_code_widget_undo_change(Evas_Object *widget, Elm_Code_Widget_Change_Info *info) { Elm_Code_Widget_Data *pd; - unsigned int textlen, position, row, col; + unsigned int textlen, position, row, col, newrow, remainlen; short nllen; + char *content; Elm_Code_Line *line; pd = efl_data_scope_get(widget, ELM_CODE_WIDGET_CLASS); @@ -51,37 +72,40 @@ _elm_code_widget_undo_change(Evas_Object *widget, } else { + newrow = info->start_line; + content = info->content; + remainlen = info->length; elm_code_widget_selection_clear(widget); - elm_code_widget_cursor_position_set(widget, info->start_line, info->start_col); - unsigned int newrow = info->start_line; + elm_code_widget_cursor_position_set(widget, info->start_line, + info->start_col); while (newrow <= info->end_line) { line = elm_code_file_line_get(pd->code->file, newrow); if (newrow != info->end_line) { - textlen = info->length; - textlen = elm_code_text_newlinenpos(info->content, info->length, &nllen); - info->length -= textlen + nllen; + textlen = remainlen; + textlen = elm_code_text_newlinenpos(content, remainlen, + &nllen); + remainlen -= textlen + nllen; _elm_code_widget_text_at_cursor_insert_no_undo(widget, - info->content, + content, textlen); elm_obj_code_widget_cursor_position_get(widget, &row, &col); position = elm_code_widget_line_text_position_for_column_get(widget, line, col); elm_code_line_split_at(line, position); elm_code_widget_cursor_position_set(widget, newrow + 1, 1); - info->content += textlen + nllen; + content += textlen + nllen; } else { _elm_code_widget_text_at_cursor_insert_no_undo(widget, - info->content, - info->length); + content, + strlen(content)); } newrow++; } - if (info->end_col < 1) - info->end_col = 1; - elm_code_widget_cursor_position_set(widget, info->end_line, info->end_col); + elm_code_widget_cursor_position_set(widget, info->end_line, + info->end_col + 1); } } @@ -96,9 +120,31 @@ _elm_code_widget_undo(Eo *obj EINA_UNUSED, Elm_Code_Widget_Data *pd) info = eina_list_data_get(pd->undo_stack_ptr); _elm_code_widget_undo_change(obj, info); - if (eina_list_next(pd->undo_stack_ptr)) - pd->undo_stack_ptr = eina_list_next(pd->undo_stack_ptr); - else - pd->undo_stack_ptr = NULL; + pd->undo_stack_ptr = eina_list_next(pd->undo_stack_ptr); +} + +static void +_elm_code_widget_redo(Eo *obj EINA_UNUSED, Elm_Code_Widget_Data *pd) +{ + Elm_Code_Widget_Change_Info *info, *redo_info; + Eina_List *redo_ptr; + + if (pd->undo_stack_ptr) + redo_ptr = eina_list_prev(pd->undo_stack_ptr); + else + redo_ptr = eina_list_last(pd->undo_stack); + + if (!redo_ptr) + return; + + info = eina_list_data_get(redo_ptr); + redo_info = _elm_code_widget_undo_info_copy(info); + redo_info->insert = redo_info->insert ? EINA_FALSE : EINA_TRUE; + _elm_code_widget_undo_change(obj, redo_info); + + pd->undo_stack_ptr = redo_ptr; + + free(redo_info->content); + free(redo_info); }