@send-text allow sending from files and stdin
This commit is contained in:
parent
6dde573ed9
commit
7b33a87725
@ -12,7 +12,7 @@ from .cli import emph, parse_args
|
|||||||
from .config import parse_send_text_bytes
|
from .config import parse_send_text_bytes
|
||||||
from .constants import appname, version
|
from .constants import appname, version
|
||||||
from .tabs import SpecialWindow
|
from .tabs import SpecialWindow
|
||||||
from .utils import read_with_timeout
|
from .utils import non_blocking_read, read_with_timeout
|
||||||
|
|
||||||
|
|
||||||
def cmd(short_desc, desc=None, options_spec=None, no_response=False):
|
def cmd(short_desc, desc=None, options_spec=None, no_response=False):
|
||||||
@ -80,24 +80,76 @@ for that window is used.
|
|||||||
' and |_ \\u21fa| to send unicode characters. If you use the |_ --match| option'
|
' and |_ \\u21fa| to send unicode characters. If you use the |_ --match| option'
|
||||||
' the text will be sent to all matched windows. By default, text is sent to'
|
' the text will be sent to all matched windows. By default, text is sent to'
|
||||||
' only the currently active window.',
|
' only the currently active window.',
|
||||||
options_spec=MATCH_WINDOW_OPTION,
|
options_spec=MATCH_WINDOW_OPTION + '''\n
|
||||||
|
--stdin
|
||||||
|
type=bool-set
|
||||||
|
Read the text to be sent from |_ stdin|. Note that in this case the text is sent as is,
|
||||||
|
not interpreted for escapes. If stdin is a terminal, you can press Ctrl-D to end reading.
|
||||||
|
|
||||||
|
|
||||||
|
--from-file
|
||||||
|
Path to a file whose contents you wish to send. Note that in this case the file contents
|
||||||
|
are sent as is, not interpreted for escapes.
|
||||||
|
''',
|
||||||
no_response=True
|
no_response=True
|
||||||
)
|
)
|
||||||
def cmd_send_text(global_opts, opts, args):
|
def cmd_send_text(global_opts, opts, args):
|
||||||
text = ' '.join(args)
|
|
||||||
limit = 1024
|
limit = 1024
|
||||||
if len(text) <= limit:
|
ret = {'match': opts.match, 'is_binary': False}
|
||||||
return {'text': ' '.join(args), 'match': opts.match}
|
|
||||||
|
|
||||||
# Overly large escape sequences are ignored by kitty, so chunk up the
|
def pipe(src=sys.stdin):
|
||||||
# data
|
ret['is_binary'] = True
|
||||||
|
import select
|
||||||
|
with non_blocking_read() as fd:
|
||||||
|
keep_going = True
|
||||||
|
while keep_going:
|
||||||
|
rd = select.select([fd], [], [])
|
||||||
|
if rd:
|
||||||
|
data = sys.stdin.buffer.read()
|
||||||
|
if not data:
|
||||||
|
break
|
||||||
|
data = data.decode('utf-8')
|
||||||
|
if '\x04' in data:
|
||||||
|
data = data[:data.index('\x04')]
|
||||||
|
keep_going = False
|
||||||
|
while data:
|
||||||
|
ret['text'] = data[:limit]
|
||||||
|
yield ret
|
||||||
|
data = data[limit:]
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
def chunks():
|
def chunks(text):
|
||||||
nonlocal text
|
ret['is_binary'] = False
|
||||||
while text:
|
while text:
|
||||||
yield {'text': text[:limit], 'match': opts.match}
|
ret['text'] = text[:limit]
|
||||||
|
yield ret
|
||||||
text = text[limit:]
|
text = text[limit:]
|
||||||
return chunks()
|
|
||||||
|
def file_pipe(path):
|
||||||
|
ret['is_binary'] = True
|
||||||
|
with open(path, encoding='utf-8') as f:
|
||||||
|
while True:
|
||||||
|
data = f.read(limit)
|
||||||
|
if not data:
|
||||||
|
break
|
||||||
|
ret['text'] = data
|
||||||
|
yield ret
|
||||||
|
|
||||||
|
sources = []
|
||||||
|
if opts.stdin:
|
||||||
|
sources.append(pipe())
|
||||||
|
|
||||||
|
if opts.from_file:
|
||||||
|
sources.append(file_pipe(opts.from_file))
|
||||||
|
|
||||||
|
text = ' '.join(args)
|
||||||
|
sources.append(chunks(text))
|
||||||
|
|
||||||
|
def chain():
|
||||||
|
for src in sources:
|
||||||
|
yield from src
|
||||||
|
return chain()
|
||||||
|
|
||||||
|
|
||||||
def send_text(boss, window, payload):
|
def send_text(boss, window, payload):
|
||||||
@ -105,9 +157,10 @@ def send_text(boss, window, payload):
|
|||||||
match = payload['match']
|
match = payload['match']
|
||||||
if match:
|
if match:
|
||||||
windows = tuple(boss.match_windows(match))
|
windows = tuple(boss.match_windows(match))
|
||||||
|
data = payload['text'].encode('utf-8') if payload['is_binary'] else parse_send_text_bytes(payload['text'])
|
||||||
for window in windows:
|
for window in windows:
|
||||||
if window is not None:
|
if window is not None:
|
||||||
window.write_to_child(parse_send_text_bytes(payload['text']))
|
window.write_to_child(data)
|
||||||
|
|
||||||
|
|
||||||
@cmd(
|
@cmd(
|
||||||
|
|||||||
@ -267,18 +267,27 @@ def single_instance(group_id=None):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def read_with_timeout(more_needed, timeout=10, src=sys.stdin):
|
@contextmanager
|
||||||
|
def non_blocking_read(src=sys.stdin):
|
||||||
import termios
|
import termios
|
||||||
import tty
|
import tty
|
||||||
import fcntl
|
import fcntl
|
||||||
import select
|
|
||||||
fd = src.fileno()
|
fd = src.fileno()
|
||||||
|
if src.isatty():
|
||||||
old = termios.tcgetattr(fd)
|
old = termios.tcgetattr(fd)
|
||||||
|
tty.setraw(fd)
|
||||||
oldfl = fcntl.fcntl(fd, fcntl.F_GETFL)
|
oldfl = fcntl.fcntl(fd, fcntl.F_GETFL)
|
||||||
fcntl.fcntl(fd, fcntl.F_SETFL, oldfl | os.O_NONBLOCK)
|
fcntl.fcntl(fd, fcntl.F_SETFL, oldfl | os.O_NONBLOCK)
|
||||||
tty.setraw(fd)
|
yield fd
|
||||||
|
if src.isatty():
|
||||||
|
termios.tcsetattr(fd, termios.TCSADRAIN, old)
|
||||||
|
fcntl.fcntl(fd, fcntl.F_SETFL, oldfl)
|
||||||
|
|
||||||
|
|
||||||
|
def read_with_timeout(more_needed, timeout=10, src=sys.stdin):
|
||||||
|
import select
|
||||||
start_time = monotonic()
|
start_time = monotonic()
|
||||||
try:
|
with non_blocking_read(src) as fd:
|
||||||
while timeout > monotonic() - start_time:
|
while timeout > monotonic() - start_time:
|
||||||
rd = select.select([fd], [], [], max(0, timeout - (monotonic() - start_time)))[0]
|
rd = select.select([fd], [], [], max(0, timeout - (monotonic() - start_time)))[0]
|
||||||
if rd:
|
if rd:
|
||||||
@ -287,6 +296,5 @@ def read_with_timeout(more_needed, timeout=10, src=sys.stdin):
|
|||||||
break # eof
|
break # eof
|
||||||
if not more_needed(data):
|
if not more_needed(data):
|
||||||
break
|
break
|
||||||
finally:
|
else:
|
||||||
termios.tcsetattr(fd, termios.TCSADRAIN, old)
|
break
|
||||||
fcntl.fcntl(fd, fcntl.F_SETFL, oldfl)
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user