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 <dh.herrmann@googlemail.com>
This commit is contained in:
David Herrmann 2012-10-07 15:05:15 +02:00
parent 742acfa093
commit 3ecd09ddd3
2 changed files with 230 additions and 0 deletions

View File

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

View File

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