mirror of
https://github.com/xonsh/xonsh.git
synced 2025-03-05 17:00:58 +01:00
Merge branch 'master' into stderr
This commit is contained in:
commit
5c57154577
10 changed files with 134 additions and 57 deletions
14
news/bashisms.rst
Normal file
14
news/bashisms.rst
Normal file
|
@ -0,0 +1,14 @@
|
|||
**Added:**
|
||||
|
||||
* New ``bashisms`` xontrib provides additional Bash-like syntax, such as ``!!``.
|
||||
This xontrib only affects the command line, and not xonsh scripts.
|
||||
|
||||
**Changed:** None
|
||||
|
||||
**Deprecated:** None
|
||||
|
||||
**Removed:** None
|
||||
|
||||
**Fixed:** None
|
||||
|
||||
**Security:** None
|
13
tests/test_bashisms.py
Normal file
13
tests/test_bashisms.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
"""Tests bashisms xontrib."""
|
||||
import pytest
|
||||
|
||||
@pytest.mark.parametrize('inp, exp', [
|
||||
('x = 42', 'x = 42'),
|
||||
('!!', 'ls'),
|
||||
])
|
||||
def test_preproc(inp, exp, xonsh_builtins):
|
||||
"""Test the bash preprocessor."""
|
||||
from xontrib.bashisms import bash_preproc
|
||||
xonsh_builtins.__xonsh_history__.inps = ['ls\n']
|
||||
obs = bash_preproc(inp)
|
||||
assert exp == obs
|
|
@ -146,7 +146,6 @@ def test_test_repo(test_repo):
|
|||
dotdir = os.path.isdir(os.path.join(test_repo['dir'],
|
||||
'.{}'.format(test_repo['name'])))
|
||||
assert dotdir
|
||||
|
||||
if test_repo['name'] == 'git':
|
||||
assert os.path.isfile(os.path.join(test_repo['dir'], 'test-file'))
|
||||
|
||||
|
@ -156,7 +155,8 @@ def test_vc_get_branch(test_repo, xonsh_builtins):
|
|||
# get corresponding function from vc module
|
||||
fun = 'get_{}_branch'.format(test_repo['name'])
|
||||
obs = getattr(vc, fun)()
|
||||
assert obs == VC_BRANCH[test_repo['name']]
|
||||
if obs is not None:
|
||||
assert obs == VC_BRANCH[test_repo['name']]
|
||||
|
||||
|
||||
def test_current_branch_calls_locate_binary_for_empty_cmds_cache(xonsh_builtins):
|
||||
|
@ -164,9 +164,7 @@ def test_current_branch_calls_locate_binary_for_empty_cmds_cache(xonsh_builtins)
|
|||
xonsh_builtins.__xonsh_env__ = DummyEnv(VC_BRANCH_TIMEOUT=1)
|
||||
cache.is_empty = Mock(return_value=True)
|
||||
cache.locate_binary = Mock(return_value='')
|
||||
|
||||
vc.current_branch()
|
||||
|
||||
assert cache.locate_binary.called
|
||||
|
||||
|
||||
|
@ -177,7 +175,5 @@ def test_current_branch_does_not_call_locate_binary_for_non_empty_cmds_cache(xon
|
|||
cache.locate_binary = Mock(return_value='')
|
||||
# make lazy locate return nothing to avoid running vc binaries
|
||||
cache.lazy_locate_binary = Mock(return_value='')
|
||||
|
||||
vc.current_branch()
|
||||
|
||||
assert not cache.locate_binary.called
|
||||
|
|
|
@ -55,8 +55,6 @@ else:
|
|||
_sys.modules['xonsh.proc'] = __amalgam__
|
||||
xontribs = __amalgam__
|
||||
_sys.modules['xonsh.xontribs'] = __amalgam__
|
||||
base_shell = __amalgam__
|
||||
_sys.modules['xonsh.base_shell'] = __amalgam__
|
||||
dirstack = __amalgam__
|
||||
_sys.modules['xonsh.dirstack'] = __amalgam__
|
||||
history = __amalgam__
|
||||
|
@ -67,8 +65,6 @@ else:
|
|||
_sys.modules['xonsh.xonfig'] = __amalgam__
|
||||
environ = __amalgam__
|
||||
_sys.modules['xonsh.environ'] = __amalgam__
|
||||
readline_shell = __amalgam__
|
||||
_sys.modules['xonsh.readline_shell'] = __amalgam__
|
||||
tracer = __amalgam__
|
||||
_sys.modules['xonsh.tracer'] = __amalgam__
|
||||
replay = __amalgam__
|
||||
|
@ -83,8 +79,12 @@ else:
|
|||
_sys.modules['xonsh.imphooks'] = __amalgam__
|
||||
shell = __amalgam__
|
||||
_sys.modules['xonsh.shell'] = __amalgam__
|
||||
base_shell = __amalgam__
|
||||
_sys.modules['xonsh.base_shell'] = __amalgam__
|
||||
main = __amalgam__
|
||||
_sys.modules['xonsh.main'] = __amalgam__
|
||||
readline_shell = __amalgam__
|
||||
_sys.modules['xonsh.readline_shell'] = __amalgam__
|
||||
del __amalgam__
|
||||
except ImportError:
|
||||
pass
|
||||
|
|
|
@ -15,6 +15,7 @@ from xonsh.codecache import (should_use_cache, code_cache_name,
|
|||
from xonsh.completer import Completer
|
||||
from xonsh.prompt.base import multiline_prompt, PromptFormatter
|
||||
from xonsh.events import events
|
||||
from xonsh.shell import fire_precommand
|
||||
|
||||
if ON_WINDOWS:
|
||||
import ctypes
|
||||
|
@ -307,7 +308,6 @@ class BaseShell(object):
|
|||
src, code = self.push(line)
|
||||
if code is None:
|
||||
return
|
||||
events.on_precommand.fire(src)
|
||||
env = builtins.__xonsh_env__
|
||||
hist = builtins.__xonsh_history__ # pylint: disable=no-member
|
||||
ts1 = None
|
||||
|
@ -355,14 +355,12 @@ class BaseShell(object):
|
|||
info['out'] = last_out
|
||||
else:
|
||||
info['out'] = tee_out + '\n' + last_out
|
||||
|
||||
events.on_postcommand.fire(
|
||||
info['inp'],
|
||||
info['rtn'],
|
||||
info.get('out', None),
|
||||
info['ts']
|
||||
)
|
||||
|
||||
)
|
||||
hist.append(info)
|
||||
hist.last_cmd_rtn = hist.last_cmd_out = None
|
||||
|
||||
|
@ -380,11 +378,17 @@ class BaseShell(object):
|
|||
"""Pushes a line onto the buffer and compiles the code in a way that
|
||||
enables multiline input.
|
||||
"""
|
||||
code = None
|
||||
self.buffer.append(line)
|
||||
if self.need_more_lines:
|
||||
return None, code
|
||||
return None, None
|
||||
src = ''.join(self.buffer)
|
||||
src = fire_precommand(src)
|
||||
return self.compile(src)
|
||||
|
||||
def compile(self, src):
|
||||
"""Compiles source code and returns the (possibly modified) source and
|
||||
a valid code object.
|
||||
"""
|
||||
_cache = should_use_cache(self.execer, 'single')
|
||||
if _cache:
|
||||
codefname = code_cache_name(src)
|
||||
|
@ -405,7 +409,7 @@ class BaseShell(object):
|
|||
partial_string_info = check_for_partial_string(src)
|
||||
in_partial_string = (partial_string_info[0] is not None and
|
||||
partial_string_info[1] is None)
|
||||
if ((line == '\n' and not in_partial_string)):
|
||||
if (src == '\n' or src.endswith('\n\n')) and not in_partial_string:
|
||||
self.reset_buffer()
|
||||
print_exception()
|
||||
return src, None
|
||||
|
|
|
@ -6,8 +6,10 @@ from prompt_toolkit.enums import DEFAULT_BUFFER
|
|||
from prompt_toolkit.filters import (Condition, IsMultiline, HasSelection,
|
||||
EmacsInsertMode, ViInsertMode)
|
||||
from prompt_toolkit.keys import Keys
|
||||
|
||||
from xonsh.aliases import xonsh_exit
|
||||
from xonsh.tools import ON_WINDOWS, check_for_partial_string
|
||||
from xonsh.shell import fire_precommand
|
||||
|
||||
env = builtins.__xonsh_env__
|
||||
DEDENT_TOKENS = frozenset(['raise', 'return', 'pass', 'break', 'continue'])
|
||||
|
@ -70,6 +72,7 @@ def _is_blank(l):
|
|||
def can_compile(src):
|
||||
"""Returns whether the code can be compiled, i.e. it is valid xonsh."""
|
||||
src = src if src.endswith('\n') else src + '\n'
|
||||
src = fire_precommand(src, show_diff=False)
|
||||
src = src.lstrip()
|
||||
try:
|
||||
builtins.__xonsh_execer__.compile(src, mode='single', glbs=None,
|
||||
|
|
|
@ -30,13 +30,11 @@ class PromptToolkitShell(BaseShell):
|
|||
self.prompter = Prompter()
|
||||
self.history = PromptToolkitHistory()
|
||||
self.pt_completer = PromptToolkitCompleter(self.completer, self.ctx)
|
||||
|
||||
key_bindings_manager_args = {
|
||||
'enable_auto_suggest_bindings': True,
|
||||
'enable_search': True,
|
||||
'enable_abort_and_exit_bindings': True,
|
||||
}
|
||||
|
||||
'enable_auto_suggest_bindings': True,
|
||||
'enable_search': True,
|
||||
'enable_abort_and_exit_bindings': True,
|
||||
}
|
||||
self.key_bindings_manager = KeyBindingManager(**key_bindings_manager_args)
|
||||
load_xonsh_bindings(self.key_bindings_manager)
|
||||
|
||||
|
@ -92,7 +90,7 @@ class PromptToolkitShell(BaseShell):
|
|||
line = self.prompter.prompt(**prompt_args)
|
||||
return line
|
||||
|
||||
def push(self, line):
|
||||
def _push(self, line):
|
||||
"""Pushes a line onto the buffer and compiles the code in a way that
|
||||
enables multiline input.
|
||||
"""
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""The xonsh shell"""
|
||||
import os
|
||||
import sys
|
||||
import random
|
||||
import difflib
|
||||
import builtins
|
||||
import warnings
|
||||
|
||||
|
@ -10,12 +12,12 @@ from xonsh.environ import xonshrc_context
|
|||
from xonsh.execer import Execer
|
||||
from xonsh.platform import (best_shell_type, has_prompt_toolkit,
|
||||
ptk_version_is_supported)
|
||||
from xonsh.tools import XonshError, to_bool_or_int
|
||||
from xonsh.tools import XonshError, to_bool_or_int, print_exception
|
||||
from xonsh.events import events
|
||||
|
||||
|
||||
events.doc('on_precommand', """
|
||||
on_precommand(cmd: str) -> None
|
||||
on_precommand(cmd: str) -> str
|
||||
|
||||
Fires just before a command is executed.
|
||||
""")
|
||||
|
@ -27,6 +29,34 @@ Fires just after a command is executed.
|
|||
""")
|
||||
|
||||
|
||||
def fire_precommand(src, show_diff=True):
|
||||
"""Returns the results of firing the precommand handles."""
|
||||
i = 0
|
||||
limit = sys.getrecursionlimit()
|
||||
lst = ''
|
||||
raw = src
|
||||
while src != lst:
|
||||
lst = src
|
||||
srcs = events.on_precommand.fire(src)
|
||||
for s in srcs:
|
||||
if s != lst:
|
||||
src = s
|
||||
break
|
||||
i += 1
|
||||
if i == limit:
|
||||
print_exception('Modifcations to source input took more than '
|
||||
'the recursion limit number of interations to '
|
||||
'converge.')
|
||||
if show_diff and builtins.__xonsh_env__.get('XONSH_DEBUG') and src != raw:
|
||||
sys.stderr.writelines(difflib.unified_diff(
|
||||
raw.splitlines(keepends=True),
|
||||
src.splitlines(keepends=True),
|
||||
fromfile='before precommand event',
|
||||
tofile='after precommand event',
|
||||
))
|
||||
return src
|
||||
|
||||
|
||||
class Shell(object):
|
||||
"""Main xonsh shell.
|
||||
|
||||
|
|
|
@ -1,4 +1,28 @@
|
|||
{"xontribs": [
|
||||
{"name": "apt_tabcomplete",
|
||||
"package": "xonsh-apt-tabcomplete",
|
||||
"url": "https://github.com/DangerOnTheRanger/xonsh-apt-tabcomplete",
|
||||
"description": ["Adds tabcomplete functionality to apt-get/apt-cache inside of xonsh."]
|
||||
},
|
||||
{"name": "autoxsh",
|
||||
"package": "xonsh-autoxsh",
|
||||
"url": "https://github.com/Granitas/xonsh-autoxsh",
|
||||
"description": ["Adds automatic execution of xonsh script files called",
|
||||
"``.autoxsh`` when enterting a directory with ``cd`` function"]
|
||||
},
|
||||
{"name": "bashisms",
|
||||
"package": "xonsh",
|
||||
"url": "http://xon.sh",
|
||||
"description": [
|
||||
"Enables additional Bash-like syntax while at the command prompt. For ",
|
||||
"example, the ``!!`` syntax for running the previous command is now usable.",
|
||||
"Note that these features are implemented as precommand events and these ",
|
||||
"additions do not affect the xonsh language when run as script. That said, ",
|
||||
"you might find them useful if you have strong muscle memory.\n\n",
|
||||
"**Warning:** This xontrib may modify user command line input to implement ",
|
||||
"its behavior. To see the modifications as they are applied (in unified diff",
|
||||
"format), please set ``$XONSH_DEBUG = True``."]
|
||||
},
|
||||
{"name": "distributed",
|
||||
"package": "xonsh",
|
||||
"url": "http://xon.sh",
|
||||
|
@ -16,22 +40,37 @@
|
|||
" print(res)\n\n",
|
||||
"This is useful for long running or non-blocking jobs."]
|
||||
},
|
||||
{"name": "docker_tabcomplete",
|
||||
"package": "xonsh-docker-tabcomplete",
|
||||
"url": "https://github.com/xsteadfastx/xonsh-docker-tabcomplete",
|
||||
"description": ["Adds tabcomplete functionality to docker inside of xonsh."]
|
||||
},
|
||||
{"name": "mpl",
|
||||
"package": "xonsh",
|
||||
"url": "http://xon.sh",
|
||||
"description": ["Matplotlib hooks for xonsh, including the new 'mpl' alias ",
|
||||
"that displays the current figure on the screen."]
|
||||
},
|
||||
{"name": "prompt_ret_code",
|
||||
"package": "xonsh",
|
||||
"url": "http://xon.sh",
|
||||
"description": ["Adds return code info to the prompt"]
|
||||
},
|
||||
{"name": "scrapy_tabcomplete",
|
||||
"package": "xonsh-scrapy-tabcomplete",
|
||||
"url": "https://github.com/Granitas/xonsh-scrapy-tabcomplete",
|
||||
"description": ["Adds tabcomplete functionality to scrapy inside of xonsh."]
|
||||
},
|
||||
{"name": "vox",
|
||||
"package": "xonsh",
|
||||
"url": "http://xon.sh",
|
||||
"description": ["Python virtual environment manager for xonsh."]
|
||||
},
|
||||
{"name": "prompt_ret_code",
|
||||
"package": "xonsh",
|
||||
"url": "http://xon.sh",
|
||||
"description": ["Adds return code info to the prompt"]
|
||||
},
|
||||
{"name": "vox_tabcomplete",
|
||||
"package": "xonsh-vox-tabcomplete",
|
||||
"url": "https://github.com/Granitas/xonsh-vox-tabcomplete",
|
||||
"description": ["Adds tabcomplete functionality to vox inside of xonsh."]
|
||||
},
|
||||
{"name": "xo",
|
||||
"package": "exofrills",
|
||||
"url": "https://github.com/scopatz/xo",
|
||||
|
@ -40,32 +79,6 @@
|
|||
"bit of the startup time when running your favorite, minimal ",
|
||||
"text editor."]
|
||||
},
|
||||
{"name": "apt_tabcomplete",
|
||||
"package": "xonsh-apt-tabcomplete",
|
||||
"url": "https://github.com/DangerOnTheRanger/xonsh-apt-tabcomplete",
|
||||
"description": ["Adds tabcomplete functionality to apt-get/apt-cache inside of xonsh."]
|
||||
},
|
||||
{"name": "docker_tabcomplete",
|
||||
"package": "xonsh-docker-tabcomplete",
|
||||
"url": "https://github.com/xsteadfastx/xonsh-docker-tabcomplete",
|
||||
"description": ["Adds tabcomplete functionality to docker inside of xonsh."]
|
||||
},
|
||||
{"name": "scrapy_tabcomplete",
|
||||
"package": "xonsh-scrapy-tabcomplete",
|
||||
"url": "https://github.com/Granitas/xonsh-scrapy-tabcomplete",
|
||||
"description": ["Adds tabcomplete functionality to scrapy inside of xonsh."]
|
||||
},
|
||||
{"name": "vox_tabcomplete",
|
||||
"package": "xonsh-vox-tabcomplete",
|
||||
"url": "https://github.com/Granitas/xonsh-vox-tabcomplete",
|
||||
"description": ["Adds tabcomplete functionality to vox inside of xonsh."]
|
||||
},
|
||||
{"name": "autoxsh",
|
||||
"package": "xonsh-autoxsh",
|
||||
"url": "https://github.com/Granitas/xonsh-autoxsh",
|
||||
"description": ["Adds automatic execution of xonsh script files called",
|
||||
"`.autoxsh` when enterting a directory with `cd` function"]
|
||||
},
|
||||
{"name": "xonda",
|
||||
"package": "xonda",
|
||||
"url": "https://github.com/gforsyth/xonda",
|
||||
|
|
6
xontrib/bashisms.py
Normal file
6
xontrib/bashisms.py
Normal file
|
@ -0,0 +1,6 @@
|
|||
"""Bash-like interface extensions for xonsh."""
|
||||
|
||||
|
||||
@events.on_precommand
|
||||
def bash_preproc(cmd):
|
||||
return cmd.replace('!!', __xonsh_history__.inps[-1].strip())
|
Loading…
Add table
Reference in a new issue