Have kitty @ use /dev/tty instead of stdout/stdin

Allows redirecting those streams, while still being able to send
messages. Downside is that if user runs it outside kitty there wont
be any useful error message.
This commit is contained in:
Kovid Goyal
2018-03-01 12:11:49 +05:30
parent aad4a1fd6a
commit bc21ec7551
2 changed files with 9 additions and 13 deletions

View File

@@ -415,17 +415,12 @@ global_options_spec = partial('''\
'''.format, appname=appname) '''.format, appname=appname)
def read_from_stdin(send, no_response): def do_io(send, no_response):
send = ('@kitty-cmd' + json.dumps(send)).encode('ascii') send = ('@kitty-cmd' + json.dumps(send)).encode('ascii')
out = sys.stdout if sys.stdout.isatty() else sys.stderr with open('/dev/tty', 'wb') as out:
if not out.isatty(): out.write(b'\x1bP' + send + b'\x1b\\')
raise SystemExit('Neither stdout nor stderr is a terminal')
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\\')
@@ -437,7 +432,8 @@ def read_from_stdin(send, no_response):
match = dcs.search(received) match = dcs.search(received)
return match is None return match is None
read_with_timeout(more_needed) with open('/dev/tty', 'rb') as src:
read_with_timeout(more_needed, src=src)
if match is None: if match is None:
raise SystemExit('Failed to receive response from ' + appname) raise SystemExit('Failed to receive response from ' + appname)
response = json.loads(match.group(1).decode('ascii')) response = json.loads(match.group(1).decode('ascii'))
@@ -474,11 +470,11 @@ def main(args):
if func.no_response and isinstance(payload, types.GeneratorType): if func.no_response and isinstance(payload, types.GeneratorType):
for item in payload: for item in payload:
send['payload'] = item send['payload'] = item
read_from_stdin(send, func.no_response) do_io(send, func.no_response)
return return
if payload is not None: if payload is not None:
send['payload'] = payload send['payload'] = payload
response = read_from_stdin(send, func.no_response) response = do_io(send, func.no_response)
if not response.get('ok'): if not response.get('ok'):
if response.get('tb'): if response.get('tb'):
print(response['tb'], file=sys.stderr) print(response['tb'], file=sys.stderr)

View File

@@ -279,14 +279,14 @@ def non_blocking_read(src=sys.stdin):
fcntl.fcntl(fd, fcntl.F_SETFL, oldfl) fcntl.fcntl(fd, fcntl.F_SETFL, oldfl)
def read_with_timeout(more_needed, timeout=10, src=sys.stdin): def read_with_timeout(more_needed, timeout=10, src=sys.stdin.buffer):
import select import select
start_time = monotonic() start_time = monotonic()
with non_blocking_read(src) as fd: 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:
data = sys.stdin.buffer.read() data = src.read()
if not data: if not data:
break # eof break # eof
if not more_needed(data): if not more_needed(data):