More work of selections as text
This commit is contained in:
parent
8156a7520f
commit
ac1aaab077
2 changed files with 55 additions and 20 deletions
|
|
@ -3479,7 +3479,9 @@ text_for_range(Screen *self, const Selection *sel, bool insert_newlines, bool st
|
|||
const int limit = MIN((int)self->lines, idata.y_limit);
|
||||
if (idata.y >= limit) return PyTuple_New(0);
|
||||
RAII_PyObject(ans, PyTuple_New(limit - idata.y));
|
||||
if (!ans) return NULL;
|
||||
RAII_PyObject(nl, PyUnicode_FromString("\n"));
|
||||
RAII_PyObject(empty, PyUnicode_FromString(""));
|
||||
if (!ans || !nl || !empty) return NULL;
|
||||
range_line(self, idata.y, &next_line);
|
||||
xrn = xrange_for_iteration_with_multicells(&idata, idata.y, &next_line);
|
||||
for (int i = 0, y = idata.y; y < limit; y++, i++) {
|
||||
|
|
@ -3492,7 +3494,7 @@ text_for_range(Screen *self, const Selection *sel, bool insert_newlines, bool st
|
|||
index_type new_limit = limit_without_trailing_whitespace(&line, x_limit);
|
||||
if (new_limit != x_limit) {
|
||||
x_limit = new_limit;
|
||||
is_only_whitespace_line = true;
|
||||
is_only_whitespace_line = new_limit <= xr.x;
|
||||
}
|
||||
}
|
||||
const bool add_trailing_newline = insert_newlines && !is_last_line;
|
||||
|
|
@ -3510,7 +3512,8 @@ text_for_range(Screen *self, const Selection *sel, bool insert_newlines, bool st
|
|||
}
|
||||
PyObject *text = NULL;
|
||||
if (x_limit <= xr.x && is_only_whitespace_line) { // we want a newline on only whitespace lines even if they are continued
|
||||
text = add_trailing_newline ? PyUnicode_FromString("\n") : PyUnicode_FromString("");
|
||||
text = add_trailing_newline ? nl : empty;
|
||||
text = Py_NewRef(text);
|
||||
} else {
|
||||
if (!unicode_in_range(&line, xr.x, x_limit, true, add_trailing_newline, false, !is_first_line, &self->as_ansi_buf)) return PyErr_NoMemory();
|
||||
if (!is_last_line) {
|
||||
|
|
@ -3539,40 +3542,63 @@ ansi_for_range(Screen *self, const Selection *sel, bool insert_newlines, bool st
|
|||
RAII_PyObject(ans, PyTuple_New(limit - idata.y + 1));
|
||||
RAII_PyObject(nl, PyUnicode_FromString("\n"));
|
||||
if (!ans || !nl) return NULL;
|
||||
ANSIBuf output = {0};
|
||||
bool has_escape_codes = false;
|
||||
bool need_newline = false;
|
||||
ANSILineState s = {.output_buf=&output};
|
||||
ANSILineState s = {.output_buf=&self->as_ansi_buf};
|
||||
Line line = {.xnum=self->columns, .text_cache=self->text_cache}, next_line = line; XRange xr, xrn = {0}; CPUCell *c;
|
||||
range_line(self, idata.y, &next_line);
|
||||
xrn = xrange_for_iteration_with_multicells(&idata, idata.y, &next_line);
|
||||
s.output_buf->active_hyperlink_id = 0; s.output_buf->len = 0;
|
||||
for (int i = 0, y = idata.y; y < limit; y++, i++) {
|
||||
Line *line = range_line_(self, y);
|
||||
XRange xr = xrange_for_iteration_with_multicells(&idata, y, line);
|
||||
output.len = 0;
|
||||
const bool is_first_line = y == idata.y, is_last_line = y + 1 >= limit;
|
||||
xr = xrn;
|
||||
line = next_line;
|
||||
s.output_buf->len = 0;
|
||||
char_type prefix_char = need_newline ? '\n' : 0;
|
||||
index_type x_limit = xr.x_limit;
|
||||
bool is_only_whitespace_line = false;
|
||||
if (strip_trailing_whitespace) {
|
||||
index_type new_limit = limit_without_trailing_whitespace(line, x_limit);
|
||||
index_type new_limit = limit_without_trailing_whitespace(&line, x_limit);
|
||||
if (new_limit != x_limit) {
|
||||
x_limit = new_limit;
|
||||
if (!x_limit) {
|
||||
PyTuple_SET_ITEM(ans, i, nl);
|
||||
continue;
|
||||
is_only_whitespace_line = new_limit <= xr.x;
|
||||
}
|
||||
}
|
||||
if (!is_last_line) {
|
||||
range_line(self, y + 1, &next_line);
|
||||
xrn = xrange_for_iteration_with_multicells(&idata, y+1, &next_line);
|
||||
for (index_type x = 0; x < xr.x; x++) {
|
||||
if ((c = &line.cpu_cells[x])->is_multicell && c->scale > 1 && c->y + 1 < c->scale && x <= xrn.x) {
|
||||
index_type mc_limit = x + mcd_x_limit(c);
|
||||
if (line_as_ansi(&line, &s, x, mc_limit, prefix_char, false)) has_escape_codes = true;
|
||||
x = mc_limit - 1;
|
||||
prefix_char = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
const bool is_first_line = y == idata.y;
|
||||
if (is_first_line) {
|
||||
if (x_limit <= xr.x && is_only_whitespace_line) { // we want a newline on only whitespace lines even if they are continued
|
||||
if (insert_newlines) need_newline = true;
|
||||
} else {
|
||||
if (line_as_ansi(&line, &s, xr.x, x_limit, prefix_char, !is_first_line)) has_escape_codes = true;
|
||||
need_newline = insert_newlines && !line.cpu_cells[line.xnum-1].next_char_was_wrapped;
|
||||
if (!is_last_line) {
|
||||
for (index_type x = x_limit; x < MIN(line.xnum, xrn.x_limit); x++) {
|
||||
if ((c = &line.cpu_cells[x])->is_multicell && c->scale > 1 && c->y + 1 < c->scale) {
|
||||
index_type mc_limit = x + mcd_x_limit(c);
|
||||
if (line_as_ansi(&line, &s, x, mc_limit, 0, false)) has_escape_codes = true;
|
||||
x = mc_limit - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (line_as_ansi(line, &s, xr.x, x_limit, prefix_char, !is_first_line)) has_escape_codes = true;
|
||||
need_newline = insert_newlines && !line->cpu_cells[line->xnum-1].next_char_was_wrapped;
|
||||
PyObject *t = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, output.buf, output.len);
|
||||
PyObject *t = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, s.output_buf->buf, s.output_buf->len);
|
||||
if (!t) return NULL;
|
||||
PyTuple_SET_ITEM(ans, i, t);
|
||||
}
|
||||
PyObject *t = PyUnicode_FromFormat("%s%s", has_escape_codes ? "\x1b[m" : "", output.active_hyperlink_id ? "\x1b]8;;\x1b\\" : "");
|
||||
PyObject *t = PyUnicode_FromFormat("%s%s", has_escape_codes ? "\x1b[m" : "", s.output_buf->active_hyperlink_id ? "\x1b]8;;\x1b\\" : "");
|
||||
if (!t) return NULL;
|
||||
PyTuple_SET_ITEM(ans, PyTuple_GET_SIZE(ans) - 1, t);
|
||||
Py_INCREF(ans);
|
||||
return ans;
|
||||
return Py_NewRef(ans);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -618,18 +618,27 @@ def as_lists(x):
|
|||
for i, (e, a) in enumerate(zip(as_lists(bytes(expected)), as_lists(actual))):
|
||||
self.ae(e, a, f'Row: {i}')
|
||||
|
||||
def ast(*expected, as_ansi=False, strip_trailing_whitespace=False):
|
||||
actual = s.text_for_selection(as_ansi, strip_trailing_whitespace)
|
||||
self.ae(expected, actual)
|
||||
|
||||
s.reset()
|
||||
s.draw('a'), multicell(s, 'b', width=2), s.draw('c')
|
||||
ss(p(), p(x=1, in_left_half_of_cell=False))
|
||||
asl((0, 0, 2))
|
||||
ast('ab')
|
||||
ss(p(x=2), p(x=3, in_left_half_of_cell=False))
|
||||
asl((0, 1, 3))
|
||||
ast('bc')
|
||||
|
||||
s.reset()
|
||||
s.draw('a'), multicell(s, 'b', scale=2), s.draw('c'), multicell(s, 'd', scale=2)
|
||||
ss(p(), p(x=4, in_left_half_of_cell=False))
|
||||
asl((0, 0, 5), (1, 1, 2), (1, 4, 5))
|
||||
ast('abcd')
|
||||
ss(p(y=1, x=1), p(y=1, x=1, in_left_half_of_cell=False))
|
||||
asl((0, 1, 2), (1, 1, 2))
|
||||
ast('b')
|
||||
ss(p(y=1, x=0), p(y=1, x=1, in_left_half_of_cell=False)) # empty leading cell before multiline on y=1
|
||||
asl((0, 1, 2), (1, 0, 2))
|
||||
ast(' b')
|
||||
|
|
|
|||
Loading…
Reference in a new issue