mirror of
https://github.com/xonsh/xonsh.git
synced 2025-03-04 08:24:40 +01:00
Merge branch 'master' into update_docs
This commit is contained in:
commit
da13eb858d
41 changed files with 1042 additions and 357 deletions
|
@ -1,4 +1,4 @@
|
|||
version: 0.2.6.{build}
|
||||
version: 0.2.7.{build}
|
||||
os: Windows Server 2012 R2
|
||||
install:
|
||||
- C:\Python34\Scripts\pip install ply pyreadline nose pygments prompt_toolkit
|
||||
|
|
4
.gitattributes
vendored
Normal file
4
.gitattributes
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
# Set the default behavior, in case people don't have core.autocrlf set.
|
||||
* text=auto
|
||||
|
||||
tests/histories/*.json text eol=lf
|
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
|
||||
|
|
|
@ -6,6 +6,48 @@ Current Developments
|
|||
====================
|
||||
**Added:**
|
||||
|
||||
* Added a new shell type ``'none'``, used to avoid importing ``readline`` or
|
||||
``prompt_toolkit`` when running scripts or running a single command.
|
||||
* New: `sudo` functionality on Windows through an alias
|
||||
* Automatically enhance colors for readability in the default terminal (cmd.exe)
|
||||
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:**
|
||||
|
||||
* Running scripts through xonsh (or running a single command with ``-c``) no
|
||||
longer runs the user's rc file, unless the ``--login`` option is specified.
|
||||
Also avoids loading aliases and environments from foreign shells, as well as
|
||||
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
|
||||
|
||||
**Removed:** None
|
||||
|
||||
**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:**
|
||||
|
||||
* Added new valid ``$SHELL_TYPE`` called ``'best'``. This selects the best value
|
||||
for the concrete shell type based on the availability on the user's machine.
|
||||
* New environment variable ``$XONSH_COLOR_STYLE`` will set the color mapping
|
||||
|
@ -47,7 +89,7 @@ Current Developments
|
|||
``re.match``, and the result of an empty regex glob does not cause the
|
||||
argument to be deleted.
|
||||
|
||||
**Deprecated:** None
|
||||
|
||||
|
||||
**Removed:**
|
||||
|
||||
|
@ -58,11 +100,12 @@ Current Developments
|
|||
|
||||
**Fixed:**
|
||||
|
||||
* Multidimensional slicing, as in numpy, no longer throws SyntaxErrors.
|
||||
* Some minor zsh fixes for more platforms and setups.
|
||||
* The ``BaseShell.settitle`` method no longer has its commands captured by
|
||||
``$(...)``
|
||||
|
||||
**Security:** None
|
||||
|
||||
|
||||
v0.2.6
|
||||
====================
|
||||
|
|
|
@ -178,6 +178,14 @@ The following aliases on Windows are expanded to ``['cmd', '/c', alias]``:
|
|||
On Windows, ``which`` is aliased to ``['where']``.
|
||||
|
||||
|
||||
``sudo`` on Windows
|
||||
====================
|
||||
On Windows, if no executables named ``sudo`` are found, Xonsh adds a ``sudo`` alias
|
||||
that poly fills the "run as Admin" behavior with the help of ``ShellExecuteEx`` and
|
||||
``ctypes``. It doesn't support any actual ``sudo`` parameters and just takes the
|
||||
command to run.
|
||||
|
||||
|
||||
``ls``
|
||||
====================
|
||||
The ``ls`` command is aliased to ``['ls', '--color=auto', '-v']`` normally. On Mac OSX
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
the xonsh shell
|
||||
===============
|
||||
|
||||
.. raw:: html
|
||||
.. raw:: html
|
||||
|
||||
<p style="text-align:center;">
|
||||
<span style="font-family:Times;font-size:28px;font-style:normal;font-weight:normal;text-decoration:none;text-transform:none;font-variant:small-caps;color:000000;">
|
||||
~
|
||||
~
|
||||
<script>
|
||||
var taglines = [
|
||||
"Exofrills in the shell",
|
||||
|
@ -23,7 +23,12 @@ the xonsh shell
|
|||
"It is pronounced <i>quanxh</i>",
|
||||
"It is pronounced <i>zonsch</i>",
|
||||
"It is pronounced <i>jeaunsch</i>",
|
||||
"It is pronounced <i>🐚</i>",
|
||||
"It is pronounced <i>măjˈĭk</i>",
|
||||
"It is pronounced <i>gif</i>",
|
||||
"It is pronounced <i>Honshu</i>",
|
||||
"It is pronounced <i>soonish</i>",
|
||||
"It is pronounced <i>vixenish</i>",
|
||||
"The shell, bourne again",
|
||||
"Snailed it",
|
||||
"Starfish loves you",
|
||||
|
@ -51,16 +56,16 @@ the xonsh shell
|
|||
Xonsh is a Python-ish, BASHwards-looking shell language and command prompt.
|
||||
The language is a superset of Python 3.4+ with additional shell primitives
|
||||
that you are used to from Bash and IPython. It works on all major systems including
|
||||
Linux, Mac OSX, and Windows. Xonsh is meant for the daily use of experts and novices
|
||||
Linux, Mac OSX, and Windows. Xonsh is meant for the daily use of experts and novices
|
||||
alike.
|
||||
|
||||
**At a glance**
|
||||
|
||||
.. raw:: html
|
||||
.. raw:: html
|
||||
|
||||
<p style="text-align:center;"><script type="text/javascript"
|
||||
src="https://asciinema.org/a/9kp21a67ahhng25wtzoep3pyx.js"
|
||||
id="asciicast-9kp21a67ahhng25wtzoep3pyx" async
|
||||
<p style="text-align:center;"><script type="text/javascript"
|
||||
src="https://asciinema.org/a/9kp21a67ahhng25wtzoep3pyx.js"
|
||||
id="asciicast-9kp21a67ahhng25wtzoep3pyx" async
|
||||
data-size="medium" data-speed="2"></script>
|
||||
</p>
|
||||
|
||||
|
@ -111,19 +116,18 @@ Contents
|
|||
faq
|
||||
todo
|
||||
|
||||
|
||||
==========
|
||||
Comparison
|
||||
==========
|
||||
Xonsh is significantly different from most other shells or shell tools. The following
|
||||
table lists features and capabilities that various tools may or may not share.
|
||||
|
||||
.. list-table::
|
||||
.. list-table::
|
||||
:widths: 3 1 1 1 1 1 1
|
||||
:header-rows: 1
|
||||
:stub-columns: 1
|
||||
|
||||
* -
|
||||
* -
|
||||
- Bash
|
||||
- zsh
|
||||
- plumbum
|
||||
|
@ -131,8 +135,8 @@ table lists features and capabilities that various tools may or may not share.
|
|||
- IPython
|
||||
- xonsh
|
||||
* - Sane language
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
- ✓
|
||||
- ✓
|
||||
- ✓
|
||||
|
@ -142,11 +146,11 @@ table lists features and capabilities that various tools may or may not share.
|
|||
- ✓
|
||||
- ✓
|
||||
- ✓
|
||||
-
|
||||
-
|
||||
- ✓
|
||||
* - Native cross-platform support
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
- ✓
|
||||
- ✓
|
||||
- ✓
|
||||
|
@ -154,58 +158,58 @@ table lists features and capabilities that various tools may or may not share.
|
|||
* - Meant as a shell
|
||||
- ✓
|
||||
- ✓
|
||||
-
|
||||
-
|
||||
- ✓
|
||||
-
|
||||
-
|
||||
- ✓
|
||||
* - Tab completion
|
||||
- ✓
|
||||
- ✓
|
||||
-
|
||||
-
|
||||
- ✓
|
||||
- ✓
|
||||
- ✓
|
||||
* - Man-page completion
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
- ✓
|
||||
-
|
||||
-
|
||||
- ✓
|
||||
* - Large standard library
|
||||
-
|
||||
-
|
||||
- ✓
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
- ✓
|
||||
- ✓
|
||||
* - Typed variables
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
- ✓
|
||||
- ✓
|
||||
- ✓
|
||||
- ✓
|
||||
* - Syntax highlighting
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
- ✓
|
||||
- in notebook
|
||||
- w/ prompt-toolkit
|
||||
* - Pun in name
|
||||
- ✓
|
||||
-
|
||||
-
|
||||
- ✓
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
- ✓
|
||||
* - Rich history
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
- ✓
|
||||
|
||||
|
||||
|
@ -232,17 +236,17 @@ Xonsh currently has the following external dependencies,
|
|||
============
|
||||
Contributing
|
||||
============
|
||||
We highly encourage contributions to xonsh! If you would like to contribute,
|
||||
it is as easy as forking the repository on GitHub, making your changes, and
|
||||
issuing a pull request. If you have any questions about this process don't
|
||||
hesitate to ask the mailing list (xonsh@googlegroups.com).
|
||||
We highly encourage contributions to xonsh! If you would like to contribute,
|
||||
it is as easy as forking the repository on GitHub, making your changes, and
|
||||
issuing a pull request. If you have any questions about this process don't
|
||||
hesitate to ask the mailing list (xonsh@googlegroups.com).
|
||||
|
||||
==========
|
||||
Contact Us
|
||||
==========
|
||||
If you have questions or comments, please send them to the mailing list
|
||||
xonsh@googlegroups.com, page us on IRC, contact the author directly, or
|
||||
open an issue on GitHub.
|
||||
open an issue on GitHub.
|
||||
`Join the mailing list here! <https://groups.google.com/forum/#!forum/xonsh>`_
|
||||
|
||||
=============
|
||||
|
|
|
@ -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
|
||||
|
@ -197,6 +219,14 @@ examples in action:
|
|||
|
||||
Not bad, xonsh, not bad.
|
||||
|
||||
If you want to check if an environment variable is present in your current
|
||||
session (say, in your awesome new ``xonsh`` script) you can pass an Ellipsis to
|
||||
the ``${}`` operator:
|
||||
|
||||
.. code-block:: xonshcon
|
||||
|
||||
>>> 'HOME' in ${...}
|
||||
True
|
||||
|
||||
Running Commands
|
||||
==============================
|
||||
|
|
247
docs/windows.rst
247
docs/windows.rst
|
@ -1,123 +1,124 @@
|
|||
==========================
|
||||
Windows Guide
|
||||
==========================
|
||||
|
||||
Installation
|
||||
================
|
||||
|
||||
The easy way
|
||||
----------------
|
||||
|
||||
The easiest way to install xonsh on windows is through the `Anaconda Python Distribution`_ and the conda package manager.
|
||||
|
||||
.. note:: Be sure to install the version with Python3.4 or later. Xonsh is not supported on legacy Python (2.7).
|
||||
|
||||
Install xonsh with the following command:
|
||||
|
||||
.. code-block:: bat
|
||||
|
||||
> conda install xonsh --channel xonsh
|
||||
|
||||
This will install xonsh and all the recommended dependencies. Next, run xonsh:
|
||||
|
||||
.. code-block:: bat
|
||||
|
||||
> xonsh
|
||||
snail@home ~ $
|
||||
|
||||
|
||||
Install from source
|
||||
-------------------
|
||||
|
||||
To install xonsh from source on Windows, first install `Python v3.4+`_ from
|
||||
http://python.org. Remember to select "Add python to PATH" during installation.
|
||||
|
||||
Next, install the prompt_toolkit dependency via ``pip``:
|
||||
|
||||
.. code-block:: bat
|
||||
|
||||
> pip install prompt-toolkit
|
||||
|
||||
While prompt-toolkit is considered an optional dependency, it is the
|
||||
recommended alternative to pyreadline for Windows users. For Windows,
|
||||
it is recommended to use a replacement console emulator. Good choices are `cmder`_ or `conemu`_.
|
||||
|
||||
Download the latest `xonsh-master.zip`_ from github and unzip it
|
||||
to ``xonsh-master``.
|
||||
|
||||
Now install xonsh:
|
||||
|
||||
.. code-block:: bat
|
||||
|
||||
> cd xonsh-master
|
||||
> python setup.py install
|
||||
|
||||
Next, run xonsh:
|
||||
|
||||
.. code-block:: bat
|
||||
|
||||
> xonsh
|
||||
snail@home ~ $
|
||||
|
||||
.. _Python v3.4+: https://www.python.org/downloads/windows/
|
||||
.. _xonsh-master.zip: https://github.com/scopatz/xonsh/archive/master.zip
|
||||
.. _cmder: http://cmder.net/
|
||||
.. _conemu: https://conemu.github.io/
|
||||
.. _Anaconda Python Distribution: https://www.continuum.io/downloads#_windows
|
||||
|
||||
.. include:: dependencies.rst
|
||||
|
||||
Usage
|
||||
================
|
||||
|
||||
Name space conflicts
|
||||
--------------------
|
||||
|
||||
Due to ambiguity with the Python ``dir`` builtin, to list the current
|
||||
directory via the ``cmd.exe`` builtin you must explicitly request
|
||||
the ``.``, like this:
|
||||
|
||||
.. code-block:: xonshcon
|
||||
|
||||
>>> dir .
|
||||
Volume in drive C is Windows
|
||||
Volume Serial Number is 30E8-8B86
|
||||
|
||||
Directory of C:\Users\snail\xonsh
|
||||
|
||||
2015-05-12 03:04 <DIR> .
|
||||
2015-05-12 03:04 <DIR> ..
|
||||
2015-05-01 01:31 <DIR> xonsh
|
||||
0 File(s) 0 bytes
|
||||
3 Dir(s) 11,008,000,000 bytes free
|
||||
|
||||
|
||||
|
||||
Many people create a ``d`` alias for the ``dir`` command to save
|
||||
typing and avoid the ambiguity altogether:
|
||||
|
||||
.. code-block:: xonshcon
|
||||
|
||||
>>> aliases['d'] = ['cmd', '/c', 'dir']
|
||||
|
||||
You can add aliases to your ``~/.xonshrc`` to have it always
|
||||
available when xonsh starts.
|
||||
|
||||
|
||||
Unicode support for Windows
|
||||
----------------------------
|
||||
|
||||
Python's utf-8 unicode is not compatible with the default shell 'cmd.exe' on Windows. The package ``win_unicode_console`` fixes this. Xonsh will use ``win_unicode_console`` if it is installed. This can be disabled/enabled with the ``$WIN_UNICODE_CONSOLE``` environment variable.
|
||||
|
||||
.. note:: Even with unicode support enabled the symbols available will depend on the font used in cmd.exe.
|
||||
|
||||
The packages ``win_unicode_console`` can be installed using pip or conda.
|
||||
|
||||
.. code-block:: bat
|
||||
|
||||
> pip install win_unicode_console
|
||||
|
||||
|
||||
.. code-block:: bat
|
||||
|
||||
> conda install --channel xonsh win_unicode_console
|
||||
==========================
|
||||
Windows Guide
|
||||
==========================
|
||||
|
||||
Installation
|
||||
================
|
||||
|
||||
The easy way
|
||||
----------------
|
||||
|
||||
The easiest way to install xonsh on windows is through the Anaconda Python
|
||||
Distribution and the conda package manager.
|
||||
|
||||
.. note::
|
||||
|
||||
Be sure to install the version with Python3.4 or later.
|
||||
Xonsh is not yet supported on legacy Python (2.7).
|
||||
|
||||
Install xonsh with the following command:
|
||||
|
||||
.. code-block:: bat
|
||||
|
||||
> conda install xonsh --channel xonsh
|
||||
|
||||
This will install xonsh and all the recommended dependencies. Next, run xonsh:
|
||||
|
||||
.. code-block:: bat
|
||||
|
||||
> xonsh
|
||||
snail@home ~ $
|
||||
|
||||
|
||||
Install from source
|
||||
-------------------
|
||||
|
||||
To install xonsh from source on Windows, first install `Python v3.4+`_ from
|
||||
http://python.org. Remember to select "Add python to PATH" during installation.
|
||||
|
||||
Next, install the prompt_toolkit dependency via ``pip``:
|
||||
|
||||
.. code-block:: bat
|
||||
|
||||
> pip install prompt-toolkit
|
||||
|
||||
While prompt-toolkit is considered an optional dependency, it is the
|
||||
recommended alternative to pyreadline for Windows users. For Windows,
|
||||
it is recommended to use a replacement console emulator. Good choices are `cmder`_ or `conemu`_.
|
||||
|
||||
Download the latest `xonsh-master.zip`_ from github and unzip it
|
||||
to ``xonsh-master``.
|
||||
|
||||
Now install xonsh:
|
||||
|
||||
.. code-block:: bat
|
||||
|
||||
> cd xonsh-master
|
||||
> python setup.py install
|
||||
|
||||
Next, run xonsh:
|
||||
|
||||
.. code-block:: bat
|
||||
|
||||
> xonsh
|
||||
snail@home ~ $
|
||||
|
||||
.. _Python v3.4+: https://www.python.org/downloads/windows/
|
||||
.. _xonsh-master.zip: https://github.com/scopatz/xonsh/archive/master.zip
|
||||
.. _cmder: http://cmder.net/
|
||||
.. _conemu: https://conemu.github.io/
|
||||
|
||||
Usage
|
||||
================
|
||||
|
||||
Name space conflicts
|
||||
--------------------
|
||||
|
||||
Due to ambiguity with the Python ``dir`` builtin, to list the current
|
||||
directory via the ``cmd.exe`` builtin you must explicitly request
|
||||
the ``.``, like this:
|
||||
|
||||
.. code-block:: xonshcon
|
||||
|
||||
>>> dir .
|
||||
Volume in drive C is Windows
|
||||
Volume Serial Number is 30E8-8B86
|
||||
|
||||
Directory of C:\Users\snail\xonsh
|
||||
|
||||
2015-05-12 03:04 <DIR> .
|
||||
2015-05-12 03:04 <DIR> ..
|
||||
2015-05-01 01:31 <DIR> xonsh
|
||||
0 File(s) 0 bytes
|
||||
3 Dir(s) 11,008,000,000 bytes free
|
||||
|
||||
|
||||
|
||||
Many people create a ``d`` alias for the ``dir`` command to save
|
||||
typing and avoid the ambiguity altogether:
|
||||
|
||||
.. code-block:: xonshcon
|
||||
|
||||
>>> aliases['d'] = ['cmd', '/c', 'dir']
|
||||
|
||||
You can add aliases to your ``~/.xonshrc`` to have it always
|
||||
available when xonsh starts.
|
||||
|
||||
|
||||
Unicode support for Windows
|
||||
----------------------------
|
||||
|
||||
Python's utf-8 unicode is not compatible with the default shell 'cmd.exe' on Windows. The package ``win_unicode_console`` fixes this. Xonsh will use ``win_unicode_console`` if it is installed. This can be disabled/enabled with the ``$WIN_UNICODE_CONSOLE``` environment variable.
|
||||
|
||||
.. note:: Even with unicode support enabled the symbols available will depend on the font used in cmd.exe.
|
||||
|
||||
The packages ``win_unicode_console`` can be installed using pip or conda.
|
||||
|
||||
.. code-block:: bat
|
||||
|
||||
> pip install win_unicode_console
|
||||
|
||||
|
||||
.. code-block:: bat
|
||||
|
||||
> conda install --channel xonsh win_unicode_console
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
Run Control File
|
||||
=========================
|
||||
Xonsh allows you to have run control files to customize your shell behavior. These are called ``xonshrc`` files.
|
||||
Xonsh allows you to have run control files to customize your shell behavior. These are called ``xonshrc`` files.
|
||||
|
||||
The system-wide ``xonshrc`` file controls options that are applied to all users of Xonsh on a given system. You can create this file in ``/etc/xonshrc`` for Linux and OSX and in ``%ALLUSERSPROFILE%\xonsh\xonshrc`` on Windows.
|
||||
The system-wide ``xonshrc`` file controls options that are applied to all users of Xonsh on a given system. You can create this file in ``/etc/xonshrc`` for Linux and OSX and in ``%ALLUSERSPROFILE%\xonsh\xonshrc`` on Windows.
|
||||
|
||||
Xonsh also allows you to have a run control file in your home directory called ``~/.xonshrc``. The options set in the local ``xonshrc`` only apply to the current user and will override any conflicting settings set in the system-wide control file.
|
||||
Xonsh also allows you to have a run control file in your home directory called ``~/.xonshrc``. The options set in the local ``xonshrc`` only apply to the current user and will override any conflicting settings set in the system-wide control file.
|
||||
|
||||
These files are written in the xonsh language, of course. They are executed exactly once
|
||||
at startup. The following is a real-world example of such a file.
|
||||
|
@ -18,16 +18,16 @@ at startup. The following is a real-world example of such a file.
|
|||
Snippets for xonshrc
|
||||
=========================
|
||||
The following are usefull snippets and code that tweaks and adjust xonsh in various ways.
|
||||
If you have any useful tricks, feel free to share them.
|
||||
If you have any useful tricks, feel free to share them.
|
||||
|
||||
Adjust how git branch label behaves
|
||||
---------------------------------
|
||||
Xonsh adds a colored branch name to the prompt when working with git or hg repositories.
|
||||
This behavior can be controlled with the ``$PROMPT`` environment variable. See how to `customize the prompt`_ .
|
||||
The branch name changes color if the work dir is dirty or not. This is controlled by the ``{branch_color}`` formatter string.
|
||||
-------------------------------------------
|
||||
Xonsh adds a colored branch name to the prompt when working with git or hg repositories.
|
||||
This behavior can be controlled with the ``$PROMPT`` environment variable. See how to `customize the prompt`_ .
|
||||
The branch name changes color if the work dir is dirty or not. This is controlled by the ``{branch_color}`` formatter string.
|
||||
|
||||
|
||||
The following snippet reimplements the formatter also to include untracked files when considering if a git directory is dirty.
|
||||
The following snippet reimplements the formatter also to include untracked files when considering if a git directory is dirty.
|
||||
|
||||
.. code-block:: xonshcon
|
||||
|
||||
|
@ -36,13 +36,13 @@ The following snippet reimplements the formatter also to include untracked files
|
|||
if git_dirty_working_directory(include_untracked=True)
|
||||
else '{BOLD_INTENSE_GREEN}')
|
||||
|
||||
|
||||
|
||||
.. _customize the prompt: http://xon.sh/tutorial.html#customizing-the-prompt
|
||||
|
||||
|
||||
Get better colors from the ``ls`` command
|
||||
----------------------------------------------
|
||||
The colors of the ``ls`` command may be hard to read in a dark terminal. If so, this is an excellent addition to the xonshrc file.
|
||||
The colors of the ``ls`` command may be hard to read in a dark terminal. If so, this is an excellent addition to the xonshrc file.
|
||||
|
||||
.. code-block:: xonshcon
|
||||
|
||||
|
|
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()
|
||||
|
|
|
@ -19,6 +19,14 @@ def test_login_shell():
|
|||
|
||||
with patch('xonsh.main.Shell', Shell), mock_xonsh_env({}):
|
||||
xonsh.main.premain([])
|
||||
assert_true(builtins.__xonsh_env__.get('XONSH_LOGIN'))
|
||||
|
||||
with patch('xonsh.main.Shell', Shell), mock_xonsh_env({}):
|
||||
xonsh.main.premain(['-l', '-c', 'echo "hi"'])
|
||||
assert_true(builtins.__xonsh_env__.get('XONSH_LOGIN'))
|
||||
|
||||
with patch('xonsh.main.Shell', Shell), mock_xonsh_env({}):
|
||||
xonsh.main.premain(['-c', 'echo "hi"'])
|
||||
assert_false(builtins.__xonsh_env__.get('XONSH_LOGIN'))
|
||||
|
||||
with patch('xonsh.main.Shell', Shell), mock_xonsh_env({}):
|
||||
|
|
|
@ -58,7 +58,7 @@ def assert_nodes_equal(x, y, include_attributes=True):
|
|||
print(pdump(x, include_attributes=include_attributes), '\n')
|
||||
print('y:\n==')
|
||||
print(pdump(y, include_attributes=include_attributes), '\n')
|
||||
assert_equal(pdump(x, include_attributes=include_attributes),
|
||||
assert_equal(pdump(x, include_attributes=include_attributes),
|
||||
pdump(y, include_attributes=include_attributes))
|
||||
|
||||
def check_ast(inp, run=True, mode='eval'):
|
||||
|
@ -310,6 +310,81 @@ def test_str_slice_lower_other():
|
|||
def test_str_slice_upper_other():
|
||||
yield check_ast, '"hello"[3::2]'
|
||||
|
||||
def test_str_2slice():
|
||||
yield check_ast, '"hello"[0:3,0:3]', False
|
||||
|
||||
def test_str_2step():
|
||||
yield check_ast, '"hello"[0:3:1,0:4:2]', False
|
||||
|
||||
def test_str_2slice_all():
|
||||
yield check_ast, '"hello"[:,:]', False
|
||||
|
||||
def test_str_2slice_upper():
|
||||
yield check_ast, '"hello"[5:,5:]', False
|
||||
|
||||
def test_str_2slice_lower():
|
||||
yield check_ast, '"hello"[:3,:3]', False
|
||||
|
||||
def test_str_2slice_lowerupper():
|
||||
yield check_ast, '"hello"[5:,:3]', False
|
||||
|
||||
def test_str_2slice_other():
|
||||
yield check_ast, '"hello"[::2,::2]', False
|
||||
|
||||
def test_str_2slice_lower_other():
|
||||
yield check_ast, '"hello"[:3:2,:3:2]', False
|
||||
|
||||
def test_str_2slice_upper_other():
|
||||
yield check_ast, '"hello"[3::2,3::2]', False
|
||||
|
||||
def test_str_3slice():
|
||||
yield check_ast, '"hello"[0:3,0:3,0:3]', False
|
||||
|
||||
def test_str_3step():
|
||||
yield check_ast, '"hello"[0:3:1,0:4:2,1:3:2]', False
|
||||
|
||||
def test_str_3slice_all():
|
||||
yield check_ast, '"hello"[:,:,:]', False
|
||||
|
||||
def test_str_3slice_upper():
|
||||
yield check_ast, '"hello"[5:,5:,5:]', False
|
||||
|
||||
def test_str_3slice_lower():
|
||||
yield check_ast, '"hello"[:3,:3,:3]', False
|
||||
|
||||
def test_str_3slice_lowerlowerupper():
|
||||
yield check_ast, '"hello"[:3,:3,:3]', False
|
||||
|
||||
def test_str_3slice_lowerupperlower():
|
||||
yield check_ast, '"hello"[:3,5:,:3]', False
|
||||
|
||||
def test_str_3slice_lowerupperupper():
|
||||
yield check_ast, '"hello"[:3,5:,5:]', False
|
||||
|
||||
def test_str_3slice_upperlowerlower():
|
||||
yield check_ast, '"hello"[5:,5:,:3]', False
|
||||
|
||||
def test_str_3slice_upperlowerupper():
|
||||
yield check_ast, '"hello"[5:,:3,5:]', False
|
||||
|
||||
def test_str_3slice_upperupperlower():
|
||||
yield check_ast, '"hello"[5:,5:,:3]', False
|
||||
|
||||
def test_str_3slice_other():
|
||||
yield check_ast, '"hello"[::2,::2,::2]', False
|
||||
|
||||
def test_str_3slice_lower_other():
|
||||
yield check_ast, '"hello"[:3:2,:3:2,:3:2]', False
|
||||
|
||||
def test_str_3slice_upper_other():
|
||||
yield check_ast, '"hello"[3::2,3::2,3::2]', False
|
||||
|
||||
def test_str_slice_true():
|
||||
yield check_ast, '"hello"[0:3,True]', False
|
||||
|
||||
def test_str_true_slice():
|
||||
yield check_ast, '"hello"[True,0:3]', False
|
||||
|
||||
def test_list_empty():
|
||||
yield check_ast, '[]'
|
||||
|
||||
|
@ -1499,6 +1574,36 @@ def test_ls_envvar_strval():
|
|||
def test_ls_envvar_listval():
|
||||
yield check_xonsh_ast, {'WAKKA': ['.', '.']}, '$(ls $WAKKA)', False
|
||||
|
||||
def test_bang_sub():
|
||||
yield check_xonsh_ast, {}, '!(ls)', False
|
||||
|
||||
def test_bang_sub_space():
|
||||
yield check_xonsh_ast, {}, '!(ls )', False
|
||||
|
||||
def test_bang_ls_dot():
|
||||
yield check_xonsh_ast, {}, '!(ls .)', False
|
||||
|
||||
def test_bang_ls_dot_nesting():
|
||||
yield check_xonsh_ast, {}, '!(ls @(None or "."))', False
|
||||
|
||||
def test_bang_ls_dot_nesting_var():
|
||||
yield check_xonsh, {}, 'x = "."; !(ls @(None or x))', False
|
||||
|
||||
def test_bang_ls_dot_str():
|
||||
yield check_xonsh_ast, {}, '!(ls ".")', False
|
||||
|
||||
def test_bang_ls_nest_ls():
|
||||
yield check_xonsh_ast, {}, '!(ls $(ls))', False
|
||||
|
||||
def test_bang_ls_nest_ls_dashl():
|
||||
yield check_xonsh_ast, {}, '!(ls $(ls) -l)', False
|
||||
|
||||
def test_bang_ls_envvar_strval():
|
||||
yield check_xonsh_ast, {'WAKKA': '.'}, '!(ls $WAKKA)', False
|
||||
|
||||
def test_bang_ls_envvar_listval():
|
||||
yield check_xonsh_ast, {'WAKKA': ['.', '.']}, '!(ls $WAKKA)', False
|
||||
|
||||
def test_question():
|
||||
yield check_xonsh_ast, {}, 'range?'
|
||||
|
||||
|
@ -1517,6 +1622,50 @@ def test_backtick():
|
|||
def test_uncaptured_sub():
|
||||
yield check_xonsh_ast, {}, '$[ls]', False
|
||||
|
||||
def test_hiddenobj_sub():
|
||||
yield check_xonsh_ast, {}, '![ls]', False
|
||||
|
||||
def test_bang_two_cmds_one_pipe():
|
||||
yield check_xonsh_ast, {}, '!(ls | grep wakka)', False
|
||||
|
||||
def test_bang_three_cmds_two_pipes():
|
||||
yield check_xonsh_ast, {}, '!(ls | grep wakka | grep jawaka)', False
|
||||
|
||||
def test_bang_one_cmd_write():
|
||||
yield check_xonsh_ast, {}, '!(ls > x.py)', False
|
||||
|
||||
def test_bang_one_cmd_append():
|
||||
yield check_xonsh_ast, {}, '!(ls >> x.py)', False
|
||||
|
||||
def test_bang_two_cmds_write():
|
||||
yield check_xonsh_ast, {}, '!(ls | grep wakka > x.py)', False
|
||||
|
||||
def test_bang_two_cmds_append():
|
||||
yield check_xonsh_ast, {}, '!(ls | grep wakka >> x.py)', False
|
||||
|
||||
def test_bang_cmd_background():
|
||||
yield check_xonsh_ast, {}, '!(emacs ugggh &)', False
|
||||
|
||||
def test_bang_cmd_background_nospace():
|
||||
yield check_xonsh_ast, {}, '!(emacs ugggh&)', False
|
||||
|
||||
def test_bang_git_quotes_no_space():
|
||||
yield check_xonsh_ast, {}, '![git commit -am "wakka"]', False
|
||||
|
||||
def test_bang_git_quotes_space():
|
||||
yield check_xonsh_ast, {}, '![git commit -am "wakka jawaka"]', False
|
||||
|
||||
def test_bang_git_two_quotes_space():
|
||||
yield check_xonsh, {}, ('![git commit -am "wakka jawaka"]\n'
|
||||
'![git commit -am "flock jawaka"]\n'), False
|
||||
|
||||
def test_bang_git_two_quotes_space_space():
|
||||
yield check_xonsh, {}, ('![git commit -am "wakka jawaka" ]\n'
|
||||
'![git commit -am "flock jawaka milwaka" ]\n'), False
|
||||
|
||||
def test_bang_ls_quotes_3_space():
|
||||
yield check_xonsh_ast, {}, '![ls "wakka jawaka baraka"]', False
|
||||
|
||||
def test_two_cmds_one_pipe():
|
||||
yield check_xonsh_ast, {}, '$(ls | grep wakka)', False
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
__version__ = '0.2.6'
|
||||
__version__ = '0.2.7'
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Aliases for the xonsh shell."""
|
||||
import os
|
||||
import shlex
|
||||
|
||||
import builtins
|
||||
import subprocess
|
||||
from warnings import warn
|
||||
import os
|
||||
from argparse import ArgumentParser
|
||||
|
||||
from xonsh.dirstack import cd, pushd, popd, dirs
|
||||
from xonsh.dirstack import cd, pushd, popd, dirs, _get_cwd
|
||||
from xonsh.jobs import jobs, fg, bg, kill_all_jobs
|
||||
from xonsh.proc import foreground
|
||||
from xonsh.timings import timeit_alias
|
||||
|
@ -223,7 +221,7 @@ DEFAULT_ALIASES = {
|
|||
'timeit': timeit_alias,
|
||||
'xonfig': xonfig,
|
||||
'scp-resume': ['rsync', '--partial', '-h', '--progress', '--rsh=ssh'],
|
||||
'ipynb': ['ipython', 'notebook', '--no-browser'],
|
||||
'ipynb': ['jupyter', 'notebook', '--no-browser'],
|
||||
'vox': vox,
|
||||
}
|
||||
|
||||
|
@ -253,6 +251,25 @@ if ON_WINDOWS:
|
|||
|
||||
DEFAULT_ALIASES['which'] = ['where']
|
||||
|
||||
if not locate_binary('sudo'):
|
||||
import xonsh.winutils as winutils
|
||||
|
||||
def sudo(args, sdin=None):
|
||||
if len(args) < 1:
|
||||
print('You need to provide an executable to run as Administrator.')
|
||||
return
|
||||
|
||||
cmd = args[0]
|
||||
|
||||
if locate_binary(cmd):
|
||||
return winutils.sudo(cmd, args[1:])
|
||||
elif cmd.lower() in WINDOWS_CMD_ALIASES:
|
||||
return winutils.sudo('cmd', ['/D', '/C', 'CD', _get_cwd(), '&&'] + args)
|
||||
else:
|
||||
print('Cannot find the path for executable "{0}".'.format(cmd))
|
||||
|
||||
DEFAULT_ALIASES['sudo'] = sudo
|
||||
|
||||
elif ON_MAC:
|
||||
DEFAULT_ALIASES['ls'] = ['ls', '-G']
|
||||
else:
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
from ast import Module, Num, Expr, Str, Bytes, UnaryOp, UAdd, USub, Invert, \
|
||||
BinOp, Add, Sub, Mult, Div, FloorDiv, Mod, Pow, Compare, Lt, Gt, \
|
||||
LtE, GtE, Eq, NotEq, In, NotIn, Is, IsNot, Not, BoolOp, Or, And, \
|
||||
Subscript, Load, Slice, List, Tuple, Set, Dict, AST, NameConstant, \
|
||||
Subscript, Load, Slice, ExtSlice, List, Tuple, Set, Dict, AST, NameConstant, \
|
||||
Name, GeneratorExp, Store, comprehension, ListComp, SetComp, DictComp, \
|
||||
Assign, AugAssign, BitXor, BitAnd, BitOr, LShift, RShift, Assert, Delete, \
|
||||
Del, Pass, Raise, Import, alias, ImportFrom, Continue, Break, Yield, \
|
||||
|
|
|
@ -108,10 +108,11 @@ class BaseShell(object):
|
|||
"""The xonsh shell."""
|
||||
|
||||
def __init__(self, execer, ctx, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
super().__init__()
|
||||
self.execer = execer
|
||||
self.ctx = ctx
|
||||
self.completer = Completer()
|
||||
if kwargs.get('completer', True):
|
||||
self.completer = Completer()
|
||||
self.buffer = []
|
||||
self.need_more_lines = False
|
||||
self.mlprompt = None
|
||||
|
|
|
@ -25,7 +25,6 @@ from xonsh.tools import (
|
|||
)
|
||||
from xonsh.inspectors import Inspector
|
||||
from xonsh.environ import Env, default_env, locate_binary
|
||||
from xonsh.aliases import DEFAULT_ALIASES
|
||||
from xonsh.jobs import add_job, wait_for_active_job
|
||||
from xonsh.proc import (ProcProxy, SimpleProcProxy, ForegroundProcProxy,
|
||||
SimpleForegroundProcProxy, TeePTYProc,
|
||||
|
@ -267,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):
|
||||
|
@ -497,6 +497,7 @@ def run_subproc(cmds, captured=False):
|
|||
prev_proc = None
|
||||
_capture_streams = captured in {'stdout', 'object'}
|
||||
for ix, cmd in enumerate(cmds):
|
||||
starttime = time.time()
|
||||
procinfo['args'] = list(cmd)
|
||||
stdin = None
|
||||
stderr = None
|
||||
|
@ -674,6 +675,7 @@ def run_subproc(cmds, captured=False):
|
|||
procinfo['stderr'] = errout
|
||||
|
||||
if (not prev_is_proxy and
|
||||
hist.last_cmd_rtn is not None and
|
||||
hist.last_cmd_rtn > 0 and
|
||||
ENV.get('RAISE_SUBPROC_ERROR')):
|
||||
raise CalledProcessError(hist.last_cmd_rtn, aliased_cmd, output=output)
|
||||
|
@ -682,6 +684,7 @@ def run_subproc(cmds, captured=False):
|
|||
elif captured is not False:
|
||||
procinfo['pid'] = prev_proc.pid
|
||||
procinfo['returncode'] = prev_proc.returncode
|
||||
procinfo['timestamp'] = (starttime, time.time())
|
||||
if captured == 'object':
|
||||
procinfo['stdout'] = output
|
||||
if _stdin_file is not None:
|
||||
|
@ -734,13 +737,13 @@ def ensure_list_of_strs(x):
|
|||
return rtn
|
||||
|
||||
|
||||
def load_builtins(execer=None, config=None):
|
||||
def load_builtins(execer=None, config=None, login=False):
|
||||
"""Loads the xonsh builtins into the Python builtins. Sets the
|
||||
BUILTINS_LOADED variable to True.
|
||||
"""
|
||||
global BUILTINS_LOADED, ENV
|
||||
# private built-ins
|
||||
builtins.__xonsh_env__ = ENV = Env(default_env(config=config))
|
||||
builtins.__xonsh_env__ = ENV = Env(default_env(config=config, login=login))
|
||||
builtins.__xonsh_ctx__ = {}
|
||||
builtins.__xonsh_help__ = helper
|
||||
builtins.__xonsh_superhelp__ = superhelper
|
||||
|
@ -769,8 +772,12 @@ def load_builtins(execer=None, config=None):
|
|||
builtins.evalx = None if execer is None else execer.eval
|
||||
builtins.execx = None if execer is None else execer.exec
|
||||
builtins.compilex = None if execer is None else execer.compile
|
||||
|
||||
# Need this inline/lazy import here since we use locate_binary that relies on __xonsh_env__ in default aliases
|
||||
from xonsh.aliases import DEFAULT_ALIASES
|
||||
builtins.default_aliases = builtins.aliases = Aliases(DEFAULT_ALIASES)
|
||||
builtins.aliases.update(load_foreign_aliases(issue_warning=False))
|
||||
if login:
|
||||
builtins.aliases.update(load_foreign_aliases(issue_warning=False))
|
||||
# history needs to be started after env and aliases
|
||||
# would be nice to actually include non-detyped versions.
|
||||
builtins.__xonsh_history__ = History(env=ENV.detype(),
|
||||
|
|
|
@ -5,7 +5,7 @@ from itertools import zip_longest
|
|||
from difflib import SequenceMatcher
|
||||
|
||||
from xonsh import lazyjson
|
||||
from xonsh.tools import print_color, format_color
|
||||
from xonsh.tools import print_color
|
||||
|
||||
NO_COLOR = '{NO_COLOR}'
|
||||
RED = '{RED}'
|
||||
|
|
185
xonsh/environ.py
185
xonsh/environ.py
|
@ -2,10 +2,12 @@
|
|||
"""Environment for the xonsh shell."""
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import json
|
||||
import socket
|
||||
import string
|
||||
import locale
|
||||
import marshal
|
||||
import builtins
|
||||
import subprocess
|
||||
from itertools import chain
|
||||
|
@ -23,7 +25,8 @@ from xonsh.tools import (
|
|||
history_tuple_to_str, is_float, string_types, is_string, DEFAULT_ENCODING,
|
||||
is_completions_display_value, to_completions_display_value, is_string_set,
|
||||
csv_to_set, set_to_csv, get_sep, is_int, is_bool_seq, csv_to_bool_seq,
|
||||
bool_seq_to_csv, DefaultNotGiven, setup_win_unicode_console
|
||||
bool_seq_to_csv, DefaultNotGiven, setup_win_unicode_console,
|
||||
intensify_colors_on_win_setter
|
||||
)
|
||||
from xonsh.dirstack import _get_cwd
|
||||
from xonsh.foreign_shells import DEFAULT_SHELLS, load_foreign_envs
|
||||
|
@ -67,6 +70,7 @@ DEFAULT_ENSURERS = {
|
|||
'FORCE_POSIX_PATHS': (is_bool, to_bool, bool_to_str),
|
||||
'HISTCONTROL': (is_string_set, csv_to_set, set_to_csv),
|
||||
'IGNOREEOF': (is_bool, to_bool, bool_to_str),
|
||||
'INTENSIFY_COLORS_ON_WIN':(always_false, intensify_colors_on_win_setter, bool_to_str),
|
||||
'LC_COLLATE': (always_false, locale_convert('LC_COLLATE'), ensure_string),
|
||||
'LC_CTYPE': (always_false, locale_convert('LC_CTYPE'), ensure_string),
|
||||
'LC_MESSAGES': (always_false, locale_convert('LC_MESSAGES'), ensure_string),
|
||||
|
@ -81,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),
|
||||
|
@ -167,6 +172,7 @@ DEFAULT_VALUES = {
|
|||
'HISTCONTROL': set(),
|
||||
'IGNOREEOF': False,
|
||||
'INDENT': ' ',
|
||||
'INTENSIFY_COLORS_ON_WIN': True,
|
||||
'LC_CTYPE': locale.setlocale(locale.LC_CTYPE),
|
||||
'LC_COLLATE': locale.setlocale(locale.LC_COLLATE),
|
||||
'LC_TIME': locale.setlocale(locale.LC_TIME),
|
||||
|
@ -179,8 +185,6 @@ DEFAULT_VALUES = {
|
|||
'PATH': (),
|
||||
'PATHEXT': (),
|
||||
'PROMPT': DEFAULT_PROMPT,
|
||||
'PROMPT_TOOLKIT_COLORS': {},
|
||||
'PROMPT_TOOLKIT_STYLES': None,
|
||||
'PUSHD_MINUS': False,
|
||||
'PUSHD_SILENT': False,
|
||||
'RAISE_SUBPROC_ERROR': False,
|
||||
|
@ -191,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')),
|
||||
|
@ -307,6 +312,10 @@ DEFAULT_DOCS = {
|
|||
"exit status) to not be added to the history list."),
|
||||
'IGNOREEOF': VarDocs('Prevents Ctrl-D from exiting the shell.'),
|
||||
'INDENT': VarDocs('Indentation string for multiline input'),
|
||||
'INTENSIFY_COLORS_ON_WIN': VarDocs('Enhance style colors for readability '
|
||||
'when using the default terminal (cmd.exe) on winodws. Blue colors, '
|
||||
'which are hard to read, are replaced with cyan. Other colors are '
|
||||
'generally replaced by their bright counter parts.'),
|
||||
'LOADED_CONFIG': VarDocs('Whether or not the xonsh config file was loaded',
|
||||
configurable=False),
|
||||
'LOADED_RC_FILES': VarDocs(
|
||||
|
@ -333,17 +342,6 @@ DEFAULT_DOCS = {
|
|||
"auto-formatted, see 'Customizing the Prompt' at "
|
||||
'http://xon.sh/tutorial.html#customizing-the-prompt.',
|
||||
default='xonsh.environ.DEFAULT_PROMPT'),
|
||||
'PROMPT_TOOLKIT_COLORS': VarDocs(
|
||||
'This is a mapping of from color names to HTML color codes. Whenever '
|
||||
'prompt-toolkit would color a word a particular color (in the prompt, '
|
||||
'or in syntax highlighting), it will use the value specified here to '
|
||||
'represent that color, instead of its default. If a color is not '
|
||||
'specified here, prompt-toolkit uses the colors from '
|
||||
"'xonsh.tools._PT_COLORS'.", configurable=False),
|
||||
'PROMPT_TOOLKIT_STYLES': VarDocs(
|
||||
'This is a mapping of pygments tokens to user-specified styles for '
|
||||
'prompt-toolkit. See the prompt-toolkit and pygments documentation '
|
||||
'for more details. If None, this is skipped.', configurable=False),
|
||||
'PUSHD_MINUS': VarDocs(
|
||||
'Flag for directory pushing functionality. False is the normal '
|
||||
'behavior.'),
|
||||
|
@ -398,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(
|
||||
|
@ -495,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
|
||||
|
@ -503,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)
|
||||
|
@ -567,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]
|
||||
|
@ -589,6 +605,8 @@ class Env(MutableMapping):
|
|||
#
|
||||
|
||||
def __getitem__(self, key):
|
||||
if key is Ellipsis:
|
||||
return self
|
||||
m = self._arg_regex.match(key)
|
||||
if (m is not None) and (key not in self._d) and ('ARGS' in self._d):
|
||||
args = self._d['ARGS']
|
||||
|
@ -615,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.
|
||||
|
@ -685,10 +714,15 @@ def _is_executable_file(path):
|
|||
|
||||
|
||||
def yield_executables_windows(directory, name):
|
||||
normalized_name = os.path.normcase(name)
|
||||
extensions = builtins.__xonsh_env__.get('PATHEXT')
|
||||
for a_file in os.listdir(directory):
|
||||
base_name, ext = os.path.splitext(a_file)
|
||||
if name == base_name and ext.upper() in extensions:
|
||||
normalized_file_name = os.path.normcase(a_file)
|
||||
base_name, ext = os.path.splitext(normalized_file_name)
|
||||
|
||||
if (
|
||||
normalized_name == base_name or normalized_name == normalized_file_name
|
||||
) and ext.upper() in extensions:
|
||||
yield os.path.join(directory, a_file)
|
||||
|
||||
|
||||
|
@ -706,9 +740,15 @@ def locate_binary(name):
|
|||
if os.path.isfile(name) and name != os.path.basename(name):
|
||||
return name
|
||||
|
||||
directories = builtins.__xonsh_env__.get('PATH')
|
||||
|
||||
# Windows users expect t obe able to execute files in the same directory without `./`
|
||||
if ON_WINDOWS:
|
||||
directories = [_get_cwd()] + directories
|
||||
|
||||
try:
|
||||
return next(chain.from_iterable(yield_executables(directory, name) for
|
||||
directory in builtins.__xonsh_env__.get('PATH') if os.path.isdir(directory)))
|
||||
directory in directories if os.path.isdir(directory)))
|
||||
except StopIteration:
|
||||
return None
|
||||
|
||||
|
@ -1135,9 +1175,36 @@ def load_static_config(ctx, config=None):
|
|||
return conf
|
||||
|
||||
|
||||
def _splitpath(path, sofar=[]):
|
||||
folder, path = os.path.split(path)
|
||||
if path == "":
|
||||
return sofar[::-1]
|
||||
elif folder == "":
|
||||
return (sofar + [path])[::-1]
|
||||
else:
|
||||
return _splitpath(folder, sofar + [path])
|
||||
|
||||
_CHARACTER_MAP = {chr(o): '_%s' % chr(o+32) for o in range(65, 91)}
|
||||
_CHARACTER_MAP.update({'.': '_.', '_': '__'})
|
||||
|
||||
|
||||
def _cache_renamer(path):
|
||||
path = os.path.abspath(path)
|
||||
o = [''.join(_CHARACTER_MAP.get(i, i) for i in w) for w in _splitpath(path)]
|
||||
o[-1] = "{}.{}".format(o[-1], sys.implementation.cache_tag)
|
||||
return o
|
||||
|
||||
|
||||
def _make_if_not_exists(dirname):
|
||||
if not os.path.isdir(dirname):
|
||||
os.makedirs(dirname)
|
||||
|
||||
|
||||
def xonshrc_context(rcfiles=None, execer=None):
|
||||
"""Attempts to read in xonshrc file, and return the contents."""
|
||||
loaded = builtins.__xonsh_env__['LOADED_RC_FILES'] = []
|
||||
datadir = builtins.__xonsh_env__['XONSH_DATA_DIR']
|
||||
cachedir = os.path.join(datadir, 'xonshrc_cache')
|
||||
if (rcfiles is None or execer is None):
|
||||
return {}
|
||||
env = {}
|
||||
|
@ -1145,21 +1212,38 @@ def xonshrc_context(rcfiles=None, execer=None):
|
|||
if not os.path.isfile(rcfile):
|
||||
loaded.append(False)
|
||||
continue
|
||||
with open(rcfile, 'r') as f:
|
||||
rc = f.read()
|
||||
if not rc.endswith('\n'):
|
||||
rc += '\n'
|
||||
fname = execer.filename
|
||||
try:
|
||||
execer.filename = rcfile
|
||||
execer.exec(rc, glbs=env)
|
||||
loaded.append(True)
|
||||
except SyntaxError as err:
|
||||
loaded.append(False)
|
||||
msg = 'syntax error in xonsh run control file {0!r}: {1!s}'
|
||||
warn(msg.format(rcfile, err), RuntimeWarning)
|
||||
finally:
|
||||
execer.filename = fname
|
||||
use_cached = False
|
||||
cachefname = os.path.join(cachedir, *_cache_renamer(rcfile))
|
||||
if os.path.isfile(cachefname):
|
||||
if os.stat(cachefname).st_mtime >= os.stat(rcfile).st_mtime:
|
||||
# use the compiled version and leave
|
||||
with open(cachefname, 'rb') as cfile:
|
||||
ccode = marshal.load(cfile)
|
||||
use_cached = True
|
||||
loaded.append(True)
|
||||
if not use_cached:
|
||||
with open(rcfile, 'r') as f:
|
||||
rc = f.read()
|
||||
if not rc.endswith('\n'):
|
||||
rc += '\n'
|
||||
fname = execer.filename
|
||||
try:
|
||||
execer.filename = rcfile
|
||||
ccode = execer.compile(rc, glbs=env)
|
||||
_make_if_not_exists(os.path.dirname(cachefname))
|
||||
with open(cachefname, 'wb') as cfile:
|
||||
marshal.dump(ccode, cfile)
|
||||
loaded.append(True)
|
||||
except SyntaxError as err:
|
||||
loaded.append(False)
|
||||
msg = 'syntax error in xonsh run control file {0!r}: {1!s}'
|
||||
warn(msg.format(rcfile, err), RuntimeWarning)
|
||||
continue
|
||||
finally:
|
||||
execer.filename = fname
|
||||
if ccode is None:
|
||||
return env
|
||||
exec(ccode, env, None)
|
||||
return env
|
||||
|
||||
|
||||
|
@ -1182,15 +1266,18 @@ def windows_env_fixes(ctx):
|
|||
ctx['PWD'] = _get_cwd()
|
||||
|
||||
|
||||
def default_env(env=None, config=None):
|
||||
def default_env(env=None, config=None, login=True):
|
||||
"""Constructs a default xonsh environment."""
|
||||
# in order of increasing precedence
|
||||
ctx = dict(BASE_ENV)
|
||||
ctx.update(os.environ)
|
||||
conf = load_static_config(ctx, config=config)
|
||||
ctx.update(conf.get('env', ()))
|
||||
ctx.update(load_foreign_envs(shells=conf.get('foreign_shells', DEFAULT_SHELLS),
|
||||
issue_warning=False))
|
||||
if login:
|
||||
ctx = dict(BASE_ENV)
|
||||
ctx.update(os.environ)
|
||||
conf = load_static_config(ctx, config=config)
|
||||
ctx.update(conf.get('env', ()))
|
||||
ctx.update(load_foreign_envs(shells=conf.get('foreign_shells', DEFAULT_SHELLS),
|
||||
issue_warning=False))
|
||||
else:
|
||||
ctx = {}
|
||||
if ON_WINDOWS:
|
||||
windows_env_fixes(ctx)
|
||||
# finalize env
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Implements the xonsh executer."""
|
||||
import re
|
||||
import os
|
||||
import types
|
||||
import inspect
|
||||
import builtins
|
||||
from collections import Iterable, Sequence, Mapping
|
||||
from collections import Mapping
|
||||
|
||||
from xonsh import ast
|
||||
from xonsh.parser import Parser
|
||||
|
@ -17,7 +15,7 @@ class Execer(object):
|
|||
"""Executes xonsh code in a context."""
|
||||
|
||||
def __init__(self, filename='<xonsh-code>', debug_level=0, parser_args=None,
|
||||
unload=True, config=None):
|
||||
unload=True, config=None, login=True):
|
||||
"""Parameters
|
||||
----------
|
||||
filename : str, optional
|
||||
|
@ -37,7 +35,7 @@ class Execer(object):
|
|||
self.debug_level = debug_level
|
||||
self.unload = unload
|
||||
self.ctxtransformer = ast.CtxAwareTransformer(self.parser)
|
||||
load_builtins(execer=self, config=config)
|
||||
load_builtins(execer=self, config=config, login=login)
|
||||
|
||||
def __del__(self):
|
||||
if self.unload:
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Hooks for Jupyter Xonsh Kernel."""
|
||||
import io
|
||||
import sys
|
||||
import builtins
|
||||
from pprint import pformat
|
||||
from tempfile import SpooledTemporaryFile
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"""The main xonsh script."""
|
||||
import os
|
||||
import sys
|
||||
import enum
|
||||
import builtins
|
||||
from argparse import ArgumentParser, ArgumentTypeError
|
||||
from contextlib import contextmanager
|
||||
|
@ -138,6 +139,11 @@ def _pprint_displayhook(value):
|
|||
pprint(value) # black & white case
|
||||
builtins._ = value
|
||||
|
||||
class XonshMode(enum.Enum):
|
||||
single_command = 0
|
||||
script_from_file = 1
|
||||
script_from_stdin = 2
|
||||
interactive = 3
|
||||
|
||||
def premain(argv=None):
|
||||
"""Setup for main xonsh entry point, returns parsed arguments."""
|
||||
|
@ -156,19 +162,35 @@ def premain(argv=None):
|
|||
version = '/'.join(('xonsh', __version__)),
|
||||
print(version)
|
||||
exit()
|
||||
shell_kwargs = {'shell_type': args.shell_type}
|
||||
shell_kwargs = {'shell_type': args.shell_type,
|
||||
'completer': False,
|
||||
'login': False}
|
||||
if args.login:
|
||||
shell_kwargs['login'] = True
|
||||
if args.config_path is None:
|
||||
shell_kwargs['config'] = args.config_path
|
||||
if args.norc:
|
||||
shell_kwargs['rc'] = ()
|
||||
setattr(sys, 'displayhook', _pprint_displayhook)
|
||||
if args.command is not None:
|
||||
args.mode = XonshMode.single_command
|
||||
shell_kwargs['shell_type'] = 'none'
|
||||
elif args.file is not None:
|
||||
args.mode = XonshMode.script_from_file
|
||||
shell_kwargs['shell_type'] = 'none'
|
||||
elif not sys.stdin.isatty() and not args.force_interactive:
|
||||
args.mode = XonshMode.script_from_stdin
|
||||
shell_kwargs['shell_type'] = 'none'
|
||||
else:
|
||||
args.mode = XonshMode.interactive
|
||||
shell_kwargs['completer'] = True
|
||||
shell_kwargs['login'] = True
|
||||
shell = builtins.__xonsh_shell__ = Shell(**shell_kwargs)
|
||||
from xonsh import imphooks
|
||||
env = builtins.__xonsh_env__
|
||||
env['XONSH_LOGIN'] = shell_kwargs['login']
|
||||
if args.defines is not None:
|
||||
env.update([x.split('=', 1) for x in args.defines])
|
||||
if args.login:
|
||||
env['XONSH_LOGIN'] = True
|
||||
env['XONSH_INTERACTIVE'] = False
|
||||
if ON_WINDOWS:
|
||||
setup_win_unicode_console(env.get('WIN_UNICODE_CONSOLE', True))
|
||||
|
@ -180,10 +202,10 @@ def main(argv=None):
|
|||
args = premain(argv)
|
||||
env = builtins.__xonsh_env__
|
||||
shell = builtins.__xonsh_shell__
|
||||
if args.command is not None:
|
||||
if args.mode == XonshMode.single_command:
|
||||
# run a single command and exit
|
||||
shell.default(args.command)
|
||||
elif args.file is not None:
|
||||
elif args.mode == XonshMode.script_from_file:
|
||||
# run a script contained in a file
|
||||
if os.path.isfile(args.file):
|
||||
with open(args.file) as f:
|
||||
|
@ -196,7 +218,7 @@ def main(argv=None):
|
|||
shell.execer.exec(code, mode='exec', glbs=shell.ctx)
|
||||
else:
|
||||
print('xonsh: {0}: No such file or directory.'.format(args.file))
|
||||
elif not sys.stdin.isatty() and not args.force_interactive:
|
||||
elif args.mode == XonshMode.script_from_stdin:
|
||||
# run a script given on stdin
|
||||
code = sys.stdin.read()
|
||||
code = code if code.endswith('\n') else code + '\n'
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Implements the base xonsh parser."""
|
||||
import os
|
||||
import sys
|
||||
from collections import Iterable, Sequence, Mapping
|
||||
|
||||
from ply import yacc
|
||||
|
@ -128,9 +126,12 @@ def xonsh_superhelp(x, lineno=None, col=None):
|
|||
return xonsh_call('__xonsh_superhelp__', [x], lineno=lineno, col=col)
|
||||
|
||||
|
||||
def xonsh_regexpath(x, lineno=None, col=None):
|
||||
"""Creates the AST node for calling the __xonsh_regexpath__() function."""
|
||||
return xonsh_call('__xonsh_regexpath__', [x], lineno=lineno, col=col)
|
||||
def xonsh_regexpath(x, pymode=False, lineno=None, col=None):
|
||||
"""Creates the AST node for calling the __xonsh_regexpath__() function.
|
||||
The pymode argument indicate if it is called from subproc or python mode"""
|
||||
pymode = ast.NameConstant(value=pymode, lineno=lineno, col_offset=col)
|
||||
return xonsh_call('__xonsh_regexpath__', args=[x, pymode], lineno=lineno,
|
||||
col=col)
|
||||
|
||||
|
||||
def load_ctx(x):
|
||||
|
@ -1593,7 +1594,7 @@ class BaseParser(object):
|
|||
return leader
|
||||
p0 = leader
|
||||
for trailer in trailers:
|
||||
if isinstance(trailer, (ast.Index, ast.Slice)):
|
||||
if isinstance(trailer, (ast.Index, ast.Slice, ast.ExtSlice)):
|
||||
p0 = ast.Subscript(value=leader,
|
||||
slice=trailer,
|
||||
ctx=ast.Load(),
|
||||
|
@ -1722,7 +1723,8 @@ class BaseParser(object):
|
|||
"""atom : REGEXPATH"""
|
||||
p1 = ast.Str(s=p[1].strip('`'), lineno=self.lineno,
|
||||
col_offset=self.col)
|
||||
p[0] = xonsh_regexpath(p1, lineno=self.lineno, col=self.col)
|
||||
p[0] = xonsh_regexpath(p1, pymode=True, lineno=self.lineno,
|
||||
col=self.col)
|
||||
|
||||
def p_atom_dname(self, p):
|
||||
"""atom : DOLLAR_NAME"""
|
||||
|
@ -1798,7 +1800,12 @@ class BaseParser(object):
|
|||
def p_subscriptlist(self, p):
|
||||
"""subscriptlist : subscript comma_subscript_list_opt comma_opt"""
|
||||
p1, p2 = p[1], p[2]
|
||||
if p2 is not None:
|
||||
if p2 is None:
|
||||
pass
|
||||
elif isinstance(p1, ast.Slice) or \
|
||||
any([isinstance(x, ast.Slice) for x in p2]):
|
||||
p1 = ast.ExtSlice(dims=[p1]+p2)
|
||||
else:
|
||||
p1.value = ast.Tuple(elts=[p1.value] + [x.value for x in p2],
|
||||
ctx=ast.Load(), lineno=p1.lineno,
|
||||
col_offset=p1.col_offset)
|
||||
|
@ -2167,22 +2174,6 @@ class BaseParser(object):
|
|||
p0._cliarg_action = 'splitlines'
|
||||
p[0] = p0
|
||||
|
||||
def p_subproc_atom_captured_object(self, p):
|
||||
"""subproc_atom : bang_lparen_tok subproc RPAREN"""
|
||||
p1 = p[1]
|
||||
p0 = xonsh_call('__xonsh_subproc_captured_object__', args=p[2],
|
||||
lineno=p1.lineno, col=p1.lexpos)
|
||||
p0._cliarg_action = 'splitlines'
|
||||
p[0] = p0
|
||||
|
||||
def p_subproc_atom_captured_hiddenobject(self, p):
|
||||
"""subproc_atom : bang_lbracket_tok subproc RBRACKET"""
|
||||
p1 = p[1]
|
||||
p0 = xonsh_call('__xonsh_subproc_captured_hiddenobject__', args=p[2],
|
||||
lineno=p1.lineno, col=p1.lexpos)
|
||||
p0._cliarg_action = 'splitlines'
|
||||
p[0] = p0
|
||||
|
||||
def p_subproc_atom_pyenv_lookup(self, p):
|
||||
"""subproc_atom : dollar_lbrace_tok test RBRACE"""
|
||||
p1 = p[1]
|
||||
|
@ -2227,7 +2218,8 @@ class BaseParser(object):
|
|||
"""subproc_atom : REGEXPATH"""
|
||||
p1 = ast.Str(s=p[1].strip('`'), lineno=self.lineno,
|
||||
col_offset=self.col)
|
||||
p0 = xonsh_regexpath(p1, lineno=self.lineno, col=self.col)
|
||||
p0 = xonsh_regexpath(p1, pymode=False, lineno=self.lineno,
|
||||
col=self.col)
|
||||
p0._cliarg_action = 'extend'
|
||||
p[0] = p0
|
||||
|
||||
|
|
|
@ -1,12 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Implements the xonsh parser for Python v3.4."""
|
||||
import os
|
||||
import sys
|
||||
from collections import Iterable, Sequence, Mapping
|
||||
|
||||
from xonsh import ast
|
||||
from xonsh.lexer import LexToken
|
||||
from xonsh.parsers.base import BaseParser, xonsh_help, xonsh_superhelp
|
||||
from xonsh.parsers.base import BaseParser
|
||||
|
||||
|
||||
class Parser(BaseParser):
|
||||
|
|
|
@ -1,12 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Implements the xonsh parser for Python v3.5."""
|
||||
import os
|
||||
import sys
|
||||
from collections import Iterable, Sequence, Mapping
|
||||
|
||||
from xonsh import ast
|
||||
from xonsh.lexer import LexToken
|
||||
from xonsh.parsers.base import BaseParser, xonsh_help, xonsh_superhelp
|
||||
from xonsh.parsers.base import BaseParser
|
||||
|
||||
|
||||
class Parser(BaseParser):
|
||||
|
|
|
@ -539,7 +539,8 @@ _CCTuple = namedtuple("_CCTuple", ["stdin",
|
|||
"alias",
|
||||
"stdin_redirect",
|
||||
"stdout_redirect",
|
||||
"stderr_redirect"])
|
||||
"stderr_redirect",
|
||||
"timestamp"])
|
||||
|
||||
class CompletedCommand(_CCTuple):
|
||||
"""Represents a completed subprocess-mode command."""
|
||||
|
|
|
@ -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,
|
||||
|
@ -48,14 +48,15 @@ class PromptToolkitCompleter(Completer):
|
|||
except AttributeError:
|
||||
#new layout to become default
|
||||
window = cli.application.layout.children[1].content
|
||||
h = window.render_info.content_height
|
||||
r = builtins.__xonsh_env__.get('COMPLETIONS_MENU_ROWS')
|
||||
size = h + r
|
||||
def comp_height(cli):
|
||||
# If there is an autocompletion menu to be shown, make sure that o
|
||||
# layout has at least a minimal height in order to display it.
|
||||
if not cli.is_done:
|
||||
return LayoutDimension(min=size)
|
||||
else:
|
||||
return LayoutDimension()
|
||||
window._height = comp_height
|
||||
if window and window.render_info:
|
||||
h = window.render_info.content_height
|
||||
r = builtins.__xonsh_env__.get('COMPLETIONS_MENU_ROWS')
|
||||
size = h + r
|
||||
def comp_height(cli):
|
||||
# If there is an autocompletion menu to be shown, make sure that o
|
||||
# layout has at least a minimal height in order to display it.
|
||||
if not cli.is_done:
|
||||
return LayoutDimension(min=size)
|
||||
else:
|
||||
return LayoutDimension()
|
||||
window._height = comp_height
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""History object for use with prompt_toolkit."""
|
||||
import os
|
||||
import time
|
||||
import builtins
|
||||
from threading import Thread
|
||||
|
||||
import prompt_toolkit.history
|
||||
from prompt_toolkit.buffer import Buffer
|
||||
|
||||
from xonsh import lazyjson
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""The prompt_toolkit based xonsh shell."""
|
||||
import builtins
|
||||
from warnings import warn
|
||||
|
||||
from prompt_toolkit.key_binding.manager import KeyBindingManager
|
||||
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
|
||||
|
@ -15,7 +14,7 @@ from pygments.token import (Keyword, Name, Comment, String, Error, Number,
|
|||
Operator, Generic, Whitespace, Token)
|
||||
|
||||
from xonsh.base_shell import BaseShell
|
||||
from xonsh.tools import print_exception, format_color
|
||||
from xonsh.tools import print_exception
|
||||
from xonsh.environ import partial_format_prompt
|
||||
from xonsh.pyghooks import XonshLexer, XonshStyle, partial_color_tokenize, \
|
||||
xonsh_style_proxy
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""A prompt-toolkit inspired shortcut collection."""
|
||||
from prompt_toolkit.interface import CommandLineInterface
|
||||
from prompt_toolkit.utils import DummyContext
|
||||
from prompt_toolkit.shortcuts import (create_prompt_application,
|
||||
from prompt_toolkit.shortcuts import (create_prompt_application,
|
||||
create_eventloop, create_asyncio_eventloop, create_output)
|
||||
|
||||
from xonsh.shell import prompt_toolkit_version_info
|
||||
|
@ -9,7 +9,7 @@ from xonsh.shell import prompt_toolkit_version_info
|
|||
class Prompter(object):
|
||||
|
||||
def __init__(self, cli=None, *args, **kwargs):
|
||||
"""Implements a prompt that statefully holds a command-line
|
||||
"""Implements a prompt that statefully holds a command-line
|
||||
interface. When used as a context manager, it will return itself
|
||||
on entry and reset itself on exit.
|
||||
|
||||
|
@ -33,18 +33,18 @@ class Prompter(object):
|
|||
def prompt(self, message='', **kwargs):
|
||||
"""Get input from the user and return it.
|
||||
|
||||
This is a wrapper around a lot of prompt_toolkit functionality and
|
||||
can be a replacement for raw_input. (or GNU readline.) If you want
|
||||
to keep your history across several calls, create one
|
||||
`~prompt_toolkit.history.History instance and pass it every
|
||||
time. This function accepts many keyword arguments. Except for the
|
||||
following. they are a proxy to the arguments of
|
||||
This is a wrapper around a lot of prompt_toolkit functionality and
|
||||
can be a replacement for raw_input. (or GNU readline.) If you want
|
||||
to keep your history across several calls, create one
|
||||
`~prompt_toolkit.history.History instance and pass it every
|
||||
time. This function accepts many keyword arguments. Except for the
|
||||
following. they are a proxy to the arguments of
|
||||
create_prompt_application().
|
||||
|
||||
Parameters
|
||||
----------
|
||||
patch_stdout : file-like, optional
|
||||
Replace ``sys.stdout`` by a proxy that ensures that print
|
||||
Replace ``sys.stdout`` by a proxy that ensures that print
|
||||
statements from other threads won't destroy the prompt. (They
|
||||
will be printed above the prompt instead.)
|
||||
return_asyncio_coroutine : bool, optional
|
||||
|
@ -64,6 +64,8 @@ class Prompter(object):
|
|||
|
||||
# Create CommandLineInterface.
|
||||
if self.cli is None:
|
||||
if self.major_minor < (0, 57):
|
||||
kwargs.pop('reserve_space_for_menu', None)
|
||||
if self.major_minor <= (0, 57):
|
||||
kwargs.pop('get_rprompt_tokens', None)
|
||||
kwargs.pop('get_continuation_tokens', None)
|
||||
|
@ -93,9 +95,9 @@ class Prompter(object):
|
|||
'''), exec_context)
|
||||
return exec_context['prompt_coro']()
|
||||
else:
|
||||
# Note: We pass `reset_current_buffer=False`, because that way
|
||||
# it's easy to give DEFAULT_BUFFER a default value, without it
|
||||
# getting erased. We don't have to reset anyway, because this is
|
||||
# Note: We pass `reset_current_buffer=False`, because that way
|
||||
# it's easy to give DEFAULT_BUFFER a default value, without it
|
||||
# getting erased. We don't have to reset anyway, because this is
|
||||
# the first and only time that this CommandLineInterface will run.
|
||||
try:
|
||||
with patch_context:
|
||||
|
@ -140,7 +142,7 @@ except ImportError:
|
|||
This method was forked from the mainline prompt-toolkit repo.
|
||||
Copyright (c) 2014, Jonathan Slenders, All rights reserved.
|
||||
This is deprecated and slated for removal after a prompt-toolkit
|
||||
v0.57+ release.
|
||||
v0.57+ release.
|
||||
"""
|
||||
stdout = stdout or sys.__stdout__
|
||||
true_color = to_simple_filter(true_color)
|
||||
|
@ -179,7 +181,7 @@ except ImportError:
|
|||
This method was forked from the mainline prompt-toolkit repo.
|
||||
Copyright (c) 2014, Jonathan Slenders, All rights reserved.
|
||||
This is deprecated and slated for removal after a prompt-toolkit
|
||||
v0.57+ release.
|
||||
v0.57+ release.
|
||||
"""
|
||||
assert isinstance(style, Style)
|
||||
output = create_output(true_color=true_color)
|
||||
|
|
|
@ -16,6 +16,8 @@ from pygments.style import Style
|
|||
from pygments.styles import get_style_by_name
|
||||
import pygments.util
|
||||
|
||||
from xonsh.tools import (ON_WINDOWS, intensify_colors_for_cmd_exe,
|
||||
expand_gray_colors_for_cmd_exe)
|
||||
|
||||
class XonshSubprocLexer(BashLexer):
|
||||
"""Lexer for xonsh subproc mode."""
|
||||
|
@ -28,8 +30,8 @@ class XonshSubprocLexer(BashLexer):
|
|||
ROOT_TOKENS = [(r'\?', Keyword),
|
||||
(r'\$\w+', Name.Variable),
|
||||
(r'\$\{', Keyword, ('pymode', )),
|
||||
(r'\$\(', Keyword, ('subproc', )),
|
||||
(r'\$\[', Keyword, ('subproc', )),
|
||||
(r'[\!\$]\(', Keyword, ('subproc', )),
|
||||
(r'[\!\$]\[', Keyword, ('subproc', )),
|
||||
(r'@\(', Keyword, ('pymode', )),
|
||||
inherit, ]
|
||||
|
||||
|
@ -281,7 +283,8 @@ class XonshStyle(Style):
|
|||
style_name : str, optional
|
||||
The style name to initialize with.
|
||||
"""
|
||||
self.trap = {} # for custom colors
|
||||
self.trap = {} # for traping custom colors set by user
|
||||
self._smap = {}
|
||||
self._style_name = ''
|
||||
self.style_name = style_name
|
||||
super().__init__()
|
||||
|
@ -301,17 +304,34 @@ class XonshStyle(Style):
|
|||
RuntimeWarning)
|
||||
cmap = DEFAULT_STYLE
|
||||
try:
|
||||
smap = get_style_by_name(value)().styles
|
||||
self._smap = get_style_by_name(value)().styles.copy()
|
||||
except (ImportError, pygments.util.ClassNotFound):
|
||||
smap = XONSH_BASE_STYLE
|
||||
compound = CompoundColorMap(ChainMap(self.trap, cmap, PTK_STYLE, smap))
|
||||
self.styles = ChainMap(self.trap, cmap, PTK_STYLE, smap, compound)
|
||||
self._smap = XONSH_BASE_STYLE.copy()
|
||||
compound = CompoundColorMap(ChainMap(self.trap, cmap, PTK_STYLE, self._smap))
|
||||
self.styles = ChainMap(self.trap, cmap, PTK_STYLE, self._smap, compound)
|
||||
self._style_name = value
|
||||
if ON_WINDOWS:
|
||||
self.enhance_colors_for_cmd_exe()
|
||||
|
||||
@style_name.deleter
|
||||
def style_name(self):
|
||||
self._style_name = ''
|
||||
|
||||
def enhance_colors_for_cmd_exe(self):
|
||||
""" Enhance colors when using cmd.exe on windows.
|
||||
When using the default style all blue and dark red colors
|
||||
are changed to CYAN and intence red.
|
||||
"""
|
||||
env = builtins.__xonsh_env__
|
||||
# Ensure we are not using ConEmu
|
||||
if 'CONEMUANSI' not in env:
|
||||
# Auto suggest needs to be a darker shade to be distinguishable
|
||||
# from the default color
|
||||
self.styles[Token.AutoSuggestion] = '#444444'
|
||||
if env.get('INTENSIFY_COLORS_ON_WIN', False):
|
||||
self._smap.update(expand_gray_colors_for_cmd_exe(self._smap))
|
||||
self._smap.update(intensify_colors_for_cmd_exe(self._smap))
|
||||
|
||||
|
||||
def xonsh_style_proxy(styler):
|
||||
"""Factory for a proxy class to a xonsh style."""
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""The readline based xonsh shell."""
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import select
|
||||
import builtins
|
||||
from cmd import Cmd
|
||||
from warnings import warn
|
||||
from threading import Thread, Lock
|
||||
from threading import Thread
|
||||
from collections import deque
|
||||
|
||||
from xonsh import lazyjson
|
||||
|
|
|
@ -73,6 +73,8 @@ class Shell(object):
|
|||
rc : list of str, optional
|
||||
Sequence of paths to run control files.
|
||||
"""
|
||||
self.login = kwargs.get('login', True)
|
||||
self.stype = shell_type
|
||||
self._init_environ(ctx, config, rc)
|
||||
env = builtins.__xonsh_env__
|
||||
# pick a valid shell
|
||||
|
@ -88,23 +90,23 @@ class Shell(object):
|
|||
warn('prompt_toolkit is not available, using readline instead.')
|
||||
shell_type = env['SHELL_TYPE'] = 'readline'
|
||||
# actually make the shell
|
||||
if shell_type == 'prompt_toolkit':
|
||||
if shell_type == 'none':
|
||||
from xonsh.base_shell import BaseShell as shell_class
|
||||
elif shell_type == 'prompt_toolkit':
|
||||
vptk = prompt_toolkit_version()
|
||||
minor = int(vptk.split('.')[1])
|
||||
if minor < 57 or vptk == '<0.57': # TODO: remove in future
|
||||
msg = ('prompt-toolkit version < v0.57 and may not work as '
|
||||
'expected. Please update.')
|
||||
warn(msg, RuntimeWarning)
|
||||
from xonsh.ptk.shell import PromptToolkitShell
|
||||
self.shell = PromptToolkitShell(execer=self.execer,
|
||||
ctx=self.ctx, **kwargs)
|
||||
from xonsh.ptk.shell import PromptToolkitShell as shell_class
|
||||
elif shell_type == 'readline':
|
||||
from xonsh.readline_shell import ReadlineShell
|
||||
self.shell = ReadlineShell(execer=self.execer,
|
||||
ctx=self.ctx, **kwargs)
|
||||
from xonsh.readline_shell import ReadlineShell as shell_class
|
||||
else:
|
||||
raise XonshError('{} is not recognized as a shell type'.format(
|
||||
shell_type))
|
||||
self.shell = shell_class(execer=self.execer,
|
||||
ctx=self.ctx, **kwargs)
|
||||
# allows history garbace colector to start running
|
||||
builtins.__xonsh_history__.gc.wait_for_shell = False
|
||||
|
||||
|
@ -113,11 +115,14 @@ class Shell(object):
|
|||
return getattr(self.shell, attr)
|
||||
|
||||
def _init_environ(self, ctx, config, rc):
|
||||
self.execer = Execer(config=config)
|
||||
self.execer = Execer(config=config, login=self.login)
|
||||
env = builtins.__xonsh_env__
|
||||
if ctx is None:
|
||||
rc = env.get('XONSHRC') if rc is None else rc
|
||||
self.ctx = xonshrc_context(rcfiles=rc, execer=self.execer)
|
||||
if self.stype == 'none' and not self.login:
|
||||
self.ctx = {}
|
||||
else:
|
||||
rc = env.get('XONSHRC') if rc is None else rc
|
||||
self.ctx = xonshrc_context(rcfiles=rc, execer=self.execer)
|
||||
else:
|
||||
self.ctx = ctx
|
||||
builtins.__xonsh_ctx__ = self.ctx
|
||||
|
|
|
@ -733,6 +733,78 @@ def color_style():
|
|||
return builtins.__xonsh_shell__.shell.color_style()
|
||||
|
||||
|
||||
try:
|
||||
import prompt_toolkit
|
||||
except ImportError:
|
||||
prompt_toolkit = None
|
||||
|
||||
|
||||
def _get_color_indexes(style_map):
|
||||
""" Generates the color and windows color index for a style """
|
||||
table = prompt_toolkit.terminal.win32_output.ColorLookupTable()
|
||||
pt_style = prompt_toolkit.styles.style_from_dict(style_map)
|
||||
for token in style_map:
|
||||
attr = pt_style.token_to_attrs[token]
|
||||
if attr.color is not None:
|
||||
index = table.lookup_color(attr.color, attr.bgcolor)
|
||||
try:
|
||||
rgb = (int(attr.color[0:2], 16),
|
||||
int(attr.color[2:4], 16),
|
||||
int(attr.color[4:6], 16))
|
||||
except:
|
||||
rgb = None
|
||||
yield token, index, rgb
|
||||
|
||||
|
||||
def intensify_colors_for_cmd_exe(style_map, replace_colors=None):
|
||||
"""Returns a modified style to where colors that maps to dark
|
||||
colors are replaced with brighter versions. Also expands the
|
||||
range used by the gray colors
|
||||
"""
|
||||
modified_style = {}
|
||||
if not ON_WINDOWS or prompt_toolkit is None:
|
||||
return modified_style
|
||||
if replace_colors is None:
|
||||
replace_colors = {1: '#44ffff', # subst blue with bright cyan
|
||||
2: '#44ff44', # subst green with bright green
|
||||
4: '#ff4444', # subst red with bright red
|
||||
5: '#ff44ff', # subst magenta with bright magenta
|
||||
6: '#ffff44', # subst yellow with bright yellow
|
||||
9: '#00aaaa', # subst intense blue (hard to read)
|
||||
# with dark cyan (which is readable)
|
||||
}
|
||||
for token, idx, _ in _get_color_indexes(style_map):
|
||||
if idx in replace_colors:
|
||||
modified_style[token] = replace_colors[idx]
|
||||
return modified_style
|
||||
|
||||
|
||||
def expand_gray_colors_for_cmd_exe(style_map):
|
||||
""" Expand the style's gray scale color range.
|
||||
All gray scale colors has a tendency to map to the same default GRAY
|
||||
in cmd.exe.
|
||||
"""
|
||||
modified_style = {}
|
||||
if not ON_WINDOWS or prompt_toolkit is None:
|
||||
return modified_style
|
||||
for token, idx, rgb in _get_color_indexes(style_map):
|
||||
if idx == 7 and rgb:
|
||||
if sum(rgb) <= 306:
|
||||
# Equal and below '#666666 is reset to dark gray
|
||||
modified_style[token] = '#444444'
|
||||
elif sum(rgb) >= 408:
|
||||
# Equal and above 0x888888 is reset to white
|
||||
modified_style[token] = '#ffffff'
|
||||
return modified_style
|
||||
|
||||
|
||||
def intensify_colors_on_win_setter(enable):
|
||||
""" Resets the style when setting the INTENSIFY_COLORS_ON_WIN
|
||||
environment variable. """
|
||||
enable = to_bool(enable)
|
||||
delattr(builtins.__xonsh_shell__.shell.styler, 'style_name')
|
||||
return enable
|
||||
|
||||
|
||||
_RE_STRING_START = "[bBrRuU]*"
|
||||
_RE_STRING_TRIPLE_DOUBLE = '"""'
|
||||
|
@ -917,6 +989,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:
|
||||
|
|
130
xonsh/winutils.py
Normal file
130
xonsh/winutils.py
Normal file
|
@ -0,0 +1,130 @@
|
|||
"""
|
||||
This file is based on the code from https://github.com/JustAMan/pyWinClobber/blob/master/win32elevate.py
|
||||
|
||||
Copyright (c) 2013 by JustAMan at GitHub
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
import ctypes
|
||||
from ctypes.wintypes import HANDLE, BOOL, DWORD, HWND, HINSTANCE, HKEY
|
||||
from ctypes import c_ulong, c_char_p, c_int, c_void_p
|
||||
|
||||
P_HANDLE = ctypes.POINTER(HANDLE)
|
||||
P_WORD = ctypes.POINTER(DWORD)
|
||||
|
||||
CloseHandle = ctypes.windll.kernel32.CloseHandle
|
||||
CloseHandle.argtypes = (HANDLE, )
|
||||
CloseHandle.restype = BOOL
|
||||
|
||||
GetActiveWindow = ctypes.windll.user32.GetActiveWindow
|
||||
GetActiveWindow.argtypes = ()
|
||||
GetActiveWindow.restype = HANDLE
|
||||
|
||||
TOKEN_READ = 0x20008
|
||||
|
||||
|
||||
class ShellExecuteInfo(ctypes.Structure):
|
||||
_fields_ = [
|
||||
('cbSize', DWORD),
|
||||
('fMask', c_ulong),
|
||||
('hwnd', HWND),
|
||||
('lpVerb', c_char_p),
|
||||
('lpFile', c_char_p),
|
||||
('lpParameters', c_char_p),
|
||||
('lpDirectory', c_char_p),
|
||||
('nShow', c_int),
|
||||
('hInstApp', HINSTANCE),
|
||||
('lpIDList', c_void_p),
|
||||
('lpClass', c_char_p),
|
||||
('hKeyClass', HKEY),
|
||||
('dwHotKey', DWORD),
|
||||
('hIcon', HANDLE),
|
||||
('hProcess', HANDLE)
|
||||
]
|
||||
|
||||
def __init__(self, **kw):
|
||||
ctypes.Structure.__init__(self)
|
||||
self.cbSize = ctypes.sizeof(self)
|
||||
for field_name, field_value in kw.items():
|
||||
setattr(self, field_name, field_value)
|
||||
|
||||
PShellExecuteInfo = ctypes.POINTER(ShellExecuteInfo)
|
||||
|
||||
ShellExecuteEx = ctypes.windll.Shell32.ShellExecuteExA
|
||||
ShellExecuteEx.argtypes = (PShellExecuteInfo, )
|
||||
ShellExecuteEx.restype = BOOL
|
||||
|
||||
WaitForSingleObject = ctypes.windll.kernel32.WaitForSingleObject
|
||||
WaitForSingleObject.argtypes = (HANDLE, DWORD)
|
||||
WaitForSingleObject.restype = DWORD
|
||||
|
||||
# SW_HIDE = 0
|
||||
SW_SHOW = 5
|
||||
SEE_MASK_NOCLOSEPROCESS = 0x00000040
|
||||
SEE_MASK_NO_CONSOLE = 0x00008000
|
||||
INFINITE = -1
|
||||
|
||||
|
||||
def wait_and_close_handle(process_handle):
|
||||
"""
|
||||
Waits till spawned process finishes and closes the handle for it
|
||||
|
||||
:param process_handle: The Windows handle for the process
|
||||
:type process_handle: HANDLE
|
||||
"""
|
||||
WaitForSingleObject(process_handle, INFINITE)
|
||||
CloseHandle(process_handle)
|
||||
|
||||
|
||||
def sudo(executable, args=None):
|
||||
"""
|
||||
This will re-run current Python script requesting to elevate administrative rights.
|
||||
|
||||
:param executable: The path/name of the executable
|
||||
:type executable: str
|
||||
:param args: The arguments to be passed to the executable
|
||||
:type args: list
|
||||
"""
|
||||
if not args:
|
||||
args = []
|
||||
|
||||
execute_info = ShellExecuteInfo(
|
||||
fMask=SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NO_CONSOLE,
|
||||
hwnd=GetActiveWindow(),
|
||||
lpVerb=b'runas',
|
||||
lpFile=executable.encode('utf-8'),
|
||||
lpParameters=subprocess.list2cmdline(args).encode('utf-8'),
|
||||
lpDirectory=None,
|
||||
nShow=SW_SHOW
|
||||
)
|
||||
|
||||
if not all(stream.isatty() for stream in (sys.stdin, sys.stdout, sys.stderr)):
|
||||
# TODO: Some streams were redirected, we need to manually work them
|
||||
raise NotImplementedError("Redirection is not supported")
|
||||
|
||||
if not ShellExecuteEx(ctypes.byref(execute_info)):
|
||||
raise ctypes.WinError()
|
||||
|
||||
wait_and_close_handle(execute_info.hProcess)
|
||||
|
||||
|
||||
__all__ = ('sudo', )
|
|
@ -6,7 +6,7 @@ import json
|
|||
import builtins
|
||||
import textwrap
|
||||
from pprint import pformat
|
||||
from collections.abc import MutableSequence, Mapping, Sequence
|
||||
from collections.abc import Mapping, Sequence
|
||||
|
||||
from xonsh.tools import to_bool, to_bool_or_break, backup_file, print_color
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
"""The xonsh configuration (xonfig) utility."""
|
||||
import os
|
||||
import ast
|
||||
import json
|
||||
import shutil
|
||||
|
@ -324,6 +323,8 @@ def _tok_colors(cmap, cols):
|
|||
|
||||
def _colors(ns):
|
||||
cols, _ = shutil.get_terminal_size()
|
||||
if tools.ON_WINDOWS:
|
||||
cols -= 1
|
||||
cmap = tools.color_style()
|
||||
akey = next(iter(cmap))
|
||||
if isinstance(akey, str):
|
||||
|
|
Loading…
Add table
Reference in a new issue