diff --git a/docs/changelog.rst b/docs/changelog.rst index 91f786ab3..57595dd70 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -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`) +- 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`) - :doc:`Remote control `: Expose :code:`session_name` and :code:`last_focused_at` in the output of ``kitten @ ls`` for each window (:iss:`9732`, :iss:`9799`) diff --git a/docs/conf.rst b/docs/conf.rst index 196870d69..5291bddc8 100644 --- a/docs/conf.rst +++ b/docs/conf.rst @@ -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` (:kbd:`⌘+,` on macOS). A :file:`kitty.conf` with commented default 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 ``SIGUSR1`` signal with ``kill -SIGUSR1 $KITTY_PID``. You can also display the current configuration by pressing :sc:`debug_config` (:kbd:`⌥+⌘+,` on macOS). diff --git a/kitty/boss.py b/kitty/boss.py index ed6bbd025..9c18f1621 100644 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -1390,10 +1390,15 @@ class Boss: else: 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 run_update_check(get_options().update_check_interval * 60 * 60) 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: if tm := self.os_window_map.get(os_window_id): diff --git a/kitty/options/definition.py b/kitty/options/definition.py index 4ddca2fa3..8898809c4 100644 --- a/kitty/options/definition.py +++ b/kitty/options/definition.py @@ -2393,6 +2393,15 @@ reloading the config is not supported. ''' ) +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', option_type='config_or_absolute_path', long_text=''' diff --git a/kitty/options/parse.py b/kitty/options/parse.py index d3abbaeef..662601a2b 100644 --- a/kitty/options/parse.py +++ b/kitty/options/parse.py @@ -71,6 +71,9 @@ class Parser: 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: ans['background'] = to_color(val) diff --git a/kitty/options/types.py b/kitty/options/types.py index ca38b3658..100981472 100644 --- a/kitty/options/types.py +++ b/kitty/options/types.py @@ -53,6 +53,7 @@ option_names = ( 'allow_cloning', 'allow_hyperlinks', 'allow_remote_control', + 'auto_reload_config', 'background', 'background_blur', 'background_image', @@ -527,6 +528,7 @@ class Options: allow_cloning: choices_for_allow_cloning = 'ask' allow_hyperlinks: int = 1 allow_remote_control: choices_for_allow_remote_control = 'no' + auto_reload_config: float = 0.1 background: Color = Color(0, 0, 0) background_blur: int = 0 background_image: tuple[str, ...] = () diff --git a/tools/cmd/tool/main.go b/tools/cmd/tool/main.go index aa875e4a0..ca458b029 100644 --- a/tools/cmd/tool/main.go +++ b/tools/cmd/tool/main.go @@ -37,6 +37,7 @@ import ( "github.com/kovidgoyal/kitty/tools/cmd/update_self" "github.com/kovidgoyal/kitty/tools/tui" "github.com/kovidgoyal/kitty/tools/utils/images" + "github.com/kovidgoyal/kitty/tools/watch" ) var _ = fmt.Print @@ -135,7 +136,7 @@ func KittyToolEntryPoints(root *cli.Command) { }, }) // __watch_conf__ - + watch.EntryPoint(root) // __convert_image__ images.ConvertEntryPoint(root) // __atexit__ diff --git a/tools/watch/api.go b/tools/watch/api.go index 35e9056f5..1af77eb21 100644 --- a/tools/watch/api.go +++ b/tools/watch/api.go @@ -27,7 +27,9 @@ func watch_dirs(ctx context.Context, paths []string, debounce time.Duration, eve fswatcher.WithCooldown(debounce), } 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...) if err != nil {