Use a single generic function to get text and ANSI representations of all buffers

This commit is contained in:
Kovid Goyal 2018-02-14 20:38:53 +05:30
parent 97b4256ba4
commit 9c21610215
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
8 changed files with 81 additions and 57 deletions

View file

@ -406,10 +406,8 @@ def run_simple_kitten(self, type_of_input, kitten, *args):
args = shlex.split(cmdline) if cmdline else []
if '--program' not in cmdline:
args.extend(('--program', self.opts.open_url_with))
if type_of_input in ('text', 'history'):
data = (w.buffer_as_text if type_of_input == 'history' else w.as_text)().encode('utf-8')
elif type_of_input in ('ansi', 'ansi-history'):
data = (w.buffer_as_ansi() if type_of_input == 'ansi-history' else w.as_text(as_ansi=True)).encode('utf-8')
if type_of_input in ('text', 'history', 'ansi', 'ansi-history'):
data = w.as_text(as_ansi='ansi' in type_of_input, add_history='history' in type_of_input).encode('utf-8')
elif type_of_input == 'none':
data = None
else:
@ -494,9 +492,13 @@ def data_for_at(arg):
if arg == '@selection':
return w.text_for_selection()
if arg == '@ansi':
return w.buffer_as_ansi()
return w.as_text(as_ansi=True, add_history=True)
if arg == '@text':
return w.buffer_as_text()
return w.as_text(add_history=True)
if arg == '@screen':
return w.as_text()
if arg == '@ansi_screen':
return w.as_text(as_ansi=True)
if args[0].startswith('@'):
stdin = data_for_at(args[0]) or None

View file

@ -202,6 +202,18 @@ as_ansi(HistoryBuf *self, PyObject *callback) {
Py_RETURN_NONE;
}
static inline Line*
get_line(HistoryBuf *self, index_type y, Line *l) { init_line(self, y, l); return l; }
static PyObject*
as_text(HistoryBuf *self, PyObject *args) {
Line l = {.xnum=self->xnum};
#define gl(self, y) get_line(self, y, &l);
as_text_generic(args, self, gl, self->count, self->xnum, callback, as_ansi);
#undef gl
}
static PyObject*
dirty_lines(HistoryBuf *self) {
#define dirty_lines_doc "dirty_lines() -> Line numbers of all lines that have dirty text."
@ -223,6 +235,7 @@ static PyMethodDef methods[] = {
METHOD(change_num_of_lines, METH_O)
METHOD(line, METH_O)
METHOD(as_ansi, METH_O)
METHODB(as_text, METH_VARARGS),
METHOD(dirty_lines, METH_NOARGS)
METHOD(push, METH_VARARGS)
METHOD(rewrap, METH_VARARGS)

View file

@ -298,7 +298,8 @@ map ctrl+shift+0 tenth_window
# map ctrl+shift+y new_window less @selection
#
# You can even send the contents of the current screen + history buffer as stdin using
# the placeholders @text (which is the plain text) and @ansi (which includes text styling escape codes)
# the placeholders @text (which is the plain text) and @ansi (which includes text styling escape codes).
# For only the current screen, use @screen or @ansi_screen.
# For example, the following command opens the scrollback buffer in less in a new window.
# map ctrl+shift+y new_window @ansi less +G -R
#

View file

@ -406,6 +406,18 @@ as_ansi(LineBuf *self, PyObject *callback) {
Py_RETURN_NONE;
}
static inline Line*
get_line(LineBuf *self, index_type y) {
linebuf_init_line(self, y);
return self->line;
}
static PyObject*
as_text(LineBuf *self, PyObject *args) {
as_text_generic(args, self, get_line, self->ynum, self->xnum, callback, as_ansi);
}
static PyObject*
__str__(LineBuf *self) {
PyObject *lines = PyTuple_New(self->ynum);
@ -440,6 +452,7 @@ static PyMethodDef methods[] = {
METHOD(rewrap, METH_VARARGS)
METHOD(clear, METH_NOARGS)
METHOD(as_ansi, METH_O)
METHODB(as_text, METH_VARARGS),
METHOD(set_attribute, METH_VARARGS)
METHOD(set_continued, METH_VARARGS)
METHOD(dirty_lines, METH_NOARGS)

View file

@ -44,6 +44,7 @@ xlimit_for_line(Line *line) {
return xlimit;
}
void line_clear_text(Line *self, unsigned int at, unsigned int num, char_type ch);
void line_apply_cursor(Line *self, Cursor *cursor, unsigned int at, unsigned int num, bool clear_char);
void line_set_char(Line *, unsigned int , uint32_t , unsigned int , Cursor *, bool);
@ -79,3 +80,39 @@ void historybuf_mark_line_clean(HistoryBuf *self, index_type y);
void historybuf_mark_line_dirty(HistoryBuf *self, index_type y);
void historybuf_refresh_sprite_positions(HistoryBuf *self);
void historybuf_clear(HistoryBuf *self);
#define as_text_generic(args, container, get_line, lines, columns, callback, as_ansi) { \
PyObject *callback; \
int as_ansi = 0; \
if (!PyArg_ParseTuple(args, "O|p", &callback, &as_ansi)) return NULL; \
PyObject *ret = NULL, *t = NULL; \
Py_UCS4 *buf = NULL; \
PyObject *nl = PyUnicode_FromString("\n"); \
if (nl == NULL) goto end; \
if (as_ansi) { \
buf = malloc(sizeof(Py_UCS4) * columns * 100); \
if (buf == NULL) { PyErr_NoMemory(); goto end; } \
} \
for (index_type y = 0; y < lines; y++) { \
Line *line = get_line(container, y); \
if (!line->continued && y > 0) { \
ret = PyObject_CallFunctionObjArgs(callback, nl, NULL); \
if (ret == NULL) goto end; \
Py_CLEAR(ret); \
} \
if (as_ansi) { \
index_type num = line_as_ansi(line, buf, columns * 100 - 2); \
t = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, buf, num); \
} else { \
t = PyObject_Str((PyObject*)line); \
} \
if (t == NULL) goto end; \
ret = PyObject_CallFunctionObjArgs(callback, t, NULL); \
Py_DECREF(t); if (ret == NULL) goto end; Py_DECREF(ret); \
} \
end: \
Py_CLEAR(nl); free(buf); \
if (PyErr_Occurred()) return NULL; \
Py_RETURN_NONE; \
}

View file

@ -387,8 +387,7 @@ def get_text(boss, window, payload):
if payload['extent'] == 'selection':
ans = window.text_for_selection()
else:
f = window.buffer_as_ansi if payload['ansi'] else window.buffer_as_text
ans = f(add_history=payload['extent'] == 'all')
ans = window.as_text(as_ansi=bool(payload['ansi']), add_history=True)
return ans

View file

@ -1454,37 +1454,7 @@ screen_open_url(Screen *self) {
static PyObject*
as_text(Screen *self, PyObject *args) {
PyObject *callback, *ret = NULL, *t = NULL;
Py_UCS4 *buf = NULL;
int as_ansi = 0;
if (!PyArg_ParseTuple(args, "O|p", &callback, &as_ansi)) return NULL;
PyObject *nl = PyUnicode_FromString("\n");
if (nl == NULL) goto end;
if (as_ansi) {
buf = malloc(sizeof(Py_UCS4) * self->columns * 100);
if (buf == NULL) { PyErr_NoMemory(); goto end; }
}
for (index_type y = 0; y < self->lines; y++) {
Line *line = visual_line_(self, y);
if (!line->continued && y > 0) {
ret = PyObject_CallFunctionObjArgs(callback, nl, NULL);
if (ret == NULL) goto end;
Py_CLEAR(ret);
}
if (as_ansi) {
index_type num = line_as_ansi(line, buf, self->columns * 100 - 2);
t = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, buf, num);
} else {
t = PyObject_Str((PyObject*)line);
}
if (t == NULL) goto end;
ret = PyObject_CallFunctionObjArgs(callback, t, NULL);
Py_DECREF(t); if (ret == NULL) goto end; Py_DECREF(ret);
}
end:
Py_CLEAR(nl); free(buf);
if (PyErr_Occurred()) return NULL;
Py_RETURN_NONE;
as_text_generic(args, self, visual_line_, self->lines, self->columns, callback, as_ansi);
}
static PyObject*

View file

@ -315,30 +315,19 @@ def destroy(self):
self.screen.reset_callbacks()
self.screen = None
def buffer_as_ansi(self, add_history=True):
data = []
if add_history:
self.screen.historybuf.as_ansi(data.append)
self.screen.linebuf.as_ansi(data.append)
return ''.join(data)
def buffer_as_text(self, add_history=True):
ans = str(self.screen.linebuf).rstrip('\n')
if add_history:
h = str(self.screen.historybuf)
if h.strip():
ans = h + '\n' + ans
return ans
def as_text(self, as_ansi=False):
def as_text(self, as_ansi=False, add_history=False):
lines = []
self.screen.as_text(lines.append, as_ansi)
if add_history:
h = []
self.screen.historybuf.as_text(h.append, as_ansi)
lines = h + lines
return ''.join(lines)
# actions {{{
def show_scrollback(self):
get_boss().display_scrollback(self, self.buffer_as_ansi().encode('utf-8'))
get_boss().display_scrollback(self, self.as_text(as_ansi=True, add_history=True).encode('utf-8'))
def paste(self, text):
if text and not self.destroyed: