diff --git a/docs/changelog.rst b/docs/changelog.rst index 5fdb18e66..51c5204b6 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -42,6 +42,8 @@ Detailed list of changes - A new kitten :ref:`run-shell ` to allow creating sub-shells with shell integration enabled +- The :option:`--hold` flag now holds the window open at a shell prompt instead of asking the user to press a key + - A new option :opt:`text_fg_override_threshold` to force text colors to have high contrast regardless of color scheme (:pull:`6283`) - When resizing OS Windows make the animation less jerky. Also show the window size in cells during the resize (:iss:`6341`) diff --git a/kitty/cli.py b/kitty/cli.py index 87ba27730..33e688b88 100644 --- a/kitty/cli.py +++ b/kitty/cli.py @@ -904,9 +904,9 @@ the :opt:`startup_session` option has been specified in kitty.conf. --hold type=bool-set -Remain open after child process exits. Note that this only affects the first -window. You can quit by either using the close window shortcut or pressing any -key. +Remain open, at a shell prompt, after child process exits. Note that this only +affects the first window. You can quit by either using the close window +shortcut or running the exit command. --single-instance -1 diff --git a/kitty/launch.py b/kitty/launch.py index 97135d720..8d818003d 100644 --- a/kitty/launch.py +++ b/kitty/launch.py @@ -12,12 +12,12 @@ from .child import Child from .cli import parse_args from .cli_stub import LaunchCLIOptions from .clipboard import set_clipboard_string, set_primary_selection -from .constants import kitten_exe, shell_path +from .constants import shell_path from .fast_data_types import add_timer, get_boss, get_options, get_os_window_title, patch_color_profiles from .options.utils import env as parse_env from .tabs import Tab, TabManager from .types import OverlayType, run_once -from .utils import get_editor, log_error, resolve_custom_file, which +from .utils import cmdline_for_hold, get_editor, log_error, resolve_custom_file, which from .window import CwdRequest, CwdRequestType, Watchers, Window try: @@ -109,7 +109,7 @@ environment variable. --hold type=bool-set -Keep the window open even after the command being executed exits. +Keep the window open even after the command being executed exits, at a shell prompt. --copy-colors @@ -581,7 +581,7 @@ def _launch( cmd = kw['cmd'] or [shell_path] if not os.path.isabs(cmd[0]): cmd[0] = which(cmd[0]) or cmd[0] - kw['cmd'] = [kitten_exe(), '__hold_till_enter__'] + cmd + kw['cmd'] = cmdline_for_hold(cmd) if force_target_tab: tab = target_tab else: diff --git a/kitty/session.py b/kitty/session.py index c93e15f5f..283c734f7 100644 --- a/kitty/session.py +++ b/kitty/session.py @@ -9,13 +9,12 @@ from functools import partial from typing import TYPE_CHECKING, Callable, Generator, Iterator, List, Mapping, Optional, Tuple, Union from .cli_stub import CLIOptions -from .constants import kitten_exe from .layout.interface import all_layouts from .options.types import Options from .options.utils import resize_window, to_layout_names, window_size from .os_window_size import WindowSize, WindowSizeData, WindowSizes from .typing import SpecialWindowInstance -from .utils import expandvars, log_error, resolve_custom_file, resolved_shell, which +from .utils import cmdline_for_hold, expandvars, log_error, resolve_custom_file, resolved_shell, which if TYPE_CHECKING: from .launch import LaunchSpec @@ -238,7 +237,7 @@ def create_sessions( cmd = args.args if args and args.args else resolved_shell(opts) if args and args.hold: cmd[0] = which(cmd[0]) or cmd[0] - cmd = [kitten_exe(), '__hold_till_enter__'] + cmd + cmd = cmdline_for_hold(cmd) from kitty.tabs import SpecialWindow cwd: Optional[str] = args.directory if respect_cwd and args else None special_window = SpecialWindow(cmd, cwd_from=cwd_from, cwd=cwd) diff --git a/kitty/tabs.py b/kitty/tabs.py index 9740c7c48..ea6c8c07a 100644 --- a/kitty/tabs.py +++ b/kitty/tabs.py @@ -28,7 +28,7 @@ from typing import ( from .borders import Border, Borders from .child import Child from .cli_stub import CLIOptions -from .constants import appname, kitten_exe +from .constants import appname from .fast_data_types import ( GLFW_MOUSE_BUTTON_LEFT, GLFW_MOUSE_BUTTON_MIDDLE, @@ -57,7 +57,7 @@ from .layout.interface import create_layout_object_for, evict_cached_layouts from .tab_bar import TabBar, TabBarData from .types import ac from .typing import EdgeLiteral, SessionTab, SessionType, TypedDict -from .utils import log_error, platform_window_id, resolved_shell +from .utils import cmdline_for_hold, log_error, platform_window_id, resolved_shell from .window import CwdRequest, Watchers, Window, WindowDict from .window_list import WindowList @@ -474,7 +474,7 @@ class Tab: # {{{ else: cmd[:0] = [resolved_shell(get_options())[0]] cmd[0] = which(cmd[0]) or cmd[0] - cmd[:0] = [kitten_exe(), '__hold_till_enter__'] + cmd = cmdline_for_hold(cmd) fenv: Dict[str, str] = {} if env: fenv.update(env) diff --git a/kitty/utils.py b/kitty/utils.py index fd02457cd..d8caea349 100644 --- a/kitty/utils.py +++ b/kitty/utils.py @@ -12,7 +12,25 @@ import sys from contextlib import contextmanager, suppress from functools import lru_cache from time import monotonic -from typing import TYPE_CHECKING, Any, Callable, Dict, Generator, Iterable, Iterator, List, Mapping, Match, NamedTuple, Optional, Pattern, Tuple, Union, cast +from typing import ( + TYPE_CHECKING, + Any, + Callable, + Dict, + Generator, + Iterable, + Iterator, + List, + Mapping, + Match, + NamedTuple, + Optional, + Pattern, + Sequence, + Tuple, + Union, + cast, +) from .constants import ( appname, @@ -20,11 +38,12 @@ from .constants import ( config_dir, is_macos, is_wayland, + kitten_exe, runtime_dir, shell_path, ssh_control_master_template, ) -from .fast_data_types import WINDOW_FULLSCREEN, WINDOW_MAXIMIZED, WINDOW_MINIMIZED, WINDOW_NORMAL, Color, open_tty +from .fast_data_types import WINDOW_FULLSCREEN, WINDOW_MAXIMIZED, WINDOW_MINIMIZED, WINDOW_NORMAL, Color, get_options, open_tty from .rgb import to_color from .types import run_once from .typing import AddressFamily, PopenType, Socket, StartupCtx @@ -658,7 +677,6 @@ def get_editor_from_env_vars(opts: Optional[Options] = None) -> List[str]: def get_editor(opts: Optional[Options] = None, path_to_edit: str = '', line_number: int = 0) -> List[str]: if opts is None: - from .fast_data_types import get_options try: opts = get_options() except RuntimeError: @@ -730,7 +748,6 @@ def resolve_abs_or_config_path(path: str, env: Optional[Mapping[str, str]] = Non def resolve_custom_file(path: str) -> str: - from .fast_data_types import get_options opts: Optional[Options] = None with suppress(RuntimeError): opts = get_options() @@ -786,7 +803,6 @@ def which(name: str, only_system: bool = False) -> Optional[str]: return name import shutil - from .fast_data_types import get_options opts: Optional[Options] = None with suppress(RuntimeError): opts = get_options() @@ -1154,3 +1170,16 @@ def is_png(path: str) -> bool: header = f.read(8) return header.startswith(b'\211PNG\r\n\032\n') return False + + +def cmdline_for_hold(cmd: Sequence[str] = (), opts: Optional['Options'] = None) -> List[str]: + if opts is None: + with suppress(RuntimeError): + opts = get_options() + if opts is None: + from .options.types import defaults + opts = defaults + ksi = ' '.join(opts.shell_integration) + import shlex + shell = shlex.join(resolved_shell(opts)) + return [kitten_exe(), 'run-shell', f'--shell={shell}', f'--shell-integration={ksi}'] + list(cmd)