Implement auto reload of config

This commit is contained in:
Kovid Goyal 2026-04-16 14:39:51 +05:30
parent efbfbb49f9
commit e9f3844f64
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
8 changed files with 29 additions and 4 deletions

View file

@ -181,6 +181,8 @@ Detailed list of changes
- Draw a progress bar at the top of the window when a program reports progress using the OSC 9;4 escape sequence, controlled by :opt:`progress_bar` (:iss:`9777`) - Draw a progress bar at the top of the window when a program reports progress using the OSC 9;4 escape sequence, controlled by :opt:`progress_bar` (:iss:`9777`)
- Automatically reload configuration on changes, controlled by :opt:`auto_reload_config`
- Allow specifying multiple background images for :opt:`background_image` that are stored on GPU to allow fast image switching (:pull:`9836`) - Allow specifying multiple background images for :opt:`background_image` that are stored on GPU to allow fast image switching (:pull:`9836`)
- :doc:`Remote control <remote-control>`: Expose :code:`session_name` and :code:`last_focused_at` in the output of ``kitten @ ls`` for each window (:iss:`9732`, :iss:`9799`) - :doc:`Remote control <remote-control>`: Expose :code:`session_name` and :code:`last_focused_at` in the output of ``kitten @ ls`` for each window (:iss:`9732`, :iss:`9799`)

View file

@ -16,7 +16,8 @@ frames-per-second. See below for an overview of all customization possibilities.
You can open the config file within |kitty| by pressing :sc:`edit_config_file` You can open the config file within |kitty| by pressing :sc:`edit_config_file`
(:kbd:`⌘+,` on macOS). A :file:`kitty.conf` with commented default (:kbd:`⌘+,` on macOS). A :file:`kitty.conf` with commented default
configurations and descriptions will be created if the file does not exist. configurations and descriptions will be created if the file does not exist.
You can reload the config file within |kitty| by pressing The configuration is automatically reloaded when modified, controlled by
:opt:`auto_reload_config`. You can manually reload the config by pressing
:sc:`reload_config_file` (:kbd:`⌃+⌘+,` on macOS) or sending |kitty| the :sc:`reload_config_file` (:kbd:`⌃+⌘+,` on macOS) or sending |kitty| the
``SIGUSR1`` signal with ``kill -SIGUSR1 $KITTY_PID``. You can also display the ``SIGUSR1`` signal with ``kill -SIGUSR1 $KITTY_PID``. You can also display the
current configuration by pressing :sc:`debug_config` (:kbd:`⌥+⌘+,` on macOS). current configuration by pressing :sc:`debug_config` (:kbd:`⌥+⌘+,` on macOS).

View file

@ -1390,10 +1390,15 @@ def start(self, first_os_window_id: int, startup_sessions: Iterable[Session]) ->
else: else:
self.startup_first_child(first_os_window_id, startup_sessions=startup_sessions) self.startup_first_child(first_os_window_id, startup_sessions=startup_sessions)
if get_options().update_check_interval > 0 and not self.update_check_started and getattr(sys, 'frozen', False):
if (opts := get_options()).update_check_interval > 0 and not self.update_check_started and getattr(sys, 'frozen', False):
from .update_check import run_update_check from .update_check import run_update_check
run_update_check(get_options().update_check_interval * 60 * 60) run_update_check(get_options().update_check_interval * 60 * 60)
self.update_check_started = True self.update_check_started = True
if opts.auto_reload_config >= 0 and not hasattr(self, 'config_reload_watcher_process'):
self.config_reload_watcher_process = subprocess.Popen(
[kitten_exe(), '__watch_conf__', str(os.getpid()), str(int(opts.auto_reload_config * 1000))] +
list(opts.all_config_paths), stdin=subprocess.PIPE)
def handle_window_title_bar_mouse(self, os_window_id: int, window_id: int, x: float, y: float, button: int, modifiers: int, action: int) -> None: def handle_window_title_bar_mouse(self, os_window_id: int, window_id: int, x: float, y: float, button: int, modifiers: int, action: int) -> None:
if tm := self.os_window_map.get(os_window_id): if tm := self.os_window_map.get(os_window_id):

View file

@ -2393,6 +2393,15 @@
''' '''
) )
opt('auto_reload_config', '0.1', option_type='float', long_text='''
Automatically reload configuration files when they are changed. The setting
is the number of seconds to wait before reloading the config files. This allows
multiple changes to be debounced. Use a negative value to disable automatic reload.
You can manually reload with :sc:`reload_config_file`. Note that automatic
reload works only if the :file:`kitty.conf` already exists when kitty is started.
Changes to this setting by reloading configuration are ignored.
''')
opt('startup_session', 'none', opt('startup_session', 'none',
option_type='config_or_absolute_path', option_type='config_or_absolute_path',
long_text=''' long_text='''

View file

@ -71,6 +71,9 @@ def allow_remote_control(self, val: str, ans: dict[str, typing.Any]) -> None:
choices_for_allow_remote_control = frozenset(('password', 'socket-only', 'socket', 'no', 'n', 'false', 'yes', 'y', 'true')) choices_for_allow_remote_control = frozenset(('password', 'socket-only', 'socket', 'no', 'n', 'false', 'yes', 'y', 'true'))
def auto_reload_config(self, val: str, ans: dict[str, typing.Any]) -> None:
ans['auto_reload_config'] = float(val)
def background(self, val: str, ans: dict[str, typing.Any]) -> None: def background(self, val: str, ans: dict[str, typing.Any]) -> None:
ans['background'] = to_color(val) ans['background'] = to_color(val)

View file

@ -53,6 +53,7 @@
'allow_cloning', 'allow_cloning',
'allow_hyperlinks', 'allow_hyperlinks',
'allow_remote_control', 'allow_remote_control',
'auto_reload_config',
'background', 'background',
'background_blur', 'background_blur',
'background_image', 'background_image',
@ -527,6 +528,7 @@ class Options:
allow_cloning: choices_for_allow_cloning = 'ask' allow_cloning: choices_for_allow_cloning = 'ask'
allow_hyperlinks: int = 1 allow_hyperlinks: int = 1
allow_remote_control: choices_for_allow_remote_control = 'no' allow_remote_control: choices_for_allow_remote_control = 'no'
auto_reload_config: float = 0.1
background: Color = Color(0, 0, 0) background: Color = Color(0, 0, 0)
background_blur: int = 0 background_blur: int = 0
background_image: tuple[str, ...] = () background_image: tuple[str, ...] = ()

View file

@ -37,6 +37,7 @@ import (
"github.com/kovidgoyal/kitty/tools/cmd/update_self" "github.com/kovidgoyal/kitty/tools/cmd/update_self"
"github.com/kovidgoyal/kitty/tools/tui" "github.com/kovidgoyal/kitty/tools/tui"
"github.com/kovidgoyal/kitty/tools/utils/images" "github.com/kovidgoyal/kitty/tools/utils/images"
"github.com/kovidgoyal/kitty/tools/watch"
) )
var _ = fmt.Print var _ = fmt.Print
@ -135,7 +136,7 @@ func KittyToolEntryPoints(root *cli.Command) {
}, },
}) })
// __watch_conf__ // __watch_conf__
watch.EntryPoint(root)
// __convert_image__ // __convert_image__
images.ConvertEntryPoint(root) images.ConvertEntryPoint(root)
// __atexit__ // __atexit__

View file

@ -27,7 +27,9 @@ func watch_dirs(ctx context.Context, paths []string, debounce time.Duration, eve
fswatcher.WithCooldown(debounce), fswatcher.WithCooldown(debounce),
} }
for _, path := range paths { for _, path := range paths {
opts = append(opts, fswatcher.WithPath(path)) if unix.Access(path, unix.R_OK|unix.X_OK) == nil {
opts = append(opts, fswatcher.WithPath(path))
}
} }
w, err := fswatcher.New(opts...) w, err := fswatcher.New(opts...)
if err != nil { if err != nil {