mirror of
https://github.com/xonsh/xonsh.git
synced 2025-03-04 08:24:40 +01:00
cl fix
This commit is contained in:
commit
230174235d
19 changed files with 332 additions and 70 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -33,3 +33,6 @@ include/
|
|||
|
||||
# Mac
|
||||
.DS_Store
|
||||
|
||||
# Editor project files
|
||||
*.komodo*
|
||||
|
|
|
@ -3,6 +3,6 @@ python:
|
|||
- 3.4
|
||||
- 3.5
|
||||
install:
|
||||
- pip install ply nose pygments prompt_toolkit
|
||||
- pip install -r requirements-tests.txt
|
||||
script:
|
||||
- nosetests -q
|
||||
|
|
|
@ -15,7 +15,9 @@ Current Developments
|
|||
on Windows. This functionality can be enabled/disabled with the
|
||||
$INTENSIFY_COLORS_ON_WIN environment variable.
|
||||
* Added ``Ellipsis`` lookup to ``__xonsh_env__`` to allow environment variable checks, e.g. ``'HOME' in ${...}``
|
||||
|
||||
* Added an option to update ``os.environ`` every time the xonsh environment changes.
|
||||
This disabled by default, but can be enabled by setting ``$UPDATE_OS_ENVIRON`` to
|
||||
True.
|
||||
|
||||
**Changed:**
|
||||
|
||||
|
@ -25,6 +27,9 @@ Current Developments
|
|||
loading bash completions.
|
||||
* rc files are now compiled and cached, to avoid re-parsing when they haven't
|
||||
changed.
|
||||
* Left and Right arrows in the ``prompt_toolkit`` shell now wrap in multiline
|
||||
environments
|
||||
* Regexpath matching with backticks, now returns an empty list in python mode.
|
||||
|
||||
**Deprecated:** None
|
||||
|
||||
|
@ -33,9 +38,11 @@ Current Developments
|
|||
**Fixed:**
|
||||
|
||||
* Fixed bug with loading prompt-toolkit shell < v0.57.
|
||||
* Fixed bug with prompt-toolkit completion when the cursor is not at the end of the line
|
||||
|
||||
**Security:** None
|
||||
|
||||
|
||||
v0.2.7
|
||||
====================
|
||||
**Added:**
|
||||
|
@ -82,7 +89,6 @@ v0.2.7
|
|||
argument to be deleted.
|
||||
|
||||
|
||||
|
||||
**Removed:**
|
||||
|
||||
* The ``xonsh.tools.TERM_COLORS`` mapping has been axed, along with all
|
||||
|
|
24
docs/add_to_shell.rst
Normal file
24
docs/add_to_shell.rst
Normal file
|
@ -0,0 +1,24 @@
|
|||
Additional Setup
|
||||
================
|
||||
|
||||
If you want to use xonsh as your default shell, you will first have to add xonsh to `/etc/shells`.
|
||||
|
||||
First ensure that xonsh is on your ``$PATH``
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ which xonsh
|
||||
|
||||
Then, as root, add xonsh to the shell list
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# echo $(which xonsh) >> /etc/shells
|
||||
|
||||
To change shells, run
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ chsh -s $(which xonsh)
|
||||
|
||||
You will have to log out and log back in before the changes take effect.
|
|
@ -59,4 +59,5 @@ For those of you who want the gritty details.
|
|||
jupyter_kernel
|
||||
wizard
|
||||
xonfig
|
||||
vox
|
||||
|
||||
|
|
17
docs/dependencies.rst
Normal file
17
docs/dependencies.rst
Normal file
|
@ -0,0 +1,17 @@
|
|||
Dependencies
|
||||
============
|
||||
Xonsh currently has the following external dependencies,
|
||||
|
||||
*Run Time:*
|
||||
|
||||
#. Python v3.4+
|
||||
#. PLY
|
||||
#. prompt-toolkit (optional)
|
||||
#. Jupyter (optional)
|
||||
#. setproctitle (optional)
|
||||
|
||||
*Documentation:*
|
||||
|
||||
#. `Sphinx <http://sphinx-doc.org/>`_ (which uses `reStructuredText <http://sphinx-doc.org/rest.html>`_)
|
||||
#. Numpydoc
|
||||
#. Cloud Sphinx Theme
|
|
@ -74,10 +74,34 @@ If you want to lint the entire code base run::
|
|||
|
||||
How to Test
|
||||
================
|
||||
First, install nose: http://nose.readthedocs.org/en/latest/. Second, ensure
|
||||
your cwd is the root directory of the project (i.e., the one containing the
|
||||
|
||||
Ensure your cwd is the root directory of the project (i.e., the one containing the
|
||||
.git directory).
|
||||
|
||||
----------------------------------
|
||||
Dependencies
|
||||
----------------------------------
|
||||
|
||||
Prep your environment for running the tests::
|
||||
|
||||
$ pip install requirements-tests.txt
|
||||
|
||||
|
||||
----------------------------------
|
||||
Running the Tests - Basic
|
||||
----------------------------------
|
||||
|
||||
Run all the tests using Nose::
|
||||
|
||||
$ nosetests -q
|
||||
|
||||
Use "-q" to keep nose from outputing a dot for every test. There are A LOT of tests
|
||||
and you will waste time waiting for all the dots to get pushed through stdout.
|
||||
|
||||
----------------------------------
|
||||
Running the Tests - Advanced
|
||||
----------------------------------
|
||||
|
||||
To perform all unit tests::
|
||||
|
||||
$ scripts/run_tests.xsh all
|
||||
|
|
|
@ -93,6 +93,6 @@ manually use the ``$[]`` or ``$()`` operators on your code.
|
|||
|
||||
5. Context-sensitive parsing is gross
|
||||
--------------------------------------
|
||||
Yes, context-sensitive parsing is gross. But the point of xonsh is that it
|
||||
Yes, context-sensitive parsing is gross. But the point of xonsh is that it uses xontext-sensitive parsing and
|
||||
is ultimately a lot less gross than other shell languages, such as BASH.
|
||||
Furthermore, its use is heavily limited here.
|
||||
|
|
|
@ -72,6 +72,16 @@ alike.
|
|||
=========
|
||||
Contents
|
||||
=========
|
||||
**Installation:**
|
||||
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
:maxdepth: 1
|
||||
|
||||
linux
|
||||
osx
|
||||
windows
|
||||
|
||||
**Guides:**
|
||||
|
||||
.. toctree::
|
||||
|
@ -106,52 +116,6 @@ Contents
|
|||
faq
|
||||
todo
|
||||
|
||||
============
|
||||
Installation
|
||||
============
|
||||
You can install xonsh using conda, pip, or from source.
|
||||
|
||||
**conda:**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ conda install -c xonsh xonsh
|
||||
|
||||
.. note:: For the bleeding edge development version use ``conda install -c xonsh/channel/dev xonsh``
|
||||
|
||||
|
||||
**pip:**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ pip install xonsh
|
||||
|
||||
**source:** Download the source `from github <https://github.com/scopatz/xonsh>`_
|
||||
(`zip file <https://github.com/scopatz/xonsh/archive/master.zip>`_), then run
|
||||
the following from the source directory,
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python setup.py install
|
||||
|
||||
Arch Linux users can install xonsh from the Arch User Repository with e.g.
|
||||
yaourt or aura:
|
||||
|
||||
**yaourt:**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ yaourt -Sa xonsh # yaourt will call sudo when needed
|
||||
|
||||
**aura:**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ sudo aura -A xonsh
|
||||
|
||||
If you run into any problems, please let us know!
|
||||
|
||||
|
||||
==========
|
||||
Comparison
|
||||
==========
|
||||
|
@ -264,8 +228,7 @@ Xonsh currently has the following external dependencies,
|
|||
|
||||
*Documentation:*
|
||||
|
||||
#. `Sphinx <http://sphinx-doc.org/>` (which uses
|
||||
`reStructuredText <http://sphinx-doc.org/rest.html>`)
|
||||
#. `Sphinx <http://sphinx-doc.org/>`_ (which uses `reStructuredText <http://sphinx-doc.org/rest.html>`_)
|
||||
#. Numpydoc
|
||||
#. Cloud Sphinx Theme
|
||||
|
||||
|
|
60
docs/linux.rst
Normal file
60
docs/linux.rst
Normal file
|
@ -0,0 +1,60 @@
|
|||
==========================
|
||||
Linux Guide
|
||||
==========================
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
You can install xonsh using ``conda``, ``pip``, or from source.
|
||||
|
||||
**conda:**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ conda install -c xonsh xonsh
|
||||
|
||||
.. note:: For the bleeding edge development version use ``conda install -c xonsh/channel/dev xonsh``
|
||||
|
||||
|
||||
**pip:**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ pip install xonsh
|
||||
|
||||
|
||||
**source:** Download the source `from github <https://github.com/scopatz/xonsh>`_
|
||||
(`zip file <https://github.com/scopatz/xonsh/archive/master.zip>`_), then run
|
||||
the following from the source directory,
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python setup.py install
|
||||
|
||||
|
||||
Arch Linux users can install xonsh from the Arch User Repository with e.g.
|
||||
``yaourt``, ``aura``, ``pacaur``, ``PKGBUILD``, etc...:
|
||||
|
||||
**yaourt:**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ yaourt -Sa xonsh # yaourt will call sudo when needed
|
||||
|
||||
**aura:**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ sudo aura -A xonsh
|
||||
|
||||
**pacaur:**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ pacaur -S xonsh
|
||||
|
||||
If you run into any problems, please let us know!
|
||||
|
||||
.. include:: add_to_shell.rst
|
||||
|
||||
.. include:: dependencies.rst
|
37
docs/osx.rst
Normal file
37
docs/osx.rst
Normal file
|
@ -0,0 +1,37 @@
|
|||
==========================
|
||||
OSX Guide
|
||||
==========================
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
You can install xonsh using conda, pip, or from source.
|
||||
|
||||
**conda:**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ conda install -c xonsh xonsh
|
||||
|
||||
.. note:: For the bleeding edge development version use ``conda install -c xonsh/channel/dev xonsh``
|
||||
|
||||
|
||||
**pip:**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ pip install xonsh
|
||||
|
||||
|
||||
**source:** Download the source `from github <https://github.com/scopatz/xonsh>`_
|
||||
(`zip file <https://github.com/scopatz/xonsh/archive/master.zip>`_), then run
|
||||
the following from the source directory,
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python setup.py install
|
||||
|
||||
|
||||
.. include:: add_to_shell.rst
|
||||
|
||||
.. include:: dependencies.rst
|
|
@ -134,9 +134,31 @@ variable in Python. The same is true for deleting them too.
|
|||
Become the Lord of the Files
|
||||
>>> del $GOAL
|
||||
|
||||
Very nice. All environment variables live in the built-in
|
||||
``__xonsh_env__`` mapping. You can access this mapping directly, but in most
|
||||
situations, you shouldn't need to.
|
||||
Very nice.
|
||||
|
||||
__xonsh_env__
|
||||
--------------
|
||||
|
||||
All environment variables live in the built-in ``__xonsh_env__`` mapping. You can access this
|
||||
mapping directly, but in most situations, you shouldn't need to.
|
||||
|
||||
One helpful method on the __xonsh_env__ is :func:`~xonsh.environ.Env.swap`. It can be used to temporarily set an
|
||||
environment variable:
|
||||
|
||||
|
||||
.. code-block:: xonshcon
|
||||
|
||||
>>> with __xonsh_env__.swap(SOMEVAR='foo'):
|
||||
... echo $SOMEVAR
|
||||
...
|
||||
...
|
||||
foo
|
||||
>>> echo $SOMEVAR
|
||||
|
||||
>>>
|
||||
|
||||
Environment Types
|
||||
-----------------
|
||||
|
||||
Like other variables in Python, environment variables have a type. Sometimes
|
||||
this type is imposed based on the variable name. The current rules are pretty
|
||||
|
|
4
requirements-tests.txt
Normal file
4
requirements-tests.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
ply
|
||||
nose
|
||||
prompt-toolkit
|
||||
pygments
|
|
@ -72,5 +72,35 @@ def test_HISTCONTROL():
|
|||
assert_true('ignoreerr' in env['HISTCONTROL'])
|
||||
assert_true('ignoredups' in env['HISTCONTROL'])
|
||||
|
||||
def test_swap():
|
||||
|
||||
env = Env(VAR='wakka')
|
||||
assert_equal(env['VAR'], 'wakka')
|
||||
|
||||
# positional arg
|
||||
with env.swap({'VAR': 'foo'}):
|
||||
assert_equal(env['VAR'], 'foo')
|
||||
|
||||
# make sure the environment goes back outside the context manager
|
||||
assert_equal(env['VAR'], 'wakka')
|
||||
|
||||
# kwargs only
|
||||
with env.swap(VAR1='foo', VAR2='bar'):
|
||||
assert_equal(env['VAR1'], 'foo')
|
||||
assert_equal(env['VAR2'], 'bar')
|
||||
|
||||
# positional and kwargs
|
||||
with env.swap({'VAR3': 'baz'}, VAR1='foo', VAR2='bar'):
|
||||
assert_equal(env['VAR1'], 'foo')
|
||||
assert_equal(env['VAR2'], 'bar')
|
||||
assert_equal(env['VAR3'], 'baz')
|
||||
|
||||
# make sure the environment goes back outside the context manager
|
||||
assert_equal(env['VAR'], 'wakka')
|
||||
assert 'VAR1' not in env
|
||||
assert 'VAR2' not in env
|
||||
assert 'VAR3' not in env
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
nose.runmodule()
|
||||
|
|
|
@ -266,13 +266,14 @@ def reglob(path, parts=None, i=None):
|
|||
return paths
|
||||
|
||||
|
||||
def regexpath(s):
|
||||
def regexpath(s, pymode=False):
|
||||
"""Takes a regular expression string and returns a list of file
|
||||
paths that match the regex.
|
||||
"""
|
||||
s = expand_path(s)
|
||||
o = reglob(s)
|
||||
return o if len(o) != 0 else [s]
|
||||
no_match = [] if pymode else [s]
|
||||
return o if len(o) != 0 else no_match
|
||||
|
||||
|
||||
def globpath(s, ignore_case=False):
|
||||
|
|
|
@ -85,6 +85,7 @@ DEFAULT_ENSURERS = {
|
|||
'RAISE_SUBPROC_ERROR': (is_bool, to_bool, bool_to_str),
|
||||
'RIGHT_PROMPT': (is_string, ensure_string, ensure_string),
|
||||
'TEEPTY_PIPE_DELAY': (is_float, float, str),
|
||||
'UPDATE_OS_ENVIRON': (is_bool, to_bool, bool_to_str),
|
||||
'XONSHRC': (is_env_path, str_to_env_path, env_path_to_str),
|
||||
'XONSH_COLOR_STYLE': (is_string, ensure_string, ensure_string),
|
||||
'XONSH_ENCODING': (is_string, ensure_string, ensure_string),
|
||||
|
@ -194,6 +195,7 @@ DEFAULT_VALUES = {
|
|||
'SUGGEST_THRESHOLD': 3,
|
||||
'TEEPTY_PIPE_DELAY': 0.01,
|
||||
'TITLE': DEFAULT_TITLE,
|
||||
'UPDATE_OS_ENVIRON': False,
|
||||
'VI_MODE': False,
|
||||
'WIN_UNICODE_CONSOLE': True,
|
||||
'XDG_CONFIG_HOME': os.path.expanduser(os.path.join('~', '.config')),
|
||||
|
@ -394,6 +396,9 @@ DEFAULT_DOCS = {
|
|||
"in the same manner as $PROMPT, see 'Customizing the Prompt' "
|
||||
'http://xon.sh/tutorial.html#customizing-the-prompt.',
|
||||
default='xonsh.environ.DEFAULT_TITLE'),
|
||||
'UPDATE_OS_ENVIRON': VarDocs("If True os.environ will always be updated "
|
||||
"when the xonsh environment changes. The environment can be reset to "
|
||||
"the default value by calling '__xonsh_env__.undo_replace_env()'"),
|
||||
'VI_MODE': VarDocs(
|
||||
"Flag to enable 'vi_mode' in the 'prompt_toolkit' shell."),
|
||||
'VIRTUAL_ENV': VarDocs(
|
||||
|
@ -491,6 +496,7 @@ class Env(MutableMapping):
|
|||
def __init__(self, *args, **kwargs):
|
||||
"""If no initial environment is given, os.environ is used."""
|
||||
self._d = {}
|
||||
self._orig_env = None
|
||||
self.ensurers = {k: Ensurer(*v) for k, v in DEFAULT_ENSURERS.items()}
|
||||
self.defaults = DEFAULT_VALUES
|
||||
self.docs = DEFAULT_DOCS
|
||||
|
@ -499,14 +505,17 @@ class Env(MutableMapping):
|
|||
for key, val in dict(*args, **kwargs).items():
|
||||
self[key] = val
|
||||
self._detyped = None
|
||||
self._orig_env = None
|
||||
|
||||
|
||||
@staticmethod
|
||||
def detypeable(val):
|
||||
return not (callable(val) or isinstance(val, MutableMapping))
|
||||
|
||||
def detype(self):
|
||||
if self._detyped is not None:
|
||||
return self._detyped
|
||||
ctx = {}
|
||||
for key, val in self._d.items():
|
||||
if callable(val) or isinstance(val, MutableMapping):
|
||||
if not self.detypeable(val):
|
||||
continue
|
||||
if not isinstance(key, string_types):
|
||||
key = str(key)
|
||||
|
@ -563,16 +572,27 @@ class Env(MutableMapping):
|
|||
return vd
|
||||
|
||||
@contextmanager
|
||||
def swap(self, other):
|
||||
def swap(self, other=None, **kwargs):
|
||||
"""Provides a context manager for temporarily swapping out certain
|
||||
environment variables with other values. On exit from the context
|
||||
manager, the original values are restored.
|
||||
"""
|
||||
old = {}
|
||||
for k, v in other.items():
|
||||
|
||||
# single positional argument should be a dict-like object
|
||||
if other is not None:
|
||||
for k, v in other.items():
|
||||
old[k] = self.get(k, NotImplemented)
|
||||
self[k] = v
|
||||
|
||||
# kwargs could also have been sent in
|
||||
for k, v in kwargs.items():
|
||||
old[k] = self.get(k, NotImplemented)
|
||||
self[k] = v
|
||||
|
||||
yield self
|
||||
|
||||
# restore the values
|
||||
for k, v in old.items():
|
||||
if v is NotImplemented:
|
||||
del self[k]
|
||||
|
@ -613,12 +633,23 @@ class Env(MutableMapping):
|
|||
if not ensurer.validate(val):
|
||||
val = ensurer.convert(val)
|
||||
self._d[key] = val
|
||||
self._detyped = None
|
||||
|
||||
if self.detypeable(val):
|
||||
self._detyped = None
|
||||
if self.get('UPDATE_OS_ENVIRON'):
|
||||
if self._orig_env is None:
|
||||
self.replace_env()
|
||||
else:
|
||||
dval = ensurer.detype(val)
|
||||
os.environ[key] = dval
|
||||
|
||||
def __delitem__(self, key):
|
||||
del self._d[key]
|
||||
self._detyped = None
|
||||
|
||||
val = self._d.pop(key)
|
||||
if self.detypeable(val):
|
||||
self._detyped = None
|
||||
if self.get('UPDATE_OS_ENVIRON'):
|
||||
if key in os.environ:
|
||||
del os.environ[key]
|
||||
|
||||
def get(self, key, default=None):
|
||||
"""The environment will look up default values from its own defaults if a
|
||||
default is not given here.
|
||||
|
|
|
@ -25,7 +25,7 @@ class PromptToolkitCompleter(Completer):
|
|||
if complete_event.completion_requested:
|
||||
line = document.current_line.lstrip()
|
||||
endidx = document.cursor_position_col
|
||||
begidx = line.rfind(' ') + 1 if line.rfind(' ') >= 0 else 0
|
||||
begidx = line[:endidx].rfind(' ') + 1 if line[:endidx].rfind(' ') >= 0 else 0
|
||||
prefix = line[begidx:endidx]
|
||||
completions, l = self.completer.complete(prefix,
|
||||
line,
|
||||
|
|
|
@ -70,6 +70,28 @@ class TabShouldInsertIndentFilter(Filter):
|
|||
|
||||
return bool(before_cursor.isspace())
|
||||
|
||||
class BeginningOfLine(Filter):
|
||||
"""
|
||||
Check if cursor is at beginning of a line other than the first line
|
||||
in a multiline document
|
||||
"""
|
||||
def __call__(self, cli):
|
||||
before_cursor = cli.current_buffer.document.current_line_before_cursor
|
||||
|
||||
return bool(len(before_cursor) == 0
|
||||
and not cli.current_buffer.document.on_first_line)
|
||||
|
||||
class EndOfLine(Filter):
|
||||
"""
|
||||
Check if cursor is at the end of a line other than the last line
|
||||
in a multiline document
|
||||
"""
|
||||
def __call__(self, cli):
|
||||
d = cli.current_buffer.document
|
||||
at_end = d.is_cursor_at_the_end_of_line
|
||||
last_line = d.is_cursor_at_the_end
|
||||
|
||||
return bool(at_end and not last_line)
|
||||
|
||||
def can_compile(src):
|
||||
"""Returns whether the code can be compiled, i.e. it is valid xonsh."""
|
||||
|
@ -109,6 +131,21 @@ def load_xonsh_bindings(key_bindings_manager):
|
|||
b = event.cli.current_buffer
|
||||
carriage_return(b, event.cli)
|
||||
|
||||
@handle(Keys.Left, filter=BeginningOfLine())
|
||||
def wrap_cursor_back(event):
|
||||
"""Move cursor to end of previous line unless at beginning of document"""
|
||||
b = event.cli.current_buffer
|
||||
b.cursor_up(count=1)
|
||||
relative_end_index = b.document.get_end_of_line_position()
|
||||
b.cursor_right(count=relative_end_index)
|
||||
|
||||
@handle(Keys.Right, filter=EndOfLine())
|
||||
def wrap_cursor_forward(event):
|
||||
"""Move cursor to beginning of next line unless at end of document"""
|
||||
b = event.cli.current_buffer
|
||||
relative_begin_index = b.document.get_start_of_line_position()
|
||||
b.cursor_left(count=abs(relative_begin_index))
|
||||
b.cursor_down(count=1)
|
||||
|
||||
def _is_blank(l):
|
||||
return len(l.strip()) == 0
|
||||
|
|
|
@ -993,6 +993,8 @@ def expandvars(path):
|
|||
var = eval(var, builtins.__xonsh_ctx__)
|
||||
if _is_in_env(var):
|
||||
value = _get_env_string(var)
|
||||
elif var is Ellipsis:
|
||||
value = dollar + brace + '...' + rbrace
|
||||
else:
|
||||
value = dollar + brace + var + rbrace
|
||||
except:
|
||||
|
|
Loading…
Add table
Reference in a new issue