mirror of
https://github.com/kovidgoyal/kitty.git
synced 2026-07-03 11:12:30 +08:00
Start work on multicell support for selection_as_text
This commit is contained in:
@@ -19,7 +19,6 @@ typedef enum {
|
||||
FREETYPE_CLEANUP_FUNC,
|
||||
SYSTEMD_CLEANUP_FUNC,
|
||||
SHADERS_CLEANUP_FUNC,
|
||||
LINE_CLEANUP_FUNC,
|
||||
|
||||
NUM_CLEANUP_FUNCS
|
||||
} AtExitCleanupFunc;
|
||||
|
||||
@@ -268,7 +268,7 @@ pagerhist_push(HistoryBuf *self, ANSIBuf *as_ansi_buf) {
|
||||
Line l = {.xnum=self->xnum, .text_cache=self->text_cache};
|
||||
init_line(self, self->start_of_data, &l);
|
||||
ANSILineState s = {.output_buf=as_ansi_buf};
|
||||
line_as_ansi(&l, &s, 0, l.xnum, 0);
|
||||
line_as_ansi(&l, &s, 0, l.xnum, 0, true);
|
||||
pagerhist_write_bytes(ph, (const uint8_t*)"\x1b[m", 3);
|
||||
if (pagerhist_write_ucs4(ph, as_ansi_buf->buf, as_ansi_buf->len)) {
|
||||
char line_end[2]; size_t num = 0;
|
||||
@@ -320,9 +320,10 @@ static PyObject*
|
||||
__str__(HistoryBuf *self) {
|
||||
PyObject *lines = PyTuple_New(self->count);
|
||||
if (lines == NULL) return PyErr_NoMemory();
|
||||
RAII_ANSIBuf(buf);
|
||||
for (index_type i = 0; i < self->count; i++) {
|
||||
init_line(self, index_of(self, i), self->line);
|
||||
PyObject *t = line_as_unicode(self->line, false);
|
||||
PyObject *t = line_as_unicode(self->line, false, &buf);
|
||||
if (t == NULL) { Py_CLEAR(lines); return NULL; }
|
||||
PyTuple_SET_ITEM(lines, i, t);
|
||||
}
|
||||
@@ -350,7 +351,7 @@ as_ansi(HistoryBuf *self, PyObject *callback) {
|
||||
ANSIBuf output = {0}; ANSILineState s = {.output_buf=&output};
|
||||
for(unsigned int i = 0; i < self->count; i++) {
|
||||
init_line(self, i, &l);
|
||||
line_as_ansi(&l, &s, 0, l.xnum, 0);
|
||||
line_as_ansi(&l, &s, 0, l.xnum, 0, true);
|
||||
if (!l.cpu_cells[l.xnum - 1].next_char_was_wrapped) {
|
||||
ensure_space_for(&output, buf, Py_UCS4, output.len + 1, capacity, 2048, false);
|
||||
output.buf[output.len++] = '\n';
|
||||
|
||||
@@ -470,7 +470,7 @@ as_ansi(LineBuf *self, PyObject *callback) {
|
||||
ANSIBuf output = {0}; ANSILineState s = {.output_buf=&output};
|
||||
do {
|
||||
init_line(self, &l, self->line_map[ylimit]);
|
||||
line_as_ansi(&l, &s, 0, l.xnum, 0);
|
||||
line_as_ansi(&l, &s, 0, l.xnum, 0, true);
|
||||
if (output.len) break;
|
||||
ylimit--;
|
||||
} while(ylimit > 0);
|
||||
@@ -478,7 +478,7 @@ as_ansi(LineBuf *self, PyObject *callback) {
|
||||
for(index_type i = 0; i <= ylimit; i++) {
|
||||
bool output_newline = !linebuf_line_ends_with_continuation(self, i);
|
||||
init_line(self, &l, self->line_map[i]);
|
||||
line_as_ansi(&l, &s, 0, l.xnum, 0);
|
||||
line_as_ansi(&l, &s, 0, l.xnum, 0, true);
|
||||
if (output_newline) {
|
||||
ensure_space_for(&output, buf, Py_UCS4, output.len + 1, capacity, 2048, false);
|
||||
output.buf[output.len++] = 10; // 10 = \n
|
||||
@@ -515,10 +515,11 @@ as_text(LineBuf *self, PyObject *args) {
|
||||
static PyObject*
|
||||
__str__(LineBuf *self) {
|
||||
RAII_PyObject(lines, PyTuple_New(self->ynum));
|
||||
RAII_ANSIBuf(buf);
|
||||
if (lines == NULL) return PyErr_NoMemory();
|
||||
for (index_type i = 0; i < self->ynum; i++) {
|
||||
init_line(self, self->line, self->line_map[i]);
|
||||
PyObject *t = line_as_unicode(self->line, false);
|
||||
PyObject *t = line_as_unicode(self->line, false, &buf);
|
||||
if (t == NULL) return NULL;
|
||||
PyTuple_SET_ITEM(lines, i, t);
|
||||
}
|
||||
|
||||
69
kitty/line.c
69
kitty/line.c
@@ -5,8 +5,6 @@
|
||||
* Distributed under terms of the GPL3 license.
|
||||
*/
|
||||
|
||||
#include "cleanup.h"
|
||||
#define EXTRA_INIT register_at_exit_cleanup_func(LINE_CLEANUP_FUNC, cleanup_module);
|
||||
|
||||
#include "state.h"
|
||||
#include "unicode-data.h"
|
||||
@@ -109,9 +107,9 @@ multicell_is_continuation_of_previous(const CPUCell *prev, const CPUCell *curr)
|
||||
}
|
||||
|
||||
static void
|
||||
text_in_cell_ansi(ANSILineState *s, const CPUCell *c, TextCache *tc) {
|
||||
text_in_cell_ansi(ANSILineState *s, const CPUCell *c, TextCache *tc, bool skip_multiline_non_zero_lines) {
|
||||
if (c->is_multicell) {
|
||||
if (c->x || c->y) return;
|
||||
if (c->x || (skip_multiline_non_zero_lines && c->y)) return;
|
||||
if (s->current_multicell_state) {
|
||||
if (!multicell_is_continuation_of_previous(s->current_multicell_state, c)) {
|
||||
close_multicell(s);
|
||||
@@ -364,42 +362,43 @@ cell_as_utf8_for_fallback(const ListOfChars *lc, char *buf) {
|
||||
return n;
|
||||
}
|
||||
|
||||
static ListOfChars global_unicode_in_range_buf = {0};
|
||||
|
||||
PyObject*
|
||||
unicode_in_range(const Line *self, const index_type start, const index_type limit, const bool include_cc, const bool add_trailing_newline, const bool skip_zero_cells) {
|
||||
size_t n = 0;
|
||||
bool
|
||||
unicode_in_range(const Line *self, const index_type start, const index_type limit, const bool include_cc, const bool add_trailing_newline, const bool skip_zero_cells, bool skip_multiline_non_zero_lines, ANSIBuf *buf) {
|
||||
ListOfChars lc;
|
||||
for (index_type i = start; i < limit; i++) {
|
||||
lc.chars = global_unicode_in_range_buf.chars + n; lc.capacity = global_unicode_in_range_buf.capacity - n;
|
||||
lc.chars = buf->buf + buf->len; lc.capacity = buf->capacity - buf->len;
|
||||
while (!text_in_cell_without_alloc(self->cpu_cells + i, self->text_cache, &lc)) {
|
||||
size_t ns = MAX(4096u, 2 * global_unicode_in_range_buf.capacity);
|
||||
char_type *np = realloc(global_unicode_in_range_buf.chars, ns);
|
||||
if (!np) return PyErr_NoMemory();
|
||||
global_unicode_in_range_buf.capacity = ns; global_unicode_in_range_buf.chars = np;
|
||||
lc.chars = global_unicode_in_range_buf.chars + n; lc.capacity = global_unicode_in_range_buf.capacity - n;
|
||||
size_t ns = MAX(4096u, 2 * buf->capacity);
|
||||
char_type *np = realloc(buf->buf, ns);
|
||||
if (!np) return false;
|
||||
buf->capacity = ns; buf->buf = np;
|
||||
lc.chars = buf->buf + buf->len; lc.capacity = buf->capacity - buf->len;
|
||||
}
|
||||
if (self->cpu_cells[i].is_multicell && (self->cpu_cells[i].x || self->cpu_cells[i].y)) continue;
|
||||
if (self->cpu_cells[i].is_multicell && (self->cpu_cells[i].x || (skip_multiline_non_zero_lines && self->cpu_cells[i].y))) continue;
|
||||
if (!lc.chars[0]) {
|
||||
if (skip_zero_cells) continue;
|
||||
lc.chars[0] = ' ';
|
||||
}
|
||||
if (lc.chars[0] == '\t') {
|
||||
n++;
|
||||
buf->len++;
|
||||
unsigned num_cells_to_skip_for_tab = lc.count > 1 ? lc.chars[1] : 0;
|
||||
while (num_cells_to_skip_for_tab && i + 1 < limit && cell_is_char(self->cpu_cells+i+1, ' ')) {
|
||||
i++;
|
||||
num_cells_to_skip_for_tab--;
|
||||
}
|
||||
} else n += include_cc ? lc.count : 1;
|
||||
} else buf->len += include_cc ? lc.count : 1;
|
||||
}
|
||||
if (add_trailing_newline && !self->cpu_cells[self->xnum-1].next_char_was_wrapped && n < global_unicode_in_range_buf.capacity) global_unicode_in_range_buf.chars[n++] = '\n';
|
||||
return PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, global_unicode_in_range_buf.chars, n);
|
||||
if (add_trailing_newline && !self->cpu_cells[self->xnum-1].next_char_was_wrapped && buf->len < buf->capacity) buf->buf[buf->len++] = '\n';
|
||||
return true;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
line_as_unicode(Line* self, bool skip_zero_cells) {
|
||||
return unicode_in_range(self, 0, xlimit_for_line(self), true, false, skip_zero_cells);
|
||||
line_as_unicode(Line* self, bool skip_zero_cells, ANSIBuf *buf) {
|
||||
size_t before = buf->len;
|
||||
if (!unicode_in_range(self, 0, xlimit_for_line(self), true, false, skip_zero_cells, true, buf)) return PyErr_NoMemory();
|
||||
PyObject *ans = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, buf->buf + before, buf->len - before);
|
||||
buf->len = before;
|
||||
return ans;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
@@ -485,7 +484,7 @@ write_mark_to_ansi_buf(ANSILineState *s, const char *m) {
|
||||
}
|
||||
|
||||
bool
|
||||
line_as_ansi(Line *self, ANSILineState *s, index_type start_at, index_type stop_before, char_type prefix_char) {
|
||||
line_as_ansi(Line *self, ANSILineState *s, index_type start_at, index_type stop_before, char_type prefix_char, bool skip_multiline_non_zero_lines) {
|
||||
s->output_buf->len = 0;
|
||||
s->limit = MIN(stop_before, xlimit_for_line(self));
|
||||
s->current_multicell_state = NULL;
|
||||
@@ -520,7 +519,7 @@ line_as_ansi(Line *self, ANSILineState *s, index_type start_at, index_type stop_
|
||||
if (*sgr) write_sgr_to_ansi_buf(s, sgr);
|
||||
}
|
||||
|
||||
text_in_cell_ansi(s, self->cpu_cells + s->pos, self->text_cache);
|
||||
text_in_cell_ansi(s, self->cpu_cells + s->pos, self->text_cache, skip_multiline_non_zero_lines);
|
||||
s->prev_gpu_cell = cell;
|
||||
}
|
||||
close_multicell(s);
|
||||
@@ -533,7 +532,7 @@ static PyObject*
|
||||
as_ansi(Line* self, PyObject *a UNUSED) {
|
||||
#define as_ansi_doc "Return the line's contents with ANSI (SGR) escape codes for formatting"
|
||||
ANSIBuf output = {0}; ANSILineState s = {.output_buf=&output};
|
||||
line_as_ansi(self, &s, 0, self->xnum, 0);
|
||||
line_as_ansi(self, &s, 0, self->xnum, 0, true);
|
||||
PyObject *ans = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, output.buf, output.len);
|
||||
free(output.buf);
|
||||
return ans;
|
||||
@@ -554,7 +553,8 @@ set_wrapped_flag(Line* self, PyObject *is_wrapped) {
|
||||
|
||||
static PyObject*
|
||||
__repr__(Line* self) {
|
||||
PyObject *s = line_as_unicode(self, false);
|
||||
RAII_ANSIBuf(buf);
|
||||
PyObject *s = line_as_unicode(self, false, &buf);
|
||||
if (s == NULL) return NULL;
|
||||
PyObject *ans = PyObject_Repr(s);
|
||||
Py_CLEAR(s);
|
||||
@@ -563,7 +563,8 @@ __repr__(Line* self) {
|
||||
|
||||
static PyObject*
|
||||
__str__(Line* self) {
|
||||
return line_as_unicode(self, false);
|
||||
RAII_ANSIBuf(buf);
|
||||
return line_as_unicode(self, false, &buf);
|
||||
}
|
||||
|
||||
|
||||
@@ -938,12 +939,12 @@ apply_marker(PyObject *marker, Line *line, const PyObject *text) {
|
||||
}
|
||||
|
||||
void
|
||||
mark_text_in_line(PyObject *marker, Line *line) {
|
||||
mark_text_in_line(PyObject *marker, Line *line, ANSIBuf *buf) {
|
||||
if (!marker) {
|
||||
for (index_type i = 0; i < line->xnum; i++) line->gpu_cells[i].attrs.mark = 0;
|
||||
return;
|
||||
}
|
||||
PyObject *text = line_as_unicode(line, false);
|
||||
PyObject *text = line_as_unicode(line, false, buf);
|
||||
if (PyUnicode_GET_LENGTH(text) > 0) {
|
||||
apply_marker(marker, line, text);
|
||||
} else {
|
||||
@@ -978,11 +979,11 @@ as_text_generic(PyObject *args, void *container, get_line_func get_line, index_t
|
||||
// makes writing pagers easier.
|
||||
// see https://github.com/kovidgoyal/kitty/issues/2381
|
||||
s.prev_gpu_cell = NULL;
|
||||
line_as_ansi(line, &s, 0, line->xnum, 0);
|
||||
line_as_ansi(line, &s, 0, line->xnum, 0, true);
|
||||
t = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, ansibuf->buf, ansibuf->len);
|
||||
if (t && ansibuf->len > 0) APPEND(sgr_reset);
|
||||
} else {
|
||||
t = line_as_unicode(line, false);
|
||||
t = line_as_unicode(line, false, ansibuf);
|
||||
}
|
||||
APPEND_AND_DECREF(t);
|
||||
if (insert_wrap_markers) APPEND(cr);
|
||||
@@ -1064,12 +1065,6 @@ Line *alloc_line(TextCache *tc) {
|
||||
return ans;
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup_module(void) {
|
||||
free(global_unicode_in_range_buf.chars);
|
||||
global_unicode_in_range_buf = (ListOfChars){0};
|
||||
}
|
||||
|
||||
RICHCMP(Line)
|
||||
INIT_TYPE(Line)
|
||||
// }}}
|
||||
|
||||
@@ -108,6 +108,8 @@ typedef struct ANSILineOutput {
|
||||
bool escape_code_written;
|
||||
} ANSILineState;
|
||||
|
||||
static inline void cleanup_ansibuf(ANSIBuf *b) { free(b->buf); zero_at_ptr(b); }
|
||||
#define RAII_ANSIBuf(name) __attribute__((cleanup(cleanup_ansibuf))) ANSIBuf name = {0}
|
||||
|
||||
Line* alloc_line(TextCache *text_cache);
|
||||
void apply_sgr_to_cells(GPUCell *first_cell, unsigned int cell_count, int *params, unsigned int count, bool is_group);
|
||||
|
||||
@@ -72,12 +72,12 @@ char_type line_get_char(Line *self, index_type at);
|
||||
index_type line_url_start_at(Line *self, index_type x);
|
||||
index_type line_url_end_at(Line *self, index_type x, bool, char_type, bool, bool, index_type);
|
||||
bool line_startswith_url_chars(Line*, bool);
|
||||
bool line_as_ansi(Line *self, ANSILineState *s, index_type start_at, index_type stop_before, char_type prefix_char) __attribute__((nonnull));
|
||||
bool line_as_ansi(Line *self, ANSILineState *s, index_type start_at, index_type stop_before, char_type prefix_char, bool skip_multiline_non_zero_lines) __attribute__((nonnull));
|
||||
unsigned int line_length(Line *self);
|
||||
size_t cell_as_unicode_for_fallback(const ListOfChars *lc, Py_UCS4 *buf);
|
||||
size_t cell_as_utf8_for_fallback(const ListOfChars *lc, char *buf);
|
||||
PyObject* unicode_in_range(const Line *self, const index_type start, const index_type limit, const bool include_cc, const bool add_trailing_newline, const bool skip_zero_cells);
|
||||
PyObject* line_as_unicode(Line *, bool);
|
||||
bool unicode_in_range(const Line *self, const index_type start, const index_type limit, const bool include_cc, const bool add_trailing_newline, const bool skip_zero_cells, bool skip_multiline_non_zero_lines, ANSIBuf*);
|
||||
PyObject* line_as_unicode(Line *, bool, ANSIBuf*);
|
||||
|
||||
void linebuf_init_line(LineBuf *, index_type);
|
||||
void linebuf_init_line_at(LineBuf *, index_type, Line*);
|
||||
@@ -109,7 +109,7 @@ void historybuf_mark_line_dirty(HistoryBuf *self, index_type y);
|
||||
void historybuf_set_line_has_image_placeholders(HistoryBuf *self, index_type y, bool val);
|
||||
void historybuf_refresh_sprite_positions(HistoryBuf *self);
|
||||
void historybuf_clear(HistoryBuf *self);
|
||||
void mark_text_in_line(PyObject *marker, Line *line);
|
||||
void mark_text_in_line(PyObject *marker, Line *line, ANSIBuf *buf);
|
||||
bool line_has_mark(Line *, uint16_t mark);
|
||||
PyObject* as_text_generic(PyObject *args, void *container, get_line_func get_line, index_type lines, ANSIBuf *ansibuf, bool add_trailing_newline);
|
||||
bool colors_for_cell(Line *self, const ColorProfile *cp, index_type *x, color_type *fg, color_type *bg, bool *reversed);
|
||||
|
||||
101
kitty/screen.c
101
kitty/screen.c
@@ -601,12 +601,18 @@ zero_cells(text_loop_state *s, CPUCell *c, GPUCell *g) { *c = s->cc; *g = s->g;
|
||||
|
||||
typedef Line*(linefunc_t)(Screen*, int);
|
||||
|
||||
static void
|
||||
init_line_(Screen *self, index_type y, Line *line) {
|
||||
linebuf_init_line_at(self->linebuf, y, line);
|
||||
if (y == 0 && self->linebuf == self->main_linebuf) {
|
||||
if (history_buf_endswith_wrap(self->historybuf)) line->attrs.is_continued = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static Line*
|
||||
init_line(Screen *self, index_type y) {
|
||||
linebuf_init_line(self->linebuf, y);
|
||||
if (y == 0 && self->linebuf == self->main_linebuf) {
|
||||
if (history_buf_endswith_wrap(self->historybuf)) self->linebuf->line->attrs.is_continued = true;
|
||||
}
|
||||
init_line_(self, y, self->linebuf->line);
|
||||
return self->linebuf->line;
|
||||
}
|
||||
|
||||
@@ -632,6 +638,13 @@ range_line_(Screen *self, int y) {
|
||||
return init_line(self, y);
|
||||
}
|
||||
|
||||
static void
|
||||
range_line(Screen *self, int y, Line *line) {
|
||||
if (y < 0) historybuf_init_line(self->historybuf, -(y + 1), line);
|
||||
else init_line_(self, y, line);
|
||||
}
|
||||
|
||||
|
||||
static Line*
|
||||
checked_range_line(Screen *self, int y) {
|
||||
if (
|
||||
@@ -3189,7 +3202,8 @@ screen_update_cell_data(Screen *self, void *address, FONTS_DATA_HANDLE fonts_dat
|
||||
if (linebuf->line->attrs.has_dirty_text) {
|
||||
render_line(fonts_data, linebuf->line, y, &self->paused_rendering.cursor, self->disable_ligatures, self->lc);
|
||||
screen_render_line_graphics(self, linebuf->line, y);
|
||||
if (linebuf->line->attrs.has_dirty_text && screen_has_marker(self)) mark_text_in_line(self->marker, linebuf->line);
|
||||
if (linebuf->line->attrs.has_dirty_text && screen_has_marker(self)) mark_text_in_line(
|
||||
self->marker, linebuf->line, &self->as_ansi_buf);
|
||||
linebuf_mark_line_clean(linebuf, y);
|
||||
}
|
||||
update_line_data(linebuf->line, y, address);
|
||||
@@ -3213,7 +3227,7 @@ screen_update_cell_data(Screen *self, void *address, FONTS_DATA_HANDLE fonts_dat
|
||||
screen_render_line_graphics(self, self->historybuf->line, y - self->scrolled_by);
|
||||
if (self->historybuf->line->attrs.has_dirty_text) {
|
||||
render_line(fonts_data, self->historybuf->line, lnum, self->cursor, self->disable_ligatures, self->lc);
|
||||
if (screen_has_marker(self)) mark_text_in_line(self->marker, self->historybuf->line);
|
||||
if (screen_has_marker(self)) mark_text_in_line(self->marker, self->historybuf->line, &self->as_ansi_buf);
|
||||
historybuf_mark_line_clean(self->historybuf, lnum);
|
||||
}
|
||||
update_line_data(self->historybuf->line, y, address);
|
||||
@@ -3225,7 +3239,8 @@ screen_update_cell_data(Screen *self, void *address, FONTS_DATA_HANDLE fonts_dat
|
||||
(cursor_has_moved && (self->cursor->y == lnum || self->last_rendered.cursor_y == lnum))) {
|
||||
render_line(fonts_data, self->linebuf->line, lnum, self->cursor, self->disable_ligatures, self->lc);
|
||||
screen_render_line_graphics(self, self->linebuf->line, y - self->scrolled_by);
|
||||
if (self->linebuf->line->attrs.has_dirty_text && screen_has_marker(self)) mark_text_in_line(self->marker, self->linebuf->line);
|
||||
if (self->linebuf->line->attrs.has_dirty_text && screen_has_marker(self)) mark_text_in_line(
|
||||
self->marker, self->linebuf->line, &self->as_ansi_buf);
|
||||
if (is_overlay_active && lnum == self->overlay_line.ynum) render_overlay_line(self, self->linebuf->line, fonts_data);
|
||||
linebuf_mark_line_clean(self->linebuf, lnum);
|
||||
}
|
||||
@@ -3459,30 +3474,61 @@ static PyObject*
|
||||
text_for_range(Screen *self, const Selection *sel, bool insert_newlines, bool strip_trailing_whitespace) {
|
||||
IterationData idata;
|
||||
iteration_data(sel, &idata, self->columns, -self->historybuf->count, 0);
|
||||
int limit = MIN((int)self->lines, idata.y_limit);
|
||||
PyObject *ans = PyTuple_New(limit - idata.y);
|
||||
Line line = {.xnum=self->columns, .text_cache=self->text_cache}, next_line = line; XRange xr, xrn = {0}; CPUCell *c;
|
||||
size_t before = self->as_ansi_buf.len;
|
||||
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;
|
||||
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++) {
|
||||
Line *line = range_line_(self, y);
|
||||
XRange xr = xrange_for_iteration(&idata, y, line);
|
||||
const bool is_first_line = y == idata.y, is_last_line = y + 1 >= limit;
|
||||
xr = xrn;
|
||||
line = next_line;
|
||||
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) {
|
||||
PyObject *text = PyUnicode_FromString("\n");
|
||||
if (text == NULL) { Py_DECREF(ans); return PyErr_NoMemory(); }
|
||||
PyTuple_SET_ITEM(ans, i, text);
|
||||
continue;
|
||||
is_only_whitespace_line = true;
|
||||
}
|
||||
}
|
||||
const bool add_trailing_newline = insert_newlines && !is_last_line;
|
||||
self->as_ansi_buf.len = before;
|
||||
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 (!unicode_in_range(&line, x, mc_limit, true, false, false, false, &self->as_ansi_buf)) return PyErr_NoMemory();
|
||||
x = mc_limit - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
PyObject *text = unicode_in_range(line, xr.x, x_limit, true, insert_newlines && y != limit-1, false);
|
||||
if (text == NULL) { Py_DECREF(ans); return PyErr_NoMemory(); }
|
||||
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("");
|
||||
} 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) {
|
||||
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 (!unicode_in_range(&line, x, mc_limit, true, false, false, false, &self->as_ansi_buf)) return PyErr_NoMemory();
|
||||
x = mc_limit - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
text = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, self->as_ansi_buf.buf + before, self->as_ansi_buf.len - before);
|
||||
}
|
||||
if (!text) return NULL;
|
||||
PyTuple_SET_ITEM(ans, i, text);
|
||||
}
|
||||
return ans;
|
||||
self->as_ansi_buf.len = before;
|
||||
return Py_NewRef(ans);
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
@@ -3499,7 +3545,7 @@ ansi_for_range(Screen *self, const Selection *sel, bool insert_newlines, bool st
|
||||
ANSILineState s = {.output_buf=&output};
|
||||
for (int i = 0, y = idata.y; y < limit; y++, i++) {
|
||||
Line *line = range_line_(self, y);
|
||||
XRange xr = xrange_for_iteration(&idata, y, line);
|
||||
XRange xr = xrange_for_iteration_with_multicells(&idata, y, line);
|
||||
output.len = 0;
|
||||
char_type prefix_char = need_newline ? '\n' : 0;
|
||||
index_type x_limit = xr.x_limit;
|
||||
@@ -3513,7 +3559,10 @@ ansi_for_range(Screen *self, const Selection *sel, bool insert_newlines, bool st
|
||||
}
|
||||
}
|
||||
}
|
||||
if (line_as_ansi(line, &s, xr.x, x_limit, prefix_char)) has_escape_codes = true;
|
||||
const bool is_first_line = y == idata.y;
|
||||
if (is_first_line) {
|
||||
}
|
||||
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);
|
||||
if (!t) return NULL;
|
||||
@@ -4928,15 +4977,15 @@ static void
|
||||
screen_mark_all(Screen *self) {
|
||||
for (index_type y = 0; y < self->main_linebuf->ynum; y++) {
|
||||
linebuf_init_line(self->main_linebuf, y);
|
||||
mark_text_in_line(self->marker, self->main_linebuf->line);
|
||||
mark_text_in_line(self->marker, self->main_linebuf->line, &self->as_ansi_buf);
|
||||
}
|
||||
for (index_type y = 0; y < self->alt_linebuf->ynum; y++) {
|
||||
linebuf_init_line(self->alt_linebuf, y);
|
||||
mark_text_in_line(self->marker, self->alt_linebuf->line);
|
||||
mark_text_in_line(self->marker, self->alt_linebuf->line, &self->as_ansi_buf);
|
||||
}
|
||||
for (index_type y = 0; y < self->historybuf->count; y++) {
|
||||
historybuf_init_line(self->historybuf, y, self->historybuf->line);
|
||||
mark_text_in_line(self->marker, self->historybuf->line);
|
||||
mark_text_in_line(self->marker, self->historybuf->line, &self->as_ansi_buf);
|
||||
}
|
||||
self->is_dirty = true;
|
||||
}
|
||||
@@ -5164,7 +5213,7 @@ dump_line_with_attrs(Screen *self, int y, PyObject *accum) {
|
||||
if (line->attrs.is_continued) call_string("continued ");
|
||||
if (line->attrs.has_dirty_text) call_string("dirty ");
|
||||
call_string("\n");
|
||||
RAII_PyObject(t, line_as_unicode(line, false)); if (!t) return;
|
||||
RAII_PyObject(t, line_as_unicode(line, false, &self->as_ansi_buf)); if (!t) return;
|
||||
RAII_PyObject(r2, PyObject_CallOneArg(accum, t)); if (!r2) return;
|
||||
call_string("\n");
|
||||
#undef call_string
|
||||
|
||||
Reference in New Issue
Block a user