From 3ecd09ddd30e2139b437d10ba7ad66daeb4ba89e Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Sun, 7 Oct 2012 15:05:15 +0200 Subject: [PATCH] tsm: screen: implement selection extraction This adds a new helper that returns the UTF8 encoded data of the selected parts in the tsm-screen object. There is still much to do and it isn't a nice solution. However, it's a proof-of-concept and works for now so we can just keep it. Signed-off-by: David Herrmann --- src/tsm_screen.c | 229 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/tsm_screen.h | 1 + 2 files changed, 230 insertions(+) diff --git a/src/tsm_screen.c b/src/tsm_screen.c index 32f9417..c7ae68f 100644 --- a/src/tsm_screen.c +++ b/src/tsm_screen.c @@ -1420,6 +1420,235 @@ void tsm_screen_selection_target(struct tsm_screen *con, selection_set(con, &con->sel_end, posx, posy); } +/* TODO: tsm_ucs4_to_utf8 expects UCS4 characters, but a cell contains a + * tsm-symbol (which can contain multiple UCS4 chars). Fix this when introducing + * support for combining characters. */ +static unsigned int copy_line(struct line *line, char *buf, + unsigned int start, unsigned int len) +{ + unsigned int i, end; + char *pos = buf; + + end = start + len; + for (i = start; i < line->size && i < end; ++i) { + if (i < line->size || !line->cells[i].ch) + pos += tsm_ucs4_to_utf8(line->cells[i].ch, pos); + else + pos += tsm_ucs4_to_utf8(' ', pos); + } + + return pos - buf; +} + +/* TODO: This beast definitely needs some "beautification", however, it's meant + * as a "proof-of-concept" so its enough for now. */ +int tsm_screen_selection_copy(struct tsm_screen *con, char **out) +{ + unsigned int len, i; + struct selection_pos *start, *end; + struct line *iter; + char *str, *pos; + + if (!con || !out) + return -EINVAL; + + if (!con->sel_active) + return -ENOENT; + + /* check whether sel_start or sel_end comes first */ + if (!con->sel_start.line && con->sel_start.y == SELECTION_TOP) { + if (!con->sel_end.line && con->sel_end.y == SELECTION_TOP) { + str = strdup(""); + if (!str) + return -ENOMEM; + *out = str; + return 0; + } + start = &con->sel_start; + end = &con->sel_end; + } else if (!con->sel_end.line && con->sel_end.y == SELECTION_TOP) { + start = &con->sel_end; + end = &con->sel_start; + } else if (con->sel_start.line && con->sel_end.line) { + if (con->sel_start.line->sb_id < con->sel_end.line->sb_id) { + start = &con->sel_start; + end = &con->sel_end; + } else if (con->sel_start.line->sb_id > con->sel_end.line->sb_id) { + start = &con->sel_end; + end = &con->sel_start; + } else if (con->sel_start.x < con->sel_end.x) { + start = &con->sel_start; + end = &con->sel_end; + } else { + start = &con->sel_end; + end = &con->sel_start; + } + } else if (con->sel_start.line) { + start = &con->sel_start; + end = &con->sel_end; + } else if (con->sel_end.line) { + start = &con->sel_end; + end = &con->sel_start; + } else if (con->sel_start.y < con->sel_end.y) { + start = &con->sel_start; + end = &con->sel_end; + } else if (con->sel_start.y > con->sel_end.y) { + start = &con->sel_end; + end = &con->sel_start; + } else if (con->sel_start.x < con->sel_end.x) { + start = &con->sel_start; + end = &con->sel_end; + } else { + start = &con->sel_end; + end = &con->sel_start; + } + + /* calculate size of buffer */ + len = 0; + iter = start->line; + if (!iter && start->y == SELECTION_TOP) + iter = con->sb_first; + + while (iter) { + if (iter == start->line && iter == end->line) { + if (iter->size > start->x) { + if (iter->size > end->x) + len += end->x - start->x + 1; + else + len += iter->size - start->x; + } + break; + } else if (iter == start->line) { + if (iter->size > start->x) + len += iter->size - start->x; + } else if (iter == end->line) { + if (iter->size > end->x) + len += end->x + 1; + else + len += iter->size; + break; + } else { + len += iter->size; + } + + ++len; + iter = iter->next; + } + + if (!end->line) { + if (start->line || start->y == SELECTION_TOP) + i = 0; + else + i = start->y; + for ( ; i < con->size_y; ++i) { + if (!start->line && start->y == i && end->y == i) { + if (con->size_x > start->x) { + if (con->size_x > end->x) + len += end->x - start->x + 1; + else + len += con->size_x - start->x; + } + break; + } else if (!start->line && start->y == i) { + if (con->size_x > start->x) + len += con->size_x - start->x; + } else if (end->y == i) { + if (con->size_x > end->x) + len += end->x + 1; + else + len += con->size_x; + break; + } else { + len += con->size_x; + } + + ++len; + } + } + + /* allocate buffer */ + len *= 4; + ++len; + str = malloc(len); + if (!str) + return -ENOMEM; + pos = str; + + /* copy data into buffer */ + iter = start->line; + if (!iter && start->y == SELECTION_TOP) + iter = con->sb_first; + + while (iter) { + if (iter == start->line && iter == end->line) { + if (iter->size > start->x) { + if (iter->size > end->x) + len = end->x - start->x + 1; + else + len = iter->size - start->x; + pos += copy_line(iter, pos, start->x, len); + } + break; + } else if (iter == start->line) { + if (iter->size > start->x) + pos += copy_line(iter, pos, start->x, + iter->size - start->x); + } else if (iter == end->line) { + if (iter->size > end->x) + len = end->x + 1; + else + len = iter->size; + pos += copy_line(iter, pos, 0, len); + break; + } else { + pos += copy_line(iter, pos, 0, iter->size); + } + + *pos++ = '\n'; + iter = iter->next; + } + + if (!end->line) { + if (start->line || start->y == SELECTION_TOP) + i = 0; + else + i = start->y; + for ( ; i < con->size_y; ++i) { + iter = con->lines[i]; + if (!start->line && start->y == i && end->y == i) { + if (con->size_x > start->x) { + if (con->size_x > end->x) + len = end->x - start->x + 1; + else + len = con->size_x - start->x; + pos += copy_line(iter, pos, start->x, len); + } + break; + } else if (!start->line && start->y == i) { + if (con->size_x > start->x) + pos += copy_line(iter, pos, start->x, + con->size_x - start->x); + } else if (end->y == i) { + if (con->size_x > end->x) + len = end->x + 1; + else + len = con->size_x; + pos += copy_line(iter, pos, 0, len); + break; + } else { + pos += copy_line(iter, pos, 0, con->size_x); + } + + *pos++ = '\n'; + } + } + + /* return buffer */ + *pos = 0; + *out = str; + return pos - str; +} + void tsm_screen_draw(struct tsm_screen *con, tsm_screen_prepare_cb prepare_cb, tsm_screen_draw_cb draw_cb, diff --git a/src/tsm_screen.h b/src/tsm_screen.h index 3fc6f8b..9e3807d 100644 --- a/src/tsm_screen.h +++ b/src/tsm_screen.h @@ -181,6 +181,7 @@ void tsm_screen_selection_start(struct tsm_screen *con, void tsm_screen_selection_target(struct tsm_screen *con, unsigned int posx, unsigned int posy); +int tsm_screen_selection_copy(struct tsm_screen *con, char **out); void tsm_screen_draw(struct tsm_screen *con, tsm_screen_prepare_cb prepare_cb, -- 2.7.4