Allow reloading conf in all kitty instances as well

This commit is contained in:
Kovid Goyal 2021-08-08 09:33:36 +05:30
parent a49f6799de
commit ca9143bebc
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 84 additions and 8 deletions

View File

@ -12,12 +12,15 @@
import tempfile
import zipfile
from contextlib import suppress
from typing import Any, Callable, Dict, Iterator, Match, Optional, Tuple, Union
from typing import (
Any, Callable, Dict, Iterable, Iterator, List, Match, Optional, Tuple,
Union
)
from urllib.error import HTTPError
from urllib.request import Request, urlopen
from kitty.config import atomic_save, parse_config
from kitty.constants import cache_dir, config_dir
from kitty.constants import cache_dir, config_dir, is_macos
from kitty.options.types import Options as KittyOptions
from kitty.rgb import Color
@ -27,6 +30,28 @@
MARK_AFTER = '\033[39m'
def is_kitty_gui(cmd: List[str]) -> bool:
if not cmd:
return False
if os.path.basename(cmd[0]) != 'kitty':
return False
if len(cmd) == 1:
return True
if '+' in cmd or '@' in cmd or cmd[1].startswith('+') or cmd[1].startswith('@'):
return False
return True
def get_all_processes() -> Iterable[int]:
if is_macos:
from kitty.fast_data_types import get_all_processes as f
yield from f()
else:
for c in os.listdir('/proc'):
if c.isdigit():
yield int(c)
def patch_conf(raw: str) -> str:
addition = '# BEGIN_KITTY_THEME\ninclude current-theme.conf\n# END_KITTY_THEME'
nraw, num = re.subn(r'^# BEGIN_KITTY_THEME.+?# END_KITTY_THEME', addition, raw, flags=re.MULTILINE | re.DOTALL)
@ -254,7 +279,7 @@ def kitty_opts(self) -> KittyOptions:
def save_in_dir(self, dirpath: str) -> None:
atomic_save(self.raw.encode('utf-8'), os.path.join(dirpath, f'{self.name}.conf'))
def save_in_conf(self, confdir: str) -> None:
def save_in_conf(self, confdir: str, reload_in: str) -> None:
atomic_save(self.raw.encode('utf-8'), os.path.join(confdir, 'current-theme.conf'))
confpath = os.path.join(confdir, 'kitty.conf')
try:
@ -267,8 +292,18 @@ def save_in_conf(self, confdir: str) -> None:
with open(confpath + '.bak', 'w') as f:
f.write(raw)
atomic_save(nraw.encode('utf-8'), confpath)
if 'KITTY_PID' in os.environ:
os.kill(int(os.environ['KITTY_PID']), signal.SIGUSR1)
if reload_in == 'parent':
if 'KITTY_PID' in os.environ:
os.kill(int(os.environ['KITTY_PID']), signal.SIGUSR1)
elif reload_in == 'all':
from kitty.child import cmdline_of_process # type: ignore
for pid in get_all_processes():
try:
cmd = cmdline_of_process(pid)
except Exception:
continue
if cmd and is_kitty_gui(cmd):
os.kill(pid, signal.SIGUSR1)
class Themes:

View File

@ -466,7 +466,7 @@ def on_accepting_key_event(self, key_event: KeyEventType, in_bracketed_paste: bo
self.quit_loop(0)
return
if key_event.matches('m'):
self.themes_list.current_theme.save_in_conf(config_dir)
self.themes_list.current_theme.save_in_conf(config_dir, self.cli_opts.reload_in)
self.update_recent()
self.quit_loop(0)
return
@ -520,6 +520,20 @@ def on_eot(self) -> None:
is not available.
--reload-in
default=parent
choices=none,parent,all
By default, this kitten will signal only the parent kitty instance it is
running in to reload its config, after making changes. Use this option
to instead either not reload the config at all or in all running
kitty instances.
--dump-theme
type=bool-set
default=false
When running non-interactively, dump the specified theme to STDOUT
instead of changing kitty.conf.
'''.format
@ -536,7 +550,10 @@ def non_interactive(cli_opts: ThemesCLIOptions, theme_name: str) -> None:
theme = themes[theme_name]
except KeyError:
raise SystemExit(f'No theme named: {theme_name}')
theme.save_in_conf(config_dir)
if cli_opts.dump_theme:
print(theme.raw)
return
theme.save_in_conf(config_dir, cli_opts.reload_in)
def main(args: List[str]) -> None:
@ -548,7 +565,7 @@ def main(args: List[str]) -> None:
input(_('Press Enter to quit'))
return None
if len(items) > 1:
raise SystemExit('At most one theme name must be specified')
items = [' '.join(items[1:])]
if len(items) == 1:
return non_interactive(cli_opts, items[0])

View File

@ -1213,3 +1213,7 @@ class OSWindowSize(TypedDict):
def get_os_window_size(os_window_id: int) -> Optional[OSWindowSize]:
pass
def get_all_processes() -> Tuple[int, ...]:
pass

View File

@ -34,6 +34,25 @@ get_argmax() {
return 0;
}
static PyObject*
get_all_processes(PyObject *self UNUSED, PyObject *args UNUSED) {
pid_t num = proc_listallpids(NULL, 0);
if (num <= 0) return PyTuple_New(0);
size_t sz = sizeof(pid_t) * num * 2;
pid_t *buf = malloc(sz);
if (!buf) return PyErr_NoMemory();
num = proc_listallpids(buf, sz);
if (num <= 0) { free(buf); return PyTuple_New(0); }
PyObject *ans = PyTuple_New(num);
if (!ans) { free(buf); return NULL; }
for (pid_t i = 0; i < num; i++) {
long long pid = buf[i];
PyObject *t = PyLong_FromLongLong(pid);
if (!t) { free(buf); Py_CLEAR(ans); return NULL; }
PyTuple_SET_ITEM(ans, i, t);
}
return ans;
}
static PyObject*
cmdline_of_process(PyObject *self UNUSED, PyObject *pid_) {
@ -255,6 +274,7 @@ static PyMethodDef module_methods[] = {
{"cwd_of_process", (PyCFunction)cwd_of_process, METH_O, ""},
{"cmdline_of_process", (PyCFunction)cmdline_of_process, METH_O, ""},
{"environ_of_process", (PyCFunction)environ_of_process, METH_O, ""},
{"get_all_processes", (PyCFunction)get_all_processes, METH_NOARGS, ""},
{NULL, NULL, 0, NULL} /* Sentinel */
};