Files
kitty/kitty/child.py
Kovid Goyal d689c21283 Fix pasting large amounts of text very slow.
Fixes #682

Apparently when refactoring child.py I somehow lost the code to make the
child fd non-blocking.
2018-06-26 18:20:46 +05:30

102 lines
3.2 KiB
Python

#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
import fcntl
import os
import kitty.fast_data_types as fast_data_types
from .constants import is_macos, shell_path, terminfo_dir
def cwd_of_process(pid):
if is_macos:
from kitty.fast_data_types import cwd_of_process
ans = cwd_of_process(pid)
else:
ans = '/proc/{}/cwd'.format(pid)
return os.path.realpath(ans)
def cmdline_of_process(pid):
if is_macos:
# TODO: macOS implementation, see DarwinProcess.c in htop for inspiration
raise NotImplementedError()
return list(filter(None, open('/proc/{}/cmdline'.format(pid), 'rb').read().decode('utf-8').split('\0')))
def remove_cloexec(fd):
fcntl.fcntl(fd, fcntl.F_SETFD, fcntl.fcntl(fd, fcntl.F_GETFD) & ~fcntl.FD_CLOEXEC)
class Child:
child_fd = pid = None
forked = False
def __init__(self, argv, cwd, opts, stdin=None, env=None, cwd_from=None):
self.argv = argv
if cwd_from is not None:
try:
cwd = cwd_of_process(cwd_from)
except Exception:
import traceback
traceback.print_exc()
else:
cwd = os.path.expandvars(os.path.expanduser(cwd or os.getcwd()))
self.cwd = os.path.abspath(cwd)
self.opts = opts
self.stdin = stdin
self.env = env or {}
def fork(self):
if self.forked:
return
self.forked = True
master, slave = os.openpty() # Note that master and slave are in blocking mode
remove_cloexec(slave)
fast_data_types.set_iutf8(master, True)
stdin, self.stdin = self.stdin, None
if stdin is not None:
stdin_read_fd, stdin_write_fd = os.pipe()
remove_cloexec(stdin_read_fd)
else:
stdin_read_fd = stdin_write_fd = -1
env = os.environ.copy()
env.update(self.env)
env['TERM'] = self.opts.term
env['COLORTERM'] = 'truecolor'
if os.path.isdir(terminfo_dir):
env['TERMINFO'] = terminfo_dir
env = tuple('{}={}'.format(k, v) for k, v in env.items())
argv = list(self.argv)
exe = argv[0]
if is_macos and exe == shell_path:
# Some macOS machines need the shell to have argv[0] prefixed by
# hyphen, see https://github.com/kovidgoyal/kitty/issues/247
argv[0] = ('-' + exe.split('/')[-1])
pid = fast_data_types.spawn(exe, self.cwd, tuple(argv), env, master, slave, stdin_read_fd, stdin_write_fd)
os.close(slave)
self.pid = pid
self.child_fd = master
if stdin is not None:
os.close(stdin_read_fd)
fast_data_types.thread_write(stdin_write_fd, stdin)
fcntl.fcntl(self.child_fd, fcntl.F_SETFL, fcntl.fcntl(self.child_fd, fcntl.F_GETFL) | os.O_NONBLOCK)
return pid
@property
def cmdline(self):
try:
return cmdline_of_process(self.pid) or list(self.argv)
except Exception:
return list(self.argv)
@property
def current_cwd(self):
try:
return cwd_of_process(self.pid)
except Exception:
pass