ajwillia-ms pushed a commit to branch master.

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

commit 5b1a45cf45460d8c400c4d93046d23d06c15f0ed
Author: Andy Williams <a...@andywilliams.me>
Date:   Sun Feb 21 23:46:10 2016 +0000

    [editor] add delete and backspace undo hooks
---
 ChangeLog                                          |  2 +-
 elm_code/src/lib/widget/elm_code_widget.c          | 40 ++++++----
 elm_code/src/lib/widget/elm_code_widget.eo         |  9 +++
 elm_code/src/lib/widget/elm_code_widget_private.h  |  6 +-
 .../src/lib/widget/elm_code_widget_selection.c     | 85 +++-------------------
 elm_code/src/lib/widget/elm_code_widget_text.c     | 81 +++++++++++++++++++++
 elm_code/src/lib/widget/elm_code_widget_undo.c     | 27 ++++++-
 .../src/tests/widget/elm_code_test_widget_undo.c   | 46 ++++++++++++
 8 files changed, 202 insertions(+), 94 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index aac0318..0130c03 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,7 +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)
+       * Begin the re-add of the undo feature (just keyboard input so far)
 
 2016-02-11 ajwillia.ms (Andy Williams)
 
diff --git a/elm_code/src/lib/widget/elm_code_widget.c 
b/elm_code/src/lib/widget/elm_code_widget.c
index fe78a82..203c1d1 100644
--- a/elm_code/src/lib/widget/elm_code_widget.c
+++ b/elm_code/src/lib/widget/elm_code_widget.c
@@ -988,14 +988,14 @@ _elm_code_widget_delete_selection(Elm_Code_Widget *widget)
 }
 
 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_create(unsigned int start_col, unsigned int start_line,
+                               unsigned int end_col, unsigned int end_line,
+                               const char *text, unsigned int length, 
Eina_Bool insert)
 {
    Elm_Code_Widget_Change_Info *info;
 
    info = calloc(1, sizeof(*info));
-   info->insert = EINA_TRUE;
+   info->insert = insert;
 
    info->start_col = start_col;
    info->start_line = start_line;
@@ -1003,7 +1003,8 @@ _elm_code_widget_change_create_insert(unsigned int 
start_col, unsigned int start
    info->end_line = end_line;
 
    info->content = malloc((length + 1) * sizeof(char));
-   strncpy((char *)info->content, text, length + 1);
+   strncpy(info->content, text, length);
+   info->content[length] = '\0';
    info->length = length;
 
    return info;
@@ -1045,7 +1046,7 @@ _elm_code_widget_text_at_cursor_insert(Elm_Code_Widget 
*widget, const char *text
          elm_obj_code_widget_cursor_position_set(col + col_width, row),
          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);
+   change = _elm_code_widget_change_create(col, row, col + col_width - 1, row, 
text, length, EINA_TRUE);
    _elm_code_widget_undo_change_add(widget, change);
    _elm_code_widget_change_free(change);
 }
@@ -1054,7 +1055,6 @@ static void
 _elm_code_widget_tab_at_cursor_insert(Elm_Code_Widget *widget)
 {
    Elm_Code_Widget_Data *pd;
-   Elm_Code_Widget_Change_Info *change;
    unsigned int col, row, rem;
 
    pd = eo_data_scope_get(widget, ELM_CODE_WIDGET_CLASS);
@@ -1113,7 +1113,7 @@ _elm_code_widget_newline(Elm_Code_Widget *widget)
          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);
+   change = _elm_code_widget_change_create(width + 1, row, indent - 1, row + 
1, "\n", 1, EINA_TRUE);
    _elm_code_widget_undo_change_add(widget, change);
    _elm_code_widget_change_free(change);
 }
@@ -1149,15 +1149,17 @@ _elm_code_widget_backspaceline(Elm_Code_Widget *widget, 
Eina_Bool nextline)
    eo_do(widget, eo_event_callback_call(ELM_CODE_WIDGET_EVENT_CHANGED_USER, 
NULL));
 }
 
-static void
+void
 _elm_code_widget_backspace(Elm_Code_Widget *widget)
 {
    Elm_Code *code;
    Elm_Code_Line *line;
+   Elm_Code_Widget_Change_Info *change;
    unsigned int row, col, position, start_col, char_width;
+   const char *text;
 
    if (_elm_code_widget_delete_selection(widget))
-     return;
+     return; // TODO fire the change and log it
 
    eo_do(widget,
          code = elm_obj_code_widget_code_get(),
@@ -1179,23 +1181,29 @@ _elm_code_widget_backspace(Elm_Code_Widget *widget)
       elm_code_widget_line_text_position_for_column_get(widget, line, col - 
1));
    char_width = position - 
elm_code_widget_line_text_position_for_column_get(widget, line, start_col);
 
+   text = elm_code_widget_text_between_positions_get(widget, start_col, row, 
start_col, row);
    elm_code_line_text_remove(line, position - char_width, char_width);
    eo_do(widget,
          elm_obj_code_widget_cursor_position_set(start_col, row));
 
-// TODO construct and pass a change object
    eo_do(widget, eo_event_callback_call(ELM_CODE_WIDGET_EVENT_CHANGED_USER, 
NULL));
+
+   change = _elm_code_widget_change_create(start_col, row, col, row, text, 
char_width, EINA_FALSE);
+   _elm_code_widget_undo_change_add(widget, change);
+   _elm_code_widget_change_free(change);
 }
 
-static void
+void
 _elm_code_widget_delete(Elm_Code_Widget *widget)
 {
    Elm_Code *code;
    Elm_Code_Line *line;
+   Elm_Code_Widget_Change_Info *change;
    unsigned int row, col, position, char_width, start_col;
+   const char *text;
 
    if (_elm_code_widget_delete_selection(widget))
-     return;
+     return; // TODO fire the change and log it
 
    eo_do(widget,
          code = elm_obj_code_widget_code_get(),
@@ -1214,11 +1222,15 @@ _elm_code_widget_delete(Elm_Code_Widget *widget)
    char_width = elm_code_widget_line_text_position_for_column_get(widget, 
line, col + 1) - position;
    start_col = elm_code_widget_line_text_column_width_to_position(widget, 
line, position);
 
+   text = elm_code_widget_text_between_positions_get(widget, start_col, row, 
start_col, row);
    elm_code_line_text_remove(line, position, char_width?char_width:1);
    eo_do(widget,
          elm_obj_code_widget_cursor_position_set(start_col, 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(start_col, row, col, row, text, 
char_width, EINA_FALSE);
+   _elm_code_widget_undo_change_add(widget, change);
+   _elm_code_widget_change_free(change);
 }
 
 static void
diff --git a/elm_code/src/lib/widget/elm_code_widget.eo 
b/elm_code/src/lib/widget/elm_code_widget.eo
index e07459a..ace043a 100644
--- a/elm_code/src/lib/widget/elm_code_widget.eo
+++ b/elm_code/src/lib/widget/elm_code_widget.eo
@@ -175,6 +175,15 @@ class Elm.Code_Widget (Elm.Layout, 
Elm.Interface_Atspi_Text)
       text_line_number_width_get {
          return: int; [[the column width required to represent the number of 
lines in the widget.]]
       }
+      text_between_positions_get {
+         params {
+            start_col: uint; [[the widget column of the first character to 
get]]
+            start_line: uint; [[the line of the first character to get]]
+            end_col: uint; [[the widget column of the last character to get]]
+            end_line: uint; [[the line of the last character to get]]
+         }
+         return: char *; [[the text content between start and end positions]]
+      }
 
       line_text_column_width_to_position {
          params {
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 fab43c2..b4e1900 100644
--- a/elm_code/src/lib/widget/elm_code_widget_private.h
+++ b/elm_code/src/lib/widget/elm_code_widget_private.h
@@ -35,7 +35,7 @@ typedef struct
 
 typedef struct
 {
-   const char *content;
+   char *content;
    unsigned int length;
    unsigned int start_line, start_col, end_line, end_col;
 
@@ -48,6 +48,10 @@ void _elm_code_widget_text_at_cursor_insert(Elm_Code_Widget 
*widget, const char
 
 void _elm_code_widget_newline(Elm_Code_Widget *widget);
 
+void _elm_code_widget_backspace(Elm_Code_Widget *widget);
+
+void _elm_code_widget_delete(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);
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 9a558ec..d4d2142 100644
--- a/elm_code/src/lib/widget/elm_code_widget_selection.c
+++ b/elm_code/src/lib/widget/elm_code_widget_selection.c
@@ -317,91 +317,26 @@ elm_code_widget_selection_select_word(Evas_Object 
*widget, unsigned int line, un
                                  
elm_code_widget_line_text_column_width_to_position(widget, lineobj, pos));
 }
 
-static char *
-_elm_code_widget_selection_text_single_get(Elm_Code_Widget *widget, 
Elm_Code_Widget_Data *pd)
-{
-   Elm_Code_Line *line;
-   unsigned int start, end;
-   Elm_Code_Widget_Selection_Data *selection;
-
-   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);
-}
-
-static char *
-_elm_code_widget_selection_text_multi_get(Elm_Code_Widget *widget, 
Elm_Code_Widget_Data *pd)
-{
-   Elm_Code_Line *line;
-   char *first, *last, *ret, *ptr;
-   const char *newline;
-   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, 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, 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 < selection->end_line; row++)
-     {
-        line = elm_code_file_line_get(pd->code->file, row);
-        ret_len += line->length + newline_len;
-     }
-
-   ret = malloc(sizeof(char) * (ret_len + 1));
-   snprintf(ret, strlen(first) + newline_len + 1, "%s%s", first, newline);
-
-   ptr = ret;
-   ptr += strlen(first) + newline_len;
-
-   for (row = selection->start_line + 1; row < selection->end_line; row++)
-     {
-        line = elm_code_file_line_get(pd->code->file, row);
-        if (line->modified)
-          snprintf(ptr, line->length + 1, "%s", line->modified);
-        else
-          snprintf(ptr, line->length + 1, "%s", line->content);
-
-        snprintf(ptr + line->length, newline_len + 1, "%s", newline);
-        ptr += line->length + newline_len;
-     }
-   snprintf(ptr, strlen(last) + 1, "%s", last);
-
-   free(selection);
-   free(first);
-   free(last);
-   return ret;
-}
-
 EAPI char *
 elm_code_widget_selection_text_get(Evas_Object *widget)
 {
    Elm_Code_Widget_Data *pd;
+   Elm_Code_Widget_Selection_Data *selection;
+   char *text;
 
    pd = eo_data_scope_get(widget, ELM_CODE_WIDGET_CLASS);
 
    if (!pd->selection)
      return strdup("");
 
-   if (pd->selection->start_line == pd->selection->end_line)
-     return _elm_code_widget_selection_text_single_get(widget, pd);
-   else
-     return _elm_code_widget_selection_text_multi_get(widget, pd);
+   selection = elm_code_widget_selection_normalized_get(widget);
+
+   text = elm_code_widget_text_between_positions_get(widget,
+                                                     selection->start_col, 
selection->start_line,
+                                                     selection->end_col, 
selection->end_line);
+
+   free(selection);
+   return text;
 }
 
 static void
diff --git a/elm_code/src/lib/widget/elm_code_widget_text.c 
b/elm_code/src/lib/widget/elm_code_widget_text.c
index 0ae2595..3689e82 100644
--- a/elm_code/src/lib/widget/elm_code_widget_text.c
+++ b/elm_code/src/lib/widget/elm_code_widget_text.c
@@ -34,6 +34,87 @@ _elm_code_widget_text_left_gutter_width_get(Eo *obj, 
Elm_Code_Widget_Data *pd)
    return width;
 }
 
+static char *
+_elm_code_widget_text_multi_get(Elm_Code_Widget *widget, Elm_Code_Widget_Data 
*pd,
+                                unsigned int start_col, unsigned int 
start_line,
+                                unsigned int end_col, unsigned int end_line)
+{
+   Elm_Code_Line *line;
+   char *first, *last, *ret, *ptr;
+   const char *newline;
+   short newline_len;
+   int ret_len;
+   unsigned int row, start, end;
+
+   newline = elm_code_file_line_ending_chars_get(pd->code->file, &newline_len);
+
+   line = elm_code_file_line_get(pd->code->file, start_line);
+   start = elm_code_widget_line_text_position_for_column_get(widget, line, 
start_col);
+   first = elm_code_line_text_substr(line, start, line->length - start + 1);
+
+   line = elm_code_file_line_get(pd->code->file, end_line);
+   end = elm_code_widget_line_text_position_for_column_get(widget, line, 
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 < end_line; row++)
+     {
+        line = elm_code_file_line_get(pd->code->file, row);
+        ret_len += line->length + newline_len;
+     }
+
+   ret = malloc(sizeof(char) * (ret_len + 1));
+
+   snprintf(ret, strlen(first) + newline_len + 1, "%s%s", first, newline);
+
+   ptr = ret;
+   ptr += strlen(first) + newline_len;
+
+   for (row = start_line + 1; row < end_line; row++)
+     {
+        line = elm_code_file_line_get(pd->code->file, row);
+        if (line->modified)
+          snprintf(ptr, line->length + 1, "%s", line->modified);
+        else
+          snprintf(ptr, line->length + 1, "%s", line->content);
+
+        snprintf(ptr + line->length, newline_len + 1, "%s", newline);
+        ptr += line->length + newline_len;
+     }
+   snprintf(ptr, strlen(last) + 1, "%s", last);
+
+   free(first);
+   free(last);
+   return ret;
+}
+
+static char *
+_elm_code_widget_text_single_get(Elm_Code_Widget *widget, Elm_Code_Widget_Data 
*pd,
+                                           unsigned int start_col, unsigned 
int start_line,
+                                           unsigned int end_col)
+{
+   Elm_Code_Line *line;
+   unsigned int start, end;
+
+   line = elm_code_file_line_get(pd->code->file, start_line);
+   start = elm_code_widget_line_text_position_for_column_get(widget, line, 
start_col);
+   end = elm_code_widget_line_text_position_for_column_get(widget, line, 
end_col + 1);
+
+   return elm_code_line_text_substr(line, start, end - start);
+}
+
+static char *
+_elm_code_widget_text_between_positions_get(Eo *widget, Elm_Code_Widget_Data 
*pd,
+                                            unsigned int start_col, unsigned 
int start_line,
+                                            unsigned int end_col, unsigned int 
end_line)
+{
+   if (start_line == end_line)
+     return _elm_code_widget_text_single_get(widget, pd, start_col, 
start_line, end_col);
+   else
+     return _elm_code_widget_text_multi_get(widget, pd, start_col, start_line, 
end_col, end_line);
+}
+
 static unsigned int
 _elm_code_widget_line_text_column_width_to_position(Eo *obj, 
Elm_Code_Widget_Data *pd EINA_UNUSED, Elm_Code_Line *line, unsigned int 
position)
 {
diff --git a/elm_code/src/lib/widget/elm_code_widget_undo.c 
b/elm_code/src/lib/widget/elm_code_widget_undo.c
index d51cc5f..6511be7 100644
--- a/elm_code/src/lib/widget/elm_code_widget_undo.c
+++ b/elm_code/src/lib/widget/elm_code_widget_undo.c
@@ -6,6 +6,19 @@
 
 #include "elm_code_widget_private.h"
 
+Elm_Code_Widget_Change_Info *
+_elm_code_widget_undo_info_copy(Elm_Code_Widget_Change_Info *info)
+{
+   Elm_Code_Widget_Change_Info *copy;
+
+   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);
+
+   return copy;
+}
+
 void
 _elm_code_widget_undo_change_add(Evas_Object *widget,
                                  Elm_Code_Widget_Change_Info *info)
@@ -13,9 +26,7 @@ _elm_code_widget_undo_change_add(Evas_Object *widget,
    Elm_Code_Widget_Data *pd;
    Elm_Code_Widget_Change_Info *info_copy;
 
-   info_copy = calloc(1, sizeof(*info));
-   memcpy(info_copy, info, sizeof(*info));
-
+   info_copy = _elm_code_widget_undo_info_copy(info);
    pd = eo_data_scope_get(widget, ELM_CODE_WIDGET_CLASS);
 
    pd->undo_stack_ptr = eina_list_prepend(pd->undo_stack_ptr, info_copy);
@@ -26,6 +37,10 @@ static void
 _elm_code_widget_undo_change(Evas_Object *widget,
                              Elm_Code_Widget_Change_Info *info)
 {
+   Elm_Code_Line *line;
+   Elm_Code_Widget_Data *pd;
+   unsigned int position;
+
    if (info->insert)
      {
         elm_code_widget_selection_start(widget, info->start_line, 
info->start_col);
@@ -34,6 +49,12 @@ _elm_code_widget_undo_change(Evas_Object *widget,
      }
    else
      {
+        pd = eo_data_scope_get(widget, ELM_CODE_WIDGET_CLASS);
+        line = elm_code_file_line_get(pd->code->file, info->start_line);
+        position = elm_code_widget_line_text_position_for_column_get(widget, 
line, info->start_col);
+
+        elm_code_line_text_insert(line, position, info->content, info->length);
+        elm_code_widget_cursor_position_set(widget, info->end_col, 
info->end_line);
      }
 }
 
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
index f6c13f0..6f20909 100644
--- a/elm_code/src/tests/widget/elm_code_test_widget_undo.c
+++ b/elm_code/src/tests/widget/elm_code_test_widget_undo.c
@@ -93,9 +93,55 @@ START_TEST (elm_code_test_widget_undo_newline)
 }
 END_TEST
 
+START_TEST (elm_code_test_widget_undo_delete)
+{
+   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, 4, 1);
+   _elm_code_widget_backspace(widget);
+
+   line = elm_code_file_line_get(file, 1);
+   content = elm_code_line_text_get(line, &length);
+   ck_assert_strn_eq("tet", 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, 2, 1);
+   _elm_code_widget_delete(widget);
+
+   line = elm_code_file_line_get(file, 1);
+   content = elm_code_line_text_get(line, &length);
+   ck_assert_strn_eq("tst", 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
+
 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);
+   tcase_add_test(tc, elm_code_test_widget_undo_delete);
 }
 

-- 


Reply via email to