1# -*- coding: utf-8 -*- 2"""Environment for the xonsh shell.""" 3import os 4import re 5import sys 6import pprint 7import textwrap 8import locale 9import builtins 10import warnings 11import contextlib 12import collections 13import collections.abc as cabc 14 15from xonsh import __version__ as XONSH_VERSION 16from xonsh.lazyasd import LazyObject, lazyobject 17from xonsh.codecache import run_script_with_cache 18from xonsh.dirstack import _get_cwd 19from xonsh.events import events 20from xonsh.platform import ( 21 BASH_COMPLETIONS_DEFAULT, 22 DEFAULT_ENCODING, 23 PATH_DEFAULT, 24 ON_WINDOWS, 25 ON_LINUX, 26 os_environ, 27) 28 29from xonsh.tools import ( 30 always_true, 31 always_false, 32 ensure_string, 33 is_env_path, 34 str_to_env_path, 35 env_path_to_str, 36 is_bool, 37 to_bool, 38 bool_to_str, 39 is_history_tuple, 40 to_history_tuple, 41 history_tuple_to_str, 42 is_float, 43 is_string, 44 is_string_or_callable, 45 is_completions_display_value, 46 to_completions_display_value, 47 is_string_set, 48 csv_to_set, 49 set_to_csv, 50 is_int, 51 is_bool_seq, 52 to_bool_or_int, 53 bool_or_int_to_str, 54 csv_to_bool_seq, 55 bool_seq_to_csv, 56 DefaultNotGiven, 57 print_exception, 58 setup_win_unicode_console, 59 intensify_colors_on_win_setter, 60 is_dynamic_cwd_width, 61 to_dynamic_cwd_tuple, 62 dynamic_cwd_tuple_to_str, 63 is_logfile_opt, 64 to_logfile_opt, 65 logfile_opt_to_str, 66 executables_in, 67 is_nonstring_seq_of_strings, 68 pathsep_to_upper_seq, 69 seq_to_upper_pathsep, 70 print_color, 71 is_history_backend, 72 to_itself, 73 swap_values, 74 ptk2_color_depth_setter, 75) 76import xonsh.prompt.base as prompt 77 78 79events.doc( 80 "on_envvar_new", 81 """ 82on_envvar_new(name: str, value: Any) -> None 83 84Fires after a new environment variable is created. 85Note: Setting envvars inside the handler might 86cause a recursion until the limit. 87""", 88) 89 90 91events.doc( 92 "on_envvar_change", 93 """ 94on_envvar_change(name: str, oldvalue: Any, newvalue: Any) -> None 95 96Fires after an environment variable is changed. 97Note: Setting envvars inside the handler might 98cause a recursion until the limit. 99""", 100) 101 102 103@lazyobject 104def HELP_TEMPLATE(): 105 return ( 106 "{{INTENSE_RED}}{envvar}{{NO_COLOR}}:\n\n" 107 "{{INTENSE_YELLOW}}{docstr}{{NO_COLOR}}\n\n" 108 "default: {{CYAN}}{default}{{NO_COLOR}}\n" 109 "configurable: {{CYAN}}{configurable}{{NO_COLOR}}" 110 ) 111 112 113@lazyobject 114def LOCALE_CATS(): 115 lc = { 116 "LC_CTYPE": locale.LC_CTYPE, 117 "LC_COLLATE": locale.LC_COLLATE, 118 "LC_NUMERIC": locale.LC_NUMERIC, 119 "LC_MONETARY": locale.LC_MONETARY, 120 "LC_TIME": locale.LC_TIME, 121 } 122 if hasattr(locale, "LC_MESSAGES"): 123 lc["LC_MESSAGES"] = locale.LC_MESSAGES 124 return lc 125 126 127def locale_convert(key): 128 """Creates a converter for a locale key.""" 129 130 def lc_converter(val): 131 try: 132 locale.setlocale(LOCALE_CATS[key], val) 133 val = locale.setlocale(LOCALE_CATS[key]) 134 except (locale.Error, KeyError): 135 msg = "Failed to set locale {0!r} to {1!r}".format(key, val) 136 warnings.warn(msg, RuntimeWarning) 137 return val 138 139 return lc_converter 140 141 142def to_debug(x): 143 """Converts value using to_bool_or_int() and sets this value on as the 144 execer's debug level. 145 """ 146 val = to_bool_or_int(x) 147 if hasattr(builtins, "__xonsh_execer__"): 148 builtins.__xonsh_execer__.debug_level = val 149 return val 150 151 152Ensurer = collections.namedtuple("Ensurer", ["validate", "convert", "detype"]) 153Ensurer.__doc__ = """Named tuples whose elements are functions that 154represent environment variable validation, conversion, detyping. 155""" 156 157 158@lazyobject 159def DEFAULT_ENSURERS(): 160 return { 161 "AUTO_CD": (is_bool, to_bool, bool_to_str), 162 "AUTO_PUSHD": (is_bool, to_bool, bool_to_str), 163 "AUTO_SUGGEST": (is_bool, to_bool, bool_to_str), 164 "AUTO_SUGGEST_IN_COMPLETIONS": (is_bool, to_bool, bool_to_str), 165 "BASH_COMPLETIONS": (is_env_path, str_to_env_path, env_path_to_str), 166 "CASE_SENSITIVE_COMPLETIONS": (is_bool, to_bool, bool_to_str), 167 re.compile("\w*DIRS$"): (is_env_path, str_to_env_path, env_path_to_str), 168 "COLOR_INPUT": (is_bool, to_bool, bool_to_str), 169 "COLOR_RESULTS": (is_bool, to_bool, bool_to_str), 170 "COMPLETIONS_BRACKETS": (is_bool, to_bool, bool_to_str), 171 "COMPLETIONS_CONFIRM": (is_bool, to_bool, bool_to_str), 172 "COMPLETIONS_DISPLAY": ( 173 is_completions_display_value, 174 to_completions_display_value, 175 str, 176 ), 177 "COMPLETIONS_MENU_ROWS": (is_int, int, str), 178 "COMPLETION_QUERY_LIMIT": (is_int, int, str), 179 "DIRSTACK_SIZE": (is_int, int, str), 180 "DOTGLOB": (is_bool, to_bool, bool_to_str), 181 "DYNAMIC_CWD_WIDTH": ( 182 is_dynamic_cwd_width, 183 to_dynamic_cwd_tuple, 184 dynamic_cwd_tuple_to_str, 185 ), 186 "DYNAMIC_CWD_ELISION_CHAR": (is_string, ensure_string, ensure_string), 187 "EXPAND_ENV_VARS": (is_bool, to_bool, bool_to_str), 188 "FORCE_POSIX_PATHS": (is_bool, to_bool, bool_to_str), 189 "FOREIGN_ALIASES_SUPPRESS_SKIP_MESSAGE": (is_bool, to_bool, bool_to_str), 190 "FOREIGN_ALIASES_OVERRIDE": (is_bool, to_bool, bool_to_str), 191 "FUZZY_PATH_COMPLETION": (is_bool, to_bool, bool_to_str), 192 "GLOB_SORTED": (is_bool, to_bool, bool_to_str), 193 "HISTCONTROL": (is_string_set, csv_to_set, set_to_csv), 194 "IGNOREEOF": (is_bool, to_bool, bool_to_str), 195 "INTENSIFY_COLORS_ON_WIN": ( 196 always_false, 197 intensify_colors_on_win_setter, 198 bool_to_str, 199 ), 200 "LANG": (is_string, ensure_string, ensure_string), 201 "LC_COLLATE": (always_false, locale_convert("LC_COLLATE"), ensure_string), 202 "LC_CTYPE": (always_false, locale_convert("LC_CTYPE"), ensure_string), 203 "LC_MESSAGES": (always_false, locale_convert("LC_MESSAGES"), ensure_string), 204 "LC_MONETARY": (always_false, locale_convert("LC_MONETARY"), ensure_string), 205 "LC_NUMERIC": (always_false, locale_convert("LC_NUMERIC"), ensure_string), 206 "LC_TIME": (always_false, locale_convert("LC_TIME"), ensure_string), 207 "LOADED_RC_FILES": (is_bool_seq, csv_to_bool_seq, bool_seq_to_csv), 208 "MOUSE_SUPPORT": (is_bool, to_bool, bool_to_str), 209 "MULTILINE_PROMPT": (is_string_or_callable, ensure_string, ensure_string), 210 re.compile("\w*PATH$"): (is_env_path, str_to_env_path, env_path_to_str), 211 "PATHEXT": ( 212 is_nonstring_seq_of_strings, 213 pathsep_to_upper_seq, 214 seq_to_upper_pathsep, 215 ), 216 "PRETTY_PRINT_RESULTS": (is_bool, to_bool, bool_to_str), 217 "PROMPT": (is_string_or_callable, ensure_string, ensure_string), 218 "PROMPT_TOOLKIT_COLOR_DEPTH": ( 219 always_false, 220 ptk2_color_depth_setter, 221 ensure_string, 222 ), 223 "PUSHD_MINUS": (is_bool, to_bool, bool_to_str), 224 "PUSHD_SILENT": (is_bool, to_bool, bool_to_str), 225 "RAISE_SUBPROC_ERROR": (is_bool, to_bool, bool_to_str), 226 "RIGHT_PROMPT": (is_string_or_callable, ensure_string, ensure_string), 227 "BOTTOM_TOOLBAR": (is_string_or_callable, ensure_string, ensure_string), 228 "SUBSEQUENCE_PATH_COMPLETION": (is_bool, to_bool, bool_to_str), 229 "SUGGEST_COMMANDS": (is_bool, to_bool, bool_to_str), 230 "SUGGEST_MAX_NUM": (is_int, int, str), 231 "SUGGEST_THRESHOLD": (is_int, int, str), 232 "SUPPRESS_BRANCH_TIMEOUT_MESSAGE": (is_bool, to_bool, bool_to_str), 233 "UPDATE_COMPLETIONS_ON_KEYPRESS": (is_bool, to_bool, bool_to_str), 234 "UPDATE_OS_ENVIRON": (is_bool, to_bool, bool_to_str), 235 "UPDATE_PROMPT_ON_KEYPRESS": (is_bool, to_bool, bool_to_str), 236 "VC_BRANCH_TIMEOUT": (is_float, float, str), 237 "VC_HG_SHOW_BRANCH": (is_bool, to_bool, bool_to_str), 238 "VI_MODE": (is_bool, to_bool, bool_to_str), 239 "VIRTUAL_ENV": (is_string, ensure_string, ensure_string), 240 "WIN_UNICODE_CONSOLE": (always_false, setup_win_unicode_console, bool_to_str), 241 "XONSHRC": (is_env_path, str_to_env_path, env_path_to_str), 242 "XONSH_APPEND_NEWLINE": (is_bool, to_bool, bool_to_str), 243 "XONSH_AUTOPAIR": (is_bool, to_bool, bool_to_str), 244 "XONSH_CACHE_SCRIPTS": (is_bool, to_bool, bool_to_str), 245 "XONSH_CACHE_EVERYTHING": (is_bool, to_bool, bool_to_str), 246 "XONSH_COLOR_STYLE": (is_string, ensure_string, ensure_string), 247 "XONSH_DEBUG": (always_false, to_debug, bool_or_int_to_str), 248 "XONSH_ENCODING": (is_string, ensure_string, ensure_string), 249 "XONSH_ENCODING_ERRORS": (is_string, ensure_string, ensure_string), 250 "XONSH_HISTORY_BACKEND": (is_history_backend, to_itself, ensure_string), 251 "XONSH_HISTORY_FILE": (is_string, ensure_string, ensure_string), 252 "XONSH_HISTORY_MATCH_ANYWHERE": (is_bool, to_bool, bool_to_str), 253 "XONSH_HISTORY_SIZE": ( 254 is_history_tuple, 255 to_history_tuple, 256 history_tuple_to_str, 257 ), 258 "XONSH_LOGIN": (is_bool, to_bool, bool_to_str), 259 "XONSH_PROC_FREQUENCY": (is_float, float, str), 260 "XONSH_SHOW_TRACEBACK": (is_bool, to_bool, bool_to_str), 261 "XONSH_STDERR_PREFIX": (is_string, ensure_string, ensure_string), 262 "XONSH_STDERR_POSTFIX": (is_string, ensure_string, ensure_string), 263 "XONSH_STORE_STDOUT": (is_bool, to_bool, bool_to_str), 264 "XONSH_STORE_STDIN": (is_bool, to_bool, bool_to_str), 265 "XONSH_TRACEBACK_LOGFILE": (is_logfile_opt, to_logfile_opt, logfile_opt_to_str), 266 "XONSH_DATETIME_FORMAT": (is_string, ensure_string, ensure_string), 267 } 268 269 270# 271# Defaults 272# 273def default_value(f): 274 """Decorator for making callable default values.""" 275 f._xonsh_callable_default = True 276 return f 277 278 279def is_callable_default(x): 280 """Checks if a value is a callable default.""" 281 return callable(x) and getattr(x, "_xonsh_callable_default", False) 282 283 284DEFAULT_TITLE = "{current_job:{} | }{user}@{hostname}: {cwd} | xonsh" 285 286 287@default_value 288def xonsh_data_dir(env): 289 """Ensures and returns the $XONSH_DATA_DIR""" 290 xdd = os.path.expanduser(os.path.join(env.get("XDG_DATA_HOME"), "xonsh")) 291 os.makedirs(xdd, exist_ok=True) 292 return xdd 293 294 295@default_value 296def xonsh_config_dir(env): 297 """Ensures and returns the $XONSH_CONFIG_DIR""" 298 xcd = os.path.expanduser(os.path.join(env.get("XDG_CONFIG_HOME"), "xonsh")) 299 os.makedirs(xcd, exist_ok=True) 300 return xcd 301 302 303def xonshconfig(env): 304 """Ensures and returns the $XONSHCONFIG""" 305 xcd = env.get("XONSH_CONFIG_DIR") 306 xc = os.path.join(xcd, "config.json") 307 return xc 308 309 310@default_value 311def default_xonshrc(env): 312 """Creates a new instance of the default xonshrc tuple.""" 313 xcdrc = os.path.join(xonsh_config_dir(env), "rc.xsh") 314 if ON_WINDOWS: 315 dxrc = ( 316 os.path.join(os_environ["ALLUSERSPROFILE"], "xonsh", "xonshrc"), 317 xcdrc, 318 os.path.expanduser("~/.xonshrc"), 319 ) 320 else: 321 dxrc = ("/etc/xonshrc", xcdrc, os.path.expanduser("~/.xonshrc")) 322 # Check if old config file exists and issue warning 323 old_config_filename = xonshconfig(env) 324 if os.path.isfile(old_config_filename): 325 print( 326 "WARNING! old style configuration (" 327 + old_config_filename 328 + ") is no longer supported. " 329 + "Please migrate to xonshrc." 330 ) 331 return dxrc 332 333 334@default_value 335def xonsh_append_newline(env): 336 """Appends a newline if we are in interactive mode""" 337 return env.get("XONSH_INTERACTIVE", False) 338 339 340# Default values should generally be immutable, that way if a user wants 341# to set them they have to do a copy and write them to the environment. 342# try to keep this sorted. 343@lazyobject 344def DEFAULT_VALUES(): 345 dv = { 346 "AUTO_CD": False, 347 "AUTO_PUSHD": False, 348 "AUTO_SUGGEST": True, 349 "AUTO_SUGGEST_IN_COMPLETIONS": False, 350 "BASH_COMPLETIONS": BASH_COMPLETIONS_DEFAULT, 351 "CASE_SENSITIVE_COMPLETIONS": ON_LINUX, 352 "CDPATH": (), 353 "COLOR_INPUT": True, 354 "COLOR_RESULTS": True, 355 "COMPLETIONS_BRACKETS": True, 356 "COMPLETIONS_CONFIRM": False, 357 "COMPLETIONS_DISPLAY": "multi", 358 "COMPLETIONS_MENU_ROWS": 5, 359 "COMPLETION_QUERY_LIMIT": 100, 360 "DIRSTACK_SIZE": 20, 361 "DOTGLOB": False, 362 "DYNAMIC_CWD_WIDTH": (float("inf"), "c"), 363 "DYNAMIC_CWD_ELISION_CHAR": "", 364 "EXPAND_ENV_VARS": True, 365 "FORCE_POSIX_PATHS": False, 366 "FOREIGN_ALIASES_SUPPRESS_SKIP_MESSAGE": False, 367 "FOREIGN_ALIASES_OVERRIDE": False, 368 "PROMPT_FIELDS": dict(prompt.PROMPT_FIELDS), 369 "FUZZY_PATH_COMPLETION": True, 370 "GLOB_SORTED": True, 371 "HISTCONTROL": set(), 372 "IGNOREEOF": False, 373 "INDENT": " ", 374 "INTENSIFY_COLORS_ON_WIN": True, 375 "LANG": "C.UTF-8", 376 "LC_CTYPE": locale.setlocale(locale.LC_CTYPE), 377 "LC_COLLATE": locale.setlocale(locale.LC_COLLATE), 378 "LC_TIME": locale.setlocale(locale.LC_TIME), 379 "LC_MONETARY": locale.setlocale(locale.LC_MONETARY), 380 "LC_NUMERIC": locale.setlocale(locale.LC_NUMERIC), 381 "LOADED_RC_FILES": (), 382 "MOUSE_SUPPORT": False, 383 "MULTILINE_PROMPT": ".", 384 "PATH": PATH_DEFAULT, 385 "PATHEXT": [".COM", ".EXE", ".BAT", ".CMD"] if ON_WINDOWS else [], 386 "PRETTY_PRINT_RESULTS": True, 387 "PROMPT": prompt.default_prompt(), 388 "PROMPT_TOOLKIT_COLOR_DEPTH": "", 389 "PUSHD_MINUS": False, 390 "PUSHD_SILENT": False, 391 "RAISE_SUBPROC_ERROR": False, 392 "RIGHT_PROMPT": "", 393 "BOTTOM_TOOLBAR": "", 394 "SHELL_TYPE": "best", 395 "SUBSEQUENCE_PATH_COMPLETION": True, 396 "SUPPRESS_BRANCH_TIMEOUT_MESSAGE": False, 397 "SUGGEST_COMMANDS": True, 398 "SUGGEST_MAX_NUM": 5, 399 "SUGGEST_THRESHOLD": 3, 400 "TITLE": DEFAULT_TITLE, 401 "UPDATE_COMPLETIONS_ON_KEYPRESS": False, 402 "UPDATE_OS_ENVIRON": False, 403 "UPDATE_PROMPT_ON_KEYPRESS": False, 404 "VC_BRANCH_TIMEOUT": 0.2 if ON_WINDOWS else 0.1, 405 "VC_HG_SHOW_BRANCH": True, 406 "VI_MODE": False, 407 "WIN_UNICODE_CONSOLE": True, 408 "XDG_CONFIG_HOME": os.path.expanduser(os.path.join("~", ".config")), 409 "XDG_DATA_HOME": os.path.expanduser(os.path.join("~", ".local", "share")), 410 "XONSHRC": default_xonshrc, 411 "XONSH_APPEND_NEWLINE": xonsh_append_newline, 412 "XONSH_AUTOPAIR": False, 413 "XONSH_CACHE_SCRIPTS": True, 414 "XONSH_CACHE_EVERYTHING": False, 415 "XONSH_COLOR_STYLE": "default", 416 "XONSH_CONFIG_DIR": xonsh_config_dir, 417 "XONSH_DATA_DIR": xonsh_data_dir, 418 "XONSH_DEBUG": 0, 419 "XONSH_ENCODING": DEFAULT_ENCODING, 420 "XONSH_ENCODING_ERRORS": "surrogateescape", 421 "XONSH_HISTORY_BACKEND": "json", 422 "XONSH_HISTORY_FILE": os.path.expanduser("~/.xonsh_history.json"), 423 "XONSH_HISTORY_MATCH_ANYWHERE": False, 424 "XONSH_HISTORY_SIZE": (8128, "commands"), 425 "XONSH_LOGIN": False, 426 "XONSH_PROC_FREQUENCY": 1e-4, 427 "XONSH_SHOW_TRACEBACK": False, 428 "XONSH_STDERR_PREFIX": "", 429 "XONSH_STDERR_POSTFIX": "", 430 "XONSH_STORE_STDIN": False, 431 "XONSH_STORE_STDOUT": False, 432 "XONSH_TRACEBACK_LOGFILE": None, 433 "XONSH_DATETIME_FORMAT": "%Y-%m-%d %H:%M", 434 } 435 if hasattr(locale, "LC_MESSAGES"): 436 dv["LC_MESSAGES"] = locale.setlocale(locale.LC_MESSAGES) 437 return dv 438 439 440VarDocs = collections.namedtuple( 441 "VarDocs", ["docstr", "configurable", "default", "store_as_str"] 442) 443VarDocs.__doc__ = """Named tuple for environment variable documentation 444 445Parameters 446---------- 447docstr : str 448 The environment variable docstring. 449configurable : bool, optional 450 Flag for whether the environment variable is configurable or not. 451default : str, optional 452 Custom docstring for the default value for complex defaults. 453 Is this is DefaultNotGiven, then the default will be looked up 454 from DEFAULT_VALUES and converted to a str. 455store_as_str : bool, optional 456 Flag for whether the environment variable should be stored as a 457 string. This is used when persisting a variable that is not JSON 458 serializable to the config file. For example, sets, frozensets, and 459 potentially other non-trivial data types. default, False. 460""" 461# iterates from back 462VarDocs.__new__.__defaults__ = (True, DefaultNotGiven, False) 463 464 465# Please keep the following in alphabetic order - scopatz 466@lazyobject 467def DEFAULT_DOCS(): 468 return { 469 "ANSICON": VarDocs( 470 "This is used on Windows to set the title, " "if available.", 471 configurable=False, 472 ), 473 "AUTO_CD": VarDocs( 474 "Flag to enable changing to a directory by entering the dirname or " 475 "full path only (without the cd command)." 476 ), 477 "AUTO_PUSHD": VarDocs( 478 "Flag for automatically pushing directories onto the directory stack." 479 ), 480 "AUTO_SUGGEST": VarDocs( 481 "Enable automatic command suggestions based on history, like in the fish " 482 "shell.\n\nPressing the right arrow key inserts the currently " 483 "displayed suggestion. Only usable with ``$SHELL_TYPE=prompt_toolkit.``" 484 ), 485 "AUTO_SUGGEST_IN_COMPLETIONS": VarDocs( 486 "Places the auto-suggest result as the first option in the completions. " 487 "This enables you to tab complete the auto-suggestion." 488 ), 489 "BASH_COMPLETIONS": VarDocs( 490 "This is a list (or tuple) of strings that specifies where the " 491 "``bash_completion`` script may be found. " 492 "The first valid path will be used. For better performance, " 493 "bash-completion v2.x is recommended since it lazy-loads individual " 494 "completion scripts. " 495 "For both bash-completion v1.x and v2.x, paths of individual completion " 496 "scripts (like ``.../completes/ssh``) do not need to be included here. " 497 "The default values are platform " 498 "dependent, but sane. To specify an alternate list, do so in the run " 499 "control file.", 500 default=( 501 "Normally this is:\n\n" 502 " ``('/usr/share/bash-completion/bash_completion', )``\n\n" 503 "But, on Mac it is:\n\n" 504 " ``('/usr/local/share/bash-completion/bash_completion', " 505 "'/usr/local/etc/bash_completion')``\n\n" 506 "Other OS-specific defaults may be added in the future." 507 ), 508 ), 509 "CASE_SENSITIVE_COMPLETIONS": VarDocs( 510 "Sets whether completions should be case sensitive or case " "insensitive.", 511 default="True on Linux, False otherwise.", 512 ), 513 "CDPATH": VarDocs( 514 "A list of paths to be used as roots for a cd, breaking compatibility " 515 "with Bash, xonsh always prefer an existing relative path." 516 ), 517 "COLOR_INPUT": VarDocs("Flag for syntax highlighting interactive input."), 518 "COLOR_RESULTS": VarDocs("Flag for syntax highlighting return values."), 519 "COMPLETIONS_BRACKETS": VarDocs( 520 "Flag to enable/disable inclusion of square brackets and parentheses " 521 "in Python attribute completions.", 522 default="True", 523 ), 524 "COMPLETIONS_DISPLAY": VarDocs( 525 "Configure if and how Python completions are displayed by the " 526 "``prompt_toolkit`` shell.\n\nThis option does not affect Bash " 527 "completions, auto-suggestions, etc.\n\nChanging it at runtime will " 528 "take immediate effect, so you can quickly disable and enable " 529 "completions during shell sessions.\n\n" 530 "- If ``$COMPLETIONS_DISPLAY`` is ``none`` or ``false``, do not display\n" 531 " those completions.\n" 532 "- If ``$COMPLETIONS_DISPLAY`` is ``single``, display completions in a\n" 533 " single column while typing.\n" 534 "- If ``$COMPLETIONS_DISPLAY`` is ``multi`` or ``true``, display completions\n" 535 " in multiple columns while typing.\n\n" 536 "- If ``$COMPLETIONS_DISPLAY`` is ``readline``, display completions\n" 537 " will emulate the behavior of readline.\n\n" 538 "These option values are not case- or type-sensitive, so e.g." 539 "writing ``$COMPLETIONS_DISPLAY = None`` " 540 "and ``$COMPLETIONS_DISPLAY = 'none'`` are equivalent. Only usable with " 541 "``$SHELL_TYPE=prompt_toolkit``" 542 ), 543 "COMPLETIONS_CONFIRM": VarDocs( 544 "While tab-completions menu is displayed, press <Enter> to confirm " 545 "completion instead of running command. This only affects the " 546 "prompt-toolkit shell." 547 ), 548 "COMPLETIONS_MENU_ROWS": VarDocs( 549 "Number of rows to reserve for tab-completions menu if " 550 "``$COMPLETIONS_DISPLAY`` is ``single`` or ``multi``. This only affects the " 551 "prompt-toolkit shell." 552 ), 553 "COMPLETION_QUERY_LIMIT": VarDocs( 554 "The number of completions to display before the user is asked " 555 "for confirmation." 556 ), 557 "DIRSTACK_SIZE": VarDocs("Maximum size of the directory stack."), 558 "DOTGLOB": VarDocs( 559 'Globbing files with "*" or "**" will also match ' 560 "dotfiles, or those 'hidden' files whose names " 561 "begin with a literal '.'. Such files are filtered " 562 "out by default." 563 ), 564 "DYNAMIC_CWD_WIDTH": VarDocs( 565 "Maximum length in number of characters " 566 "or as a percentage for the ``cwd`` prompt variable. For example, " 567 '"20" is a twenty character width and "10%" is ten percent of the ' 568 "number of columns available." 569 ), 570 "DYNAMIC_CWD_ELISION_CHAR": VarDocs( 571 "The string used to show a shortened directory in a shortened cwd, " 572 "e.g. ``'…'``." 573 ), 574 "EXPAND_ENV_VARS": VarDocs( 575 "Toggles whether environment variables are expanded inside of strings " 576 "in subprocess mode." 577 ), 578 "FORCE_POSIX_PATHS": VarDocs( 579 "Forces forward slashes (``/``) on Windows systems when using auto " 580 "completion if set to anything truthy.", 581 configurable=ON_WINDOWS, 582 ), 583 "FOREIGN_ALIASES_SUPPRESS_SKIP_MESSAGE": VarDocs( 584 "Whether or not foreign aliases should suppress the message " 585 "that informs the user when a foreign alias has been skipped " 586 "because it already exists in xonsh.", 587 configurable=True, 588 ), 589 "FOREIGN_ALIASES_OVERRIDE": VarDocs( 590 "Whether or not foreign aliases should override xonsh aliases " 591 "with the same name. Note that setting of this must happen in the " 592 "environment that xonsh was started from. " 593 "It cannot be set in the ``.xonshrc`` as loading of foreign aliases happens before" 594 "``.xonshrc`` is parsed", 595 configurable=True, 596 ), 597 "PROMPT_FIELDS": VarDocs( 598 "Dictionary containing variables to be used when formatting $PROMPT " 599 "and $TITLE. See 'Customizing the Prompt' " 600 "http://xon.sh/tutorial.html#customizing-the-prompt", 601 configurable=False, 602 default="``xonsh.prompt.PROMPT_FIELDS``", 603 ), 604 "FUZZY_PATH_COMPLETION": VarDocs( 605 "Toggles 'fuzzy' matching of paths for tab completion, which is only " 606 "used as a fallback if no other completions succeed but can be used " 607 "as a way to adjust for typographical errors. If ``True``, then, e.g.," 608 " ``xonhs`` will match ``xonsh``." 609 ), 610 "GLOB_SORTED": VarDocs( 611 "Toggles whether globbing results are manually sorted. If ``False``, " 612 "the results are returned in arbitrary order." 613 ), 614 "HISTCONTROL": VarDocs( 615 "A set of strings (comma-separated list in string form) of options " 616 "that determine what commands are saved to the history list. By " 617 "default all commands are saved. The option ``ignoredups`` will not " 618 "save the command if it matches the previous command. The option " 619 "'ignoreerr' will cause any commands that fail (i.e. return non-zero " 620 "exit status) to not be added to the history list.", 621 store_as_str=True, 622 ), 623 "IGNOREEOF": VarDocs("Prevents Ctrl-D from exiting the shell."), 624 "INDENT": VarDocs("Indentation string for multiline input"), 625 "INTENSIFY_COLORS_ON_WIN": VarDocs( 626 "Enhance style colors for readability " 627 "when using the default terminal (``cmd.exe``) on Windows. Blue colors, " 628 "which are hard to read, are replaced with cyan. Other colors are " 629 "generally replaced by their bright counter parts.", 630 configurable=ON_WINDOWS, 631 ), 632 "LANG": VarDocs("Fallback locale setting for systems where it matters"), 633 "LOADED_RC_FILES": VarDocs( 634 "Whether or not any of the xonsh run control files were loaded at " 635 "startup. This is a sequence of bools in Python that is converted " 636 "to a CSV list in string form, ie ``[True, False]`` becomes " 637 "``'True,False'``.", 638 configurable=False, 639 ), 640 "MOUSE_SUPPORT": VarDocs( 641 "Enable mouse support in the ``prompt_toolkit`` shell. This allows " 642 "clicking for positioning the cursor or selecting a completion. In " 643 "some terminals however, this disables the ability to scroll back " 644 "through the history of the terminal. Only usable with " 645 "``$SHELL_TYPE=prompt_toolkit``" 646 ), 647 "MULTILINE_PROMPT": VarDocs( 648 "Prompt text for 2nd+ lines of input, may be str or function which " 649 "returns a str." 650 ), 651 "OLDPWD": VarDocs( 652 "Used to represent a previous present working directory.", 653 configurable=False, 654 ), 655 "PATH": VarDocs("List of strings representing where to look for executables."), 656 "PATHEXT": VarDocs( 657 "Sequence of extension strings (eg, ``.EXE``) for " 658 "filtering valid executables by. Each element must be " 659 "uppercase." 660 ), 661 "PRETTY_PRINT_RESULTS": VarDocs('Flag for "pretty printing" return values.'), 662 "PROMPT": VarDocs( 663 "The prompt text. May contain keyword arguments which are " 664 "auto-formatted, see 'Customizing the Prompt' at " 665 "http://xon.sh/tutorial.html#customizing-the-prompt. " 666 "This value is never inherited from parent processes.", 667 default="``xonsh.environ.DEFAULT_PROMPT``", 668 ), 669 "PROMPT_TOOLKIT_COLOR_DEPTH": VarDocs( 670 "The color depth used by prompt toolkit 2. Possible values are: " 671 "``DEPTH_1_BIT``, ``DEPTH_4_BIT``, ``DEPTH_8_BIT``, ``DEPTH_24_BIT`` " 672 "colors. Default is an empty string which means that prompt toolkit decide." 673 ), 674 "PUSHD_MINUS": VarDocs( 675 "Flag for directory pushing functionality. False is the normal " "behavior." 676 ), 677 "PUSHD_SILENT": VarDocs( 678 "Whether or not to suppress directory stack manipulation output." 679 ), 680 "RAISE_SUBPROC_ERROR": VarDocs( 681 "Whether or not to raise an error if a subprocess (captured or " 682 "uncaptured) returns a non-zero exit status, which indicates failure. " 683 "This is most useful in xonsh scripts or modules where failures " 684 "should cause an end to execution. This is less useful at a terminal. " 685 "The error that is raised is a ``subprocess.CalledProcessError``." 686 ), 687 "RIGHT_PROMPT": VarDocs( 688 "Template string for right-aligned text " 689 "at the prompt. This may be parametrized in the same way as " 690 "the ``$PROMPT`` variable. Currently, this is only available in the " 691 "prompt-toolkit shell." 692 ), 693 "BOTTOM_TOOLBAR": VarDocs( 694 "Template string for the bottom toolbar. " 695 "This may be parametrized in the same way as " 696 "the ``$PROMPT`` variable. Currently, this is only available in the " 697 "prompt-toolkit shell." 698 ), 699 "SHELL_TYPE": VarDocs( 700 "Which shell is used. Currently two base shell types are supported:\n\n" 701 " - ``readline`` that is backed by Python's readline module\n" 702 " - ``prompt_toolkit`` that uses external library of the same name\n" 703 " - ``random`` selects a random shell from the above on startup\n" 704 " - ``best`` selects the most feature-rich shell available on the\n" 705 " user's system\n\n" 706 "To use the ``prompt_toolkit`` shell you need to have the " 707 "`prompt_toolkit <https://github.com/jonathanslenders/python-prompt-toolkit>`_" 708 " library installed. To specify which shell should be used, do so in " 709 "the run control file.", 710 default="``best``", 711 ), 712 "SUBSEQUENCE_PATH_COMPLETION": VarDocs( 713 "Toggles subsequence matching of paths for tab completion. " 714 "If ``True``, then, e.g., ``~/u/ro`` can match ``~/lou/carcolh``." 715 ), 716 "SUGGEST_COMMANDS": VarDocs( 717 "When a user types an invalid command, xonsh will try to offer " 718 "suggestions of similar valid commands if this is True." 719 ), 720 "SUGGEST_MAX_NUM": VarDocs( 721 "xonsh will show at most this many suggestions in response to an " 722 "invalid command. If negative, there is no limit to how many " 723 "suggestions are shown." 724 ), 725 "SUGGEST_THRESHOLD": VarDocs( 726 "An error threshold. If the Levenshtein distance between the entered " 727 "command and a valid command is less than this value, the valid " 728 'command will be offered as a suggestion. Also used for "fuzzy" ' 729 "tab completion of paths." 730 ), 731 "SUPPRESS_BRANCH_TIMEOUT_MESSAGE": VarDocs( 732 "Whether or not to suppress branch timeout warning messages." 733 ), 734 "TERM": VarDocs( 735 "TERM is sometimes set by the terminal emulator. This is used (when " 736 "valid) to determine whether or not to set the title. Users shouldn't " 737 "need to set this themselves. Note that this variable should be set as " 738 "early as possible in order to ensure it is effective. Here are a few " 739 "options:\n\n" 740 "* Set this from the program that launches xonsh. On POSIX systems, \n" 741 " this can be performed by using env, e.g. \n" 742 " ``/usr/bin/env TERM=xterm-color xonsh`` or similar.\n" 743 "* From the xonsh command line, namely ``xonsh -DTERM=xterm-color``.\n" 744 '* In the config file with ``{"env": {"TERM": "xterm-color"}}``.\n' 745 "* Lastly, in xonshrc with ``$TERM``\n\n" 746 "Ideally, your terminal emulator will set this correctly but that does " 747 "not always happen.", 748 configurable=False, 749 ), 750 "TITLE": VarDocs( 751 "The title text for the window in which xonsh is running. Formatted " 752 "in the same manner as ``$PROMPT``, see 'Customizing the Prompt' " 753 "http://xon.sh/tutorial.html#customizing-the-prompt.", 754 default="``xonsh.environ.DEFAULT_TITLE``", 755 ), 756 "UPDATE_COMPLETIONS_ON_KEYPRESS": VarDocs( 757 "Completions display is evaluated and presented whenever a key is " 758 "pressed. This avoids the need to press TAB, except to cycle through " 759 "the possibilities. This currently only affects the prompt-toolkit shell." 760 ), 761 "UPDATE_OS_ENVIRON": VarDocs( 762 "If True ``os_environ`` will always be updated " 763 "when the xonsh environment changes. The environment can be reset to " 764 "the default value by calling ``__xonsh_env__.undo_replace_env()``" 765 ), 766 "UPDATE_PROMPT_ON_KEYPRESS": VarDocs( 767 "Disables caching the prompt between commands, " 768 "so that it would be reevaluated on each keypress. " 769 "Disabled by default because of the incurred performance penalty." 770 ), 771 "VC_BRANCH_TIMEOUT": VarDocs( 772 "The timeout (in seconds) for version control " 773 "branch computations. This is a timeout per subprocess call, so the " 774 "total time to compute will be larger than this in many cases." 775 ), 776 "VC_HG_SHOW_BRANCH": VarDocs( 777 "Whether or not to show the Mercurial branch in the prompt." 778 ), 779 "VI_MODE": VarDocs( 780 "Flag to enable ``vi_mode`` in the ``prompt_toolkit`` shell." 781 ), 782 "VIRTUAL_ENV": VarDocs( 783 "Path to the currently active Python environment.", configurable=False 784 ), 785 "WIN_UNICODE_CONSOLE": VarDocs( 786 "Enables unicode support in windows terminals. Requires the external " 787 "library ``win_unicode_console``.", 788 configurable=ON_WINDOWS, 789 ), 790 "XDG_CONFIG_HOME": VarDocs( 791 "Open desktop standard configuration home dir. This is the same " 792 "default as used in the standard.", 793 configurable=False, 794 default="``~/.config``", 795 ), 796 "XDG_DATA_HOME": VarDocs( 797 "Open desktop standard data home dir. This is the same default as " 798 "used in the standard.", 799 default="``~/.local/share``", 800 ), 801 "XONSHRC": VarDocs( 802 "A list of the locations of run control files, if they exist. User " 803 "defined run control file will supersede values set in system-wide " 804 "control file if there is a naming collision.", 805 default=( 806 "On Linux & Mac OSX: ``['/etc/xonshrc', '~/.config/xonsh/rc.xsh', '~/.xonshrc']``\n" 807 "\nOn Windows: " 808 "``['%ALLUSERSPROFILE%\\\\xonsh\\\\xonshrc', '~/.config/xonsh/rc.xsh', '~/.xonshrc']``" 809 ), 810 ), 811 "XONSH_APPEND_NEWLINE": VarDocs( 812 "Append new line when a partial line is preserved in output." 813 ), 814 "XONSH_AUTOPAIR": VarDocs( 815 "Whether Xonsh will auto-insert matching parentheses, brackets, and " 816 "quotes. Only available under the prompt-toolkit shell." 817 ), 818 "XONSH_CACHE_SCRIPTS": VarDocs( 819 "Controls whether the code for scripts run from xonsh will be cached" 820 " (``True``) or re-compiled each time (``False``)." 821 ), 822 "XONSH_CACHE_EVERYTHING": VarDocs( 823 "Controls whether all code (including code entered at the interactive" 824 " prompt) will be cached." 825 ), 826 "XONSH_COLOR_STYLE": VarDocs( 827 "Sets the color style for xonsh colors. This is a style name, not " 828 "a color map. Run ``xonfig styles`` to see the available styles." 829 ), 830 "XONSH_CONFIG_DIR": VarDocs( 831 "This is the location where xonsh configuration information is stored.", 832 configurable=False, 833 default="``$XDG_CONFIG_HOME/xonsh``", 834 ), 835 "XONSH_DEBUG": VarDocs( 836 "Sets the xonsh debugging level. This may be an integer or a boolean. " 837 "Setting this variable prior to stating xonsh to ``1`` or ``True`` " 838 "will suppress amalgamated imports. Setting it to ``2`` will get some " 839 "basic information like input transformation, command replacement. " 840 "With ``3`` or a higher number will make more debugging information " 841 "presented, like PLY parsing messages.", 842 configurable=False, 843 ), 844 "XONSH_DATA_DIR": VarDocs( 845 "This is the location where xonsh data files are stored, such as " 846 "history.", 847 default="``$XDG_DATA_HOME/xonsh``", 848 ), 849 "XONSH_ENCODING": VarDocs( 850 "This is the encoding that xonsh should use for subprocess operations.", 851 default="``sys.getdefaultencoding()``", 852 ), 853 "XONSH_ENCODING_ERRORS": VarDocs( 854 "The flag for how to handle encoding errors should they happen. " 855 "Any string flag that has been previously registered with Python " 856 "is allowed. See the 'Python codecs documentation' " 857 "(https://docs.python.org/3/library/codecs.html#error-handlers) " 858 "for more information and available options.", 859 default="``surrogateescape``", 860 ), 861 "XONSH_GITSTATUS_*": VarDocs( 862 "Symbols for gitstatus prompt. Default values are: \n\n" 863 "* ``XONSH_GITSTATUS_HASH``: ``:``\n" 864 "* ``XONSH_GITSTATUS_BRANCH``: ``{CYAN}``\n" 865 "* ``XONSH_GITSTATUS_OPERATION``: ``{CYAN}``\n" 866 "* ``XONSH_GITSTATUS_STAGED``: ``{RED}●``\n" 867 "* ``XONSH_GITSTATUS_CONFLICTS``: ``{RED}×``\n" 868 "* ``XONSH_GITSTATUS_CHANGED``: ``{BLUE}+``\n" 869 "* ``XONSH_GITSTATUS_UNTRACKED``: ``…``\n" 870 "* ``XONSH_GITSTATUS_STASHED``: ``⚑``\n" 871 "* ``XONSH_GITSTATUS_CLEAN``: ``{BOLD_GREEN}✓``\n" 872 "* ``XONSH_GITSTATUS_AHEAD``: ``↑·``\n" 873 "* ``XONSH_GITSTATUS_BEHIND``: ``↓·``\n" 874 ), 875 "XONSH_HISTORY_BACKEND": VarDocs( 876 "Set which history backend to use. Options are: 'json', " 877 "'sqlite', and 'dummy'. The default is 'json'. " 878 "``XONSH_HISTORY_BACKEND`` also accepts a class type that inherits " 879 "from ``xonsh.history.base.History``, or its instance." 880 ), 881 "XONSH_HISTORY_FILE": VarDocs( 882 "Location of history file (deprecated).", 883 configurable=False, 884 default="``~/.xonsh_history``", 885 ), 886 "XONSH_HISTORY_MATCH_ANYWHERE": VarDocs( 887 "When searching history from a partial string (by pressing up arrow), " 888 "match command history anywhere in a given line (not just the start)", 889 default="False", 890 ), 891 "XONSH_HISTORY_SIZE": VarDocs( 892 "Value and units tuple that sets the size of history after garbage " 893 "collection. Canonical units are:\n\n" 894 "- ``commands`` for the number of past commands executed,\n" 895 "- ``files`` for the number of history files to keep,\n" 896 "- ``s`` for the number of seconds in the past that are allowed, and\n" 897 "- ``b`` for the number of bytes that history may consume.\n\n" 898 "Common abbreviations, such as '6 months' or '1 GB' are also allowed.", 899 default="``(8128, 'commands')`` or ``'8128 commands'``", 900 ), 901 "XONSH_INTERACTIVE": VarDocs( 902 "``True`` if xonsh is running interactively, and ``False`` otherwise.", 903 configurable=False, 904 ), 905 "XONSH_LOGIN": VarDocs( 906 "``True`` if xonsh is running as a login shell, and ``False`` otherwise.", 907 configurable=False, 908 ), 909 "XONSH_PROC_FREQUENCY": VarDocs( 910 "The process frequency is the time that " 911 "xonsh process threads sleep for while running command pipelines. " 912 "The value has units of seconds [s]." 913 ), 914 "XONSH_SHOW_TRACEBACK": VarDocs( 915 "Controls if a traceback is shown if exceptions occur in the shell. " 916 "Set to ``True`` to always show traceback or ``False`` to always hide. " 917 "If undefined then the traceback is hidden but a notice is shown on how " 918 "to enable the full traceback." 919 ), 920 "XONSH_SOURCE": VarDocs( 921 "When running a xonsh script, this variable contains the absolute path " 922 "to the currently executing script's file.", 923 configurable=False, 924 ), 925 "XONSH_STDERR_PREFIX": VarDocs( 926 "A format string, using the same keys and colors as ``$PROMPT``, that " 927 "is prepended whenever stderr is displayed. This may be used in " 928 "conjunction with ``$XONSH_STDERR_POSTFIX`` to close out the block." 929 "For example, to have stderr appear on a red background, the " 930 'prefix & postfix pair would be "{BACKGROUND_RED}" & "{NO_COLOR}".' 931 ), 932 "XONSH_STDERR_POSTFIX": VarDocs( 933 "A format string, using the same keys and colors as ``$PROMPT``, that " 934 "is appended whenever stderr is displayed. This may be used in " 935 "conjunction with ``$XONSH_STDERR_PREFIX`` to start the block." 936 "For example, to have stderr appear on a red background, the " 937 'prefix & postfix pair would be "{BACKGROUND_RED}" & "{NO_COLOR}".' 938 ), 939 "XONSH_STORE_STDIN": VarDocs( 940 "Whether or not to store the stdin that is supplied to the " 941 "``!()`` and ``![]`` operators." 942 ), 943 "XONSH_STORE_STDOUT": VarDocs( 944 "Whether or not to store the ``stdout`` and ``stderr`` streams in the " 945 "history files." 946 ), 947 "XONSH_TRACEBACK_LOGFILE": VarDocs( 948 "Specifies a file to store the traceback log to, regardless of whether " 949 "``XONSH_SHOW_TRACEBACK`` has been set. Its value must be a writable file " 950 "or None / the empty string if traceback logging is not desired. " 951 "Logging to a file is not enabled by default." 952 ), 953 "XONSH_DATETIME_FORMAT": VarDocs( 954 "The format that is used for ``datetime.strptime()`` in various places" 955 "i.e the history timestamp option" 956 ), 957 } 958 959 960# 961# actual environment 962# 963 964 965class Env(cabc.MutableMapping): 966 """A xonsh environment, whose variables have limited typing 967 (unlike BASH). Most variables are, by default, strings (like BASH). 968 However, the following rules also apply based on variable-name: 969 970 * PATH: any variable whose name ends in PATH is a list of strings. 971 * XONSH_HISTORY_SIZE: this variable is an (int | float, str) tuple. 972 * LC_* (locale categories): locale category names get/set the Python 973 locale via locale.getlocale() and locale.setlocale() functions. 974 975 An Env instance may be converted to an untyped version suitable for 976 use in a subprocess. 977 """ 978 979 _arg_regex = None 980 981 def __init__(self, *args, **kwargs): 982 """If no initial environment is given, os_environ is used.""" 983 self._d = {} 984 # sentinel value for non existing envvars 985 self._no_value = object() 986 self._orig_env = None 987 self._ensurers = {k: Ensurer(*v) for k, v in DEFAULT_ENSURERS.items()} 988 self._defaults = DEFAULT_VALUES 989 self._docs = DEFAULT_DOCS 990 if len(args) == 0 and len(kwargs) == 0: 991 args = (os_environ,) 992 for key, val in dict(*args, **kwargs).items(): 993 self[key] = val 994 if ON_WINDOWS: 995 path_key = next((k for k in self._d if k.upper() == "PATH"), None) 996 if path_key: 997 self["PATH"] = self._d.pop(path_key) 998 if "PATH" not in self._d: 999 # this is here so the PATH is accessible to subprocs and so that 1000 # it can be modified in-place in the xonshrc file 1001 self._d["PATH"] = list(PATH_DEFAULT) 1002 self._detyped = None 1003 1004 @staticmethod 1005 def detypeable(val): 1006 return not (callable(val) or isinstance(val, cabc.MutableMapping)) 1007 1008 def detype(self): 1009 if self._detyped is not None: 1010 return self._detyped 1011 ctx = {} 1012 for key, val in self._d.items(): 1013 if not self.detypeable(val): 1014 continue 1015 if not isinstance(key, str): 1016 key = str(key) 1017 ensurer = self.get_ensurer(key) 1018 val = ensurer.detype(val) 1019 ctx[key] = val 1020 self._detyped = ctx 1021 return ctx 1022 1023 def replace_env(self): 1024 """Replaces the contents of os_environ with a detyped version 1025 of the xonsh environment. 1026 """ 1027 if self._orig_env is None: 1028 self._orig_env = dict(os_environ) 1029 os_environ.clear() 1030 os_environ.update(self.detype()) 1031 1032 def undo_replace_env(self): 1033 """Replaces the contents of os_environ with a detyped version 1034 of the xonsh environment. 1035 """ 1036 if self._orig_env is not None: 1037 os_environ.clear() 1038 os_environ.update(self._orig_env) 1039 self._orig_env = None 1040 1041 def get_ensurer(self, key, default=Ensurer(always_true, None, ensure_string)): 1042 """Gets an ensurer for the given key.""" 1043 if key in self._ensurers: 1044 return self._ensurers[key] 1045 for k, ensurer in self._ensurers.items(): 1046 if isinstance(k, str): 1047 continue 1048 if k.match(key) is not None: 1049 break 1050 else: 1051 ensurer = default 1052 self._ensurers[key] = ensurer 1053 return ensurer 1054 1055 def get_docs(self, key, default=VarDocs("<no documentation>")): 1056 """Gets the documentation for the environment variable.""" 1057 vd = self._docs.get(key, None) 1058 if vd is None: 1059 return default 1060 if vd.default is DefaultNotGiven: 1061 dval = pprint.pformat(self._defaults.get(key, "<default not set>")) 1062 vd = vd._replace(default=dval) 1063 self._docs[key] = vd 1064 return vd 1065 1066 def help(self, key): 1067 """Get information about a specific environment variable.""" 1068 vardocs = self.get_docs(key) 1069 width = min(79, os.get_terminal_size()[0]) 1070 docstr = "\n".join(textwrap.wrap(vardocs.docstr, width=width)) 1071 template = HELP_TEMPLATE.format( 1072 envvar=key, 1073 docstr=docstr, 1074 default=vardocs.default, 1075 configurable=vardocs.configurable, 1076 ) 1077 print_color(template) 1078 1079 def is_manually_set(self, varname): 1080 """ 1081 Checks if an environment variable has been manually set. 1082 """ 1083 return varname in self._d 1084 1085 @contextlib.contextmanager 1086 def swap(self, other=None, **kwargs): 1087 """Provides a context manager for temporarily swapping out certain 1088 environment variables with other values. On exit from the context 1089 manager, the original values are restored. 1090 """ 1091 old = {} 1092 # single positional argument should be a dict-like object 1093 if other is not None: 1094 for k, v in other.items(): 1095 old[k] = self.get(k, NotImplemented) 1096 self[k] = v 1097 # kwargs could also have been sent in 1098 for k, v in kwargs.items(): 1099 old[k] = self.get(k, NotImplemented) 1100 self[k] = v 1101 1102 exception = None 1103 try: 1104 yield self 1105 except Exception as e: 1106 exception = e 1107 finally: 1108 # restore the values 1109 for k, v in old.items(): 1110 if v is NotImplemented: 1111 del self[k] 1112 else: 1113 self[k] = v 1114 if exception is not None: 1115 raise exception from None 1116 1117 # 1118 # Mutable mapping interface 1119 # 1120 1121 def __getitem__(self, key): 1122 # remove this block on next release 1123 if key == "FORMATTER_DICT": 1124 print( 1125 "PendingDeprecationWarning: FORMATTER_DICT is an alias of " 1126 "PROMPT_FIELDS and will be removed in the next release", 1127 file=sys.stderr, 1128 ) 1129 return self["PROMPT_FIELDS"] 1130 if key is Ellipsis: 1131 return self 1132 elif key in self._d: 1133 val = self._d[key] 1134 elif key in self._defaults: 1135 val = self._defaults[key] 1136 if is_callable_default(val): 1137 val = val(self) 1138 else: 1139 e = "Unknown environment variable: ${}" 1140 raise KeyError(e.format(key)) 1141 if isinstance( 1142 val, (cabc.MutableSet, cabc.MutableSequence, cabc.MutableMapping) 1143 ): 1144 self._detyped = None 1145 return val 1146 1147 def __setitem__(self, key, val): 1148 ensurer = self.get_ensurer(key) 1149 if not ensurer.validate(val): 1150 val = ensurer.convert(val) 1151 # existing envvars can have any value including None 1152 old_value = self._d[key] if key in self._d else self._no_value 1153 self._d[key] = val 1154 if self.detypeable(val): 1155 self._detyped = None 1156 if self.get("UPDATE_OS_ENVIRON"): 1157 if self._orig_env is None: 1158 self.replace_env() 1159 else: 1160 os_environ[key] = ensurer.detype(val) 1161 if old_value is self._no_value: 1162 events.on_envvar_new.fire(name=key, value=val) 1163 elif old_value != val: 1164 events.on_envvar_change.fire(name=key, oldvalue=old_value, newvalue=val) 1165 1166 def __delitem__(self, key): 1167 val = self._d.pop(key) 1168 if self.detypeable(val): 1169 self._detyped = None 1170 if self.get("UPDATE_OS_ENVIRON") and key in os_environ: 1171 del os_environ[key] 1172 1173 def get(self, key, default=None): 1174 """The environment will look up default values from its own defaults if a 1175 default is not given here. 1176 """ 1177 try: 1178 return self[key] 1179 except KeyError: 1180 return default 1181 1182 def __iter__(self): 1183 yield from (set(self._d) | set(self._defaults)) 1184 1185 def __contains__(self, item): 1186 return item in self._d or item in self._defaults 1187 1188 def __len__(self): 1189 return len(self._d) 1190 1191 def __str__(self): 1192 return str(self._d) 1193 1194 def __repr__(self): 1195 return "{0}.{1}(...)".format( 1196 self.__class__.__module__, self.__class__.__name__, self._d 1197 ) 1198 1199 def _repr_pretty_(self, p, cycle): 1200 name = "{0}.{1}".format(self.__class__.__module__, self.__class__.__name__) 1201 with p.group(0, name + "(", ")"): 1202 if cycle: 1203 p.text("...") 1204 elif len(self): 1205 p.break_() 1206 p.pretty(dict(self)) 1207 1208 1209def _yield_executables(directory, name): 1210 if ON_WINDOWS: 1211 base_name, ext = os.path.splitext(name.lower()) 1212 for fname in executables_in(directory): 1213 fbase, fext = os.path.splitext(fname.lower()) 1214 if base_name == fbase and (len(ext) == 0 or ext == fext): 1215 yield os.path.join(directory, fname) 1216 else: 1217 for x in executables_in(directory): 1218 if x == name: 1219 yield os.path.join(directory, name) 1220 return 1221 1222 1223def locate_binary(name): 1224 """Locates an executable on the file system.""" 1225 return builtins.__xonsh_commands_cache__.locate_binary(name) 1226 1227 1228BASE_ENV = LazyObject( 1229 lambda: { 1230 "BASH_COMPLETIONS": list(DEFAULT_VALUES["BASH_COMPLETIONS"]), 1231 "PROMPT_FIELDS": dict(DEFAULT_VALUES["PROMPT_FIELDS"]), 1232 "XONSH_VERSION": XONSH_VERSION, 1233 }, 1234 globals(), 1235 "BASE_ENV", 1236) 1237 1238 1239def xonshrc_context(rcfiles=None, execer=None, ctx=None, env=None, login=True): 1240 """Attempts to read in all xonshrc files and return the context.""" 1241 loaded = env["LOADED_RC_FILES"] = [] 1242 ctx = {} if ctx is None else ctx 1243 if rcfiles is None: 1244 return env 1245 env["XONSHRC"] = tuple(rcfiles) 1246 for rcfile in rcfiles: 1247 if not os.path.isfile(rcfile): 1248 loaded.append(False) 1249 continue 1250 _, ext = os.path.splitext(rcfile) 1251 status = xonsh_script_run_control(rcfile, ctx, env, execer=execer, login=login) 1252 loaded.append(status) 1253 return ctx 1254 1255 1256def windows_foreign_env_fixes(ctx): 1257 """Environment fixes for Windows. Operates in-place.""" 1258 # remove these bash variables which only cause problems. 1259 for ev in ["HOME", "OLDPWD"]: 1260 if ev in ctx: 1261 del ctx[ev] 1262 # Override path-related bash variables; on Windows bash uses 1263 # /c/Windows/System32 syntax instead of C:\\Windows\\System32 1264 # which messes up these environment variables for xonsh. 1265 for ev in ["PATH", "TEMP", "TMP"]: 1266 if ev in os_environ: 1267 ctx[ev] = os_environ[ev] 1268 elif ev in ctx: 1269 del ctx[ev] 1270 ctx["PWD"] = _get_cwd() or "" 1271 1272 1273def foreign_env_fixes(ctx): 1274 """Environment fixes for all operating systems""" 1275 if "PROMPT" in ctx: 1276 del ctx["PROMPT"] 1277 1278 1279def xonsh_script_run_control(filename, ctx, env, execer=None, login=True): 1280 """Loads a xonsh file and applies it as a run control.""" 1281 if execer is None: 1282 return False 1283 updates = {"__file__": filename, "__name__": os.path.abspath(filename)} 1284 try: 1285 with swap_values(ctx, updates): 1286 run_script_with_cache(filename, execer, ctx) 1287 loaded = True 1288 except SyntaxError as err: 1289 msg = "syntax error in xonsh run control file {0!r}: {1!s}" 1290 print_exception(msg.format(filename, err)) 1291 loaded = False 1292 except Exception as err: 1293 msg = "error running xonsh run control file {0!r}: {1!s}" 1294 print_exception(msg.format(filename, err)) 1295 loaded = False 1296 return loaded 1297 1298 1299def default_env(env=None): 1300 """Constructs a default xonsh environment.""" 1301 # in order of increasing precedence 1302 ctx = dict(BASE_ENV) 1303 ctx.update(os_environ) 1304 ctx["PWD"] = _get_cwd() or "" 1305 # These can cause problems for programs (#2543) 1306 ctx.pop("LINES", None) 1307 ctx.pop("COLUMNS", None) 1308 # other shells' PROMPT definitions generally don't work in XONSH: 1309 try: 1310 del ctx["PROMPT"] 1311 except KeyError: 1312 pass 1313 # finalize env 1314 if env is not None: 1315 ctx.update(env) 1316 return ctx 1317 1318 1319def make_args_env(args=None): 1320 """Makes a dictionary containing the $ARGS and $ARG<N> environment 1321 variables. If the supplied ARGS is None, then sys.argv is used. 1322 """ 1323 if args is None: 1324 args = sys.argv 1325 env = {"ARG" + str(i): arg for i, arg in enumerate(args)} 1326 env["ARGS"] = list(args) # make a copy so we don't interfere with original variable 1327 return env 1328