From 0ee5712e0095ebcc56a54cd5c15a0be3e99f2152 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 17 Apr 2022 15:30:57 +0530 Subject: [PATCH] Start work on option to control sourcing strategies --- kitty/child.py | 1 + kitty/launch.py | 12 +++++++++--- kitty/options/definition.py | 17 +++++++++++++++++ kitty/options/parse.py | 24 ++++++++++++++---------- kitty/options/types.py | 4 +++- kitty/options/utils.py | 4 ++++ 6 files changed, 48 insertions(+), 14 deletions(-) diff --git a/kitty/child.py b/kitty/child.py index aca099d0e..6e2c251e0 100644 --- a/kitty/child.py +++ b/kitty/child.py @@ -251,6 +251,7 @@ class Child: env = {k: v for k, v in env.items() if v is not DELETE_ENV_VAR} if self.is_clone_launch: env['KITTY_IS_CLONE_LAUNCH'] = self.is_clone_launch + env['KITTY_CLONE_SOURCE_STRATEGIES'] = ',' + ','.join(opts.clone_source_strategies) + ',' self.is_clone_launch = '1' # free memory else: env.pop('KITTY_IS_CLONE_LAUNCH', None) diff --git a/kitty/launch.py b/kitty/launch.py index bb46ea190..31f95a1a7 100644 --- a/kitty/launch.py +++ b/kitty/launch.py @@ -10,7 +10,8 @@ from .cli import parse_args from .cli_stub import LaunchCLIOptions from .constants import kitty_exe, shell_path from .fast_data_types import ( - get_boss, get_os_window_title, patch_color_profiles, set_clipboard_string + get_boss, get_options, get_os_window_title, patch_color_profiles, + set_clipboard_string ) from .options.utils import env as parse_env from .tabs import Tab, TabManager @@ -594,13 +595,18 @@ def clone_and_launch(msg: str, window: Window) -> None: is_clone_launch = serialize_env(c.shell, c.env or {}) ssh_kitten_cmdline = window.ssh_kitten_cmdline() if ssh_kitten_cmdline: - from kittens.ssh.main import set_cwd_in_cmdline, set_env_in_cmdline, patch_cmdline + from kittens.ssh.main import ( + patch_cmdline, set_cwd_in_cmdline, set_env_in_cmdline + ) cmdline = ssh_kitten_cmdline if c.opts.cwd: set_cwd_in_cmdline(c.opts.cwd, cmdline) c.opts.cwd = None if c.env: - set_env_in_cmdline({'KITTY_IS_CLONE_LAUNCH': is_clone_launch}, cmdline) + set_env_in_cmdline({ + 'KITTY_IS_CLONE_LAUNCH': is_clone_launch, + 'KITTY_CLONE_SOURCE_STRATEGIES': ',' + ','.join(get_options().clone_source_strategies) + ',' + }, cmdline) c.env = None if c.opts.env: for entry in reversed(c.opts.env): diff --git a/kitty/options/definition.py b/kitty/options/definition.py index bcc03a31e..76fdb3c9e 100644 --- a/kitty/options/definition.py +++ b/kitty/options/definition.py @@ -2783,6 +2783,23 @@ Allowing cloning unconditionally gives programs running in the terminal the terminal is running as on the computer the terminal is running on. ''') +opt('clone_source_strategies', 'venv,conda,env_var,path', option_type='clone_source_strategies', long_text=''' +Control what shell code is sourced when running :code:`clone-in-kitty` +in the newly cloned window. The supported strategies are: + +:code:`venv` + Source the file :file:`$VIRTUAL_ENV/bin/activate` (this is used + by the Python stdlin venv module and allows cloning venvs automatically) +:code:`conda` + Run :code:`conda activate $CONDA_DEFAULT_ENV` this supports the virtual envs created by conda +:code:`env_var` + Source the contents of the environment variable :code:`KITTY_CLONE_SOURCE_CODE` +:code:`path` + Source the file pointed to by the environment variable :code:`KITTY_CLONE_SOURCE_PATH` + +This setting must be a comma separated list of the above values. +''') + opt('term', 'xterm-kitty', long_text=''' The value of the TERM environment variable to set. Changing this can break many diff --git a/kitty/options/parse.py b/kitty/options/parse.py index 929bd1c24..cfa99f676 100644 --- a/kitty/options/parse.py +++ b/kitty/options/parse.py @@ -8,15 +8,16 @@ from kitty.conf.utils import ( from kitty.options.utils import ( action_alias, active_tab_title_template, adjust_baseline, adjust_line_height, allow_hyperlinks, allow_remote_control, bell_on_tab, box_drawing_scale, clear_all_mouse_actions, clear_all_shortcuts, - clipboard_control, config_or_absolute_path, copy_on_select, cursor_text_color, - deprecated_hide_window_decorations_aliases, deprecated_macos_show_window_title_in_menubar_alias, - deprecated_send_text, disable_ligatures, edge_width, env, font_features, hide_window_decorations, - macos_option_as_alt, macos_titlebar_color, narrow_symbols, optional_edge_width, parse_map, - parse_mouse_map, paste_actions, resize_draw_strategy, scrollback_lines, - scrollback_pager_history_size, shell_integration, store_multiple, symbol_map, tab_activity_symbol, - tab_bar_edge, tab_bar_margin_height, tab_bar_min_tabs, tab_fade, tab_font_style, tab_separator, - tab_title_template, titlebar_color, to_cursor_shape, to_font_size, to_layout_names, to_modifiers, - url_prefixes, url_style, visual_window_select_characters, window_border_width, window_size + clipboard_control, clone_source_strategies, config_or_absolute_path, copy_on_select, + cursor_text_color, deprecated_hide_window_decorations_aliases, + deprecated_macos_show_window_title_in_menubar_alias, deprecated_send_text, disable_ligatures, + edge_width, env, font_features, hide_window_decorations, macos_option_as_alt, macos_titlebar_color, + narrow_symbols, optional_edge_width, parse_map, parse_mouse_map, paste_actions, + resize_draw_strategy, scrollback_lines, scrollback_pager_history_size, shell_integration, + store_multiple, symbol_map, tab_activity_symbol, tab_bar_edge, tab_bar_margin_height, + tab_bar_min_tabs, tab_fade, tab_font_style, tab_separator, tab_title_template, titlebar_color, + to_cursor_shape, to_font_size, to_layout_names, to_modifiers, url_prefixes, url_style, + visual_window_select_characters, window_border_width, window_size ) @@ -56,7 +57,7 @@ class Parser: raise ValueError(f"The value {val} is not a valid choice for allow_cloning") ans["allow_cloning"] = val - choices_for_allow_cloning = frozenset(('yes', 'no', 'ask')) + choices_for_allow_cloning = frozenset(('yes', 'y', 'true', 'no', 'n', 'false', 'ask')) def allow_hyperlinks(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: ans['allow_hyperlinks'] = allow_hyperlinks(val) @@ -120,6 +121,9 @@ class Parser: def clipboard_max_size(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: ans['clipboard_max_size'] = positive_float(val) + def clone_source_strategies(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['clone_source_strategies'] = clone_source_strategies(val) + def close_on_child_death(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: ans['close_on_child_death'] = to_bool(val) diff --git a/kitty/options/types.py b/kitty/options/types.py index 7ffed73ad..273c7244a 100644 --- a/kitty/options/types.py +++ b/kitty/options/types.py @@ -13,7 +13,7 @@ from kitty.types import FloatEdges, SingleKey import kitty.types if typing.TYPE_CHECKING: - choices_for_allow_cloning = typing.Literal['yes', 'no', 'ask'] + choices_for_allow_cloning = typing.Literal['yes', 'y', 'true', 'no', 'n', 'false', 'ask'] choices_for_background_image_layout = typing.Literal['mirror-tiled', 'scaled', 'tiled', 'clamped'] choices_for_default_pointer_shape = typing.Literal['arrow', 'beam', 'hand'] choices_for_linux_display_server = typing.Literal['auto', 'wayland', 'x11'] @@ -73,6 +73,7 @@ option_names = ( # {{{ 'click_interval', 'clipboard_control', 'clipboard_max_size', + 'clone_source_strategies', 'close_on_child_death', 'color0', 'color1', @@ -484,6 +485,7 @@ class Options: click_interval: float = -1.0 clipboard_control: typing.Tuple[str, ...] = ('write-clipboard', 'write-primary', 'read-clipboard-ask', 'read-primary-ask') clipboard_max_size: float = 64.0 + clone_source_strategies: typing.FrozenSet[str] = frozenset({'venv', 'env_var', 'conda', 'path'}) close_on_child_death: bool = False command_on_bell: typing.List[str] = ['none'] confirm_os_window_close: int = -1 diff --git a/kitty/options/utils.py b/kitty/options/utils.py index 47d7b8191..87916f39c 100644 --- a/kitty/options/utils.py +++ b/kitty/options/utils.py @@ -746,6 +746,10 @@ def tab_bar_margin_height(x: str) -> TabBarMarginHeight: return TabBarMarginHeight(next(ans), next(ans)) +def clone_source_strategies(x: str) -> FrozenSet[str]: + return frozenset({'venv', 'conda', 'path', 'env_var'} & set(x.lower().split(','))) + + def clear_all_mouse_actions(val: str, dict_with_parse_results: Optional[Dict[str, Any]] = None) -> bool: ans = to_bool(val) if ans and dict_with_parse_results is not None: