From 4e9dabfb258adc7a6ace0bcb7074c1500a1a4467 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 29 May 2019 09:42:52 +0530 Subject: [PATCH] Add an option :opt:`command_on_bell` to run an arbitrary command when a bell occurs Fixes #1660 --- docs/changelog.rst | 3 +++ kitty/child.py | 36 +++++++++++++++++++++++++----------- kitty/config_data.py | 3 +++ kitty/window.py | 6 ++++++ 4 files changed, 37 insertions(+), 11 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index bf16f75e3..a7138463d 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -7,6 +7,9 @@ To update |kitty|, :doc:`follow the instructions `. 0.14.1 [future] --------------------- +- Add an option :opt:`command_on_bell` to run an arbitrary command when + a bell occurs (:iss:`1660`) + - Add support for the underscore key found in some keyboard layouts (:iss:`1639`) diff --git a/kitty/child.py b/kitty/child.py index c1c9f86ff..aa0cd0c1e 100644 --- a/kitty/child.py +++ b/kitty/child.py @@ -57,6 +57,13 @@ else: return ans +def checked_terminfo_dir(): + ans = getattr(checked_terminfo_dir, 'ans', None) + if ans is None: + ans = checked_terminfo_dir.ans = terminfo_dir if os.path.isdir(terminfo_dir) else None + return ans + + def processes_in_group(grp): gmap = getattr(process_group_map, 'cached_map', None) if gmap is None: @@ -149,6 +156,23 @@ class Child: self.stdin = stdin self.env = env or {} + @property + def final_env(self): + env = getattr(self, '_final_env', None) + if env is None: + env = self._final_env = default_env().copy() + env.update(self.env) + env['TERM'] = self.opts.term + env['COLORTERM'] = 'truecolor' + if self.cwd: + # needed incase cwd is a symlink, in which case shells + # can use it to display the current directory name rather + # than the resolved path + env['PWD'] = self.cwd + if checked_terminfo_dir(): + env['TERMINFO'] = checked_terminfo_dir() + return env + def fork(self): if self.forked: return @@ -164,17 +188,7 @@ class Child: remove_cloexec(stdin_read_fd) else: stdin_read_fd = stdin_write_fd = -1 - env = default_env().copy() - env.update(self.env) - env['TERM'] = self.opts.term - env['COLORTERM'] = 'truecolor' - if self.cwd: - # needed incase cwd is a symlink, in which case shells - # can use it to display the current directory name rather - # than the resolved path - env['PWD'] = self.cwd - if os.path.isdir(terminfo_dir): - env['TERMINFO'] = terminfo_dir + env = self.final_env env = tuple('{}={}'.format(k, v) for k, v in env.items()) argv = list(self.argv) exe = argv[0] diff --git a/kitty/config_data.py b/kitty/config_data.py index 8cebafa66..bfa146031 100644 --- a/kitty/config_data.py +++ b/kitty/config_data.py @@ -513,6 +513,9 @@ o('bell_on_tab', True, long_text=_(''' Show a bell symbol on the tab if a bell occurs in one of the windows in the tab and the window is not the currently focused window''')) +o('command_on_bell', 'none', option_type=to_cmdline, long_text=_(''' +Program to run when a bell occurs. +''')) # }}} g('window') # {{{ diff --git a/kitty/window.py b/kitty/window.py index 09d9aee30..a7ff4b234 100644 --- a/kitty/window.py +++ b/kitty/window.py @@ -306,6 +306,12 @@ class Window: return get_boss().active_window is self def on_bell(self): + if self.opts.command_on_bell and self.opts.command_on_bell != ['none']: + import subprocess + import shlex + env = self.child.final_env + env['KITTY_CHILD_CMDLINE'] = ' '.join(map(shlex.quote, self.child.cmdline)) + subprocess.Popen(self.opts.command_on_bell, env=env, cwd=self.child.foreground_cwd) if not self.is_active: self.needs_attention = True tab = self.tabref()