diff --git a/docs/changelog.rst b/docs/changelog.rst index d5eaa720a..6c33a3651 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -9,6 +9,9 @@ To update |kitty|, :doc:`follow the instructions `. - Remote control: Add a command `kitty @ scroll-window` to scroll windows +- Allow passing a ``!neighbor`` argument to the new_window mapping to open a + new window next to the active window (:iss:`1746`) + - Fix an out of bounds read causing a crash when selecting text with the mouse in the alternate screen mode (:iss:`1578`) diff --git a/kitty/boss.py b/kitty/boss.py index 3ab27ee12..9b1a7894a 100644 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -988,10 +988,14 @@ class Boss: def _new_window(self, args, cwd_from=None): tab = self.active_tab if tab is not None: + location = None + if args and args[0].startswith('!'): + location = args[0][1:].lower() + args = args[1:] if args: - return tab.new_special_window(self.args_to_special_window(args, cwd_from=cwd_from)) + return tab.new_special_window(self.args_to_special_window(args, cwd_from=cwd_from), location=location) else: - return tab.new_window(cwd_from=cwd_from) + return tab.new_window(cwd_from=cwd_from, location=location) def new_window(self, *args): self._new_window(args) diff --git a/kitty/config_data.py b/kitty/config_data.py index 7564c943d..1720c8bd1 100644 --- a/kitty/config_data.py +++ b/kitty/config_data.py @@ -1066,6 +1066,13 @@ Any programs running in that window will be allowed to control kitty. For example:: map ctrl+enter new_window @ some_program + +You can open a new window next to the currently active window or as the first window, +with:: + + map ctrl+n new_window !neighbor some_program + map ctrl+f new_window !first some_program + ''')) if is_macos: k('new_window', 'cmd+enter', 'new_window', _('New window'), add_to_docs=False) diff --git a/kitty/layout.py b/kitty/layout.py index 5be8933f9..99c201483 100644 --- a/kitty/layout.py +++ b/kitty/layout.py @@ -267,7 +267,7 @@ class Layout: # {{{ self.swap_windows_in_os_window(nidx, idx) return self.set_active_window(all_windows, nidx) - def add_window(self, all_windows, window, current_active_window_idx): + def add_window(self, all_windows, window, current_active_window_idx, location=None): active_window_idx = None if window.overlay_for is not None: i = idx_for_id(window.overlay_for, all_windows) @@ -278,6 +278,16 @@ class Layout: # {{{ all_windows.append(all_windows[i]) all_windows[i] = window active_window_idx = i + elif location is not None: + if location == 'neighbor' and current_active_window_idx is not None: + active_window_idx = current_active_window_idx + 1 + elif location == 'first': + active_window_idx = 0 + if active_window_idx is not None: + for i in range(len(all_windows), active_window_idx, -1): + self.swap_windows_in_os_window(i, i - 1) + all_windows.insert(active_window_idx, window) + if active_window_idx is None: active_window_idx = len(all_windows) all_windows.append(window) diff --git a/kitty/tabs.py b/kitty/tabs.py index 68207f6da..d5adfe1d3 100644 --- a/kitty/tabs.py +++ b/kitty/tabs.py @@ -232,7 +232,7 @@ class Tab: # {{{ ans.fork() return ans - def new_window(self, use_shell=True, cmd=None, stdin=None, override_title=None, cwd_from=None, cwd=None, overlay_for=None, env=None): + def new_window(self, use_shell=True, cmd=None, stdin=None, override_title=None, cwd_from=None, cwd=None, overlay_for=None, env=None, location=None): child = self.launch_child(use_shell=use_shell, cmd=cmd, stdin=stdin, cwd_from=cwd_from, cwd=cwd, env=env) window = Window(self, child, self.opts, self.args, override_title=override_title) if overlay_for is not None: @@ -241,12 +241,12 @@ class Tab: # {{{ overlaid.overlay_window_id = window.id # Must add child before laying out so that resize_pty succeeds get_boss().add_child(window) - self.active_window_idx = self.current_layout.add_window(self.windows, window, self.active_window_idx) + self.active_window_idx = self.current_layout.add_window(self.windows, window, self.active_window_idx, location) self.relayout_borders() return window - def new_special_window(self, special_window): - return self.new_window(False, *special_window) + def new_special_window(self, special_window, location=None): + return self.new_window(False, *special_window, location=location) def close_window(self): if self.windows: