Improve some utility functions

Make expandvars accept both $VARNAME and ${VARNAME} now matches
the behavior of posixpath.expandvars

Allow overriding the environment variables to_cmdline expands against
This commit is contained in:
Kovid Goyal 2020-09-18 13:25:59 +05:30
parent e36d41b46f
commit be1ff61e4a
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 44 additions and 14 deletions

View File

@ -11,7 +11,7 @@ from typing import (
) )
from ..rgb import Color, to_color as as_color from ..rgb import Color, to_color as as_color
from ..utils import log_error from ..utils import log_error, expandvars
key_pat = re.compile(r'([a-zA-Z][a-zA-Z0-9_-]*)\s+(.+)$') key_pat = re.compile(r'([a-zA-Z][a-zA-Z0-9_-]*)\s+(.+)$')
T = TypeVar('T') T = TypeVar('T')
@ -53,13 +53,36 @@ def to_bool(x: str) -> bool:
return x.lower() in ('y', 'yes', 'true') return x.lower() in ('y', 'yes', 'true')
def to_cmdline(x: str) -> List[str]: class ToCmdline:
return list(
map( def __init__(self) -> None:
lambda y: os.path.expandvars(os.path.expanduser(y)), self.override_env: Optional[Dict[str, str]] = None
shlex.split(x)
def __enter__(self) -> 'ToCmdline':
return self
def __exit__(self, *a: Any) -> None:
self.override_env = None
def filter_env_vars(self, *a: str) -> 'ToCmdline':
remove = frozenset(a)
self.override_env = {k: v for k, v in os.environ.items() if k not in remove}
return self
def __call__(self, x: str) -> List[str]:
return list(
map(
lambda y: expandvars(
os.path.expanduser(y),
os.environ if self.override_env is None else self.override_env,
fallback_to_os_env=False
),
shlex.split(x)
)
) )
)
to_cmdline = ToCmdline()
def python_string(text: str) -> str: def python_string(text: str) -> str:

View File

@ -13,7 +13,7 @@ from typing import (
from . import fast_data_types as defines from . import fast_data_types as defines
from .conf.definition import Option, Shortcut, option_func from .conf.definition import Option, Shortcut, option_func
from .conf.utils import ( from .conf.utils import (
choices, positive_float, positive_int, to_bool, to_cmdline, to_color, choices, positive_float, positive_int, to_bool, to_cmdline as tc, to_color,
to_color_or_none, unit_float to_color_or_none, unit_float
) )
from .constants import FloatEdges, config_dir, is_macos from .constants import FloatEdges, config_dir, is_macos
@ -29,6 +29,10 @@ mod_map = {'CTRL': 'CONTROL', 'CMD': 'SUPER', '⌘': 'SUPER',
'': 'ALT', 'OPTION': 'ALT', 'KITTY_MOD': 'KITTY'} '': 'ALT', 'OPTION': 'ALT', 'KITTY_MOD': 'KITTY'}
def to_cmdline(x: str) -> List[str]:
return tc(x)
def parse_mods(parts: Iterable[str], sc: str) -> Optional[int]: def parse_mods(parts: Iterable[str], sc: str) -> Optional[int]:
def map_mod(m: str) -> str: def map_mod(m: str) -> str:

View File

@ -14,7 +14,7 @@ from contextlib import suppress
from functools import lru_cache from functools import lru_cache
from time import monotonic from time import monotonic
from typing import ( from typing import (
Any, Callable, Dict, Generator, Iterable, List, Match, NamedTuple, Any, Callable, Dict, Generator, Iterable, List, Mapping, Match, NamedTuple,
Optional, Tuple, Union, cast Optional, Tuple, Union, cast
) )
@ -28,18 +28,21 @@ from .typing import AddressFamily, PopenType, Socket, StartupCtx
BASE = os.path.dirname(os.path.abspath(__file__)) BASE = os.path.dirname(os.path.abspath(__file__))
def expandvars(val: str, env: Dict[str, str] = {}) -> str: def expandvars(val: str, env: Mapping[str, str] = {}, fallback_to_os_env: bool = True) -> str:
def sub(m: Match) -> str: def sub(m: Match) -> str:
key = m.group(1) key = m.group(1) or m.group(2)
result = env.get(key) result = env.get(key)
if result is None: if result is None and fallback_to_os_env:
result = os.environ.get(key) result = os.environ.get(key)
if result is None: if result is None:
result = m.group() result = m.group()
return result return result
return re.sub(r'\$\{(\S+?)\}', sub, val) if '$' not in val:
return val
return re.sub(r'\$(?:(\w+)|\{([^}]+)\})', sub, val)
def platform_window_id(os_window_id: int) -> Optional[int]: def platform_window_id(os_window_id: int) -> Optional[int]:
@ -561,7 +564,7 @@ def read_shell_environment(opts: Optional[Options] = None) -> Dict[str, str]:
def parse_uri_list(text: str) -> Generator[str, None, None]: def parse_uri_list(text: str) -> Generator[str, None, None]:
' Get paths from file:// URLs ' ' Get paths from file:// URLs '
from urllib.parse import urlparse, unquote from urllib.parse import unquote, urlparse
for line in text.splitlines(): for line in text.splitlines():
if not line or line.startswith('#'): if not line or line.startswith('#'):
continue continue