ajwillia-ms pushed a commit to branch master.

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

commit 6bd0d56e132512829fac60bbd487a0aed6188dcf
Author: Andy Williams <a...@andywilliams.me>
Date:   Sun Apr 19 15:00:10 2015 +0100

    elm_code: add multiline paste support.
    
    Creating and breaking out a few helper text methods at the same time.
    Test all that we can for this reasonably complex operation
---
 elm_code/src/lib/elm_code_line.c                   | 18 +++++++
 elm_code/src/lib/elm_code_line.h                   | 14 ++++-
 elm_code/src/lib/elm_code_text.c                   | 42 +++++++++++++--
 elm_code/src/lib/elm_code_text.h                   |  4 ++
 elm_code/src/lib/widget/elm_code_widget.c          | 15 ++----
 .../src/lib/widget/elm_code_widget_selection.c     | 59 ++++++++++++++++++----
 elm_code/src/tests/elm_code_test_line.c            | 23 +++++++++
 elm_code/src/tests/elm_code_test_text.c            | 11 ++++
 8 files changed, 159 insertions(+), 27 deletions(-)

diff --git a/elm_code/src/lib/elm_code_line.c b/elm_code/src/lib/elm_code_line.c
index 5195972..f9d3b08 100644
--- a/elm_code/src/lib/elm_code_line.c
+++ b/elm_code/src/lib/elm_code_line.c
@@ -20,6 +20,24 @@ elm_code_line_free(Elm_Code_Line *line)
    free(line);
 }
 
+EAPI void elm_code_line_split_at(Elm_Code_Line *line, unsigned int position)
+{
+   Elm_Code_Line *newline;
+   char *content;
+   unsigned int length;
+
+   content = (char *) elm_code_line_text_get(line, &length);
+   content = strndup(content, length);
+   elm_code_file_line_insert(line->file, line->number + 1, "", 0, NULL);
+   newline = elm_code_file_line_get(line->file, line->number + 1);
+// TODO we need to split tokens from these lines
+
+   elm_code_line_text_set(newline, content + position, length - position);
+   elm_code_line_text_set(line, content, position);
+
+   free(content);
+}
+
 EAPI void elm_code_line_status_set(Elm_Code_Line *line, Elm_Code_Status_Type 
status)
 {
    if (!line)
diff --git a/elm_code/src/lib/elm_code_line.h b/elm_code/src/lib/elm_code_line.h
index e3ad128..6a0f767 100644
--- a/elm_code/src/lib/elm_code_line.h
+++ b/elm_code/src/lib/elm_code_line.h
@@ -38,8 +38,20 @@ typedef struct _Elm_Code_Line
 EAPI void elm_code_line_free(Elm_Code_Line *line);
 
 /**
+ * @brief Line manipulation functions.
+ * @defgroup Content
+ * @{
+ *
+ * Functions for changing the content of lines in an Elm_Code_File
+ */
+
+EAPI void elm_code_line_split_at(Elm_Code_Line *line, unsigned int position);
+
+/**
+ * @}
+ *
  * @brief Line markup functions.
- * @defgroup Line highlighting and status manipulation
+ * @defgroup Highlighting
  *
  * @{
  *
diff --git a/elm_code/src/lib/elm_code_text.c b/elm_code/src/lib/elm_code_text.c
index 206a6cf..8b22f3a 100644
--- a/elm_code/src/lib/elm_code_text.c
+++ b/elm_code/src/lib/elm_code_text.c
@@ -42,14 +42,12 @@ elm_code_line_text_set(Elm_Code_Line *line, const char 
*chars, unsigned int leng
 }
 
 EAPI int
-elm_code_line_text_strpos(Elm_Code_Line *line, const char *search, int offset)
+elm_code_text_strnpos(const char *content, unsigned int length, const char 
*search, int offset)
 {
-   unsigned int length, searchlen, c;
-   const char *content;
+   unsigned int searchlen, c;
    char *ptr;
 
    searchlen = strlen(search);
-   content = elm_code_line_text_get(line, &length);
    ptr = (char *) content;
 
    if (searchlen > length)
@@ -67,6 +65,16 @@ elm_code_line_text_strpos(Elm_Code_Line *line, const char 
*search, int offset)
    return ELM_CODE_TEXT_NOT_FOUND;
 }
 
+EAPI int
+elm_code_line_text_strpos(Elm_Code_Line *line, const char *search, int offset)
+{
+   unsigned int length;
+   const char *content;
+
+   content = elm_code_line_text_get(line, &length);
+   return elm_code_text_strnpos(content, length, search, offset);
+}
+
 EAPI Eina_Bool
 elm_code_line_text_contains(Elm_Code_Line *line, const char *search)
 {
@@ -201,12 +209,36 @@ elm_code_line_text_remove(Elm_Code_Line *line, unsigned 
int position, int length
 
 /* generic text functions */
 
-unsigned int
+EAPI unsigned int
 elm_code_text_tabwidth_at_position(unsigned int position, unsigned int tabstop)
 {
    return tabstop - (position % tabstop);
 }
 
+EAPI int
+elm_code_text_newlinenpos(const char *text, unsigned int length)
+{
+   int lfpos, crpos;
+   int check;
+
+   lfpos = elm_code_text_strnpos(text, length, "\n", 0);
+   check = length;
+   if (lfpos != ELM_CODE_TEXT_NOT_FOUND)
+     check = lfpos;
+   crpos = elm_code_text_strnpos(text, check, "\r", 0);
+
+   if (lfpos == ELM_CODE_TEXT_NOT_FOUND && crpos == ELM_CODE_TEXT_NOT_FOUND)
+     return ELM_CODE_TEXT_NOT_FOUND;
+
+   if (crpos == ELM_CODE_TEXT_NOT_FOUND)
+     return lfpos;
+   if (lfpos == ELM_CODE_TEXT_NOT_FOUND)
+     return crpos;
+   if (lfpos < crpos)
+     return lfpos;
+   return crpos;
+}
+
 EAPI unsigned int
 elm_code_line_text_column_width_to_position(Elm_Code_Line *line, unsigned int 
position, unsigned int tabstop)
 {
diff --git a/elm_code/src/lib/elm_code_text.h b/elm_code/src/lib/elm_code_text.h
index 17a47eb..15b236e 100644
--- a/elm_code/src/lib/elm_code_text.h
+++ b/elm_code/src/lib/elm_code_text.h
@@ -50,6 +50,10 @@ EAPI void elm_code_line_text_remove(Elm_Code_Line *line, 
unsigned int position,
 
 EAPI unsigned int elm_code_text_tabwidth_at_position(unsigned int position, 
unsigned int tabstop);
 
+EAPI int elm_code_text_strnpos(const char *text, unsigned int length, const 
char *search, int offset);
+
+EAPI int elm_code_text_newlinenpos(const char *text, unsigned int length);
+
 EAPI unsigned int elm_code_line_text_column_width_to_position(Elm_Code_Line 
*line, unsigned int length, unsigned int tabstop);
 
 EAPI unsigned int elm_code_line_text_column_width(Elm_Code_Line *line, 
unsigned int tabstop);
diff --git a/elm_code/src/lib/widget/elm_code_widget.c 
b/elm_code/src/lib/widget/elm_code_widget.c
index f641906..4c1edc4 100644
--- a/elm_code/src/lib/widget/elm_code_widget.c
+++ b/elm_code/src/lib/widget/elm_code_widget.c
@@ -859,10 +859,9 @@ static void
 _elm_code_widget_newline(Elm_Code_Widget *widget)
 {
    Elm_Code *code;
-   Elm_Code_Line *line, *newline;
+   Elm_Code_Line *line;
    Elm_Code_Widget_Data *pd;
-   unsigned int row, col, length, position;
-   char *content;
+   unsigned int row, col, position;
 
    pd = eo_data_scope_get(widget, ELM_CODE_WIDGET_CLASS);
    _elm_code_widget_delete_selection(widget);
@@ -871,17 +870,9 @@ _elm_code_widget_newline(Elm_Code_Widget *widget)
          elm_code_widget_cursor_position_get(&col, &row));
    line = elm_code_file_line_get(code->file, row);
 
-   content = (char *) elm_code_line_text_get(line, &length);
-   content = strndup(content, length);
-   elm_code_file_line_insert(code->file, line->number + 1, "", 0, NULL);
-   newline = elm_code_file_line_get(code->file, line->number + 1);
-// TODO we need to split tokens from these lines (move this to elm_code_line?)
-
    position = elm_code_line_text_position_for_column_get(line, col - 1, 
pd->tabstop);
-   elm_code_line_text_set(newline, content + position, length - position);
-   elm_code_line_text_set(line, content, position);
+   elm_code_line_split_at(line, position);
 
-   free(content);
    eo_do(widget,
          elm_code_widget_cursor_position_set(1, row + 1),
 // TODO construct and pass a change object
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 a7a5c01..473d999 100644
--- a/elm_code/src/lib/widget/elm_code_widget_selection.c
+++ b/elm_code/src/lib/widget/elm_code_widget_selection.c
@@ -287,14 +287,58 @@ elm_code_widget_selection_copy(Evas_Object *widget)
    free(text);
 }
 
+static void
+_selection_paste_single(Elm_Code_Widget *widget, Elm_Code_Widget_Data *pd, 
Elm_Code *code,
+                        unsigned int col, unsigned int row, const char *text, 
unsigned int len)
+{
+   Elm_Code_Line *line;
+   unsigned int position, newcol;
+
+   line = elm_code_file_line_get(code->file, row);
+   position = elm_code_line_text_position_for_column_get(line, col - 1, 
pd->tabstop);
+   elm_code_line_text_insert(line, position + 1, text, len);
+
+   newcol = elm_code_line_text_column_width_to_position(line, position + len, 
pd->tabstop);
+   eo_do(widget,
+         elm_code_widget_cursor_position_set(newcol + 1, row));
+}
+
+static void
+_selection_paste_multi(Elm_Code_Widget *widget, Elm_Code_Widget_Data *pd, 
Elm_Code *code,
+                       unsigned int col, unsigned int row, const char *text, 
unsigned int len)
+{
+   Elm_Code_Line *line;
+   unsigned int position, newrow;
+   int nlpos;
+   char *ptr;
+
+   line = elm_code_file_line_get(code->file, row);
+   position = elm_code_line_text_position_for_column_get(line, col - 1, 
pd->tabstop);
+   elm_code_line_split_at(line, position);
+
+   newrow = row;
+   ptr = (char *)text;
+   while ((nlpos = elm_code_text_newlinenpos(ptr, len)) != 
ELM_CODE_TEXT_NOT_FOUND)
+     {
+        if (newrow == row)
+          _selection_paste_single(widget, pd, code, col, row, text, nlpos);
+        else
+          elm_code_file_line_insert(code->file, newrow, ptr, nlpos, NULL);
+
+        ptr += nlpos + 1; // TODO make this adapt to windows lengths (length 
param to newlinenpos)
+        newrow++;
+     }
+
+   _selection_paste_single(widget, pd, code, 1, newrow, ptr, len - (ptr - 
text));
+}
+
 static Eina_Bool
 _selection_paste_cb(void *data, Evas_Object *obj EINA_UNUSED, 
Elm_Selection_Data *ev)
 {
    Elm_Code *code;
    Elm_Code_Widget *widget;
-   Elm_Code_Line *line;
    Elm_Code_Widget_Data *pd;
-   unsigned int row, col, col_width, position;
+   unsigned int row, col;
 
    widget = (Elm_Code_Widget *)data;
    pd = eo_data_scope_get(widget, ELM_CODE_WIDGET_CLASS);
@@ -308,15 +352,12 @@ _selection_paste_cb(void *data, Evas_Object *obj 
EINA_UNUSED, Elm_Selection_Data
    eo_do(widget,
          code = elm_code_widget_code_get(),
          elm_code_widget_cursor_position_get(&col, &row));
-   line = elm_code_file_line_get(code->file, row);
 
-   position = elm_code_line_text_position_for_column_get(line, col - 1, 
pd->tabstop);
-   elm_code_line_text_insert(line, position + 1, ev->data, ev->len - 1);
+   if (elm_code_text_newlinenpos(ev->data, ev->len) == ELM_CODE_TEXT_NOT_FOUND)
+     _selection_paste_single(widget, pd, code, col, row, ev->data, ev->len - 
1);
+   else
+     _selection_paste_multi(widget, pd, code, col, row, ev->data, ev->len - 1);
 
-   col_width = elm_code_line_text_column_width_to_position(line, position + 
ev->len - 1, pd->tabstop) -
-               elm_code_line_text_column_width_to_position(line, position, 
pd->tabstop);
-   eo_do(widget,
-         elm_code_widget_cursor_position_set(col + col_width, row));
    return EINA_TRUE;
 }
 
diff --git a/elm_code/src/tests/elm_code_test_line.c 
b/elm_code/src/tests/elm_code_test_line.c
index 5d26897..b19bf61 100644
--- a/elm_code/src/tests/elm_code_test_line.c
+++ b/elm_code/src/tests/elm_code_test_line.c
@@ -44,9 +44,32 @@ START_TEST (elm_code_line_token_count_test)
 }
 END_TEST
 
+START_TEST (elm_code_line_split_test)
+{
+   Elm_Code *code;
+   Elm_Code_File *file;
+   Elm_Code_Line *line, *newline;
+
+   code = elm_code_create();
+   file = elm_code_file_new(code);
+
+   elm_code_file_line_append(file, "line1line2", 10, NULL);
+   line = elm_code_file_line_get(file, 1);
+   ck_assert_int_eq(1, elm_code_file_lines_get(file));
+   ck_assert_int_eq(10, line->length);
+
+   elm_code_line_split_at(line, 5);
+   ck_assert_int_eq(2, elm_code_file_lines_get(file));
+   newline = elm_code_file_line_get(file, 2);
+   ck_assert_int_eq(5, line->length);
+   ck_assert_int_eq(5, newline->length);
+}
+END_TEST
+
 void elm_code_test_line(TCase *tc)
 {
    tcase_add_test(tc, elm_code_line_create_test);
    tcase_add_test(tc, elm_code_line_token_count_test);
+   tcase_add_test(tc, elm_code_line_split_test);
 }
 
diff --git a/elm_code/src/tests/elm_code_test_text.c 
b/elm_code/src/tests/elm_code_test_text.c
index f017835..1798433 100644
--- a/elm_code/src/tests/elm_code_test_text.c
+++ b/elm_code/src/tests/elm_code_test_text.c
@@ -81,10 +81,21 @@ START_TEST (elm_code_text_strpos_test)
 }
 END_TEST
 
+START_TEST (elm_code_text_newline_position_test)
+{
+   const char *unixtext = "a test\nwith newline";
+   const char *wintext = "a windows\r\nnewline";
+
+   ck_assert_int_eq(6, elm_code_text_newlinenpos(unixtext, strlen(unixtext)));
+   ck_assert_int_eq(9, elm_code_text_newlinenpos(wintext, strlen(wintext)));
+}
+END_TEST
+
 void elm_code_test_text(TCase *tc)
 {
    tcase_add_test(tc, elm_code_text_get_test);
    tcase_add_test(tc, elm_code_text_insert_test);
    tcase_add_test(tc, elm_code_text_contains_test);
    tcase_add_test(tc, elm_code_text_strpos_test);
+   tcase_add_test(tc, elm_code_text_newline_position_test);
 }

-- 


Reply via email to