A new option exe_search_path to modify the locations kitty searches for executables to run

This commit is contained in:
Kovid Goyal 2021-12-09 12:13:26 +05:30
parent 77b15bf73f
commit 5f744368dd
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
6 changed files with 56 additions and 10 deletions

View File

@ -52,6 +52,9 @@ To update |kitty|, :doc:`follow the instructions <binary>`.
- A new option :opt:`bell_path` to specify the path to a sound file
to use as the bell sound
- A new option :opt:`exe_search_path` to modify the locations kitty searches
for executables to run
- broadcast kitten: Show a "fake" cursor in all windows being broadcast too
(:iss:`4225`)

View File

@ -2616,7 +2616,7 @@ will delete the variable from the child process' environment.
)
opt('+watcher', '',
option_type='watcher',
option_type='store_multiple',
add_to_default=False,
long_text='''
Path to python file which will be loaded for :ref:`watchers`.
@ -2627,6 +2627,28 @@ Note that reloading the config will only affect windows
created after the reload.
''')
opt('+exe_search_path', '',
option_type='store_multiple',
add_to_default=False,
long_text='''
Control where kitty looks to find programs to run. The default search order is:
First search the system wide :code:`PATH`, then :file:`~/.local/bin` and :file:`~/bin`.
If not still not found, the :code:`PATH` defined in the login shell after sourcing
all its startup files is tried. Finally, if present, the :code:`PATH` in the :opt:`env`
option is tried.
This option allows you to prepend, append, or remove paths from this search order.
It can be specified multiple times for multiple paths. A simple path will be prepended
to the search order. A path that starts with the :code:`+` sign will be append to the search
order, after :file:`~/bin` above. A path that starts with the :code:`-` sign will be removed
from the entire search order. For example::
exe_search_path /some/prepended/path
exe_search_path +/some/appended/path
exe_search_path -/some/excluded/path
''')
opt('update_check_interval', '24',
option_type='float',
long_text='''

15
kitty/options/parse.py generated
View File

@ -13,10 +13,10 @@ from kitty.options.utils import (
deprecated_send_text, disable_ligatures, edge_width, env, font_features, hide_window_decorations,
macos_option_as_alt, macos_titlebar_color, optional_edge_width, parse_map, parse_mouse_map,
resize_draw_strategy, scrollback_lines, scrollback_pager_history_size, shell_integration,
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, to_cursor_shape, to_font_size, to_layout_names,
to_modifiers, url_prefixes, url_style, visual_window_select_characters, watcher,
window_border_width, window_size
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, to_cursor_shape,
to_font_size, to_layout_names, to_modifiers, url_prefixes, url_style,
visual_window_select_characters, window_border_width, window_size
)
@ -949,6 +949,10 @@ class Parser:
for k, v in env(val, ans["env"]):
ans["env"][k] = v
def exe_search_path(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
for k, v in store_multiple(val, ans["exe_search_path"]):
ans["exe_search_path"][k] = v
def file_transfer_confirmation_bypass(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['file_transfer_confirmation_bypass'] = str(val)
@ -1255,7 +1259,7 @@ class Parser:
ans['visual_window_select_characters'] = visual_window_select_characters(val)
def watcher(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
for k, v in watcher(val, ans["watcher"]):
for k, v in store_multiple(val, ans["watcher"]):
ans["watcher"][k] = v
def wayland_titlebar_color(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
@ -1321,6 +1325,7 @@ def create_result_dict() -> typing.Dict[str, typing.Any]:
return {
'action_alias': {},
'env': {},
'exe_search_path': {},
'font_features': {},
'kitten_alias': {},
'symbol_map': {},

View File

@ -346,6 +346,7 @@ option_names = ( # {{{
'enable_audio_bell',
'enabled_layouts',
'env',
'exe_search_path',
'file_transfer_confirmation_bypass',
'focus_follows_mouse',
'font_family',
@ -588,6 +589,7 @@ class Options:
window_resize_step_lines: int = 2
action_alias: typing.Dict[str, str] = {}
env: typing.Dict[str, str] = {}
exe_search_path: typing.Dict[str, str] = {}
font_features: typing.Dict[str, typing.Tuple[kitty.fonts.FontFeature, ...]] = {}
kitten_alias: typing.Dict[str, str] = {}
symbol_map: typing.Dict[typing.Tuple[int, int], str] = {}
@ -705,6 +707,7 @@ class Options:
defaults = Options()
defaults.action_alias = {}
defaults.env = {}
defaults.exe_search_path = {}
defaults.font_features = {}
defaults.kitten_alias = {}
defaults.symbol_map = {}

View File

@ -761,7 +761,7 @@ def env(val: str, current_val: Dict[str, str]) -> Iterable[Tuple[str, str]]:
yield val, DELETE_ENV_VAR
def watcher(val: str, current_val: Container[str]) -> Iterable[Tuple[str, str]]:
def store_multiple(val: str, current_val: Container[str]) -> Iterable[Tuple[str, str]]:
val = val.strip()
if val not in current_val:
yield val, val

View File

@ -635,13 +635,26 @@ def which(name: str, only_system: bool = False) -> Optional[str]:
with suppress(RuntimeError):
opts = get_options()
tried_paths = set()
paths = []
append_paths = []
if opts and opts.exe_search_path:
for x in opts.exe_search_path:
x = x.strip()
if x:
if x[0] == '-':
tried_paths.add(x[1:])
elif x[0] == '+':
append_paths.append(x[1:])
else:
paths.append(x)
ep = os.environ.get('PATH')
if ep:
paths = ep.split(os.pathsep)
paths.extend(ep.split(os.pathsep))
paths.append(os.path.expanduser('~/.local/bin'))
paths.append(os.path.expanduser('~/bin'))
ans = shutil.which(name, path=os.pathsep.join(paths))
paths.extend(append_paths)
ans = shutil.which(name, path=os.pathsep.join(x for x in paths if x not in tried_paths))
if ans:
return ans
# In case PATH is messed up try a default set of paths
@ -649,7 +662,7 @@ def which(name: str, only_system: bool = False) -> Optional[str]:
system_paths = system_paths_on_macos()
else:
system_paths = ('/usr/local/bin', '/opt/bin', '/usr/bin', '/bin', '/usr/sbin', '/sbin')
tried_paths = set(paths)
tried_paths |= set(paths)
system_paths = tuple(x for x in system_paths if x not in tried_paths)
if system_paths:
ans = shutil.which(name, path=os.pathsep.join(system_paths))