mirror of
https://github.com/xonsh/xonsh.git
synced 2025-03-04 08:24:40 +01:00
resolved conflicts with master
This commit is contained in:
commit
6aa7aba36b
11 changed files with 166 additions and 10 deletions
17
news/dotglob.rst
Normal file
17
news/dotglob.rst
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
**Added:**
|
||||||
|
|
||||||
|
* New ``$DOTGLOB`` environment variable enables globs to match
|
||||||
|
"hidden" files which start with a literal ``.``. Set this
|
||||||
|
variable to ``True`` to get this matching behavior.
|
||||||
|
Cooresponding API changes have been made to
|
||||||
|
``xonsh.tools.globpath()`` and ``xonsh.tools.iglobpath()``
|
||||||
|
|
||||||
|
**Changed:** None
|
||||||
|
|
||||||
|
**Deprecated:** None
|
||||||
|
|
||||||
|
**Removed:** None
|
||||||
|
|
||||||
|
**Fixed:** None
|
||||||
|
|
||||||
|
**Security:** None
|
16
news/fssup.rst
Normal file
16
news/fssup.rst
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
**Added:**
|
||||||
|
|
||||||
|
* New environment variable ``$FOREIGN_ALIASES_SUPPRESS_SKIP_MESSAGE``
|
||||||
|
enables the removal of skipping foreign alias messages.
|
||||||
|
* New ``--suppress-skip-message`` command line option for skipping
|
||||||
|
foreign alias messages when sourcing foreign shells.
|
||||||
|
|
||||||
|
**Changed:** None
|
||||||
|
|
||||||
|
**Deprecated:** None
|
||||||
|
|
||||||
|
**Removed:** None
|
||||||
|
|
||||||
|
**Fixed:** None
|
||||||
|
|
||||||
|
**Security:** None
|
14
news/rlcomp.rst
Normal file
14
news/rlcomp.rst
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
**Added:** None
|
||||||
|
|
||||||
|
**Changed:** None
|
||||||
|
|
||||||
|
**Deprecated:** None
|
||||||
|
|
||||||
|
**Removed:** None
|
||||||
|
|
||||||
|
**Fixed:**
|
||||||
|
|
||||||
|
* Fixed issue with TAB completion in readline not replacing values
|
||||||
|
with spaces properly when the prefix was unquoted.
|
||||||
|
|
||||||
|
**Security:** None
|
0
tests/.somedotfile
Normal file
0
tests/.somedotfile
Normal file
0
tests/bin/.someotherdotfile
Normal file
0
tests/bin/.someotherdotfile
Normal file
|
@ -74,7 +74,7 @@ from xonsh.tools import (
|
||||||
)
|
)
|
||||||
from xonsh.environ import Env
|
from xonsh.environ import Env
|
||||||
|
|
||||||
from tools import skip_if_on_windows, skip_if_on_unix
|
from tools import skip_if_on_windows, skip_if_on_unix, skip_if_py34
|
||||||
|
|
||||||
LEXER = Lexer()
|
LEXER = Lexer()
|
||||||
LEXER.build()
|
LEXER.build()
|
||||||
|
@ -1601,6 +1601,39 @@ def test_deprecated_past_expiry_raises_assertion_error(expired_version):
|
||||||
my_function()
|
my_function()
|
||||||
|
|
||||||
|
|
||||||
|
@skip_if_on_windows
|
||||||
|
def test_iglobpath_no_dotfiles(xonsh_builtins):
|
||||||
|
d = os.path.dirname(__file__)
|
||||||
|
g = d + "/*"
|
||||||
|
files = list(iglobpath(g, include_dotfiles=False))
|
||||||
|
assert d + "/.somedotfile" not in files
|
||||||
|
|
||||||
|
|
||||||
|
@skip_if_on_windows
|
||||||
|
def test_iglobpath_dotfiles(xonsh_builtins):
|
||||||
|
d = os.path.dirname(__file__)
|
||||||
|
g = d + "/*"
|
||||||
|
files = list(iglobpath(g, include_dotfiles=True))
|
||||||
|
assert d + "/.somedotfile" in files
|
||||||
|
|
||||||
|
|
||||||
|
@skip_if_on_windows
|
||||||
|
def test_iglobpath_no_dotfiles_recursive(xonsh_builtins):
|
||||||
|
d = os.path.dirname(__file__)
|
||||||
|
g = d + "/**"
|
||||||
|
files = list(iglobpath(g, include_dotfiles=False))
|
||||||
|
assert d + "/bin/.someotherdotfile" not in files
|
||||||
|
|
||||||
|
|
||||||
|
@skip_if_py34
|
||||||
|
@skip_if_on_windows
|
||||||
|
def test_iglobpath_dotfiles_recursive(xonsh_builtins):
|
||||||
|
d = os.path.dirname(__file__)
|
||||||
|
g = d + "/**"
|
||||||
|
files = list(iglobpath(g, include_dotfiles=True))
|
||||||
|
assert d + "/bin/.someotherdotfile" in files
|
||||||
|
|
||||||
|
|
||||||
def test_iglobpath_empty_str(monkeypatch, xonsh_builtins):
|
def test_iglobpath_empty_str(monkeypatch, xonsh_builtins):
|
||||||
# makes sure that iglobpath works, even when os.scandir() and os.listdir()
|
# makes sure that iglobpath works, even when os.scandir() and os.listdir()
|
||||||
# fail to return valid results, like an empty filename
|
# fail to return valid results, like an empty filename
|
||||||
|
|
|
@ -260,6 +260,13 @@ def _SOURCE_FOREIGN_PARSER():
|
||||||
help="flag for whether or not sourced aliases should "
|
help="flag for whether or not sourced aliases should "
|
||||||
"replace the current xonsh aliases.",
|
"replace the current xonsh aliases.",
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--suppress-skip-message",
|
||||||
|
default=None,
|
||||||
|
action="store_true",
|
||||||
|
dest="suppress_skip_message",
|
||||||
|
help="flag for whether or not skip messages should be suppressed.",
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--show",
|
"--show",
|
||||||
default=False,
|
default=False,
|
||||||
|
@ -280,7 +287,13 @@ def _SOURCE_FOREIGN_PARSER():
|
||||||
|
|
||||||
def source_foreign(args, stdin=None, stdout=None, stderr=None):
|
def source_foreign(args, stdin=None, stdout=None, stderr=None):
|
||||||
"""Sources a file written in a foreign shell language."""
|
"""Sources a file written in a foreign shell language."""
|
||||||
|
env = builtins.__xonsh__.env
|
||||||
ns = _SOURCE_FOREIGN_PARSER.parse_args(args)
|
ns = _SOURCE_FOREIGN_PARSER.parse_args(args)
|
||||||
|
ns.suppress_skip_message = (
|
||||||
|
env.get("FOREIGN_ALIASES_SUPPRESS_SKIP_MESSAGE")
|
||||||
|
if ns.suppress_skip_message is None
|
||||||
|
else ns.suppress_skip_message
|
||||||
|
)
|
||||||
if ns.prevcmd is not None:
|
if ns.prevcmd is not None:
|
||||||
pass # don't change prevcmd if given explicitly
|
pass # don't change prevcmd if given explicitly
|
||||||
elif os.path.isfile(ns.files_or_code[0]):
|
elif os.path.isfile(ns.files_or_code[0]):
|
||||||
|
@ -315,7 +328,6 @@ def source_foreign(args, stdin=None, stdout=None, stderr=None):
|
||||||
msg += "xonsh: error: Possible reasons: File not found or syntax error\n"
|
msg += "xonsh: error: Possible reasons: File not found or syntax error\n"
|
||||||
return (None, msg, 1)
|
return (None, msg, 1)
|
||||||
# apply results
|
# apply results
|
||||||
env = builtins.__xonsh__.env
|
|
||||||
denv = env.detype()
|
denv = env.detype()
|
||||||
for k, v in fsenv.items():
|
for k, v in fsenv.items():
|
||||||
if k in denv and v == denv[k]:
|
if k in denv and v == denv[k]:
|
||||||
|
@ -332,11 +344,15 @@ def source_foreign(args, stdin=None, stdout=None, stderr=None):
|
||||||
continue # no change from original
|
continue # no change from original
|
||||||
elif ns.overwrite_aliases or k not in baliases:
|
elif ns.overwrite_aliases or k not in baliases:
|
||||||
baliases[k] = v
|
baliases[k] = v
|
||||||
|
elif ns.suppress_skip_message:
|
||||||
|
pass
|
||||||
else:
|
else:
|
||||||
msg = (
|
msg = (
|
||||||
"Skipping application of {0!r} alias from {1!r} "
|
"Skipping application of {0!r} alias from {1!r} "
|
||||||
"since it shares a name with an existing xonsh alias. "
|
"since it shares a name with an existing xonsh alias. "
|
||||||
'Use "--overwrite-alias" option to apply it anyway.'
|
'Use "--overwrite-alias" option to apply it anyway.'
|
||||||
|
'You may prevent this message with "--suppress-skip-message" or '
|
||||||
|
'"$FOREIGN_ALIASES_SUPPRESS_SKIP_MESSAGE = True".'
|
||||||
)
|
)
|
||||||
print(msg.format(k, ns.shell), file=stderr)
|
print(msg.format(k, ns.shell), file=stderr)
|
||||||
|
|
||||||
|
|
|
@ -147,8 +147,13 @@ def regexsearch(s):
|
||||||
def globsearch(s):
|
def globsearch(s):
|
||||||
csc = builtins.__xonsh__.env.get("CASE_SENSITIVE_COMPLETIONS")
|
csc = builtins.__xonsh__.env.get("CASE_SENSITIVE_COMPLETIONS")
|
||||||
glob_sorted = builtins.__xonsh__.env.get("GLOB_SORTED")
|
glob_sorted = builtins.__xonsh__.env.get("GLOB_SORTED")
|
||||||
|
dotglob = builtins.__xonsh__.env.get("DOTGLOB")
|
||||||
return globpath(
|
return globpath(
|
||||||
s, ignore_case=(not csc), return_empty=True, sort_result=glob_sorted
|
s,
|
||||||
|
ignore_case=(not csc),
|
||||||
|
return_empty=True,
|
||||||
|
sort_result=glob_sorted,
|
||||||
|
include_dotfiles=dotglob,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -177,6 +177,7 @@ def DEFAULT_ENSURERS():
|
||||||
"COMPLETIONS_MENU_ROWS": (is_int, int, str),
|
"COMPLETIONS_MENU_ROWS": (is_int, int, str),
|
||||||
"COMPLETION_QUERY_LIMIT": (is_int, int, str),
|
"COMPLETION_QUERY_LIMIT": (is_int, int, str),
|
||||||
"DIRSTACK_SIZE": (is_int, int, str),
|
"DIRSTACK_SIZE": (is_int, int, str),
|
||||||
|
"DOTGLOB": (is_bool, to_bool, bool_to_str),
|
||||||
"DYNAMIC_CWD_WIDTH": (
|
"DYNAMIC_CWD_WIDTH": (
|
||||||
is_dynamic_cwd_width,
|
is_dynamic_cwd_width,
|
||||||
to_dynamic_cwd_tuple,
|
to_dynamic_cwd_tuple,
|
||||||
|
@ -185,6 +186,7 @@ def DEFAULT_ENSURERS():
|
||||||
"DYNAMIC_CWD_ELISION_CHAR": (is_string, ensure_string, ensure_string),
|
"DYNAMIC_CWD_ELISION_CHAR": (is_string, ensure_string, ensure_string),
|
||||||
"EXPAND_ENV_VARS": (is_bool, to_bool, bool_to_str),
|
"EXPAND_ENV_VARS": (is_bool, to_bool, bool_to_str),
|
||||||
"FORCE_POSIX_PATHS": (is_bool, to_bool, bool_to_str),
|
"FORCE_POSIX_PATHS": (is_bool, to_bool, bool_to_str),
|
||||||
|
"FOREIGN_ALIASES_SUPPRESS_SKIP_MESSAGE": (is_bool, to_bool, bool_to_str),
|
||||||
"FOREIGN_ALIASES_OVERRIDE": (is_bool, to_bool, bool_to_str),
|
"FOREIGN_ALIASES_OVERRIDE": (is_bool, to_bool, bool_to_str),
|
||||||
"FUZZY_PATH_COMPLETION": (is_bool, to_bool, bool_to_str),
|
"FUZZY_PATH_COMPLETION": (is_bool, to_bool, bool_to_str),
|
||||||
"GLOB_SORTED": (is_bool, to_bool, bool_to_str),
|
"GLOB_SORTED": (is_bool, to_bool, bool_to_str),
|
||||||
|
@ -356,10 +358,12 @@ def DEFAULT_VALUES():
|
||||||
"COMPLETIONS_MENU_ROWS": 5,
|
"COMPLETIONS_MENU_ROWS": 5,
|
||||||
"COMPLETION_QUERY_LIMIT": 100,
|
"COMPLETION_QUERY_LIMIT": 100,
|
||||||
"DIRSTACK_SIZE": 20,
|
"DIRSTACK_SIZE": 20,
|
||||||
|
"DOTGLOB": False,
|
||||||
"DYNAMIC_CWD_WIDTH": (float("inf"), "c"),
|
"DYNAMIC_CWD_WIDTH": (float("inf"), "c"),
|
||||||
"DYNAMIC_CWD_ELISION_CHAR": "",
|
"DYNAMIC_CWD_ELISION_CHAR": "",
|
||||||
"EXPAND_ENV_VARS": True,
|
"EXPAND_ENV_VARS": True,
|
||||||
"FORCE_POSIX_PATHS": False,
|
"FORCE_POSIX_PATHS": False,
|
||||||
|
"FOREIGN_ALIASES_SUPPRESS_SKIP_MESSAGE": False,
|
||||||
"FOREIGN_ALIASES_OVERRIDE": False,
|
"FOREIGN_ALIASES_OVERRIDE": False,
|
||||||
"PROMPT_FIELDS": dict(prompt.PROMPT_FIELDS),
|
"PROMPT_FIELDS": dict(prompt.PROMPT_FIELDS),
|
||||||
"FUZZY_PATH_COMPLETION": True,
|
"FUZZY_PATH_COMPLETION": True,
|
||||||
|
@ -551,6 +555,12 @@ def DEFAULT_DOCS():
|
||||||
"for confirmation."
|
"for confirmation."
|
||||||
),
|
),
|
||||||
"DIRSTACK_SIZE": VarDocs("Maximum size of the directory stack."),
|
"DIRSTACK_SIZE": VarDocs("Maximum size of the directory stack."),
|
||||||
|
"DOTGLOB": VarDocs(
|
||||||
|
'Globbing files with "*" or "**" will also match '
|
||||||
|
"dotfiles, or those 'hidden' files whose names "
|
||||||
|
"begin with a literal '.'. Such files are filtered "
|
||||||
|
"out by default."
|
||||||
|
),
|
||||||
"DYNAMIC_CWD_WIDTH": VarDocs(
|
"DYNAMIC_CWD_WIDTH": VarDocs(
|
||||||
"Maximum length in number of characters "
|
"Maximum length in number of characters "
|
||||||
"or as a percentage for the ``cwd`` prompt variable. For example, "
|
"or as a percentage for the ``cwd`` prompt variable. For example, "
|
||||||
|
@ -570,6 +580,12 @@ def DEFAULT_DOCS():
|
||||||
"completion if set to anything truthy.",
|
"completion if set to anything truthy.",
|
||||||
configurable=ON_WINDOWS,
|
configurable=ON_WINDOWS,
|
||||||
),
|
),
|
||||||
|
"FOREIGN_ALIASES_SUPPRESS_SKIP_MESSAGE": VarDocs(
|
||||||
|
"Whether or not foreign aliases should suppress the message "
|
||||||
|
"that informs the user when a foreign alias has been skipped "
|
||||||
|
"because it already exists in xonsh.",
|
||||||
|
configurable=True,
|
||||||
|
),
|
||||||
"FOREIGN_ALIASES_OVERRIDE": VarDocs(
|
"FOREIGN_ALIASES_OVERRIDE": VarDocs(
|
||||||
"Whether or not foreign aliases should override xonsh aliases "
|
"Whether or not foreign aliases should override xonsh aliases "
|
||||||
"with the same name. Note that setting of this must happen in the "
|
"with the same name. Note that setting of this must happen in the "
|
||||||
|
|
|
@ -325,7 +325,7 @@ class ReadlineShell(BaseShell, cmd.Cmd):
|
||||||
(False, True, False, True, False): False,
|
(False, True, False, True, False): False,
|
||||||
(False, True, False, False, True): False,
|
(False, True, False, False, True): False,
|
||||||
(False, True, False, False, False): False,
|
(False, True, False, False, False): False,
|
||||||
(False, False, True, True, True): True,
|
(False, False, True, True, True): False,
|
||||||
(False, False, True, True, False): False,
|
(False, False, True, True, False): False,
|
||||||
(False, False, True, False, True): False,
|
(False, False, True, False, True): False,
|
||||||
(False, False, True, False, False): True,
|
(False, False, True, False, False): True,
|
||||||
|
|
|
@ -2086,45 +2086,84 @@ def expand_case_matching(s):
|
||||||
return "".join(t)
|
return "".join(t)
|
||||||
|
|
||||||
|
|
||||||
def globpath(s, ignore_case=False, return_empty=False, sort_result=None):
|
def globpath(
|
||||||
|
s, ignore_case=False, return_empty=False, sort_result=None, include_dotfiles=None
|
||||||
|
):
|
||||||
"""Simple wrapper around glob that also expands home and env vars."""
|
"""Simple wrapper around glob that also expands home and env vars."""
|
||||||
o, s = _iglobpath(s, ignore_case=ignore_case, sort_result=sort_result)
|
o, s = _iglobpath(
|
||||||
|
s,
|
||||||
|
ignore_case=ignore_case,
|
||||||
|
sort_result=sort_result,
|
||||||
|
include_dotfiles=include_dotfiles,
|
||||||
|
)
|
||||||
o = list(o)
|
o = list(o)
|
||||||
no_match = [] if return_empty else [s]
|
no_match = [] if return_empty else [s]
|
||||||
return o if len(o) != 0 else no_match
|
return o if len(o) != 0 else no_match
|
||||||
|
|
||||||
|
|
||||||
def _iglobpath(s, ignore_case=False, sort_result=None):
|
def _dotglobstr(s):
|
||||||
s = builtins.__xonsh__.expand_path(s)
|
modified = False
|
||||||
|
dotted_s = s
|
||||||
|
if "/*" in dotted_s:
|
||||||
|
dotted_s = dotted_s.replace("/*", "/.*")
|
||||||
|
dotted_s = dotted_s.replace("/.**/.*", "/**/.*")
|
||||||
|
modified = True
|
||||||
|
if dotted_s.startswith("*") and not dotted_s.startswith("**"):
|
||||||
|
dotted_s = "." + dotted_s
|
||||||
|
modified = True
|
||||||
|
return dotted_s, modified
|
||||||
|
|
||||||
|
|
||||||
|
def _iglobpath(s, ignore_case=False, sort_result=None, include_dotfiles=None):
|
||||||
|
s = builtins.__xonsh_expand_path__(s)
|
||||||
if sort_result is None:
|
if sort_result is None:
|
||||||
sort_result = builtins.__xonsh__.env.get("GLOB_SORTED")
|
sort_result = builtins.__xonsh__.env.get("GLOB_SORTED")
|
||||||
|
if include_dotfiles is None:
|
||||||
|
include_dotfiles = builtins.__xonsh__.env.get("DOTGLOB")
|
||||||
if ignore_case:
|
if ignore_case:
|
||||||
s = expand_case_matching(s)
|
s = expand_case_matching(s)
|
||||||
if sys.version_info > (3, 5):
|
if sys.version_info > (3, 5):
|
||||||
if "**" in s and "**/*" not in s:
|
if "**" in s and "**/*" not in s:
|
||||||
s = s.replace("**", "**/*")
|
s = s.replace("**", "**/*")
|
||||||
|
if include_dotfiles:
|
||||||
|
dotted_s, dotmodified = _dotglobstr(s)
|
||||||
# `recursive` is only a 3.5+ kwarg.
|
# `recursive` is only a 3.5+ kwarg.
|
||||||
if sort_result:
|
if sort_result:
|
||||||
paths = glob.glob(s, recursive=True)
|
paths = glob.glob(s, recursive=True)
|
||||||
|
if include_dotfiles and dotmodified:
|
||||||
|
paths.extend(glob.iglob(dotted_s, recursive=True))
|
||||||
paths.sort()
|
paths.sort()
|
||||||
paths = iter(paths)
|
paths = iter(paths)
|
||||||
else:
|
else:
|
||||||
paths = glob.iglob(s, recursive=True)
|
paths = glob.iglob(s, recursive=True)
|
||||||
|
if include_dotfiles and dotmodified:
|
||||||
|
paths = itertools.chain(glob.iglob(dotted_s, recursive=True), paths)
|
||||||
return paths, s
|
return paths, s
|
||||||
else:
|
else:
|
||||||
|
if include_dotfiles:
|
||||||
|
dotted_s, dotmodified = _dotglobstr(s)
|
||||||
if sort_result:
|
if sort_result:
|
||||||
paths = glob.glob(s)
|
paths = glob.glob(s)
|
||||||
|
if include_dotfiles and dotmodified:
|
||||||
|
paths.extend(glob.iglob(dotted_s))
|
||||||
paths.sort()
|
paths.sort()
|
||||||
paths = iter(paths)
|
paths = iter(paths)
|
||||||
else:
|
else:
|
||||||
paths = glob.iglob(s)
|
paths = glob.iglob(s)
|
||||||
|
if include_dotfiles and dotmodified:
|
||||||
|
paths = itertools.chain(glob.iglob(dotted_s), paths)
|
||||||
return paths, s
|
return paths, s
|
||||||
|
|
||||||
|
|
||||||
def iglobpath(s, ignore_case=False, sort_result=None):
|
def iglobpath(s, ignore_case=False, sort_result=None, include_dotfiles=None):
|
||||||
"""Simple wrapper around iglob that also expands home and env vars."""
|
"""Simple wrapper around iglob that also expands home and env vars."""
|
||||||
try:
|
try:
|
||||||
return _iglobpath(s, ignore_case=ignore_case, sort_result=sort_result)[0]
|
return _iglobpath(
|
||||||
|
s,
|
||||||
|
ignore_case=ignore_case,
|
||||||
|
sort_result=sort_result,
|
||||||
|
include_dotfiles=include_dotfiles,
|
||||||
|
)[0]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
# something went wrong in the actual iglob() call
|
# something went wrong in the actual iglob() call
|
||||||
return iter(())
|
return iter(())
|
||||||
|
|
Loading…
Add table
Reference in a new issue