Implement @get-text

This commit is contained in:
Kovid Goyal 2018-01-09 22:48:24 +05:30
parent 6ad49bd7fb
commit e5b9bd2e5a
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 70 additions and 9 deletions

View File

@ -383,7 +383,15 @@ as_ansi(LineBuf *self, PyObject *callback) {
#define as_ansi_doc "as_ansi(callback) -> The contents of this buffer as ANSI escaped text. callback is called with each successive line." #define as_ansi_doc "as_ansi(callback) -> The contents of this buffer as ANSI escaped text. callback is called with each successive line."
static Py_UCS4 t[5120]; static Py_UCS4 t[5120];
Line l = {.xnum=self->xnum}; Line l = {.xnum=self->xnum};
for(index_type i = 0; i < self->ynum; i++) { // remove trailing empty lines
index_type ylimit = self->ynum - 1;
do {
init_line(self, (&l), self->line_map[ylimit]);
if (line_as_ansi(&l, t, 5120) != 0) break;
ylimit--;
} while(ylimit > 0);
for(index_type i = 0; i <= ylimit; i++) {
l.continued = ((i < self->ynum - 1) ? self->line_attrs[i+1] : self->line_attrs[i]) & CONTINUED_MASK; l.continued = ((i < self->ynum - 1) ? self->line_attrs[i+1] : self->line_attrs[i]) & CONTINUED_MASK;
init_line(self, (&l), self->line_map[i]); init_line(self, (&l), self->line_map[i]);
index_type num = line_as_ansi(&l, t, 5120); index_type num = line_as_ansi(&l, t, 5120);

View File

@ -244,6 +244,7 @@ line_as_ansi(Line *self, Py_UCS4 *buf, index_type buflen) {
#define WRITE_CH(val) if (i > buflen - 1) return i; buf[i++] = val; #define WRITE_CH(val) if (i > buflen - 1) return i; buf[i++] = val;
index_type limit = xlimit_for_line(self), i=0; index_type limit = xlimit_for_line(self), i=0;
if (limit == 0) return 0;
char_type previous_width = 0; char_type previous_width = 0;
WRITE_SGR("0"); WRITE_SGR("0");

View File

@ -244,6 +244,49 @@ def new_window(boss, window, payload):
return str(w.id) return str(w.id)
@cmd(
'Get text from the specified window',
options_spec=MATCH_WINDOW_OPTION + '''\n
--extent
default=screen
choices=screen, all, selection
What text to get. The default of screen means all text currently on the screen. all means
all the screen+scrollback and selection means currently selected text.
--ansi
type=bool-set
By default, only plain text is return. If you specify this flag, the text will
include the formatting escape codes for colors/bold/italic/etc. Note that when
getting the current selection, the result is always plain text.
--self
type=bool-set
If specified get text from the window this command is run in, rather than the active window.
'''
)
def cmd_get_text(global_opts, opts, args):
return {'match': opts.match, 'extent': opts.extent, 'ansi': opts.ansi, 'self': opts.self}
def get_text(boss, window, payload):
match = payload['match']
if match:
windows = tuple(boss.match_windows(match))
if not windows:
raise ValueError('No matching windows for expression: {}'.format(match))
else:
windows = [window if window and payload['self'] else boss.active_window]
window = windows[0]
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')
return ans
cmap = {v.name: v for v in globals().values() if hasattr(v, 'is_cmd')} cmap = {v.name: v for v in globals().values() if hasattr(v, 'is_cmd')}
@ -270,12 +313,15 @@ global_options_spec = partial('''\
def read_from_stdin(send, no_response): def read_from_stdin(send, no_response):
send = ('@kitty-cmd' + json.dumps(send)).encode('ascii') send = ('@kitty-cmd' + json.dumps(send)).encode('ascii')
if not sys.stdout.isatty(): out = sys.stdout if sys.stdout.isatty() else sys.stderr
raise SystemExit('stdout is not a terminal') if not out.isatty():
sys.stdout.buffer.write(b'\x1bP' + send + b'\x1b\\') raise SystemExit('Neither stdout nor stderr is a terminal')
sys.stdout.flush() out.buffer.write(b'\x1bP' + send + b'\x1b\\')
out.flush()
if no_response: if no_response:
return {'ok': True} return {'ok': True}
if not sys.stdin.isatty():
raise SystemExit('stdin is not a terminal')
received = b'' received = b''
dcs = re.compile(br'\x1bP@kitty-cmd([^\x1b]+)\x1b\\') dcs = re.compile(br'\x1bP@kitty-cmd([^\x1b]+)\x1b\\')

View File

@ -312,14 +312,20 @@ class Window:
self.screen.reset_callbacks() self.screen.reset_callbacks()
self.screen = None self.screen = None
def buffer_as_ansi(self): def buffer_as_ansi(self, add_history=True):
data = [] data = []
self.screen.historybuf.as_ansi(data.append) if add_history:
self.screen.historybuf.as_ansi(data.append)
self.screen.linebuf.as_ansi(data.append) self.screen.linebuf.as_ansi(data.append)
return ''.join(data) return ''.join(data)
def buffer_as_text(self): def buffer_as_text(self, add_history=True):
return str(self.screen.historybuf) + '\n' + str(self.screen.linebuf) ans = str(self.screen.linebuf).rstrip('\n')
if add_history:
h = str(self.screen.historybuf)
if h.strip():
ans = h + '\n' + ans
return ans
# actions {{{ # actions {{{