Implement rewrp for pagerhist using the streaming wcswidth

This commit is contained in:
Kovid Goyal
2020-09-21 19:05:23 +05:30
parent 444080f320
commit 987b41d2cb

View File

@@ -5,7 +5,7 @@
* Distributed under terms of the GPL3 license. * Distributed under terms of the GPL3 license.
*/ */
#include "data-types.h" #include "wcswidth.h"
#include "lineops.h" #include "lineops.h"
#include "charsets.h" #include "charsets.h"
#include <structmember.h> #include <structmember.h>
@@ -187,7 +187,7 @@ historybuf_clear(HistoryBuf *self) {
} }
static inline bool static inline bool
pagerhist_write(PagerHistoryBuf *ph, const uint8_t *buf, size_t sz) { pagerhist_write_bytes(PagerHistoryBuf *ph, const uint8_t *buf, size_t sz) {
if (sz > ph->max_sz) return false; if (sz > ph->max_sz) return false;
if (!sz) return true; if (!sz) return true;
if (sz > ph->buffer_size - ph->length) pagerhist_extend(ph, sz); if (sz > ph->buffer_size - ph->length) pagerhist_extend(ph, sz);
@@ -220,7 +220,7 @@ pagerhist_write_ucs4(PagerHistoryBuf *ph, const Py_UCS4 *buf, size_t sz) {
uint8_t scratch[4]; uint8_t scratch[4];
for (size_t i = 0; i < sz; i++) { for (size_t i = 0; i < sz; i++) {
unsigned int num = encode_utf8(buf[i], (char*)scratch); unsigned int num = encode_utf8(buf[i], (char*)scratch);
if (!pagerhist_write(ph, scratch, num)) return false; if (!pagerhist_write_bytes(ph, scratch, num)) return false;
} }
return true; return true;
} }
@@ -233,9 +233,9 @@ pagerhist_push(HistoryBuf *self, ANSIBuf *as_ansi_buf) {
Line l = {.xnum=self->xnum}; Line l = {.xnum=self->xnum};
init_line(self, self->start_of_data, &l); init_line(self, self->start_of_data, &l);
line_as_ansi(&l, as_ansi_buf, &prev_cell); line_as_ansi(&l, as_ansi_buf, &prev_cell);
if (ph->length != 0 && !l.continued) pagerhist_write(ph, (const uint8_t*)"\n", 1); if (ph->length != 0 && !l.continued) pagerhist_write_bytes(ph, (const uint8_t*)"\n", 1);
pagerhist_write(ph, (const uint8_t*)"\x1b[m", 3); pagerhist_write_bytes(ph, (const uint8_t*)"\x1b[m", 3);
if (pagerhist_write_ucs4(ph, as_ansi_buf->buf, as_ansi_buf->len)) pagerhist_write(ph, (const uint8_t*)"\r", 1); if (pagerhist_write_ucs4(ph, as_ansi_buf->buf, as_ansi_buf->len)) pagerhist_write_bytes(ph, (const uint8_t*)"\r", 1);
} }
static inline index_type static inline index_type
@@ -326,55 +326,85 @@ end:
static inline Line* static inline Line*
get_line(HistoryBuf *self, index_type y, Line *l) { init_line(self, index_of(self, self->count - y - 1), l); return l; } get_line(HistoryBuf *self, index_type y, Line *l) { init_line(self, index_of(self, self->count - y - 1), l); return l; }
static inline char_type
pagerhist_read_char(PagerHistoryBuf *ph, size_t pos, unsigned *count, uint8_t record[8]) {
uint32_t codep, state = UTF8_ACCEPT;
*count = 0;
while (true) {
decode_utf8(&state, &codep, ph->buffer[pos]);
record[(*count)++] = ph->buffer[pos];
if (state == UTF8_REJECT) { codep = 0; break; }
if (state == UTF8_ACCEPT) break;
pos = pos == ph->buffer_size - 1 ? 0 : (pos + 1);
}
return codep;
}
static void static void
pagerhist_rewrap(PagerHistoryBuf *ph, index_type xnum) { pagerhist_rewrap_to(HistoryBuf *self, index_type cells_in_line) {
(void)ph; (void)xnum; PagerHistoryBuf *ph = self->pagerhist;
return; // TODO: Implement this if (!ph->length) return;
/* Py_UCS4 *buf = PyMem_RawMalloc(ph->bufsize * sizeof(Py_UCS4)); */ PagerHistoryBuf *nph = PyMem_Calloc(sizeof(PagerHistoryBuf), 1);
/* if (!buf) return; */ if (!nph) return;
/* index_type s = ph->start, i = s, dest = 0, dest_bufend = 0, x = 0; */ nph->buffer_size = ph->buffer_size;
/* index_type end = ph->bufend ? ph->bufend : ph->end; */ nph->max_sz = ph->max_sz;
/* index_type lastmod_s = 0, lastmod_len = 0; */ nph->buffer = PyMem_Malloc(nph->buffer_size);
/* #define CPY(_s, _l) { if (dest + (_l) >= ph->bufsize - 1) { dest_bufend = dest; dest = 0; } \ */ if (!nph->buffer) { PyMem_Free(nph); return ; }
/* memcpy(buf + dest, ph->buffer + (_s), (_l) * sizeof(Py_UCS4)); dest += (_l); } */ size_t i = 0, pos;
/* while (i < end) { */ ssize_t ch_width = 0;
/* switch (ph->buffer[i]) { */ unsigned count;
/* case '\n': */ uint8_t record[8];
/* CPY(s, i - s + 1); */ index_type num_in_current_line = 0;
/* x = 0; s = i + 1; lastmod_len = 0; */ char_type ch;
/* break; */ WCSState wcs_state;
/* case '\r': */ initialize_wcs_state(&wcs_state);
/* CPY(s, i - s); */
/* if (!memcmp(ph->buffer + lastmod_s, ph->buffer + i + 1, lastmod_len * sizeof(Py_UCS4))) */ #define READ_CHAR(ch) { \
/* i += lastmod_len; */ ch = pagerhist_read_char(ph, pos, &count, record); \
/* s = i + 1; */ i += count; pos += count; \
/* break; */ if (pos >= ph->buffer_size) pos = pos - ph->buffer_size; \
/* case '\x1b': */ }
/* if (ph->buffer[i+1] != '[') break; */ #define WRITE_CHAR() { \
/* lastmod_s = i; */ if (num_in_current_line + ch_width > cells_in_line) { \
/* while (ph->buffer[++i] != 'm'); */ pagerhist_write_bytes(nph, (const uint8_t*)"\r", 1); \
/* lastmod_len = i - lastmod_s + 1; */ num_in_current_line = 0; \
/* break; */ }\
/* default: */ if (ch_width >= 0 || num_in_current_line >= -ch_width) num_in_current_line += ch_width; \
/* x++; break; */ pagerhist_write_bytes(nph, record, count); \
/* } */ }
/* i++; */
/* if (ph->bufend && i == ph->bufend) { */ for (i = 0; i < ph->length;) {
/* if (s != i) CPY(s, i - s); */ pos = ph->start + i;
/* end = ph->end; i = s = 0; */ if (pos >= ph->buffer_size) pos = pos - ph->buffer_size;
/* } */ READ_CHAR(ch);
/* if (x == xnum) { */ if (ch == '\n') {
/* CPY(s, i - s); buf[dest++] = '\r'; s = i; x = 0; */ initialize_wcs_state(&wcs_state);
/* if (!(ph->buffer[i] == '\x1b' && ph->buffer[i+1] == '[') && lastmod_len) */ ch_width = 1;
/* CPY(lastmod_s, lastmod_len); */ WRITE_CHAR();
/* } */ num_in_current_line = 0;
/* } */ } else if (ch != '\r') {
/* #undef CPY */ ch_width = wcswidth_step(&wcs_state, ch);
/* PyMem_Free(ph->buffer); */ WRITE_CHAR();
/* ph->buffer = buf; */ }
/* ph->end = dest; ph->bufend = dest_bufend; */ }
/* ph->start = dest_bufend ? dest + 1 : 0; */ free_pagerhist(self);
/* ph->rewrap_needed = false; */ self->pagerhist = nph;
#undef READ_CHAR
}
static PyObject*
pagerhist_write(HistoryBuf *self, PyObject *what) {
if (self->pagerhist && self->pagerhist->max_sz) {
if (PyBytes_Check(what)) pagerhist_write_bytes(self->pagerhist, (const uint8_t*)PyBytes_AS_STRING(what), PyBytes_GET_SIZE(what));
else if (PyUnicode_Check(what) && PyUnicode_READY(what) == 0) {
Py_UCS4 *buf = PyUnicode_AsUCS4Copy(what);
if (buf) {
pagerhist_write_ucs4(self->pagerhist, buf, PyUnicode_GET_LENGTH(what));
PyMem_Free(buf);
}
}
}
Py_RETURN_NONE;
} }
static PyObject * static PyObject *
@@ -383,7 +413,7 @@ pagerhist_as_text(HistoryBuf *self, PyObject *args UNUSED) {
if (!ph || !ph->length) return PyUnicode_FromString(""); if (!ph || !ph->length) return PyUnicode_FromString("");
pagerhist_ensure_start_is_valid_utf8(ph); pagerhist_ensure_start_is_valid_utf8(ph);
if (ph->rewrap_needed) pagerhist_rewrap(ph, self->xnum); if (ph->rewrap_needed) pagerhist_rewrap_to(self, self->xnum);
Line l = {.xnum=self->xnum}; get_line(self, 0, &l); Line l = {.xnum=self->xnum}; get_line(self, 0, &l);
size_t sz = ph->length; size_t sz = ph->length;
@@ -434,6 +464,14 @@ dirty_lines(HistoryBuf *self, PyObject *a UNUSED) {
return ans; return ans;
} }
static PyObject*
pagerhist_rewrap(HistoryBuf *self, PyObject *xnum) {
if (self->pagerhist) {
pagerhist_rewrap_to(self, PyLong_AsUnsignedLong(xnum));
}
Py_RETURN_NONE;
}
// Boilerplate {{{ // Boilerplate {{{
static PyObject* rewrap(HistoryBuf *self, PyObject *args); static PyObject* rewrap(HistoryBuf *self, PyObject *args);
@@ -442,6 +480,8 @@ static PyObject* rewrap(HistoryBuf *self, PyObject *args);
static PyMethodDef methods[] = { static PyMethodDef methods[] = {
METHOD(line, METH_O) METHOD(line, METH_O)
METHOD(as_ansi, METH_O) METHOD(as_ansi, METH_O)
METHODB(pagerhist_write, METH_O),
METHODB(pagerhist_rewrap, METH_O),
METHODB(pagerhist_as_text, METH_NOARGS), METHODB(pagerhist_as_text, METH_NOARGS),
METHODB(as_text, METH_VARARGS), METHODB(as_text, METH_VARARGS),
METHOD(dirty_lines, METH_NOARGS) METHOD(dirty_lines, METH_NOARGS)