Clear signal handlers when running processes
This commit is contained in:
@@ -22,8 +22,9 @@ from .cli_stub import CLIOptions
|
|||||||
from .conf.utils import BadLine, KeyAction, to_cmdline
|
from .conf.utils import BadLine, KeyAction, to_cmdline
|
||||||
from .config import common_opts_as_dict, prepare_config_file_for_editing
|
from .config import common_opts_as_dict, prepare_config_file_for_editing
|
||||||
from .constants import (
|
from .constants import (
|
||||||
appname, cache_dir, config_dir, is_macos, is_wayland, kitty_exe,
|
appname, cache_dir, clear_handled_signals, config_dir, handled_signals,
|
||||||
logo_png_file, supports_primary_selection, website_url
|
is_macos, is_wayland, kitty_exe, logo_png_file, supports_primary_selection,
|
||||||
|
website_url
|
||||||
)
|
)
|
||||||
from .fast_data_types import (
|
from .fast_data_types import (
|
||||||
CLOSE_BEING_CONFIRMED, GLFW_MOD_ALT, GLFW_MOD_CONTROL, GLFW_MOD_SHIFT,
|
CLOSE_BEING_CONFIRMED, GLFW_MOD_ALT, GLFW_MOD_CONTROL, GLFW_MOD_SHIFT,
|
||||||
@@ -733,6 +734,8 @@ class Boss:
|
|||||||
if not getattr(self, 'io_thread_started', False):
|
if not getattr(self, 'io_thread_started', False):
|
||||||
self.child_monitor.start()
|
self.child_monitor.start()
|
||||||
self.io_thread_started = True
|
self.io_thread_started = True
|
||||||
|
for signum in self.child_monitor.handled_signals():
|
||||||
|
handled_signals.add(signum)
|
||||||
urls: List[str] = getattr(sys, 'cmdline_args_for_open', [])
|
urls: List[str] = getattr(sys, 'cmdline_args_for_open', [])
|
||||||
if urls:
|
if urls:
|
||||||
delattr(sys, 'cmdline_args_for_open')
|
delattr(sys, 'cmdline_args_for_open')
|
||||||
@@ -1737,7 +1740,7 @@ class Boss:
|
|||||||
if stdin:
|
if stdin:
|
||||||
r, w = safe_pipe(False)
|
r, w = safe_pipe(False)
|
||||||
try:
|
try:
|
||||||
subprocess.Popen(cmd, env=env, stdin=r, cwd=cwd)
|
subprocess.Popen(cmd, env=env, stdin=r, cwd=cwd, preexec_fn=clear_handled_signals)
|
||||||
except Exception:
|
except Exception:
|
||||||
os.close(w)
|
os.close(w)
|
||||||
else:
|
else:
|
||||||
@@ -1745,7 +1748,7 @@ class Boss:
|
|||||||
finally:
|
finally:
|
||||||
os.close(r)
|
os.close(r)
|
||||||
else:
|
else:
|
||||||
subprocess.Popen(cmd, env=env, cwd=cwd)
|
subprocess.Popen(cmd, env=env, cwd=cwd, preexec_fn=clear_handled_signals)
|
||||||
|
|
||||||
def pipe(self, source: str, dest: str, exe: str, *args: str) -> Optional[Window]:
|
def pipe(self, source: str, dest: str, exe: str, *args: str) -> Optional[Window]:
|
||||||
cmd = [exe] + list(args)
|
cmd = [exe] + list(args)
|
||||||
@@ -1965,8 +1968,8 @@ class Boss:
|
|||||||
map f5 load_config_file /path/to/some/kitty.conf
|
map f5 load_config_file /path/to/some/kitty.conf
|
||||||
''')
|
''')
|
||||||
def load_config_file(self, *paths: str, apply_overrides: bool = True) -> None:
|
def load_config_file(self, *paths: str, apply_overrides: bool = True) -> None:
|
||||||
from .config import load_config
|
|
||||||
from .cli import default_config_paths
|
from .cli import default_config_paths
|
||||||
|
from .config import load_config
|
||||||
old_opts = get_options()
|
old_opts = get_options()
|
||||||
prev_paths = old_opts.config_paths or default_config_paths(self.args.config)
|
prev_paths = old_opts.config_paths or default_config_paths(self.args.config)
|
||||||
paths = paths or prev_paths
|
paths = paths or prev_paths
|
||||||
|
|||||||
@@ -177,6 +177,17 @@ dealloc(ChildMonitor* self) {
|
|||||||
Py_TYPE(self)->tp_free((PyObject*)self);
|
Py_TYPE(self)->tp_free((PyObject*)self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
handled_signals(ChildMonitor *self, PyObject *args UNUSED) {
|
||||||
|
PyObject *ans = PyTuple_New(self->io_loop_data.num_handled_signals);
|
||||||
|
if (ans) {
|
||||||
|
for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(ans); i++) {
|
||||||
|
PyTuple_SET_ITEM(ans, i, PyLong_FromLong((long)self->io_loop_data.handled_signals[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
wakeup_io_loop(ChildMonitor *self, bool in_signal_handler) {
|
wakeup_io_loop(ChildMonitor *self, bool in_signal_handler) {
|
||||||
wakeup_loop(&self->io_loop_data, in_signal_handler, "io_loop");
|
wakeup_loop(&self->io_loop_data, in_signal_handler, "io_loop");
|
||||||
@@ -1706,6 +1717,7 @@ static PyMethodDef methods[] = {
|
|||||||
METHOD(main_loop, METH_NOARGS)
|
METHOD(main_loop, METH_NOARGS)
|
||||||
METHOD(mark_for_close, METH_VARARGS)
|
METHOD(mark_for_close, METH_VARARGS)
|
||||||
METHOD(resize_pty, METH_VARARGS)
|
METHOD(resize_pty, METH_VARARGS)
|
||||||
|
METHODB(handled_signals, METH_NOARGS),
|
||||||
{"set_iutf8_winid", (PyCFunction)pyset_iutf8, METH_VARARGS, ""},
|
{"set_iutf8_winid", (PyCFunction)pyset_iutf8, METH_VARARGS, ""},
|
||||||
{NULL} /* Sentinel */
|
{NULL} /* Sentinel */
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -79,14 +79,16 @@ wait_for_terminal_ready(int fd) {
|
|||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
spawn(PyObject *self UNUSED, PyObject *args) {
|
spawn(PyObject *self UNUSED, PyObject *args) {
|
||||||
PyObject *argv_p, *env_p;
|
PyObject *argv_p, *env_p, *handled_signals_p;
|
||||||
int master, slave, stdin_read_fd, stdin_write_fd, ready_read_fd, ready_write_fd;
|
int master, slave, stdin_read_fd, stdin_write_fd, ready_read_fd, ready_write_fd;
|
||||||
char *cwd, *exe;
|
char *cwd, *exe;
|
||||||
if (!PyArg_ParseTuple(args, "ssO!O!iiiiii", &exe, &cwd, &PyTuple_Type, &argv_p, &PyTuple_Type, &env_p, &master, &slave, &stdin_read_fd, &stdin_write_fd, &ready_read_fd, &ready_write_fd)) return NULL;
|
if (!PyArg_ParseTuple(args, "ssO!O!iiiiiiO!", &exe, &cwd, &PyTuple_Type, &argv_p, &PyTuple_Type, &env_p, &master, &slave, &stdin_read_fd, &stdin_write_fd, &ready_read_fd, &ready_write_fd, &PyTuple_Type, &handled_signals_p)) return NULL;
|
||||||
char name[2048] = {0};
|
char name[2048] = {0};
|
||||||
if (ttyname_r(slave, name, sizeof(name) - 1) != 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; }
|
if (ttyname_r(slave, name, sizeof(name) - 1) != 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; }
|
||||||
char **argv = serialize_string_tuple(argv_p);
|
char **argv = serialize_string_tuple(argv_p);
|
||||||
char **env = serialize_string_tuple(env_p);
|
char **env = serialize_string_tuple(env_p);
|
||||||
|
int handled_signals[16] = {0}, num_handled_signals = MIN((int)arraysz(handled_signals), PyTuple_GET_SIZE(handled_signals_p));
|
||||||
|
for (Py_ssize_t i = 0; i < num_handled_signals; i++) handled_signals[i] = PyLong_AsLong(PyTuple_GET_ITEM(handled_signals_p, i));
|
||||||
|
|
||||||
#if PY_VERSION_HEX >= 0x03070000
|
#if PY_VERSION_HEX >= 0x03070000
|
||||||
PyOS_BeforeFork();
|
PyOS_BeforeFork();
|
||||||
@@ -99,10 +101,10 @@ spawn(PyObject *self UNUSED, PyObject *args) {
|
|||||||
PyOS_AfterFork_Child();
|
PyOS_AfterFork_Child();
|
||||||
#endif
|
#endif
|
||||||
// See _Py_RestoreSignals in signalmodule.c for a list of signals python nukes
|
// See _Py_RestoreSignals in signalmodule.c for a list of signals python nukes
|
||||||
sigset_t signals = {0};
|
const struct sigaction act = {.sa_handler=SIG_DFL};
|
||||||
struct sigaction act = {.sa_handler=SIG_DFL};
|
|
||||||
#define SA(which) { if (sigaction(which, &act, NULL) != 0) exit_on_err("sigaction() in child process failed"); }
|
#define SA(which) if (sigaction(which, &act, NULL) != 0) exit_on_err("sigaction() in child process failed");
|
||||||
SA(SIGINT); SA(SIGTERM); SA(SIGCHLD); SA(SIGPIPE); SA(SIGUSR1); SA(SIGUSR2);
|
for (int si = 0; si < num_handled_signals; si++) { SA(handled_signals[si]); }
|
||||||
#ifdef SIGXFSZ
|
#ifdef SIGXFSZ
|
||||||
SA(SIGXFSZ);
|
SA(SIGXFSZ);
|
||||||
#endif
|
#endif
|
||||||
@@ -110,6 +112,7 @@ spawn(PyObject *self UNUSED, PyObject *args) {
|
|||||||
SA(SIGXFZ);
|
SA(SIGXFZ);
|
||||||
#endif
|
#endif
|
||||||
#undef SA
|
#undef SA
|
||||||
|
sigset_t signals; sigemptyset(&signals);
|
||||||
if (sigprocmask(SIG_SETMASK, &signals, NULL) != 0) exit_on_err("sigprocmask() in child process failed");
|
if (sigprocmask(SIG_SETMASK, &signals, NULL) != 0) exit_on_err("sigprocmask() in child process failed");
|
||||||
// Use only signal-safe functions (man 7 signal-safety)
|
// Use only signal-safe functions (man 7 signal-safety)
|
||||||
if (chdir(cwd) != 0) { if (chdir("/") != 0) {} }; // ignore failure to chdir to /
|
if (chdir(cwd) != 0) { if (chdir("/") != 0) {} }; // ignore failure to chdir to /
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ from typing import (
|
|||||||
import kitty.fast_data_types as fast_data_types
|
import kitty.fast_data_types as fast_data_types
|
||||||
|
|
||||||
from .constants import (
|
from .constants import (
|
||||||
is_freebsd, is_macos, kitty_base_dir, shell_path, terminfo_dir
|
handled_signals, is_freebsd, is_macos, kitty_base_dir, shell_path,
|
||||||
|
terminfo_dir
|
||||||
)
|
)
|
||||||
from .types import run_once
|
from .types import run_once
|
||||||
from .utils import log_error, which
|
from .utils import log_error, which
|
||||||
@@ -289,7 +290,9 @@ class Child:
|
|||||||
argv[0] = (f'-{exe.split("/")[-1]}')
|
argv[0] = (f'-{exe.split("/")[-1]}')
|
||||||
self.final_exe = which(exe) or exe
|
self.final_exe = which(exe) or exe
|
||||||
self.final_argv0 = argv[0]
|
self.final_argv0 = argv[0]
|
||||||
pid = fast_data_types.spawn(self.final_exe, self.cwd, tuple(argv), env, master, slave, stdin_read_fd, stdin_write_fd, ready_read_fd, ready_write_fd)
|
pid = fast_data_types.spawn(
|
||||||
|
self.final_exe, self.cwd, tuple(argv), env, master, slave,
|
||||||
|
stdin_read_fd, stdin_write_fd, ready_read_fd, ready_write_fd, tuple(handled_signals))
|
||||||
os.close(slave)
|
os.close(slave)
|
||||||
self.pid = pid
|
self.pid = pid
|
||||||
self.child_fd = master
|
self.child_fd = master
|
||||||
|
|||||||
@@ -11,7 +11,9 @@ from typing import (
|
|||||||
|
|
||||||
from .cli_stub import CLIOptions
|
from .cli_stub import CLIOptions
|
||||||
from .conf.utils import resolve_config
|
from .conf.utils import resolve_config
|
||||||
from .constants import appname, defconf, is_macos, str_version, website_url
|
from .constants import (
|
||||||
|
appname, clear_handled_signals, defconf, is_macos, str_version, website_url
|
||||||
|
)
|
||||||
from .options.types import Options as KittyOpts
|
from .options.types import Options as KittyOpts
|
||||||
from .typing import BadLineType, TypedDict
|
from .typing import BadLineType, TypedDict
|
||||||
|
|
||||||
@@ -362,7 +364,7 @@ class PrintHelpForSeq:
|
|||||||
text = '\n'.join(blocks) + '\n\n' + version()
|
text = '\n'.join(blocks) + '\n\n' + version()
|
||||||
if print_help_for_seq.allow_pager and sys.stdout.isatty():
|
if print_help_for_seq.allow_pager and sys.stdout.isatty():
|
||||||
import subprocess
|
import subprocess
|
||||||
p = subprocess.Popen(['less', '-isRXF'], stdin=subprocess.PIPE)
|
p = subprocess.Popen(['less', '-isRXF'], stdin=subprocess.PIPE, preexec_fn=clear_handled_signals)
|
||||||
try:
|
try:
|
||||||
p.communicate(text.encode('utf-8'))
|
p.communicate(text.encode('utf-8'))
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import os
|
|||||||
import pwd
|
import pwd
|
||||||
import sys
|
import sys
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
from typing import TYPE_CHECKING, Iterable, NamedTuple, Optional, Set
|
from typing import TYPE_CHECKING, Any, Iterable, NamedTuple, Optional, Set
|
||||||
|
|
||||||
from .types import run_once
|
from .types import run_once
|
||||||
|
|
||||||
@@ -235,3 +235,16 @@ def website_url(doc_name: str = '') -> str:
|
|||||||
if doc_name:
|
if doc_name:
|
||||||
doc_name += '/'
|
doc_name += '/'
|
||||||
return f'https://sw.kovidgoyal.net/kitty/{doc_name}'
|
return f'https://sw.kovidgoyal.net/kitty/{doc_name}'
|
||||||
|
|
||||||
|
|
||||||
|
handled_signals: Set[int] = set()
|
||||||
|
|
||||||
|
|
||||||
|
def clear_handled_signals(*a: Any) -> None:
|
||||||
|
if not handled_signals:
|
||||||
|
return
|
||||||
|
import signal
|
||||||
|
if hasattr(signal, 'pthread_sigmask'):
|
||||||
|
signal.pthread_sigmask(signal.SIG_UNBLOCK, handled_signals)
|
||||||
|
for s in handled_signals:
|
||||||
|
signal.signal(s, signal.SIG_DFL)
|
||||||
|
|||||||
@@ -1200,6 +1200,9 @@ class ChildMonitor:
|
|||||||
def wakeup(self) -> None:
|
def wakeup(self) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def handled_signals(self) -> Tuple[int, ...]:
|
||||||
|
pass
|
||||||
|
|
||||||
def main_loop(self) -> None:
|
def main_loop(self) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -1279,7 +1282,8 @@ def spawn(
|
|||||||
stdin_read_fd: int,
|
stdin_read_fd: int,
|
||||||
stdin_write_fd: int,
|
stdin_write_fd: int,
|
||||||
ready_read_fd: int,
|
ready_read_fd: int,
|
||||||
ready_write_fd: int
|
ready_write_fd: int,
|
||||||
|
handled_signals: Tuple[int, ...],
|
||||||
) -> int:
|
) -> int:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -16,8 +16,9 @@ from .cli_stub import CLIOptions
|
|||||||
from .conf.utils import BadLine
|
from .conf.utils import BadLine
|
||||||
from .config import cached_values_for
|
from .config import cached_values_for
|
||||||
from .constants import (
|
from .constants import (
|
||||||
appname, beam_cursor_data_file, config_dir, glfw_path, is_macos,
|
appname, beam_cursor_data_file, clear_handled_signals, config_dir,
|
||||||
is_wayland, kitty_exe, logo_png_file, running_in_kitty, website_url
|
glfw_path, is_macos, is_wayland, kitty_exe, logo_png_file,
|
||||||
|
running_in_kitty, website_url
|
||||||
)
|
)
|
||||||
from .fast_data_types import (
|
from .fast_data_types import (
|
||||||
GLFW_IBEAM_CURSOR, GLFW_MOD_ALT, GLFW_MOD_SHIFT, create_os_window,
|
GLFW_IBEAM_CURSOR, GLFW_MOD_ALT, GLFW_MOD_SHIFT, create_os_window,
|
||||||
@@ -249,7 +250,7 @@ def setup_profiling() -> Generator[None, None, None]:
|
|||||||
with open(cg, 'wb') as f:
|
with open(cg, 'wb') as f:
|
||||||
subprocess.call(['pprof', '--callgrind', exe, '/tmp/kitty-profile.log'], stdout=f)
|
subprocess.call(['pprof', '--callgrind', exe, '/tmp/kitty-profile.log'], stdout=f)
|
||||||
try:
|
try:
|
||||||
subprocess.Popen(['kcachegrind', cg])
|
subprocess.Popen(['kcachegrind', cg], preexec_fn=clear_handled_signals)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
subprocess.call(['pprof', '--text', exe, '/tmp/kitty-profile.log'])
|
subprocess.call(['pprof', '--text', exe, '/tmp/kitty-profile.log'])
|
||||||
print('To view the graphical call data, use: kcachegrind', cg)
|
print('To view the graphical call data, use: kcachegrind', cg)
|
||||||
|
|||||||
@@ -9,7 +9,9 @@ from typing import Dict, NamedTuple, Optional, Tuple
|
|||||||
from urllib.request import urlopen
|
from urllib.request import urlopen
|
||||||
|
|
||||||
from .config import atomic_save
|
from .config import atomic_save
|
||||||
from .constants import Version, cache_dir, kitty_exe, version, website_url
|
from .constants import (
|
||||||
|
Version, cache_dir, clear_handled_signals, kitty_exe, version, website_url
|
||||||
|
)
|
||||||
from .fast_data_types import add_timer, get_boss, monitor_pid
|
from .fast_data_types import add_timer, get_boss, monitor_pid
|
||||||
from .notify import notify
|
from .notify import notify
|
||||||
from .utils import log_error, open_url
|
from .utils import log_error, open_url
|
||||||
@@ -115,7 +117,7 @@ def update_check() -> bool:
|
|||||||
p = subprocess.Popen([
|
p = subprocess.Popen([
|
||||||
kitty_exe(), '+runpy',
|
kitty_exe(), '+runpy',
|
||||||
'from kitty.update_check import run_worker; run_worker()'
|
'from kitty.update_check import run_worker; run_worker()'
|
||||||
], stdout=subprocess.PIPE)
|
], stdout=subprocess.PIPE, preexec_fn=clear_handled_signals)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
log_error(f'Failed to run kitty for update check, with error: {e}')
|
log_error(f'Failed to run kitty for update check, with error: {e}')
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ from typing import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from .constants import (
|
from .constants import (
|
||||||
appname, config_dir, is_macos, is_wayland, read_kitty_resource,
|
appname, clear_handled_signals, config_dir, is_macos, is_wayland,
|
||||||
runtime_dir, shell_path, ssh_control_master_template,
|
read_kitty_resource, runtime_dir, shell_path, ssh_control_master_template,
|
||||||
supports_primary_selection
|
supports_primary_selection
|
||||||
)
|
)
|
||||||
from .fast_data_types import Color, open_tty
|
from .fast_data_types import Color, open_tty
|
||||||
@@ -277,7 +277,9 @@ def open_cmd(cmd: Union[Iterable[str], List[str]], arg: Union[None, Iterable[str
|
|||||||
cmd.append(arg)
|
cmd.append(arg)
|
||||||
else:
|
else:
|
||||||
cmd.extend(arg)
|
cmd.extend(arg)
|
||||||
return subprocess.Popen(tuple(cmd), stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, cwd=cwd or None)
|
return subprocess.Popen(
|
||||||
|
tuple(cmd), stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, cwd=cwd or None,
|
||||||
|
preexec_fn=clear_handled_signals)
|
||||||
|
|
||||||
|
|
||||||
def open_url(url: str, program: Union[str, List[str]] = 'default', cwd: Optional[str] = None) -> 'PopenType[bytes]':
|
def open_url(url: str, program: Union[str, List[str]] = 'default', cwd: Optional[str] = None) -> 'PopenType[bytes]':
|
||||||
@@ -797,7 +799,9 @@ def read_shell_environment(opts: Optional[Options] = None) -> Dict[str, str]:
|
|||||||
if '-i' not in shell and '--interactive' not in shell:
|
if '-i' not in shell and '--interactive' not in shell:
|
||||||
shell += ['-i']
|
shell += ['-i']
|
||||||
try:
|
try:
|
||||||
p = subprocess.Popen(shell + ['-c', 'env'], stdout=slave, stdin=slave, stderr=slave, start_new_session=True, close_fds=True)
|
p = subprocess.Popen(
|
||||||
|
shell + ['-c', 'env'], stdout=slave, stdin=slave, stderr=slave, start_new_session=True, close_fds=True,
|
||||||
|
preexec_fn=clear_handled_signals)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
log_error('Could not find shell to read environment')
|
log_error('Could not find shell to read environment')
|
||||||
return ans
|
return ans
|
||||||
@@ -970,8 +974,8 @@ def cleanup_ssh_control_masters() -> None:
|
|||||||
except OSError:
|
except OSError:
|
||||||
return
|
return
|
||||||
workers = tuple(subprocess.Popen([
|
workers = tuple(subprocess.Popen([
|
||||||
'ssh', '-o', f'ControlPath={x}', '-O', 'exit', 'kitty-unused-host-name'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
'ssh', '-o', f'ControlPath={x}', '-O', 'exit', 'kitty-unused-host-name'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
|
||||||
for x in files)
|
preexec_fn=clear_handled_signals) for x in files)
|
||||||
for w in workers:
|
for w in workers:
|
||||||
w.wait()
|
w.wait()
|
||||||
for x in files:
|
for x in files:
|
||||||
|
|||||||
@@ -21,7 +21,9 @@ from typing import (
|
|||||||
from .child import ProcessDesc
|
from .child import ProcessDesc
|
||||||
from .cli_stub import CLIOptions
|
from .cli_stub import CLIOptions
|
||||||
from .config import build_ansi_color_table
|
from .config import build_ansi_color_table
|
||||||
from .constants import appname, config_dir, is_macos, wakeup
|
from .constants import (
|
||||||
|
appname, clear_handled_signals, config_dir, is_macos, wakeup
|
||||||
|
)
|
||||||
from .fast_data_types import (
|
from .fast_data_types import (
|
||||||
BGIMAGE_PROGRAM, BLIT_PROGRAM, CELL_BG_PROGRAM, CELL_FG_PROGRAM,
|
BGIMAGE_PROGRAM, BLIT_PROGRAM, CELL_BG_PROGRAM, CELL_FG_PROGRAM,
|
||||||
CELL_PROGRAM, CELL_SPECIAL_PROGRAM, CURSOR_BEAM, CURSOR_BLOCK,
|
CELL_PROGRAM, CELL_SPECIAL_PROGRAM, CURSOR_BEAM, CURSOR_BLOCK,
|
||||||
@@ -831,9 +833,10 @@ class Window:
|
|||||||
set_clipboard_string(url)
|
set_clipboard_string(url)
|
||||||
|
|
||||||
def handle_remote_file(self, netloc: str, remote_path: str) -> None:
|
def handle_remote_file(self, netloc: str, remote_path: str) -> None:
|
||||||
from .utils import SSHConnectionData
|
|
||||||
from kittens.ssh.main import get_connection_data
|
|
||||||
from kittens.remote_file.main import is_ssh_kitten_sentinel
|
from kittens.remote_file.main import is_ssh_kitten_sentinel
|
||||||
|
from kittens.ssh.main import get_connection_data
|
||||||
|
|
||||||
|
from .utils import SSHConnectionData
|
||||||
args = self.ssh_kitten_cmdline()
|
args = self.ssh_kitten_cmdline()
|
||||||
conn_data: Union[None, List[str], SSHConnectionData] = None
|
conn_data: Union[None, List[str], SSHConnectionData] = None
|
||||||
if args:
|
if args:
|
||||||
@@ -903,7 +906,7 @@ class Window:
|
|||||||
import subprocess
|
import subprocess
|
||||||
env = self.child.foreground_environ
|
env = self.child.foreground_environ
|
||||||
env['KITTY_CHILD_CMDLINE'] = ' '.join(map(shlex.quote, self.child.cmdline))
|
env['KITTY_CHILD_CMDLINE'] = ' '.join(map(shlex.quote, self.child.cmdline))
|
||||||
subprocess.Popen(cb, env=env, cwd=self.child.foreground_cwd)
|
subprocess.Popen(cb, env=env, cwd=self.child.foreground_cwd, preexec_fn=clear_handled_signals)
|
||||||
if not self.is_active:
|
if not self.is_active:
|
||||||
changed = not self.needs_attention
|
changed = not self.needs_attention
|
||||||
self.needs_attention = True
|
self.needs_attention = True
|
||||||
|
|||||||
Reference in New Issue
Block a user