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
This commit is contained in:
Andy Williams 2015-04-19 15:00:10 +01:00
parent 675bcb51ea
commit 6bd0d56e13
8 changed files with 159 additions and 27 deletions

View File

@ -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)

View File

@ -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
*
* @{
*

View File

@ -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)
{

View File

@ -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);

View File

@ -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

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}