resolved conflicts with master

This commit is contained in:
Anthony Scopatz 2018-09-13 10:38:17 -04:00
commit 6aa7aba36b
11 changed files with 166 additions and 10 deletions

17
news/dotglob.rst Normal file
View 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
View 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
View 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
View file

View file

View 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

View file

@ -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)

View file

@ -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,
) )

View file

@ -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 "

View file

@ -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,

View file

@ -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(())