forked from enlightenment/edi
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:
parent
675bcb51ea
commit
6bd0d56e13
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
*
|
||||
* @{
|
||||
*
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue