ajwillia-ms pushed a commit to branch master.

http://git.enlightenment.org/tools/edi.git/commit/?id=acd7b544736311de775a5a69a3dbd2ba5bd47b67

commit acd7b544736311de775a5a69a3dbd2ba5bd47b67
Author: Andy Williams <a...@andywilliams.me>
Date:   Sun Feb 21 18:11:33 2016 +0000

    [editor] begin re-adding the undo feature.
    
    This is provided completely by elm_code so can be reused in other editors.
    For now this is just text/newline insertion...
    Still have to add undo for deletion and selection
---
 ChangeLog                                          |   1 +
 NEWS                                               |   1 +
 elm_code/src/lib/widget/elm_code_widget.c          |  68 +++++++++++---
 elm_code/src/lib/widget/elm_code_widget.eo         |   2 +
 elm_code/src/lib/widget/elm_code_widget_private.h  |  19 ++++
 elm_code/src/lib/widget/elm_code_widget_undo.c     |  56 ++++++++++++
 elm_code/src/tests/Makefile.am                     |   1 +
 elm_code/src/tests/elm_code_suite.c                |   1 +
 elm_code/src/tests/elm_code_suite.h                |   1 +
 .../src/tests/widget/elm_code_test_widget_undo.c   | 101 +++++++++++++++++++++
 src/bin/editor/edi_editor.c                        |  79 +---------------
 11 files changed, 241 insertions(+), 89 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index d8a2285..aac0318 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,7 @@
 2016-02-21 ajwillia.ms (Andy Williams)
 
        * Fix crash when deleting a selection ending in newline
+       * Begin the re-add of the undo feature (just text insertion now)
 
 2016-02-11 ajwillia.ms (Andy Williams)
 
diff --git a/NEWS b/NEWS
index 9a9682a..58867fb 100644
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,7 @@ Features:
   * Update to EFL 1.17 release for better toolbar handling
   * Add file filtering for hunting down files in the list
   * Double click to select word, triple click to select line
+  * Return of the undo feature!
 
 Bug fixes:
 
diff --git a/elm_code/src/lib/widget/elm_code_widget.c 
b/elm_code/src/lib/widget/elm_code_widget.c
index 7fa5653..56f8507 100644
--- a/elm_code/src/lib/widget/elm_code_widget.c
+++ b/elm_code/src/lib/widget/elm_code_widget.c
@@ -987,11 +987,41 @@ _elm_code_widget_delete_selection(Elm_Code_Widget *widget)
    return EINA_TRUE;
 }
 
+static Elm_Code_Widget_Change_Info *
+_elm_code_widget_change_create_insert(unsigned int start_col, unsigned int 
start_line,
+                                      unsigned int end_col, unsigned int 
end_line,
+                                      const char *text, unsigned int length)
+{
+   Elm_Code_Widget_Change_Info *info;
+
+   info = calloc(1, sizeof(*info));
+   info->insert = EINA_TRUE;
+
+   info->start_col = start_col;
+   info->start_line = start_line;
+   info->end_col = end_col;
+   info->end_line = end_line;
+
+   info->content = malloc((length + 1) * sizeof(char));
+   strncpy((char *)info->content, text, length + 1);
+   info->length = length;
+
+   return info;
+}
+
 static void
+_elm_code_widget_change_free(Elm_Code_Widget_Change_Info *info)
+{
+   free((char *)info->content);
+   free(info);
+}
+
+void
 _elm_code_widget_text_at_cursor_insert(Elm_Code_Widget *widget, const char 
*text, int length)
 {
    Elm_Code *code;
    Elm_Code_Line *line;
+   Elm_Code_Widget_Change_Info *change;
    unsigned int row, col, position, col_width;
 
    _elm_code_widget_delete_selection(widget);
@@ -1013,15 +1043,19 @@ _elm_code_widget_text_at_cursor_insert(Elm_Code_Widget 
*widget, const char *text
 
    eo_do(widget,
          elm_obj_code_widget_cursor_position_set(col + col_width, row),
-// TODO construct and pass a change object
          eo_event_callback_call(ELM_CODE_WIDGET_EVENT_CHANGED_USER, NULL));
+
+   change = _elm_code_widget_change_create_insert(col, row, col + col_width - 
1, row, text, length);
+   _elm_code_widget_undo_change_add(widget, change);
+   _elm_code_widget_change_free(change);
 }
 
 static void
 _elm_code_widget_tab_at_cursor_insert(Elm_Code_Widget *widget)
 {
    Elm_Code_Widget_Data *pd;
-   unsigned int col, row;
+   Elm_Code_Widget_Change_Info *change;
+   unsigned int col, row, rem;
 
    pd = eo_data_scope_get(widget, ELM_CODE_WIDGET_CLASS);
    if (!pd->tab_inserts_spaces)
@@ -1032,21 +1066,26 @@ _elm_code_widget_tab_at_cursor_insert(Elm_Code_Widget 
*widget)
 
    eo_do(widget,
          elm_obj_code_widget_cursor_position_get(&col, &row));
-   col = (col - 1) % pd->tabstop;
+   rem = (col - 1) % pd->tabstop;
 
-   while (col < pd->tabstop)
+   while (rem < pd->tabstop)
      {
         _elm_code_widget_text_at_cursor_insert(widget, " ", 1);
-        col++;
+        rem++;
      }
+
+   change = _elm_code_widget_change_create_insert(col, row, (col - 1) % pd 
->tabstop, row, "\t", 1);
+   _elm_code_widget_undo_change_add(widget, change);
+   _elm_code_widget_change_free(change);
 }
 
-static void
+void
 _elm_code_widget_newline(Elm_Code_Widget *widget)
 {
    Elm_Code *code;
    Elm_Code_Line *line;
-   unsigned int row, col, position, oldlen, leading;
+   Elm_Code_Widget_Change_Info *change;
+   unsigned int row, col, position, oldlen, leading, width, indent;
    char *oldtext;
 
    _elm_code_widget_delete_selection(widget);
@@ -1065,6 +1104,7 @@ _elm_code_widget_newline(Elm_Code_Widget *widget)
 
    position = elm_code_widget_line_text_position_for_column_get(widget, line, 
col);
    elm_code_line_split_at(line, position);
+   width = elm_code_widget_line_text_column_width_get(widget, line);
 
    line = elm_code_file_line_get(code->file, row + 1);
    leading = elm_code_text_leading_whitespace_length(oldtext, oldlen);
@@ -1072,11 +1112,14 @@ _elm_code_widget_newline(Elm_Code_Widget *widget)
    elm_code_line_text_insert(line, 0, oldtext, leading);
    free(oldtext);
 
+   indent = elm_obj_code_widget_line_text_column_width_to_position(line, 
leading);
    eo_do(widget,
-         elm_obj_code_widget_cursor_position_set(
-            elm_obj_code_widget_line_text_column_width_to_position(line, 
leading), row + 1),
-// TODO construct and pass a change object
+         elm_obj_code_widget_cursor_position_set(indent, row + 1),
          eo_event_callback_call(ELM_CODE_WIDGET_EVENT_CHANGED_USER, NULL));
+
+   change = _elm_code_widget_change_create_insert(width + 1, row, indent - 1, 
row + 1, "\n", 1);
+   _elm_code_widget_undo_change_add(widget, change);
+   _elm_code_widget_change_free(change);
 }
 
 static void
@@ -1198,9 +1241,11 @@ _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("z", key))
+     elm_code_widget_undo(widget);
 
    eo_do(widget,
-// TODO construct and pass a change object
+// TODO construct and pass a change object for cut and paste
          eo_event_callback_call(ELM_CODE_WIDGET_EVENT_CHANGED_USER, NULL));
 }
 
@@ -1638,4 +1683,5 @@ _elm_code_widget_evas_object_smart_add(Eo *obj, 
Elm_Code_Widget_Data *pd)
 }
 
 #include "elm_code_widget_text.c"
+#include "elm_code_widget_undo.c"
 #include "elm_code_widget.eo.c"
diff --git a/elm_code/src/lib/widget/elm_code_widget.eo 
b/elm_code/src/lib/widget/elm_code_widget.eo
index b8ab71d..e07459a 100644
--- a/elm_code/src/lib/widget/elm_code_widget.eo
+++ b/elm_code/src/lib/widget/elm_code_widget.eo
@@ -202,6 +202,8 @@ class Elm.Code_Widget (Elm.Layout, Elm.Interface_Atspi_Text)
          }
          return: uint;
       }
+      undo {
+      }
    }
    implements {
       class.constructor;
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 b9f8ad2..fab43c2 100644
--- a/elm_code/src/lib/widget/elm_code_widget_private.h
+++ b/elm_code/src/lib/widget/elm_code_widget_private.h
@@ -27,14 +27,33 @@ typedef struct
 
    Elm_Code_Widget_Selection_Data *selection;
    Evas_Object *tooltip;
+
+   /* Undo stack */
+   Eina_List *undo_stack;
+   Eina_List *undo_stack_ptr;
 } Elm_Code_Widget_Data;
 
+typedef struct
+{
+   const char *content;
+   unsigned int length;
+   unsigned int start_line, start_col, end_line, end_col;
+
+   Eina_Bool insert : 1; /**< True if the change is an insertion */
+} Elm_Code_Widget_Change_Info;
+
 /* Private widget methods */
 
+void _elm_code_widget_text_at_cursor_insert(Elm_Code_Widget *widget, const 
char *text, int length);
+
+void _elm_code_widget_newline(Elm_Code_Widget *widget);
+
 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);
 
+void _elm_code_widget_undo_change_add(Evas_Object *widget, 
Elm_Code_Widget_Change_Info *info);
+
 #endif
diff --git a/elm_code/src/lib/widget/elm_code_widget_undo.c 
b/elm_code/src/lib/widget/elm_code_widget_undo.c
new file mode 100644
index 0000000..d51cc5f
--- /dev/null
+++ b/elm_code/src/lib/widget/elm_code_widget_undo.c
@@ -0,0 +1,56 @@
+#ifdef HAVE_CONFIG
+# include "config.h"
+#endif
+
+#include "Elm_Code.h"
+
+#include "elm_code_widget_private.h"
+
+void
+_elm_code_widget_undo_change_add(Evas_Object *widget,
+                                 Elm_Code_Widget_Change_Info *info)
+{
+   Elm_Code_Widget_Data *pd;
+   Elm_Code_Widget_Change_Info *info_copy;
+
+   info_copy = calloc(1, sizeof(*info));
+   memcpy(info_copy, info, sizeof(*info));
+
+   pd = eo_data_scope_get(widget, ELM_CODE_WIDGET_CLASS);
+
+   pd->undo_stack_ptr = eina_list_prepend(pd->undo_stack_ptr, info_copy);
+   pd->undo_stack = pd->undo_stack_ptr;
+}
+
+static void
+_elm_code_widget_undo_change(Evas_Object *widget,
+                             Elm_Code_Widget_Change_Info *info)
+{
+   if (info->insert)
+     {
+        elm_code_widget_selection_start(widget, info->start_line, 
info->start_col);
+        elm_code_widget_selection_end(widget, info->end_line, info->end_col);
+        elm_code_widget_selection_delete(widget);
+     }
+   else
+     {
+     }
+}
+
+static void
+_elm_code_widget_undo(Eo *obj EINA_UNUSED, Elm_Code_Widget_Data *pd)
+{
+   Elm_Code_Widget_Change_Info *info;
+
+   if (!pd->undo_stack_ptr)
+     return;
+
+   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;
+}
+
diff --git a/elm_code/src/tests/Makefile.am b/elm_code/src/tests/Makefile.am
index 6256c35..6150c6f 100644
--- a/elm_code/src/tests/Makefile.am
+++ b/elm_code/src/tests/Makefile.am
@@ -15,6 +15,7 @@ elm_code_test_text.c \
 widget/elm_code_test_widget.c \
 widget/elm_code_test_widget_text.c \
 widget/elm_code_test_widget_selection.c \
+widget/elm_code_test_widget_undo.c \
 elm_code_suite.c
 
 elm_code_suite_CPPFLAGS = \
diff --git a/elm_code/src/tests/elm_code_suite.c 
b/elm_code/src/tests/elm_code_suite.c
index f562b80..31ea7d9 100644
--- a/elm_code/src/tests/elm_code_suite.c
+++ b/elm_code/src/tests/elm_code_suite.c
@@ -21,6 +21,7 @@ static const struct {
   { "widget", elm_code_test_widget },
   { "widget_text", elm_code_test_widget_text },
   { "widget_selection", elm_code_test_widget_selection },
+  { "widget_undo", elm_code_test_widget_undo },
 };
 
 START_TEST(elm_code_initialization)
diff --git a/elm_code/src/tests/elm_code_suite.h 
b/elm_code/src/tests/elm_code_suite.h
index d541e9b..750bfd7 100644
--- a/elm_code/src/tests/elm_code_suite.h
+++ b/elm_code/src/tests/elm_code_suite.h
@@ -26,5 +26,6 @@ void elm_code_test_text(TCase *tc);
 void elm_code_test_widget(TCase *tc);
 void elm_code_test_widget_text(TCase *tc);
 void elm_code_test_widget_selection(TCase *tc);
+void elm_code_test_widget_undo(TCase *tc);
 
 #endif /* _EDLM_CODE_SUITE_H */
diff --git a/elm_code/src/tests/widget/elm_code_test_widget_undo.c 
b/elm_code/src/tests/widget/elm_code_test_widget_undo.c
new file mode 100644
index 0000000..f6c13f0
--- /dev/null
+++ b/elm_code/src/tests/widget/elm_code_test_widget_undo.c
@@ -0,0 +1,101 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "elm_code_suite.h"
+
+#include "elm_code_widget_private.h"
+
+START_TEST (elm_code_test_widget_undo_text_insert)
+{
+   Elm_Code *code;
+   Elm_Code_File *file;
+   Elm_Code_Line *line;
+   Elm_Code_Widget *widget;
+   Evas_Object *win;
+   unsigned int length;
+   const char *content;
+
+   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_text_at_cursor_insert(widget, "a", 1);
+   line = elm_code_file_line_get(file, 1);
+   content = elm_code_line_text_get(line, &length);
+   ck_assert_strn_eq("atest", content, length);
+
+   elm_code_widget_undo(widget);
+   content = elm_code_line_text_get(line, &length);
+   ck_assert_strn_eq("test", content, length);
+
+   elm_code_widget_cursor_position_set(widget, 3, 1);
+   _elm_code_widget_text_at_cursor_insert(widget, "r", 1);
+   content = elm_code_line_text_get(line, &length);
+   ck_assert_strn_eq("terst", content, length);
+
+   elm_code_widget_undo(widget);
+   content = elm_code_line_text_get(line, &length);
+   ck_assert_strn_eq("test", content, length);
+
+   elm_code_widget_cursor_position_set(widget, 4, 1);
+   _elm_code_widget_text_at_cursor_insert(widget, "\t", 1);
+   content = elm_code_line_text_get(line, &length);
+   ck_assert_strn_eq("tes\tt", content, length);
+
+   elm_code_widget_undo(widget);
+   content = elm_code_line_text_get(line, &length);
+   ck_assert_strn_eq("test", content, length);
+
+   elm_code_free(code);
+   elm_shutdown();
+}
+END_TEST
+
+START_TEST (elm_code_test_widget_undo_newline)
+{
+   Elm_Code *code;
+   Elm_Code_File *file;
+   Elm_Code_Line *line;
+   Elm_Code_Widget *widget;
+   Evas_Object *win;
+   unsigned int length;
+   const char *content;
+
+   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_cursor_position_set(widget, 5, 1);
+   _elm_code_widget_newline(widget);
+   ck_assert_int_eq(2, elm_code_file_lines_get(file));
+   line = elm_code_file_line_get(file, 1);
+   content = elm_code_line_text_get(line, &length);
+   ck_assert_strn_eq("test", content, 1);
+
+   elm_code_widget_undo(widget);
+
+   ck_assert_int_eq(1, elm_code_file_lines_get(file));
+   line = elm_code_file_line_get(file, 1);
+   content = elm_code_line_text_get(line, &length);
+   ck_assert_strn_eq("test", content, 4);
+
+   elm_code_free(code);
+   elm_shutdown();
+}
+END_TEST
+
+void elm_code_test_widget_undo(TCase *tc)
+{
+   tcase_add_test(tc, elm_code_test_widget_undo_text_insert);
+   tcase_add_test(tc, elm_code_test_widget_undo_newline);
+}
+
diff --git a/src/bin/editor/edi_editor.c b/src/bin/editor/edi_editor.c
index 0fc4bb2..236a356 100644
--- a/src/bin/editor/edi_editor.c
+++ b/src/bin/editor/edi_editor.c
@@ -52,86 +52,13 @@ _edi_editor_autosave_cb(void *data)
    return ECORE_CALLBACK_CANCEL;
 }
 
-static void
-_undo_do(Edi_Editor *editor, Elm_Entry_Change_Info *inf)
-{
-   if (inf->insert)
-     {
-        const Evas_Object *tb = elm_entry_textblock_get(editor->entry);
-        Evas_Textblock_Cursor *mcur, *end;
-        mcur = (Evas_Textblock_Cursor *) evas_object_textblock_cursor_get(tb);
-        end = evas_object_textblock_cursor_new(tb);
-
-        if (inf->insert)
-          {
-             elm_entry_cursor_pos_set(editor->entry, inf->change.insert.pos);
-             evas_textblock_cursor_pos_set(end, inf->change.insert.pos +
-                   inf->change.insert.plain_length);
-          }
-        else
-          {
-             elm_entry_cursor_pos_set(editor->entry, inf->change.del.start);
-             evas_textblock_cursor_pos_set(end, inf->change.del.end);
-          }
-
-        evas_textblock_cursor_range_delete(mcur, end);
-        evas_textblock_cursor_free(end);
-        elm_entry_calc_force(editor->entry);
-     }
-   else
-     {
-        if (inf->insert)
-          {
-             elm_entry_cursor_pos_set(editor->entry, inf->change.insert.pos);
-             elm_entry_entry_insert(editor->entry, inf->change.insert.content);
-          }
-        else
-          {
-             size_t start;
-             start = (inf->change.del.start < inf->change.del.end) ?
-                inf->change.del.start : inf->change.del.end;
-
-             elm_entry_cursor_pos_set(editor->entry, start);
-             elm_entry_entry_insert(editor->entry, inf->change.insert.content);
-             elm_entry_cursor_pos_set(editor->entry, inf->change.del.end);
-          }
-     }
-}
 
-static void
-_undo_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info 
EINA_UNUSED)
-{
-   Elm_Entry_Change_Info *change;
-   Edi_Editor *editor = data;
-
-   if (!eina_list_next(editor->undo_stack))
-      return;
-
-   change = eina_list_data_get(editor->undo_stack);
-   _undo_do(editor, change);
-   editor->undo_stack = eina_list_next(editor->undo_stack);
-}
 
 static void
-_changed_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info)
+_changed_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info 
EINA_UNUSED)
 {
-   Elm_Entry_Change_Info *change;
    Edi_Editor *editor = data;
-/*
-TODO move this code into elm_code for undo/redo
-   change = calloc(1, sizeof(*change));
-   memcpy(change, event_info, sizeof(*change));
-   if (change->insert)
-     {
-        eina_stringshare_ref(change->change.insert.content);
-     }
-   else
-     {
-        eina_stringshare_ref(change->change.del.content);
-     }
 
-   editor->undo_stack = eina_list_prepend(editor->undo_stack, change);
-*/
    editor->modified = EINA_TRUE;
 
    if (editor->save_timer)
@@ -184,10 +111,6 @@ _smart_cb_key_down(void *data EINA_UNUSED, Evas *e 
EINA_UNUSED,
           {
              edi_mainview_goto_popup_show();
           }
-        else if (!strcmp(ev->key, "z"))
-          {
-             _undo_cb(editor, obj, event);
-          }
      }
 }
 

-- 


Reply via email to