Session files: Expand environment variables
This commit is contained in:
parent
11f98592f7
commit
60791bb57b
@ -57,6 +57,8 @@ Detailed list of changes
|
||||
|
||||
- Allow using the cwd of the original process for :option:`launch --cwd` (:iss:`5672`)
|
||||
|
||||
- Session files: Expand environment variables (:disc:`5917`)
|
||||
|
||||
- Pass key events mapped to scroll actions to the program running in the terminal when the terminal is in alternate screen mode (:iss:`5839`)
|
||||
|
||||
- Implement :ref:`edit-in-kitty <edit_file>` using the new ``kitten`` static executable (:iss:`5546`, :iss:`5630`)
|
||||
|
||||
@ -173,6 +173,11 @@ option in :file:`kitty.conf`. An example, showing all available commands:
|
||||
The :doc:`launch <launch>` command when used in a session file cannot create
|
||||
new OS windows, or tabs.
|
||||
|
||||
.. note::
|
||||
Environment variables of the for :code:`${NAME}` or :code:`$NAME` are
|
||||
expanded in the session file, except in the *arguments* (not options) to the
|
||||
launch command.
|
||||
|
||||
|
||||
Creating tabs/windows
|
||||
-------------------------------
|
||||
|
||||
@ -760,9 +760,11 @@ class Boss:
|
||||
return None
|
||||
args.args = rest
|
||||
opts = create_opts(args)
|
||||
if args.session == '-':
|
||||
if data['session_data']:
|
||||
from .session import PreReadSession
|
||||
args.session = PreReadSession(data['stdin'])
|
||||
args.session = PreReadSession(data['session_data'], data['environ'])
|
||||
else:
|
||||
args.session = ''
|
||||
if not os.path.isabs(args.directory):
|
||||
args.directory = os.path.join(data['cwd'], args.directory)
|
||||
focused_os_window = os_window_id = 0
|
||||
|
||||
@ -890,8 +890,8 @@ Detach from the controlling terminal, if any.
|
||||
completion=type:file ext:session relative:conf group:"Session files"
|
||||
Path to a file containing the startup :italic:`session` (tabs, windows, layout,
|
||||
programs). Use - to read from STDIN. See the :file:`README` file for details and
|
||||
an example. Environment variables are expanded, relative paths are resolved relative
|
||||
to the kitty configuration directory.
|
||||
an example. Environment variables in the file name are expanded,
|
||||
relative paths are resolved relative to the kitty configuration directory.
|
||||
|
||||
|
||||
--hold
|
||||
|
||||
@ -80,12 +80,16 @@ def set_custom_ibeam_cursor() -> None:
|
||||
def talk_to_instance(args: CLIOptions) -> None:
|
||||
import json
|
||||
import socket
|
||||
stdin = ''
|
||||
session_data = ''
|
||||
if args.session == '-':
|
||||
stdin = sys.stdin.read()
|
||||
session_data = sys.stdin.read()
|
||||
elif args.session:
|
||||
with open(args.session) as f:
|
||||
session_data = f.read()
|
||||
|
||||
data = {'cmd': 'new_instance', 'args': tuple(sys.argv), 'cmdline_args_for_open': getattr(sys, 'cmdline_args_for_open', []),
|
||||
'startup_id': os.environ.get('DESKTOP_STARTUP_ID'), 'activation_token': os.environ.get('XDG_ACTIVATION_TOKEN'),
|
||||
'cwd': os.getcwd(), 'stdin': stdin}
|
||||
'cwd': os.getcwd(), 'session_data': session_data, 'environ': dict(os.environ)}
|
||||
notify_socket = None
|
||||
if args.wait_for_single_instance_window_close:
|
||||
address = f'\0{appname}-os-window-close-notify-{os.getpid()}-{os.geteuid()}'
|
||||
@ -461,7 +465,7 @@ def _main() -> None:
|
||||
if cli_opts.detach:
|
||||
if cli_opts.session == '-':
|
||||
from .session import PreReadSession
|
||||
cli_opts.session = PreReadSession(sys.stdin.read())
|
||||
cli_opts.session = PreReadSession(sys.stdin.read(), os.environ)
|
||||
detach()
|
||||
if cli_opts.replay_commands:
|
||||
from kitty.client import main as client_main
|
||||
|
||||
@ -1,9 +1,12 @@
|
||||
#!/usr/bin/env python3
|
||||
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import os
|
||||
import shlex
|
||||
import sys
|
||||
from typing import TYPE_CHECKING, Generator, Iterator, List, Optional, Tuple, Union
|
||||
from contextlib import suppress
|
||||
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
|
||||
@ -12,7 +15,7 @@ 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 log_error, resolve_custom_file, resolved_shell
|
||||
from .utils import expandvars, log_error, resolve_custom_file, resolved_shell
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .launch import LaunchSpec
|
||||
@ -73,11 +76,22 @@ class Session:
|
||||
raise ValueError(f'{val} is not a valid layout')
|
||||
self.tabs[-1].layout = val
|
||||
|
||||
def add_window(self, cmd: Union[None, str, List[str]]) -> None:
|
||||
def add_window(self, cmd: Union[None, str, List[str]], expand: Callable[[str], str] = lambda x: x) -> None:
|
||||
from .launch import parse_launch_args
|
||||
needs_expandvars = False
|
||||
if isinstance(cmd, str):
|
||||
needs_expandvars = True
|
||||
cmd = shlex.split(cmd)
|
||||
spec = parse_launch_args(cmd)
|
||||
if needs_expandvars:
|
||||
assert isinstance(cmd, list)
|
||||
limit = len(cmd)
|
||||
if len(spec.args):
|
||||
with suppress(ValueError):
|
||||
limit = cmd.index(spec.args[0])
|
||||
cmd = [(expand(x) if i < limit else x) for i, x in enumerate(cmd)]
|
||||
spec = parse_launch_args(cmd)
|
||||
|
||||
t = self.tabs[-1]
|
||||
if t.next_title and not spec.opts.window_title:
|
||||
spec.opts.window_title = t.next_title
|
||||
@ -113,7 +127,7 @@ class Session:
|
||||
self.tabs[-1].cwd = val
|
||||
|
||||
|
||||
def parse_session(raw: str, opts: Options) -> Generator[Session, None, None]:
|
||||
def parse_session(raw: str, opts: Options, environ: Optional[Mapping[str, str]] = None) -> Generator[Session, None, None]:
|
||||
|
||||
def finalize_session(ans: Session) -> Session:
|
||||
from .tabs import SpecialWindow
|
||||
@ -122,6 +136,9 @@ def parse_session(raw: str, opts: Options) -> Generator[Session, None, None]:
|
||||
t.windows.append(WindowSpec(SpecialWindow(cmd=resolved_shell(opts))))
|
||||
return ans
|
||||
|
||||
if environ is None:
|
||||
environ = os.environ
|
||||
expand = partial(expandvars, env=environ, fallback_to_os_env=False)
|
||||
ans = Session()
|
||||
ans.add_tab(opts)
|
||||
for line in raw.splitlines():
|
||||
@ -133,6 +150,8 @@ def parse_session(raw: str, opts: Options) -> Generator[Session, None, None]:
|
||||
else:
|
||||
cmd, rest = parts
|
||||
cmd, rest = cmd.strip(), rest.strip()
|
||||
if cmd != 'launch':
|
||||
rest = expand(rest)
|
||||
if cmd == 'new_tab':
|
||||
ans.add_tab(opts, rest)
|
||||
elif cmd == 'new_os_window':
|
||||
@ -142,7 +161,7 @@ def parse_session(raw: str, opts: Options) -> Generator[Session, None, None]:
|
||||
elif cmd == 'layout':
|
||||
ans.set_layout(rest)
|
||||
elif cmd == 'launch':
|
||||
ans.add_window(rest)
|
||||
ans.add_window(rest, expand)
|
||||
elif cmd == 'focus':
|
||||
ans.focus()
|
||||
elif cmd == 'focus_os_window':
|
||||
@ -167,9 +186,10 @@ def parse_session(raw: str, opts: Options) -> Generator[Session, None, None]:
|
||||
|
||||
class PreReadSession(str):
|
||||
|
||||
def __new__(cls, val: str) -> 'PreReadSession':
|
||||
def __new__(cls, val: str, associated_environ: Mapping[str, str]) -> 'PreReadSession':
|
||||
ans: PreReadSession = str.__new__(cls, val)
|
||||
ans.pre_read = True # type: ignore
|
||||
ans.associated_environ = associated_environ # type: ignore
|
||||
return ans
|
||||
|
||||
|
||||
@ -179,11 +199,13 @@ def create_sessions(
|
||||
special_window: Optional['SpecialWindowInstance'] = None,
|
||||
cwd_from: Optional['CwdRequest'] = None,
|
||||
respect_cwd: bool = False,
|
||||
default_session: Optional[str] = None
|
||||
default_session: Optional[str] = None,
|
||||
) -> Iterator[Session]:
|
||||
if args and args.session:
|
||||
environ: Optional[Mapping[str, str]] = None
|
||||
if isinstance(args.session, PreReadSession):
|
||||
session_data = '' + str(args.session)
|
||||
environ = args.session.associated_environ # type: ignore
|
||||
else:
|
||||
if args.session == '-':
|
||||
f = sys.stdin
|
||||
@ -191,7 +213,7 @@ def create_sessions(
|
||||
f = open(resolve_custom_file(args.session))
|
||||
with f:
|
||||
session_data = f.read()
|
||||
yield from parse_session(session_data, opts)
|
||||
yield from parse_session(session_data, opts, environ=environ)
|
||||
return
|
||||
if default_session and default_session != 'none':
|
||||
try:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user