mirror of
https://github.com/b-ryan/powerline-shell.git
synced 2026-09-10 07:26:28 -04:00
Merge remote-tracking branch 'origin/master' into bryangrimes-aws_profile
Conflicts: .gitignore README.md powerline_shell/themes/default.py
This commit is contained in:
commit
d469133a33
7
.gitignore
vendored
7
.gitignore
vendored
|
|
@ -1,6 +1,11 @@
|
|||
powerline-shell.py
|
||||
*.py[co]
|
||||
config.py
|
||||
|
||||
powerline_shell.egg-info/
|
||||
/build/
|
||||
/dist/
|
||||
tags
|
||||
config.json
|
||||
powerline-shell.json
|
||||
.DS_Store
|
||||
*sublime*
|
||||
|
|
|
|||
5
.travis.yml
Normal file
5
.travis.yml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
language: python
|
||||
script: |
|
||||
./setup.py install
|
||||
pip install -r requirements-dev.txt
|
||||
nosetests
|
||||
157
CHANGELOG.md
Normal file
157
CHANGELOG.md
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
# Changes
|
||||
|
||||
Unreleased
|
||||
|
||||
* Fix username segment's background color after "su" command
|
||||
([@Fak3](https://github.com/banga/powerline-shell/pull/175))
|
||||
* New `battery` segment which shows the percentage your battery is charged and
|
||||
an icon when your battery is charging.
|
||||
([@wattengard](https://github.com/banga/powerline-shell/pull/204))
|
||||
|
||||
2017-09-30 (version 0.3.0)
|
||||
|
||||
* Redo Fossil segment to be consistent with git, svn, etc.
|
||||
([@emansije](https://github.com/banga/powerline-shell/pull/286))
|
||||
* Fix subshell execution in bash described by
|
||||
[pw3nage](https://github.com/njhartwell/pw3nage)
|
||||
([@b-ryan](https://github.com/banga/powerline-shell/pull/282))
|
||||
* Change SSH segment to just use the text `SSH` instead of showing a lock
|
||||
symbol. Closes [#287](https://github.com/banga/powerline-shell/issues/287).
|
||||
|
||||
2017-09-18 (version 0.2.2)
|
||||
|
||||
* Fix python3 issue in uptime segment. Fixes
|
||||
[#291](https://github.com/banga/powerline-shell/issues/291).
|
||||
|
||||
2017-09-16 (version 0.2.1)
|
||||
|
||||
* Fix issues preventing fish shell from rendering.
|
||||
|
||||
2017-09-13 (version 0.2.0)
|
||||
|
||||
* Add Bazaar segment
|
||||
([@emansije](https://github.com/banga/powerline-shell/pull/283))
|
||||
* And rename properties of RepoStats for clarity
|
||||
([@emansije](https://github.com/banga/powerline-shell/pull/284))
|
||||
* Rewrite SVN segment to be consistent with git
|
||||
* Remove duplicate function in colortrans.py
|
||||
([@jmtd](https://github.com/banga/powerline-shell/pull/273))
|
||||
* Make python 3 check compatible with older Python versions
|
||||
* New theme! `solarized_light`
|
||||
([@ruturajv](https://github.com/banga/powerline-shell/pull/143)
|
||||
|
||||
2017-09-10
|
||||
|
||||
* Complete overhaul of the project
|
||||
([@b-ryan](https://github.com/banga/powerline-shell/pull/280))
|
||||
* There is now a PyPi package
|
||||
* It's significantly faster now
|
||||
* Configuration and installation is brand new. See README.md
|
||||
|
||||
2017-06-21
|
||||
|
||||
* Add `rbenv` segment
|
||||
([@dogo](https://github.com/banga/powerline-shell/pull/260))
|
||||
* Fix path segment so that current directory is emphasized
|
||||
([@inamiy](https://github.com/banga/powerline-shell/pull/235))
|
||||
|
||||
2017-06-20
|
||||
|
||||
* Add `newline` segment
|
||||
([@ffried](https://github.com/banga/powerline-shell/pull/266))
|
||||
* Add `npm_version` segment
|
||||
([@WileESpaghetti](https://github.com/banga/powerline-shell/pull/265))
|
||||
* Fix issue with conda environments
|
||||
([@drorata](https://github.com/banga/powerline-shell/pull/257))
|
||||
* Fix jobs segment for Cygwin
|
||||
([@themiwi](https://github.com/banga/powerline-shell/pull/256))
|
||||
|
||||
2017-05-15
|
||||
|
||||
* Fix the `set_term_title` segment for ZSH
|
||||
([@themiwi](https://github.com/banga/powerline-shell/pull/255))
|
||||
|
||||
2016-04-16
|
||||
|
||||
* Fix issue around unicode function for python 3
|
||||
|
||||
2016-04-01
|
||||
|
||||
* Refactor of the way the git segment manages data about git's state.
|
||||
([@b-ryan](https://github.com/milkbikis/powerline-shell/pull/221))
|
||||
|
||||
2015-12-26
|
||||
|
||||
* Beginnings of unit testing for segments. Included in this change was a
|
||||
refactor of the way segments are added to powerline. Now, instead of looking
|
||||
for a global `powerline` object, `powerline` is passed into the function to
|
||||
add the segment. Segments will also no longer add the segments by calling the
|
||||
`add` function themselves.
|
||||
([@b-ryan](https://github.com/milkbikis/powerline-shell/pull/212))
|
||||
* Python3 fixes for `lib/color_compliment.py`.
|
||||
([@ceholden](https://github.com/milkbikis/powerline-shell/pull/220))
|
||||
|
||||
2015-11-25
|
||||
|
||||
* `virtual_env` segment now supports environments made with `conda`
|
||||
([@ceholden](https://github.com/milkbikis/powerline-shell/pull/198))
|
||||
|
||||
2015-11-21
|
||||
|
||||
* Fixes for Python 3 compatibility
|
||||
([@b-ryan](https://github.com/milkbikis/powerline-shell/pull/211))
|
||||
|
||||
2015-11-18
|
||||
|
||||
* The git segment has gotten a makeover
|
||||
([@MartinWetterwald](https://github.com/milkbikis/powerline-shell/pull/136))
|
||||
* Fix git segment when git is not on the standard PATH
|
||||
([@andrejgl](https://github.com/milkbikis/powerline-shell/pull/153))
|
||||
* Fix `--cwd-max-depth` showing duplicates when it's <= 2
|
||||
([@b-ryan](https://github.com/milkbikis/powerline-shell/pull/209))
|
||||
* Add padding around `exit_code` segment
|
||||
([@phatblat](https://github.com/milkbikis/powerline-shell/pull/205))
|
||||
|
||||
2015-10-02
|
||||
|
||||
* New option (`--cwd-max-dir-size`) which allows you to limit each directory
|
||||
that is displayed to a number of characters. This currently does not apply
|
||||
if you are using `--cwd-mode plain`.
|
||||
([@mart-e](https://github.com/milkbikis/powerline-shell/pull/127))
|
||||
|
||||
2015-08-26
|
||||
|
||||
* New `plain` mode of displaying the current working directory which can be
|
||||
used by adding `--cwd-only plain` to `powerline-shell.py`.
|
||||
This deprecates the `--cwd-only` option. `--cwd-mode dironly` can be used
|
||||
instead. ([@paol](https://github.com/milkbikis/powerline-shell/pull/156))
|
||||
|
||||
2015-08-18
|
||||
|
||||
* New `time` segment
|
||||
([@filipebarros](https://github.com/milkbikis/powerline-shell/pull/107))
|
||||
|
||||
2015-08-01
|
||||
|
||||
* Use `print` function for some python3 compatibility
|
||||
([@strycore](https://github.com/milkbikis/powerline-shell/pull/195))
|
||||
|
||||
2015-07-31
|
||||
|
||||
* The current working directory no longer follows symbolic links
|
||||
* New `exit_code` segment
|
||||
([@disruptek](https://github.com/milkbikis/powerline-shell/pull/129))
|
||||
|
||||
2015-07-30
|
||||
|
||||
* Fix ZSH root indicator
|
||||
([@nkcfan](https://github.com/milkbikis/powerline-shell/pull/150))
|
||||
* Add uptime segment
|
||||
([@marcioAlmada](https://github.com/milkbikis/powerline-shell/pull/139))
|
||||
|
||||
2015-07-27
|
||||
|
||||
* Use `python2` instead of `python` in hashbangs
|
||||
([@Undeterminant](https://github.com/milkbikis/powerline-shell/pull/100))
|
||||
* Add `node_version` segment
|
||||
([@mmilleruva](https://github.com/milkbikis/powerline-shell/pull/189))
|
||||
338
README.md
338
README.md
|
|
@ -1,93 +1,90 @@
|
|||
A Powerline style prompt for your shell
|
||||
=======================================
|
||||
# A Powerline style prompt for your shell
|
||||
|
||||
A [Powerline](https://github.com/Lokaltog/vim-powerline) like prompt for Bash, ZSH and Fish:
|
||||
A [Powerline](https://github.com/Lokaltog/vim-powerline) like prompt for Bash,
|
||||
ZSH and Fish:
|
||||
|
||||

|
||||

|
||||
|
||||
* Shows some important details about the git/svn/hg/fossil branch (see below)
|
||||
* Changes color if the last command exited with a failure code
|
||||
* If you're too deep into a directory tree, shortens the displayed path with an ellipsis
|
||||
* Shows the current Python [virtualenv](http://www.virtualenv.org/) environment
|
||||
* It's easy to customize and extend. See below for details.
|
||||
- Shows some important details about the git/svn/hg/fossil branch (see below)
|
||||
- Changes color if the last command exited with a failure code
|
||||
- If you're too deep into a directory tree, shortens the displayed path with an ellipsis
|
||||
- Shows the current Python [virtualenv](http://www.virtualenv.org/) environment
|
||||
- It's easy to customize and extend. See below for details.
|
||||
|
||||
### Version Control
|
||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
|
||||
|
||||
- [Version Control](#version-control)
|
||||
- [Setup](#setup)
|
||||
- [Bash](#bash)
|
||||
- [ZSH](#zsh)
|
||||
- [Fish](#fish)
|
||||
- [Customization](#customization)
|
||||
- [Config File](#config-file)
|
||||
- [Adding, Removing and Re-arranging segments](#adding-removing-and-re-arranging-segments)
|
||||
- [Segment Separator](#segment-separator)
|
||||
- [Themes](#themes)
|
||||
- [Segment Configuration](#segment-configuration)
|
||||
- [Contributing new types of segments](#contributing-new-types-of-segments)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
## Version Control
|
||||
|
||||
All of the version control systems supported by powerline shell give you a
|
||||
quick look into the state of your repo:
|
||||
|
||||
* The current branch is displayed and changes background color when the
|
||||
- The current branch is displayed and changes background color when the
|
||||
branch is dirty.
|
||||
* When the local branch differs from the remote, the difference in number
|
||||
- When the local branch differs from the remote, the difference in number
|
||||
of commits is shown along with `⇡` or `⇣` indicating whether a git push
|
||||
or pull is pending
|
||||
|
||||
In addition, git has a few extra symbols:
|
||||
|
||||
* `✎` -- a file has been modified, but not staged for commit
|
||||
* `✔` -- a file is staged for commit
|
||||
* `✼` -- a file has conflicts
|
||||
- `✎` -- a file has been modified, but not staged for commit
|
||||
- `✔` -- a file is staged for commit
|
||||
- `✼` -- a file has conflicts
|
||||
|
||||
FIXME
|
||||
* A `+` appears when untracked files are present (except for git, which
|
||||
uses `?` instead)
|
||||
|
||||
- A `+` appears when untracked files are present (except for git, which uses
|
||||
`?` instead)
|
||||
|
||||
Each of these will have a number next to it if more than one file matches.
|
||||
|
||||
# Setup
|
||||
## Setup
|
||||
|
||||
This script uses ANSI color codes to display colors in a terminal. These are
|
||||
notoriously non-portable, so may not work for you out of the box, but try
|
||||
setting your $TERM to `xterm-256color`, because that works for me.
|
||||
|
||||
* Patch the font you use for your terminal: see https://github.com/Lokaltog/powerline-fonts
|
||||
- Patch the font you use for your terminal: see
|
||||
[powerline-fonts](https://github.com/Lokaltog/powerline-fonts)
|
||||
- If you struggle too much to get working fonts in your terminal, you can use
|
||||
"compatible" mode.
|
||||
- If you're using old patched fonts, you have to use the older symbols.
|
||||
Basically reverse [this
|
||||
commit](https://github.com/milkbikis/powerline-shell/commit/2a84ecc) in
|
||||
your copy
|
||||
|
||||
* If you struggle too much to get working fonts in your terminal, you can use "compatible" mode.
|
||||
* If you're using old patched fonts, you have to use the older symbols. Basically reverse [this commit](https://github.com/milkbikis/powerline-shell/commit/2a84ecc) in your copy
|
||||
|
||||
* Clone this repository somewhere:
|
||||
|
||||
git clone https://github.com/milkbikis/powerline-shell
|
||||
|
||||
* Copy `config.py.dist` to `config.py` and edit it to configure the segments you want. Then run
|
||||
|
||||
./install.py
|
||||
|
||||
* This will generate `powerline-shell.py`
|
||||
|
||||
* (optional) Create a symlink to this python script in your home:
|
||||
|
||||
ln -s <path/to/powerline-shell.py> ~/powerline-shell.py
|
||||
|
||||
* If you don't want the symlink, just modify the path in the commands below
|
||||
|
||||
* For python2.6 you have to install argparse
|
||||
|
||||
pip install argparse
|
||||
|
||||
### All Shells:
|
||||
There are a few optional arguments which can be seen by running `powerline-shell.py --help`.
|
||||
- Install using pip:
|
||||
|
||||
```
|
||||
--cwd-mode {fancy,plain,dironly}
|
||||
How to display the current directory
|
||||
--cwd-max-depth CWD_MAX_DEPTH
|
||||
Maximum number of directories to show in path
|
||||
--cwd-max-dir-size CWD_MAX_DIR_SIZE
|
||||
Maximum number of letters displayed for each directory
|
||||
in the path
|
||||
--colorize-hostname Colorize the hostname based on a hash of itself.
|
||||
--mode {patched,compatible,flat}
|
||||
The characters used to make separators between
|
||||
segments
|
||||
pip install powerline-shell
|
||||
```
|
||||
|
||||
### Bash:
|
||||
- Setup your shell prompt using the instructions for your shell below.
|
||||
|
||||
### Bash
|
||||
|
||||
Add the following to your `.bashrc` (or `.profile` on Mac):
|
||||
|
||||
```
|
||||
function _update_ps1() {
|
||||
PS1="$(~/powerline-shell.py $? 2> /dev/null)"
|
||||
PS1="$(powerline-shell $?)"
|
||||
}
|
||||
|
||||
if [ "$TERM" != "linux" ]; then
|
||||
|
|
@ -95,12 +92,13 @@ if [ "$TERM" != "linux" ]; then
|
|||
fi
|
||||
```
|
||||
|
||||
### ZSH:
|
||||
### ZSH
|
||||
|
||||
Add the following to your `.zshrc`:
|
||||
|
||||
```
|
||||
function powerline_precmd() {
|
||||
PS1="$(~/powerline-shell.py $? --shell zsh 2> /dev/null)"
|
||||
PS1="$(powerline-shell --shell zsh $?)"
|
||||
}
|
||||
|
||||
function install_powerline_precmd() {
|
||||
|
|
@ -117,32 +115,126 @@ if [ "$TERM" != "linux" ]; then
|
|||
fi
|
||||
```
|
||||
|
||||
### Fish:
|
||||
### Fish
|
||||
|
||||
Redefine `fish_prompt` in ~/.config/fish/config.fish:
|
||||
|
||||
```
|
||||
function fish_prompt
|
||||
~/powerline-shell.py $status --shell bare ^/dev/null
|
||||
powerline-shell --shell bare $status
|
||||
end
|
||||
```
|
||||
|
||||
# Customization
|
||||
## Customization
|
||||
|
||||
### Config File
|
||||
|
||||
Powerline-shell is customizable through the use of a config file. This file is
|
||||
expected to be located at `~/.powerline-shell.json`. You can generate the
|
||||
default config at this location using:
|
||||
|
||||
```
|
||||
powerline-shell --generate-config > ~/.powerline-shell.json
|
||||
```
|
||||
|
||||
(You can see an example config file
|
||||
[here](https://github.com/b-ryan/dotfiles/blob/master/home/powerline-shell.json))
|
||||
|
||||
### Adding, Removing and Re-arranging segments
|
||||
|
||||
The `config.py` file defines which segments are drawn and in which order. Simply
|
||||
comment out and rearrange segment names to get your desired arrangement. Every
|
||||
time you change `config.py`, run `install.py`, which will generate a new
|
||||
`powerline-shell.py` customized to your configuration. You should see the new
|
||||
prompt immediately.
|
||||
Once you have generated your config file, you can now start adding or removing
|
||||
"segments" - the building blocks of your shell. The list of segments available
|
||||
are:
|
||||
|
||||
- `bzr` - Details about the current Bazaar repo.
|
||||
- `cwd` - Shows your current working directory. See [Segment
|
||||
Configuration](#segment-configuration) for some options.
|
||||
- `exit_code` - When the previous command ends in a non-zero status, shows the
|
||||
value of the exist status in red.
|
||||
- `fossil` - Details about the current Fossil repo.
|
||||
- `git` - Details about the current Git repo.
|
||||
- `hg` - Details about the current Mercurial repo.
|
||||
- `hostname` - Current machine's hostname.
|
||||
- `jobs` - Number of background jobs currently running.
|
||||
- `newline` - Inserts a newline into the prompt.
|
||||
- `node_version` - `node --version`
|
||||
- `npm_version` - `npm --version`
|
||||
- `php_version` - Version of php on the machine
|
||||
- `rbenv` - `rbenv local`
|
||||
- `read_only` - Shows a lock icon if the current directory is read-only.
|
||||
- `root` - Shows a `#` if logged in as root, `$` otherwise.
|
||||
- `ruby_version` - `ruby --version`
|
||||
- `set_term_title` - If able, sets the title of your terminal to include some
|
||||
useful info.
|
||||
- `ssh` - If logged into over SSH, shows a network icon.
|
||||
- `svn` - Details about the current SVN repo.
|
||||
- `time` - Shows the current time
|
||||
- `uptime` - Uptime of the current machine
|
||||
- `username` - Name of the logged-in user
|
||||
- `virtual_env` - Shows the name of the current virtual env or conda env.
|
||||
|
||||
### Segment Separator
|
||||
|
||||
By default, a unicode character (resembling the > symbol) is used to separate
|
||||
each segment. This can be changed by changing the "mode" option in the config
|
||||
file. The available modes are:
|
||||
|
||||
- `patched` - The default
|
||||
- `compatible` - Attempts to use characters that may already be available using
|
||||
your chosen font.
|
||||
- `flat` - No separator is used between segments, giving each segment a
|
||||
rectangular appearance (and also saves space).
|
||||
|
||||
### Themes
|
||||
|
||||
The `powerline_shell/themes` directory stores themes for your prompt, which are
|
||||
basically color values used by segments. The `default.py` defines a default
|
||||
theme which can be used standalone, and every other theme falls back to it if
|
||||
they miss colors for any segments. Create new themes by copying any other
|
||||
existing theme and changing the values. To use a theme, set the `theme`
|
||||
variable in `~/.powerline-shell.json` to the name of your theme.
|
||||
|
||||
A script for testing color combinations is provided at `colortest.py`. Note
|
||||
that the colors you see may vary depending on your terminal. When designing a
|
||||
theme, please test your theme on multiple terminals, especially with default
|
||||
settings.
|
||||
|
||||
### Segment Configuration
|
||||
|
||||
Some segments support additional configuration. The options for the segment are
|
||||
nested under the name of the segment itself. For example, all of the options
|
||||
for the `cwd` segment are set in `~/.powerline-shell.py` like:
|
||||
|
||||
```
|
||||
{
|
||||
"segments": [...],
|
||||
"cwd": {
|
||||
options go here
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The options for the `cwd` segment are:
|
||||
|
||||
- `mode`: If "plain" then simple text will be used to show the cwd. If
|
||||
"dironly," only the current directory will be shown. Otherwise expands the
|
||||
cwd into individual directories.
|
||||
- `max_depth`: Maximum number of directories to show in path
|
||||
- `max_dir_size`: Maximum number of characters displayed for each directory in
|
||||
the path
|
||||
|
||||
The `hostname` segment provides one option:
|
||||
|
||||
- `colorize`: If true, the hostname will be colorized based on a hash of
|
||||
itself.
|
||||
|
||||
### Contributing new types of segments
|
||||
|
||||
The `segments` directory contains python scripts which are injected as is into
|
||||
a single file `powerline_shell_base.py`. Each segment script defines a function
|
||||
that inserts one or more segments into the prompt. If you want to add a new
|
||||
segment, simply create a new file in the segments directory and add its name to
|
||||
the `config.py` file at the appropriate location.
|
||||
The `powerline_shell/segments` directory contains python scripts which are
|
||||
injected as is into a single file `powerline_shell_base.py`. Each segment
|
||||
script defines a function that inserts one or more segments into the prompt. If
|
||||
you want to add a new segment, simply create a new file in the segments
|
||||
directory.
|
||||
|
||||
Make sure that your script does not introduce new globals which might conflict
|
||||
with other scripts. Your script should fail silently and run quickly in any
|
||||
|
|
@ -153,102 +245,10 @@ segment you create. Test your segment with this theme first.
|
|||
|
||||
You should add tests for your segment as best you are able. Unit and
|
||||
integration tests are both welcome. Run your tests with the `nosetests` command
|
||||
after install the requirements in `dev_requirements.txt`.
|
||||
after install the requirements in `requirements-dev.txt`.
|
||||
|
||||
### Themes
|
||||
## Troubleshooting
|
||||
|
||||
The `themes` directory stores themes for your prompt, which are basically color
|
||||
values used by segments. The `default.py` defines a default theme which can be
|
||||
used standalone, and every other theme falls back to it if they miss colors for
|
||||
any segments. Create new themes by copying any other existing theme and
|
||||
changing the values. To use a theme, set the `THEME` variable in `config.py` to
|
||||
the name of your theme.
|
||||
|
||||
A script for testing color combinations is provided at `themes/colortest.py`.
|
||||
Note that the colors you see may vary depending on your terminal. When designing
|
||||
a theme, please test your theme on multiple terminals, especially with default
|
||||
settings.
|
||||
|
||||
# Changes
|
||||
|
||||
2016-01-14
|
||||
|
||||
* AWS profle support added per the `AWS_DEFAULT_PROFILE` setup described in [the AWS docs](http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html)
|
||||
* `$ export AWS_DEFAULT_PROFILE=<NAME>`
|
||||
|
||||
|
||||
2015-12-26
|
||||
|
||||
* Beginnings of unit testing for segments. Included in this change was a
|
||||
refactor of the way segments are added to powerline. Now, instead of looking
|
||||
for a global `powerline` object, `powerline` is passed into the function to
|
||||
add the segment. Segments will also no longer add the segments by calling the
|
||||
`add` function themselves.
|
||||
([@b-ryan](https://github.com/milkbikis/powerline-shell/pull/212))
|
||||
* Python3 fixes for `lib/color_compliment.py`.
|
||||
([@ceholden](https://github.com/milkbikis/powerline-shell/pull/220))
|
||||
|
||||
2015-11-25
|
||||
|
||||
* `virtual_env` segment now supports environments made with `conda`
|
||||
([@ceholden](https://github.com/milkbikis/powerline-shell/pull/198))
|
||||
|
||||
2015-11-21
|
||||
|
||||
* Fixes for Python 3 compatibility
|
||||
([@b-ryan](https://github.com/milkbikis/powerline-shell/pull/211))
|
||||
|
||||
2015-11-18
|
||||
|
||||
* The git segment has gotten a makeover
|
||||
([@MartinWetterwald](https://github.com/milkbikis/powerline-shell/pull/136))
|
||||
* Fix git segment when git is not on the standard PATH
|
||||
([@andrejgl](https://github.com/milkbikis/powerline-shell/pull/153))
|
||||
* Fix `--cwd-max-depth` showing duplicates when it's <= 2
|
||||
([@b-ryan](https://github.com/milkbikis/powerline-shell/pull/209))
|
||||
* Add padding around `exit_code` segment
|
||||
([@phatblat](https://github.com/milkbikis/powerline-shell/pull/205))
|
||||
|
||||
2015-10-02
|
||||
|
||||
* New option (`--cwd-max-dir-size`) which allows you to limit each directory
|
||||
that is displayed to a number of characters. This currently does not apply
|
||||
if you are using `--cwd-mode plain`.
|
||||
([@mart-e](https://github.com/milkbikis/powerline-shell/pull/127))
|
||||
|
||||
2015-08-26
|
||||
|
||||
* New `plain` mode of displaying the current working directory which can be
|
||||
used by adding `--cwd-only plain` to `powerline-shell.py`.
|
||||
This deprecates the `--cwd-only` option. `--cwd-mode dironly` can be used
|
||||
instead. ([@paol](https://github.com/milkbikis/powerline-shell/pull/156))
|
||||
|
||||
2015-08-18
|
||||
|
||||
* New `time` segment
|
||||
([@filipebarros](https://github.com/milkbikis/powerline-shell/pull/107))
|
||||
|
||||
2015-08-01
|
||||
|
||||
* Use `print` function for some python3 compatibility
|
||||
([@strycore](https://github.com/milkbikis/powerline-shell/pull/195))
|
||||
|
||||
2015-07-31
|
||||
|
||||
* The current working directory no longer follows symbolic links
|
||||
* New `exit_code` segment
|
||||
([@disruptek](https://github.com/milkbikis/powerline-shell/pull/129))
|
||||
|
||||
2015-07-30
|
||||
|
||||
* Fix ZSH root indicator
|
||||
([@nkcfan](https://github.com/milkbikis/powerline-shell/pull/150))
|
||||
* Add uptime segment
|
||||
([@marcioAlmada](https://github.com/milkbikis/powerline-shell/pull/139))
|
||||
|
||||
2015-07-27
|
||||
|
||||
* Use `python2` instead of `python` in hashbangs
|
||||
([@Undeterminant](https://github.com/milkbikis/powerline-shell/pull/100))
|
||||
* Add `node_version` segment
|
||||
([@mmilleruva](https://github.com/milkbikis/powerline-shell/pull/189))
|
||||
See the [FAQ](https://github.com/banga/powerline-shell/wiki/FAQ). If you
|
||||
continue to have issues, please open an
|
||||
[issue](https://github.com/banga/powerline-shell/issues/new).
|
||||
|
|
|
|||
BIN
bash-powerline-screenshot.png
Normal file
BIN
bash-powerline-screenshot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
|
|
@ -1,5 +0,0 @@
|
|||
dependencies:
|
||||
pre:
|
||||
- sudo pip install -r dev_requirements.txt
|
||||
- git config --global user.email "tester@example.com"
|
||||
- git config --global user.name "Tester McGee"
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
# This is the configuration file for your powerline-shell prompt
|
||||
# Every time you make a change to this file, run install.py to apply changes
|
||||
#
|
||||
# For instructions on how to use the powerline-shell.py script, see the README
|
||||
|
||||
# Add, remove or rearrange these segments to customize what you see on the shell
|
||||
# prompt. Any segment you add must be present in the segments/ directory
|
||||
|
||||
SEGMENTS = [
|
||||
# Set the terminal window title to user@host:dir
|
||||
# 'set_term_title',
|
||||
|
||||
# Show current virtual environment (see http://www.virtualenv.org/)
|
||||
'virtual_env',
|
||||
|
||||
# Show the current user's username as in ordinary prompts
|
||||
'username',
|
||||
|
||||
# Show the machine's hostname. Mostly used when ssh-ing into other machines
|
||||
'hostname',
|
||||
|
||||
# Show a padlock when ssh-ing from another machine
|
||||
'ssh',
|
||||
|
||||
# Show the current directory. If the path is too long, the middle part is
|
||||
# replaced with ellipsis ('...')
|
||||
'cwd',
|
||||
|
||||
# Show a padlock if the current user has no write access to the current
|
||||
# directory
|
||||
'read_only',
|
||||
|
||||
# Show the current git branch and status
|
||||
'git',
|
||||
|
||||
# Show the current mercurial branch and status
|
||||
'hg',
|
||||
|
||||
# Show the current svn branch and status
|
||||
'svn',
|
||||
|
||||
# Show the current fossil branch and status
|
||||
'fossil',
|
||||
|
||||
# Show number of running jobs
|
||||
'jobs',
|
||||
|
||||
# Show the last command's exit code if it was non-zero
|
||||
# 'exit_code',
|
||||
|
||||
# Shows a '#' if the current user is root, '$' otherwise
|
||||
# Also, changes color if the last command exited with a non-zero error code
|
||||
'root',
|
||||
]
|
||||
|
||||
# Change the colors used to draw individual segments in your prompt
|
||||
THEME = 'default'
|
||||
49
install.py
49
install.py
|
|
@ -1,49 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
from __future__ import print_function
|
||||
import os
|
||||
import stat
|
||||
|
||||
try:
|
||||
import config
|
||||
except ImportError:
|
||||
print('Created personal config.py for your customizations')
|
||||
import shutil
|
||||
shutil.copyfile('config.py.dist', 'config.py')
|
||||
import config
|
||||
|
||||
TEMPLATE_FILE = 'powerline_shell_base.py'
|
||||
OUTPUT_FILE = 'powerline-shell.py'
|
||||
SEGMENTS_DIR = 'segments'
|
||||
THEMES_DIR = 'themes'
|
||||
|
||||
def load_source(srcfile):
|
||||
try:
|
||||
return ''.join(open(srcfile).readlines()) + '\n\n'
|
||||
except IOError:
|
||||
print('Could not open', srcfile)
|
||||
return ''
|
||||
|
||||
if __name__ == "__main__":
|
||||
source = load_source(TEMPLATE_FILE)
|
||||
source += load_source(os.path.join(THEMES_DIR, 'default.py'))
|
||||
|
||||
if config.THEME != 'default':
|
||||
source += load_source(os.path.join(THEMES_DIR, config.THEME + '.py'))
|
||||
|
||||
for segment in config.SEGMENTS:
|
||||
source += load_source(os.path.join(SEGMENTS_DIR, segment + '.py'))
|
||||
|
||||
# assumes each segment file will have a function called
|
||||
# add_segment__[segment] that accepts the powerline object
|
||||
source += 'add_{}_segment(powerline)\n'.format(segment)
|
||||
|
||||
source += 'sys.stdout.write(powerline.draw())\n'
|
||||
|
||||
try:
|
||||
open(OUTPUT_FILE, 'w').write(source)
|
||||
st = os.stat(OUTPUT_FILE)
|
||||
os.chmod(OUTPUT_FILE, st.st_mode | stat.S_IEXEC)
|
||||
print(OUTPUT_FILE, 'saved successfully')
|
||||
except IOError:
|
||||
print('ERROR: Could not write to powerline-shell.py. Make sure it is writable')
|
||||
exit(1)
|
||||
251
powerline_shell_base.py → powerline_shell/__init__.py
Executable file → Normal file
251
powerline_shell_base.py → powerline_shell/__init__.py
Executable file → Normal file
|
|
@ -1,94 +1,14 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
import importlib
|
||||
import json
|
||||
from .utils import warn, py3
|
||||
import re
|
||||
|
||||
py3 = sys.version_info.major == 3
|
||||
|
||||
|
||||
def warn(msg):
|
||||
print('[powerline-bash] ', msg)
|
||||
|
||||
|
||||
class Powerline:
|
||||
symbols = {
|
||||
'compatible': {
|
||||
'lock': 'RO',
|
||||
'network': 'SSH',
|
||||
'separator': u'\u25B6',
|
||||
'separator_thin': u'\u276F'
|
||||
},
|
||||
'patched': {
|
||||
'lock': u'\uE0A2',
|
||||
'network': u'\uE0A2',
|
||||
'separator': u'\uE0B0',
|
||||
'separator_thin': u'\uE0B1'
|
||||
},
|
||||
'flat': {
|
||||
'lock': '',
|
||||
'network': '',
|
||||
'separator': '',
|
||||
'separator_thin': ''
|
||||
},
|
||||
}
|
||||
|
||||
color_templates = {
|
||||
'bash': '\\[\\e%s\\]',
|
||||
'zsh': '%%{%s%%}',
|
||||
'bare': '%s',
|
||||
}
|
||||
|
||||
def __init__(self, args, cwd):
|
||||
self.args = args
|
||||
self.cwd = cwd
|
||||
mode, shell = args.mode, args.shell
|
||||
self.color_template = self.color_templates[shell]
|
||||
self.reset = self.color_template % '[0m'
|
||||
self.lock = Powerline.symbols[mode]['lock']
|
||||
self.network = Powerline.symbols[mode]['network']
|
||||
self.separator = Powerline.symbols[mode]['separator']
|
||||
self.separator_thin = Powerline.symbols[mode]['separator_thin']
|
||||
self.segments = []
|
||||
|
||||
def color(self, prefix, code):
|
||||
if code is None:
|
||||
return ''
|
||||
else:
|
||||
return self.color_template % ('[%s;5;%sm' % (prefix, code))
|
||||
|
||||
def fgcolor(self, code):
|
||||
return self.color('38', code)
|
||||
|
||||
def bgcolor(self, code):
|
||||
return self.color('48', code)
|
||||
|
||||
def append(self, content, fg, bg, separator=None, separator_fg=None):
|
||||
self.segments.append((content, fg, bg,
|
||||
separator if separator is not None else self.separator,
|
||||
separator_fg if separator_fg is not None else bg))
|
||||
|
||||
def draw(self):
|
||||
text = (''.join(self.draw_segment(i) for i in range(len(self.segments)))
|
||||
+ self.reset) + ' '
|
||||
if py3:
|
||||
return text
|
||||
else:
|
||||
return text.encode('utf-8')
|
||||
|
||||
def draw_segment(self, idx):
|
||||
segment = self.segments[idx]
|
||||
next_segment = self.segments[idx + 1] if idx < len(self.segments)-1 else None
|
||||
|
||||
return ''.join((
|
||||
self.fgcolor(segment[1]),
|
||||
self.bgcolor(segment[2]),
|
||||
segment[0],
|
||||
self.bgcolor(next_segment[2]) if next_segment else self.reset,
|
||||
self.fgcolor(segment[4]),
|
||||
segment[3]))
|
||||
|
||||
def get_valid_cwd():
|
||||
""" We check if the current working directory is valid or not. Typically
|
||||
|
|
@ -120,26 +40,153 @@ def get_valid_cwd():
|
|||
return cwd
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
class Powerline(object):
|
||||
symbols = {
|
||||
'compatible': {
|
||||
'lock': 'RO',
|
||||
'network': 'SSH',
|
||||
'separator': u'\u25B6',
|
||||
'separator_thin': u'\u276F'
|
||||
},
|
||||
'patched': {
|
||||
'lock': u'\uE0A2',
|
||||
'network': 'SSH',
|
||||
'separator': u'\uE0B0',
|
||||
'separator_thin': u'\uE0B1'
|
||||
},
|
||||
'flat': {
|
||||
'lock': u'\uE0A2',
|
||||
'network': 'SSH',
|
||||
'separator': '',
|
||||
'separator_thin': ''
|
||||
},
|
||||
}
|
||||
|
||||
color_templates = {
|
||||
'bash': '\\[\\e%s\\]',
|
||||
'zsh': '%%{%s%%}',
|
||||
'bare': '%s',
|
||||
}
|
||||
|
||||
def __init__(self, args, config, theme):
|
||||
self.args = args
|
||||
self.config = config
|
||||
self.theme = theme
|
||||
self.cwd = get_valid_cwd()
|
||||
mode = config.get("mode", "patched")
|
||||
self.color_template = self.color_templates[args.shell]
|
||||
self.reset = self.color_template % '[0m'
|
||||
self.lock = Powerline.symbols[mode]['lock']
|
||||
self.network = Powerline.symbols[mode]['network']
|
||||
self.separator = Powerline.symbols[mode]['separator']
|
||||
self.separator_thin = Powerline.symbols[mode]['separator_thin']
|
||||
self.segments = []
|
||||
|
||||
def segment_conf(self, seg_name, key, default=None):
|
||||
return self.config.get(seg_name, {}).get(key, default)
|
||||
|
||||
def color(self, prefix, code):
|
||||
if code is None:
|
||||
return ''
|
||||
elif code == self.theme.RESET:
|
||||
return self.reset
|
||||
else:
|
||||
return self.color_template % ('[%s;5;%sm' % (prefix, code))
|
||||
|
||||
def fgcolor(self, code):
|
||||
return self.color('38', code)
|
||||
|
||||
def bgcolor(self, code):
|
||||
return self.color('48', code)
|
||||
|
||||
def append(self, content, fg, bg, separator=None, separator_fg=None):
|
||||
self.segments.append((content, fg, bg,
|
||||
separator if separator is not None else self.separator,
|
||||
separator_fg if separator_fg is not None else bg))
|
||||
|
||||
def draw(self):
|
||||
text = (''.join(self.draw_segment(i) for i in range(len(self.segments)))
|
||||
+ self.reset) + ' '
|
||||
if py3:
|
||||
return text
|
||||
else:
|
||||
return text.encode('utf-8')
|
||||
|
||||
def draw_segment(self, idx):
|
||||
segment = self.segments[idx]
|
||||
if self.args.shell == "bash":
|
||||
sanitized = re.sub(r"([`$])", r"\\\1", segment[0])
|
||||
else:
|
||||
sanitized = segment[0]
|
||||
next_segment = self.segments[idx + 1] if idx < len(self.segments)-1 else None
|
||||
|
||||
return ''.join((
|
||||
self.fgcolor(segment[1]),
|
||||
self.bgcolor(segment[2]),
|
||||
sanitized,
|
||||
self.bgcolor(next_segment[2]) if next_segment else self.reset,
|
||||
self.fgcolor(segment[4]),
|
||||
segment[3]))
|
||||
|
||||
|
||||
def find_config():
|
||||
for location in [
|
||||
"powerline-shell.json",
|
||||
"~/.powerline-shell.json",
|
||||
]:
|
||||
full = os.path.expanduser(location)
|
||||
if os.path.exists(full):
|
||||
return full
|
||||
|
||||
DEFAULT_CONFIG = {
|
||||
"segments": [
|
||||
'virtual_env',
|
||||
'username',
|
||||
'hostname',
|
||||
'ssh',
|
||||
'cwd',
|
||||
'git',
|
||||
'hg',
|
||||
'jobs',
|
||||
'root',
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
arg_parser = argparse.ArgumentParser()
|
||||
arg_parser.add_argument('--cwd-mode', action='store',
|
||||
help='How to display the current directory', default='fancy',
|
||||
choices=['fancy', 'plain', 'dironly'])
|
||||
arg_parser.add_argument('--cwd-only', action='store_true',
|
||||
help='Deprecated. Use --cwd-mode=dironly')
|
||||
arg_parser.add_argument('--cwd-max-depth', action='store', type=int,
|
||||
default=5, help='Maximum number of directories to show in path')
|
||||
arg_parser.add_argument('--cwd-max-dir-size', action='store', type=int,
|
||||
help='Maximum number of letters displayed for each directory in the path')
|
||||
arg_parser.add_argument('--colorize-hostname', action='store_true',
|
||||
help='Colorize the hostname based on a hash of itself.')
|
||||
arg_parser.add_argument('--mode', action='store', default='patched',
|
||||
help='The characters used to make separators between segments',
|
||||
choices=['patched', 'compatible', 'flat'])
|
||||
arg_parser.add_argument('--generate-config', action='store_true',
|
||||
help='Generate the default config and print it to stdout')
|
||||
arg_parser.add_argument('--shell', action='store', default='bash',
|
||||
help='Set this to your shell type', choices=['bash', 'zsh', 'bare'])
|
||||
help='Set this to your shell type',
|
||||
choices=['bash', 'zsh', 'bare'])
|
||||
arg_parser.add_argument('prev_error', nargs='?', type=int, default=0,
|
||||
help='Error code returned by the last command')
|
||||
help='Error code returned by the last command')
|
||||
args = arg_parser.parse_args()
|
||||
|
||||
powerline = Powerline(args, get_valid_cwd())
|
||||
if args.generate_config:
|
||||
print(json.dumps(DEFAULT_CONFIG, indent=2))
|
||||
return 0
|
||||
|
||||
config_path = find_config()
|
||||
if config_path:
|
||||
with open(config_path) as f:
|
||||
config = json.loads(f.read())
|
||||
else:
|
||||
config = DEFAULT_CONFIG
|
||||
|
||||
theme_name = config.get("theme", "default")
|
||||
mod = importlib.import_module("powerline_shell.themes." + theme_name)
|
||||
theme = getattr(mod, "Color")
|
||||
|
||||
powerline = Powerline(args, config, theme)
|
||||
segments = []
|
||||
for seg_name in config["segments"]:
|
||||
mod = importlib.import_module("powerline_shell.segments." + seg_name)
|
||||
segment = getattr(mod, "Segment")(powerline)
|
||||
segment.start()
|
||||
segments.append(segment)
|
||||
for segment in segments:
|
||||
segment.add_to_powerline()
|
||||
sys.stdout.write(powerline.draw())
|
||||
return 0
|
||||
12
lib/color_compliment.py → powerline_shell/color_compliment.py
Executable file → Normal file
12
lib/color_compliment.py → powerline_shell/color_compliment.py
Executable file → Normal file
|
|
@ -1,4 +1,3 @@
|
|||
#! /usr/bin/env python
|
||||
from colorsys import hls_to_rgb, rgb_to_hls
|
||||
# md5 deprecated since Python 2.5
|
||||
try:
|
||||
|
|
@ -6,19 +5,13 @@ try:
|
|||
except ImportError:
|
||||
from hashlib import md5
|
||||
import sys
|
||||
|
||||
# Original, non-relative import errors on Python3
|
||||
from .colortrans import *
|
||||
|
||||
py3 = sys.version_info[0] == 3
|
||||
from .utils import py3
|
||||
|
||||
|
||||
def getOppositeColor(r,g,b):
|
||||
hls = rgb_to_hls(r,g,b)
|
||||
#print "hls is"
|
||||
#print hls
|
||||
opp = list(hls[:])
|
||||
#opp[0] = (opp[0]+0.5)%1 # reverse hue (a.k.a. color), reversing tends to be jarring
|
||||
opp[0] = (opp[0]+0.2)%1 # shift hue (a.k.a. color)
|
||||
if opp[1] > 255/2: # for level you want to make sure they
|
||||
opp[1] -= 255/2 # are quite different so easily readable
|
||||
|
|
@ -26,7 +19,6 @@ def getOppositeColor(r,g,b):
|
|||
opp[1] += 255/2
|
||||
if opp[2] > -0.5: # if saturation is low on first color increase second's
|
||||
opp[2] -= 0.5
|
||||
#print opp
|
||||
opp = hls_to_rgb(*opp)
|
||||
m = max(opp)
|
||||
if m > 255: #colorsys module doesn't give caps to their conversions
|
||||
|
|
@ -34,8 +26,6 @@ def getOppositeColor(r,g,b):
|
|||
return tuple([ int(x) for x in opp])
|
||||
|
||||
def stringToHashToColorAndOpposite(string):
|
||||
# Python3: Unicode string must be encoded before digest
|
||||
# Python2.7: works either way, but check in case breaks earlier py2
|
||||
if py3:
|
||||
string = string.encode('utf-8')
|
||||
string = md5(string).hexdigest()[:6] # get a random color
|
||||
|
|
@ -281,10 +281,6 @@ RGB2SHORT_DICT = {
|
|||
(255, 255, 215): 230,
|
||||
(255, 255, 255): 231}
|
||||
|
||||
|
||||
def hexstr2num(hexstr):
|
||||
return int(hexstr, 16)
|
||||
|
||||
def rgb2short(r, g, b):
|
||||
""" Find the closest xterm-256 approximation to the given RGB value.
|
||||
@param r,g,b: each is a number between 0-255 for the Red, Green, and Blue values
|
||||
31
powerline_shell/segments/battery.py
Normal file
31
powerline_shell/segments/battery.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
from ..utils import BasicSegment, warn
|
||||
import os
|
||||
|
||||
LOW_BATTERY_THRESHOLD = 20
|
||||
# See discussion in https://github.com/banga/powerline-shell/pull/204 regarding
|
||||
# the directory where battery info is saved
|
||||
DIR_OPTIONS = ["/sys/class/power_supply/BAT0",
|
||||
"/sys/class/power_supply/BAT1"]
|
||||
|
||||
|
||||
class Segment(BasicSegment):
|
||||
def add_to_powerline(self):
|
||||
if os.path.exists("/sys/class/power_supply/BAT0"):
|
||||
dir_ = "/sys/class/power_supply/BAT0"
|
||||
elif os.path.exists("/sys/class/power_supply/BAT1"):
|
||||
dir_ = "/sys/class/power_supply/BAT1"
|
||||
else:
|
||||
warn("battery directory could not be found")
|
||||
return
|
||||
with open(os.path.join(dir_, "capacity")) as f:
|
||||
cap = f.read().strip()
|
||||
with open(os.path.join(dir_, "status")) as f:
|
||||
status = f.read().strip()
|
||||
pwr = u" \u26A1 " if status == "Charging" else u" "
|
||||
if int(cap) < LOW_BATTERY_THRESHOLD:
|
||||
bg = self.powerline.theme.BATTERY_LOW_BG
|
||||
fg = self.powerline.theme.BATTERY_LOW_FG
|
||||
else:
|
||||
bg = self.powerline.theme.BATTERY_NORMAL_BG
|
||||
fg = self.powerline.theme.BATTERY_NORMAL_FG
|
||||
self.powerline.append(" " + cap + "%" + pwr, fg, bg)
|
||||
72
powerline_shell/segments/bzr.py
Normal file
72
powerline_shell/segments/bzr.py
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
import os
|
||||
import subprocess
|
||||
from ..utils import RepoStats, ThreadedSegment
|
||||
|
||||
|
||||
def get_PATH():
|
||||
"""Normally gets the PATH from the OS. This function exists to enable
|
||||
easily mocking the PATH in tests.
|
||||
"""
|
||||
return os.getenv("PATH")
|
||||
|
||||
|
||||
def bzr_subprocess_env():
|
||||
return {"PATH": get_PATH()}
|
||||
|
||||
|
||||
def _get_bzr_branch():
|
||||
p = subprocess.Popen(['bzr', 'nick'],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
||||
env=bzr_subprocess_env())
|
||||
branch = p.communicate()[0].decode("utf-8").rstrip('\n')
|
||||
return branch
|
||||
|
||||
|
||||
def parse_bzr_stats(status):
|
||||
stats = RepoStats()
|
||||
statustype = "changed"
|
||||
for statusline in status:
|
||||
if statusline[:2] == " ":
|
||||
setattr(stats, statustype, getattr(stats, statustype) + 1)
|
||||
elif statusline == "added:":
|
||||
statustype = "staged"
|
||||
elif statusline == "unknown:":
|
||||
statustype = "new"
|
||||
else: # removed, missing, renamed, modified or kind changed
|
||||
statustype = "changed"
|
||||
return stats
|
||||
|
||||
|
||||
def build_stats():
|
||||
try:
|
||||
p = subprocess.Popen(['bzr', 'status'],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
||||
env=bzr_subprocess_env())
|
||||
except OSError:
|
||||
# Popen will throw an OSError if bzr is not found
|
||||
return (None, None)
|
||||
pdata = p.communicate()
|
||||
if p.returncode != 0:
|
||||
return (None, None)
|
||||
status = pdata[0].decode("utf-8").splitlines()
|
||||
stats = parse_bzr_stats(status)
|
||||
branch = _get_bzr_branch()
|
||||
return stats, branch
|
||||
|
||||
|
||||
class Segment(ThreadedSegment):
|
||||
def run(self):
|
||||
self.stats, self.branch = build_stats()
|
||||
|
||||
def add_to_powerline(self):
|
||||
self.join()
|
||||
if not self.stats:
|
||||
return
|
||||
bg = self.powerline.theme.REPO_CLEAN_BG
|
||||
fg = self.powerline.theme.REPO_CLEAN_FG
|
||||
if self.stats.dirty:
|
||||
bg = self.powerline.theme.REPO_DIRTY_BG
|
||||
fg = self.powerline.theme.REPO_DIRTY_FG
|
||||
|
||||
self.powerline.append(" " + self.branch + " ", fg, bg)
|
||||
self.stats.add_to_powerline(self.powerline)
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
import os
|
||||
import sys
|
||||
from ..utils import warn, py3, BasicSegment
|
||||
|
||||
ELLIPSIS = u'\u2026'
|
||||
|
||||
|
|
@ -22,27 +24,32 @@ def split_path_into_names(cwd):
|
|||
return names
|
||||
|
||||
|
||||
def requires_special_home_display(name):
|
||||
def requires_special_home_display(powerline, name):
|
||||
"""Returns true if the given directory name matches the home indicator and
|
||||
the chosen theme should use a special home indicator display."""
|
||||
return (name == '~' and Color.HOME_SPECIAL_DISPLAY)
|
||||
return (name == '~' and powerline.theme.HOME_SPECIAL_DISPLAY)
|
||||
|
||||
|
||||
def maybe_shorten_name(powerline, name):
|
||||
"""If the user has asked for each directory name to be shortened, will
|
||||
return the name up to their specified length. Otherwise returns the full
|
||||
name."""
|
||||
if powerline.args.cwd_max_dir_size:
|
||||
return name[:powerline.args.cwd_max_dir_size]
|
||||
max_size = powerline.segment_conf("cwd", "max_dir_size")
|
||||
if max_size:
|
||||
return name[:max_size]
|
||||
return name
|
||||
|
||||
|
||||
def get_fg_bg(name):
|
||||
def get_fg_bg(powerline, name, is_last_dir):
|
||||
"""Returns the foreground and background color to use for the given name.
|
||||
"""
|
||||
if requires_special_home_display(name):
|
||||
return (Color.HOME_FG, Color.HOME_BG,)
|
||||
return (Color.PATH_FG, Color.PATH_BG,)
|
||||
if requires_special_home_display(powerline, name):
|
||||
return (powerline.theme.HOME_FG, powerline.theme.HOME_BG,)
|
||||
|
||||
if is_last_dir:
|
||||
return (powerline.theme.CWD_FG, powerline.theme.PATH_BG,)
|
||||
else:
|
||||
return (powerline.theme.PATH_FG, powerline.theme.PATH_BG,)
|
||||
|
||||
|
||||
def add_cwd_segment(powerline):
|
||||
|
|
@ -51,15 +58,15 @@ def add_cwd_segment(powerline):
|
|||
cwd = cwd.decode("utf-8")
|
||||
cwd = replace_home_dir(cwd)
|
||||
|
||||
if powerline.args.cwd_mode == 'plain':
|
||||
powerline.append(' %s ' % (cwd,), Color.CWD_FG, Color.PATH_BG)
|
||||
if powerline.segment_conf("cwd", "mode") == 'plain':
|
||||
powerline.append(' %s ' % (cwd,), powerline.theme.CWD_FG, powerline.theme.PATH_BG)
|
||||
return
|
||||
|
||||
names = split_path_into_names(cwd)
|
||||
|
||||
max_depth = powerline.args.cwd_max_depth
|
||||
max_depth = powerline.segment_conf("cwd", "max_depth", 5)
|
||||
if max_depth <= 0:
|
||||
warn("Ignoring --cwd-max-depth argument since it's not greater than 0")
|
||||
warn("Ignoring cwd.max_depth option since it's not greater than 0")
|
||||
elif len(names) > max_depth:
|
||||
# https://github.com/milkbikis/powerline-shell/issues/148
|
||||
# n_before is the number is the number of directories to put before the
|
||||
|
|
@ -71,20 +78,25 @@ def add_cwd_segment(powerline):
|
|||
n_before = 2 if max_depth > 2 else max_depth - 1
|
||||
names = names[:n_before] + [ELLIPSIS] + names[n_before - max_depth:]
|
||||
|
||||
if (powerline.args.cwd_mode == 'dironly' or powerline.args.cwd_only):
|
||||
if powerline.segment_conf("cwd", "mode") == "dironly":
|
||||
# The user has indicated they only want the current directory to be
|
||||
# displayed, so chop everything else off
|
||||
names = names[-1:]
|
||||
|
||||
for i, name in enumerate(names):
|
||||
fg, bg = get_fg_bg(name)
|
||||
is_last_dir = (i == len(names) - 1)
|
||||
fg, bg = get_fg_bg(powerline, name, is_last_dir)
|
||||
|
||||
separator = powerline.separator_thin
|
||||
separator_fg = Color.SEPARATOR_FG
|
||||
is_last_dir = (i == len(names) - 1)
|
||||
if requires_special_home_display(name) or is_last_dir:
|
||||
separator_fg = powerline.theme.SEPARATOR_FG
|
||||
if requires_special_home_display(powerline, name) or is_last_dir:
|
||||
separator = None
|
||||
separator_fg = None
|
||||
|
||||
powerline.append(' %s ' % maybe_shorten_name(powerline, name), fg, bg,
|
||||
separator, separator_fg)
|
||||
|
||||
|
||||
class Segment(BasicSegment):
|
||||
def add_to_powerline(self):
|
||||
add_cwd_segment(self.powerline)
|
||||
10
powerline_shell/segments/exit_code.py
Normal file
10
powerline_shell/segments/exit_code.py
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
from ..utils import BasicSegment
|
||||
|
||||
|
||||
class Segment(BasicSegment):
|
||||
def add_to_powerline(self):
|
||||
if self.powerline.args.prev_error == 0:
|
||||
return
|
||||
fg = self.powerline.theme.CMD_FAILED_FG
|
||||
bg = self.powerline.theme.CMD_FAILED_BG
|
||||
self.powerline.append(' %s ' % str(self.powerline.args.prev_error), fg, bg)
|
||||
79
powerline_shell/segments/fossil.py
Normal file
79
powerline_shell/segments/fossil.py
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
import os
|
||||
import subprocess
|
||||
from ..utils import RepoStats, ThreadedSegment
|
||||
|
||||
|
||||
def get_PATH():
|
||||
"""Normally gets the PATH from the OS. This function exists to enable
|
||||
easily mocking the PATH in tests.
|
||||
"""
|
||||
return os.getenv("PATH")
|
||||
|
||||
|
||||
def fossil_subprocess_env():
|
||||
return {"PATH": get_PATH()}
|
||||
|
||||
|
||||
def _get_fossil_branch():
|
||||
branches = os.popen("fossil branch 2>/dev/null").read().strip().split("\n")
|
||||
return ''.join([
|
||||
i.replace('*','').strip()
|
||||
for i in branches
|
||||
if i.startswith('*')
|
||||
])
|
||||
|
||||
|
||||
def parse_fossil_stats(status):
|
||||
stats = RepoStats()
|
||||
for line in status:
|
||||
if line.startswith("ADDED"):
|
||||
stats.staged += 1
|
||||
elif line.startswith("EXTRA"):
|
||||
stats.new += 1
|
||||
elif line.startswith("CONFLICT"):
|
||||
stats.conflicted += 1
|
||||
else:
|
||||
stats.changed += 1
|
||||
return stats
|
||||
|
||||
|
||||
def _get_fossil_status():
|
||||
changes = os.popen("fossil changes 2>/dev/null").read().strip().split("\n")
|
||||
extra = os.popen("fossil extras 2>/dev/null").read().strip().split("\n")
|
||||
extra = ["EXTRA " + filename for filename in extra if filename != ""]
|
||||
status = [line for line in changes + extra if line != '']
|
||||
return status
|
||||
|
||||
|
||||
def build_stats():
|
||||
try:
|
||||
subprocess.Popen(['fossil'], stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
env=fossil_subprocess_env()).communicate()
|
||||
except OSError:
|
||||
# Popen will throw an OSError if fossil is not found
|
||||
return (None, None)
|
||||
branch = _get_fossil_branch()
|
||||
if branch == "":
|
||||
return (None, None)
|
||||
status = _get_fossil_status()
|
||||
if status == []:
|
||||
return (RepoStats(), branch)
|
||||
stats = parse_fossil_stats(status)
|
||||
return stats, branch
|
||||
|
||||
|
||||
class Segment(ThreadedSegment):
|
||||
|
||||
def add_to_powerline(self):
|
||||
self.stats, self.branch = build_stats()
|
||||
if not self.stats:
|
||||
return
|
||||
bg = self.powerline.theme.REPO_CLEAN_BG
|
||||
fg = self.powerline.theme.REPO_CLEAN_FG
|
||||
if self.stats.dirty:
|
||||
bg = self.powerline.theme.REPO_DIRTY_BG
|
||||
fg = self.powerline.theme.REPO_DIRTY_FG
|
||||
|
||||
self.powerline.append(" " + self.branch + " ", fg, bg)
|
||||
self.stats.add_to_powerline(self.powerline)
|
||||
|
|
@ -1,16 +1,8 @@
|
|||
import re
|
||||
import subprocess
|
||||
import os
|
||||
from ..utils import RepoStats, ThreadedSegment
|
||||
|
||||
GIT_SYMBOLS = {
|
||||
'detached': u'\u2693',
|
||||
'ahead': u'\u2B06',
|
||||
'behind': u'\u2B07',
|
||||
'staged': u'\u2714',
|
||||
'notstaged': u'\u270E',
|
||||
'untracked': u'\u2753',
|
||||
'conflicted': u'\u273C'
|
||||
}
|
||||
|
||||
def get_PATH():
|
||||
"""Normally gets the PATH from the OS. This function exists to enable
|
||||
|
|
@ -18,6 +10,7 @@ def get_PATH():
|
|||
"""
|
||||
return os.getenv("PATH")
|
||||
|
||||
|
||||
def git_subprocess_env():
|
||||
return {
|
||||
# LANG is specified to ensure git always uses a language we are expecting.
|
||||
|
|
@ -43,74 +36,68 @@ def _get_git_detached_branch():
|
|||
env=git_subprocess_env())
|
||||
detached_ref = p.communicate()[0].decode("utf-8").rstrip('\n')
|
||||
if p.returncode == 0:
|
||||
branch = u'{} {}'.format(GIT_SYMBOLS['detached'], detached_ref)
|
||||
branch = u'{} {}'.format(RepoStats.symbols['detached'], detached_ref)
|
||||
else:
|
||||
branch = 'Big Bang'
|
||||
return branch
|
||||
|
||||
|
||||
def parse_git_stats(status):
|
||||
stats = {'untracked': 0, 'notstaged': 0, 'staged': 0, 'conflicted': 0}
|
||||
stats = RepoStats()
|
||||
for statusline in status[1:]:
|
||||
code = statusline[:2]
|
||||
if code == '??':
|
||||
stats['untracked'] += 1
|
||||
stats.new += 1
|
||||
elif code in ('DD', 'AU', 'UD', 'UA', 'DU', 'AA', 'UU'):
|
||||
stats['conflicted'] += 1
|
||||
stats.conflicted += 1
|
||||
else:
|
||||
if code[1] != ' ':
|
||||
stats['notstaged'] += 1
|
||||
stats.changed += 1
|
||||
if code[0] != ' ':
|
||||
stats['staged'] += 1
|
||||
stats.staged += 1
|
||||
|
||||
return stats
|
||||
|
||||
|
||||
def _n_or_empty(_dict, _key):
|
||||
return _dict[_key] if int(_dict[_key]) > 1 else u''
|
||||
|
||||
|
||||
def add_git_segment(powerline):
|
||||
def build_stats():
|
||||
try:
|
||||
p = subprocess.Popen(['git', 'status', '--porcelain', '-b'],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
||||
env=git_subprocess_env())
|
||||
except OSError:
|
||||
# Popen will throw an OSError if git is not found
|
||||
return
|
||||
return (None, None)
|
||||
|
||||
pdata = p.communicate()
|
||||
if p.returncode != 0:
|
||||
return
|
||||
return (None, None)
|
||||
|
||||
status = pdata[0].decode("utf-8").splitlines()
|
||||
|
||||
branch_info = parse_git_branch_info(status)
|
||||
stats = parse_git_stats(status)
|
||||
dirty = (True if sum(stats.values()) > 0 else False)
|
||||
branch_info = parse_git_branch_info(status)
|
||||
|
||||
if branch_info:
|
||||
stats.ahead = branch_info["ahead"]
|
||||
stats.behind = branch_info["behind"]
|
||||
branch = branch_info['local']
|
||||
else:
|
||||
branch = _get_git_detached_branch()
|
||||
return stats, branch
|
||||
|
||||
bg = Color.REPO_CLEAN_BG
|
||||
fg = Color.REPO_CLEAN_FG
|
||||
if dirty:
|
||||
bg = Color.REPO_DIRTY_BG
|
||||
fg = Color.REPO_DIRTY_FG
|
||||
|
||||
powerline.append(' %s ' % branch, fg, bg)
|
||||
class Segment(ThreadedSegment):
|
||||
def run(self):
|
||||
self.stats, self.branch = build_stats()
|
||||
|
||||
def _add(_dict, _key, fg, bg):
|
||||
if _dict[_key]:
|
||||
_str = u' {}{} '.format(_n_or_empty(_dict, _key), GIT_SYMBOLS[_key])
|
||||
powerline.append(_str, fg, bg)
|
||||
def add_to_powerline(self):
|
||||
self.join()
|
||||
if not self.stats:
|
||||
return
|
||||
bg = self.powerline.theme.REPO_CLEAN_BG
|
||||
fg = self.powerline.theme.REPO_CLEAN_FG
|
||||
if self.stats.dirty:
|
||||
bg = self.powerline.theme.REPO_DIRTY_BG
|
||||
fg = self.powerline.theme.REPO_DIRTY_FG
|
||||
|
||||
if branch_info:
|
||||
_add(branch_info, 'ahead', Color.GIT_AHEAD_FG, Color.GIT_AHEAD_BG)
|
||||
_add(branch_info, 'behind', Color.GIT_BEHIND_FG, Color.GIT_BEHIND_BG)
|
||||
_add(stats, 'staged', Color.GIT_STAGED_FG, Color.GIT_STAGED_BG)
|
||||
_add(stats, 'notstaged', Color.GIT_NOTSTAGED_FG, Color.GIT_NOTSTAGED_BG)
|
||||
_add(stats, 'untracked', Color.GIT_UNTRACKED_FG, Color.GIT_UNTRACKED_BG)
|
||||
_add(stats, 'conflicted', Color.GIT_CONFLICTED_FG, Color.GIT_CONFLICTED_BG)
|
||||
self.powerline.append(" " + self.branch + " ", fg, bg)
|
||||
self.stats.add_to_powerline(self.powerline)
|
||||
79
powerline_shell/segments/hg.py
Normal file
79
powerline_shell/segments/hg.py
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
import os
|
||||
import subprocess
|
||||
from ..utils import ThreadedSegment
|
||||
import subprocess
|
||||
|
||||
|
||||
def get_PATH():
|
||||
"""Normally gets the PATH from the OS. This function exists to enable
|
||||
easily mocking the PATH in tests.
|
||||
"""
|
||||
return os.getenv("PATH")
|
||||
|
||||
|
||||
def _subprocess_env():
|
||||
return {"PATH": get_PATH()}
|
||||
|
||||
|
||||
def get_hg_status():
|
||||
has_modified_files = False
|
||||
has_untracked_files = False
|
||||
has_missing_files = False
|
||||
|
||||
p = subprocess.Popen(["hg", "status"],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
env=_subprocess_env())
|
||||
output = p.communicate()[0].decode("utf-8")
|
||||
|
||||
for line in output.split("\n"):
|
||||
if line == "":
|
||||
continue
|
||||
elif line[0] == "?":
|
||||
has_untracked_files = True
|
||||
elif line[0] == "!":
|
||||
has_missing_files = True
|
||||
else:
|
||||
has_modified_files = True
|
||||
return has_modified_files, has_untracked_files, has_missing_files
|
||||
|
||||
|
||||
def build_stats():
|
||||
try:
|
||||
p = subprocess.Popen(["hg", "branch"],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
env=_subprocess_env())
|
||||
except OSError:
|
||||
# Will be thrown if hg cannot be found
|
||||
return None, None
|
||||
|
||||
pdata = p.communicate()
|
||||
if p.returncode != 0:
|
||||
return None, None
|
||||
|
||||
branch = pdata[0].decode("utf-8").strip()
|
||||
return branch, get_hg_status()
|
||||
|
||||
|
||||
class Segment(ThreadedSegment):
|
||||
def run(self):
|
||||
self.branch, self.status = build_stats()
|
||||
|
||||
def add_to_powerline(self):
|
||||
self.join()
|
||||
if not self.branch or not self.status:
|
||||
return
|
||||
bg = self.powerline.theme.REPO_CLEAN_BG
|
||||
fg = self.powerline.theme.REPO_CLEAN_FG
|
||||
has_modified, has_untracked, has_missing = self.status
|
||||
if has_modified or has_untracked or has_missing:
|
||||
bg = self.powerline.theme.REPO_DIRTY_BG
|
||||
fg = self.powerline.theme.REPO_DIRTY_FG
|
||||
extra = ""
|
||||
if has_untracked:
|
||||
extra += "+"
|
||||
if has_missing:
|
||||
extra += "!"
|
||||
self.branch += " " + extra
|
||||
return self.powerline.append(" %s " % self.branch, fg, bg)
|
||||
25
powerline_shell/segments/hostname.py
Normal file
25
powerline_shell/segments/hostname.py
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
from ..utils import BasicSegment
|
||||
from ..color_compliment import stringToHashToColorAndOpposite
|
||||
from ..colortrans import rgb2short
|
||||
from socket import gethostname
|
||||
|
||||
|
||||
class Segment(BasicSegment):
|
||||
def add_to_powerline(self):
|
||||
powerline = self.powerline
|
||||
if powerline.segment_conf("hostname", "colorize"):
|
||||
hostname = gethostname()
|
||||
FG, BG = stringToHashToColorAndOpposite(hostname)
|
||||
FG, BG = (rgb2short(*color) for color in [FG, BG])
|
||||
host_prompt = " %s " % hostname.split(".")[0]
|
||||
powerline.append(host_prompt, FG, BG)
|
||||
else:
|
||||
if powerline.args.shell == "bash":
|
||||
host_prompt = r" \h "
|
||||
elif powerline.args.shell == "zsh":
|
||||
host_prompt = " %m "
|
||||
else:
|
||||
host_prompt = " %s " % gethostname().split(".")[0]
|
||||
powerline.append(host_prompt,
|
||||
powerline.theme.HOSTNAME_FG,
|
||||
powerline.theme.HOSTNAME_BG)
|
||||
31
powerline_shell/segments/jobs.py
Normal file
31
powerline_shell/segments/jobs.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import platform
|
||||
from ..utils import ThreadedSegment
|
||||
|
||||
|
||||
class Segment(ThreadedSegment):
|
||||
def run(self):
|
||||
self.num_jobs = 0
|
||||
if platform.system().startswith('CYGWIN'):
|
||||
# cygwin ps is a special snowflake...
|
||||
output_proc = subprocess.Popen(['ps', '-af'], stdout=subprocess.PIPE)
|
||||
output = map(lambda l: int(l.split()[2].strip()),
|
||||
output_proc.communicate()[0].decode("utf-8").splitlines()[1:])
|
||||
self.num_jobs = output.count(os.getppid()) - 1
|
||||
else:
|
||||
pppid_proc = subprocess.Popen(['ps', '-p', str(os.getppid()), '-oppid='],
|
||||
stdout=subprocess.PIPE)
|
||||
pppid = pppid_proc.communicate()[0].decode("utf-8").strip()
|
||||
output_proc = subprocess.Popen(['ps', '-a', '-o', 'ppid'],
|
||||
stdout=subprocess.PIPE)
|
||||
output = output_proc.communicate()[0].decode("utf-8")
|
||||
self.num_jobs = len(re.findall(str(pppid), output)) - 1
|
||||
|
||||
def add_to_powerline(self):
|
||||
self.join()
|
||||
if self.num_jobs > 0:
|
||||
self.powerline.append(' %d ' % self.num_jobs,
|
||||
self.powerline.theme.JOBS_FG,
|
||||
self.powerline.theme.JOBS_BG)
|
||||
9
powerline_shell/segments/newline.py
Normal file
9
powerline_shell/segments/newline.py
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
from ..utils import BasicSegment
|
||||
|
||||
|
||||
class Segment(BasicSegment):
|
||||
def add_to_powerline(self):
|
||||
self.powerline.append("\n",
|
||||
self.powerline.theme.RESET,
|
||||
self.powerline.theme.RESET,
|
||||
separator="")
|
||||
18
powerline_shell/segments/node_version.py
Normal file
18
powerline_shell/segments/node_version.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import subprocess
|
||||
from ..utils import ThreadedSegment
|
||||
|
||||
|
||||
class Segment(ThreadedSegment):
|
||||
def run(self):
|
||||
try:
|
||||
p1 = subprocess.Popen(["node", "--version"], stdout=subprocess.PIPE)
|
||||
self.version = p1.communicate()[0].decode("utf-8").rstrip()
|
||||
except OSError:
|
||||
self.version = None
|
||||
|
||||
def add_to_powerline(self):
|
||||
self.join()
|
||||
if not self.version:
|
||||
return
|
||||
# FIXME no hard-coded colors
|
||||
self.powerline.append("node " + self.version, 15, 18)
|
||||
17
powerline_shell/segments/npm_version.py
Normal file
17
powerline_shell/segments/npm_version.py
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import subprocess
|
||||
from ..utils import ThreadedSegment
|
||||
|
||||
|
||||
class Segment(ThreadedSegment):
|
||||
def run(self):
|
||||
try:
|
||||
p1 = subprocess.Popen(["npm", "--version"], stdout=subprocess.PIPE)
|
||||
self.version = p1.communicate()[0].decode("utf-8").rstrip()
|
||||
except OSError:
|
||||
self.version = None
|
||||
|
||||
def add_to_powerline(self):
|
||||
self.join()
|
||||
if self.version:
|
||||
# FIXME no hard-coded colors
|
||||
self.powerline.append("npm " + self.version, 15, 18)
|
||||
19
powerline_shell/segments/php_version.py
Normal file
19
powerline_shell/segments/php_version.py
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import subprocess
|
||||
from ..utils import ThreadedSegment
|
||||
|
||||
|
||||
class Segment(ThreadedSegment):
|
||||
def run(self):
|
||||
try:
|
||||
output = subprocess.check_output(['php', '-r', 'echo PHP_VERSION;'],
|
||||
stderr=subprocess.STDOUT)
|
||||
self.version = output.split('-')[0] if '-' in output else output
|
||||
except OSError:
|
||||
self.version = None
|
||||
|
||||
def add_to_powerline(self):
|
||||
self.join()
|
||||
if not self.version:
|
||||
return
|
||||
# FIXME no hard-coded colors
|
||||
self.powerline.append(" " + self.version + " ", 15, 4)
|
||||
17
powerline_shell/segments/rbenv.py
Normal file
17
powerline_shell/segments/rbenv.py
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import subprocess
|
||||
from ..utils import BasicSegment
|
||||
|
||||
|
||||
class Segment(BasicSegment):
|
||||
def add_to_powerline(self):
|
||||
powerline = self.powerline
|
||||
try:
|
||||
p1 = subprocess.Popen(["rbenv", "local"], stdout=subprocess.PIPE)
|
||||
version = p1.communicate()[0].decode("utf-8").rstrip()
|
||||
if len(version) <= 0:
|
||||
return
|
||||
powerline.append(' %s ' % version,
|
||||
powerline.theme.VIRTUAL_ENV_FG,
|
||||
powerline.theme.VIRTUAL_ENV_BG)
|
||||
except OSError:
|
||||
return
|
||||
12
powerline_shell/segments/read_only.py
Normal file
12
powerline_shell/segments/read_only.py
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import os
|
||||
from ..utils import BasicSegment
|
||||
|
||||
|
||||
class Segment(BasicSegment):
|
||||
def add_to_powerline(self):
|
||||
powerline = self.powerline
|
||||
cwd = powerline.cwd or os.getenv('PWD')
|
||||
if not os.access(cwd, os.W_OK):
|
||||
powerline.append(' %s ' % powerline.lock,
|
||||
powerline.theme.READONLY_FG,
|
||||
powerline.theme.READONLY_BG)
|
||||
17
powerline_shell/segments/root.py
Normal file
17
powerline_shell/segments/root.py
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
from ..utils import BasicSegment
|
||||
|
||||
|
||||
class Segment(BasicSegment):
|
||||
def add_to_powerline(self):
|
||||
powerline = self.powerline
|
||||
root_indicators = {
|
||||
'bash': ' \\$ ',
|
||||
'zsh': ' %# ',
|
||||
'bare': ' $ ',
|
||||
}
|
||||
bg = powerline.theme.CMD_PASSED_BG
|
||||
fg = powerline.theme.CMD_PASSED_FG
|
||||
if powerline.args.prev_error != 0:
|
||||
fg = powerline.theme.CMD_FAILED_FG
|
||||
bg = powerline.theme.CMD_FAILED_BG
|
||||
powerline.append(root_indicators[powerline.args.shell], fg, bg)
|
||||
19
powerline_shell/segments/ruby_version.py
Normal file
19
powerline_shell/segments/ruby_version.py
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import os
|
||||
import subprocess
|
||||
from ..utils import BasicSegment
|
||||
|
||||
|
||||
class Segment(BasicSegment):
|
||||
def add_to_powerline(self):
|
||||
powerline = self.powerline
|
||||
try:
|
||||
p1 = subprocess.Popen(["ruby", "-v"], stdout=subprocess.PIPE)
|
||||
p2 = subprocess.Popen(["sed", "s/ (.*//"], stdin=p1.stdout, stdout=subprocess.PIPE)
|
||||
version = p2.communicate()[0].decode("utf-8").rstrip()
|
||||
if os.environ.has_key("GEM_HOME"):
|
||||
gem = os.environ["GEM_HOME"].split("@")
|
||||
if len(gem) > 1:
|
||||
version += " " + gem[1]
|
||||
powerline.append(version, 15, 1)
|
||||
except OSError:
|
||||
return
|
||||
22
powerline_shell/segments/set_term_title.py
Normal file
22
powerline_shell/segments/set_term_title.py
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import os
|
||||
import socket
|
||||
from ..utils import BasicSegment
|
||||
|
||||
|
||||
class Segment(BasicSegment):
|
||||
def add_to_powerline(self):
|
||||
powerline = self.powerline
|
||||
term = os.getenv('TERM')
|
||||
if not (('xterm' in term) or ('rxvt' in term)):
|
||||
return
|
||||
if powerline.args.shell == 'bash':
|
||||
set_title = '\\[\\e]0;\\u@\\h: \\w\\a\\]'
|
||||
elif powerline.args.shell == 'zsh':
|
||||
set_title = '%{\033]0;%n@%m: %~\007%}'
|
||||
else:
|
||||
set_title = '\033]0;%s@%s: %s\007' % (
|
||||
os.getenv('USER'),
|
||||
socket.gethostname().split('.')[0],
|
||||
powerline.cwd or os.getenv('PWD'),
|
||||
)
|
||||
powerline.append(set_title, None, None, '')
|
||||
11
powerline_shell/segments/ssh.py
Normal file
11
powerline_shell/segments/ssh.py
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import os
|
||||
from ..utils import BasicSegment
|
||||
|
||||
|
||||
class Segment(BasicSegment):
|
||||
def add_to_powerline(self):
|
||||
if os.getenv('SSH_CLIENT'):
|
||||
powerline = self.powerline
|
||||
powerline.append(' %s ' % powerline.network,
|
||||
powerline.theme.SSH_FG,
|
||||
powerline.theme.SSH_BG)
|
||||
29
powerline_shell/segments/svn.py
Normal file
29
powerline_shell/segments/svn.py
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import subprocess
|
||||
from ..utils import BasicSegment, RepoStats
|
||||
|
||||
|
||||
class Segment(BasicSegment):
|
||||
def add_to_powerline(self):
|
||||
is_svn = subprocess.Popen(["svn", "status"],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
is_svn_output = is_svn.communicate()[1].decode("utf-8").strip()
|
||||
if len(is_svn_output) != 0:
|
||||
return
|
||||
|
||||
try:
|
||||
p1 = subprocess.Popen(["svn", "status"], stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
except OSError:
|
||||
return
|
||||
|
||||
stdout = p1.communicate()[0]
|
||||
stats = RepoStats()
|
||||
for line in stdout.splitlines():
|
||||
if line[0] == "?":
|
||||
stats.new += 1
|
||||
elif line[0] == "C":
|
||||
stats.conflicted += 1
|
||||
elif line[0] in ["A", "D", "I", "M", "R", "!", "~"]:
|
||||
stats.changed += 1
|
||||
|
||||
stats.add_to_powerline(self.powerline)
|
||||
17
powerline_shell/segments/time.py
Normal file
17
powerline_shell/segments/time.py
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
from __future__ import absolute_import
|
||||
from ..utils import BasicSegment
|
||||
import time
|
||||
|
||||
|
||||
class Segment(BasicSegment):
|
||||
def add_to_powerline(self):
|
||||
powerline = self.powerline
|
||||
if powerline.args.shell == 'bash':
|
||||
time_ = ' \\t '
|
||||
elif powerline.args.shell == 'zsh':
|
||||
time_ = ' %* '
|
||||
else:
|
||||
time_ = ' %s ' % time.strftime('%H:%M:%S')
|
||||
powerline.append(time_,
|
||||
powerline.theme.HOSTNAME_FG,
|
||||
powerline.theme.HOSTNAME_BG)
|
||||
20
powerline_shell/segments/uptime.py
Normal file
20
powerline_shell/segments/uptime.py
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import subprocess
|
||||
import re
|
||||
from ..utils import BasicSegment
|
||||
|
||||
|
||||
class Segment(BasicSegment):
|
||||
def add_to_powerline(self):
|
||||
powerline = self.powerline
|
||||
try:
|
||||
output = subprocess.check_output(['uptime'], stderr=subprocess.STDOUT).decode("utf-8")
|
||||
raw_uptime = re.search('(?<=up).+(?=,\s+\d+\s+user)', output).group(0)
|
||||
day_search = re.search('\d+(?=\s+day)', output)
|
||||
days = '' if not day_search else '%sd ' % day_search.group(0)
|
||||
hour_search = re.search('\d{1,2}(?=\:)', raw_uptime)
|
||||
hours = '' if not hour_search else '%sh ' % hour_search.group(0)
|
||||
minutes = re.search('(?<=\:)\d{1,2}|\d{1,2}(?=\s+min)', raw_uptime).group(0)
|
||||
uptime = u' %s%s%sm \u2191 ' % (days, hours, minutes)
|
||||
powerline.append(uptime, powerline.theme.CWD_FG, powerline.theme.PATH_BG)
|
||||
except OSError:
|
||||
return
|
||||
21
powerline_shell/segments/username.py
Normal file
21
powerline_shell/segments/username.py
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
from ..utils import BasicSegment
|
||||
import os
|
||||
import pwd
|
||||
|
||||
|
||||
class Segment(BasicSegment):
|
||||
def add_to_powerline(self):
|
||||
powerline = self.powerline
|
||||
if powerline.args.shell == "bash":
|
||||
user_prompt = r" \u "
|
||||
elif powerline.args.shell == "zsh":
|
||||
user_prompt = " %n "
|
||||
else:
|
||||
user_prompt = " %s " % os.getenv("USER")
|
||||
|
||||
if pwd.getpwuid(os.getuid())[0] == "root":
|
||||
bgcolor = powerline.theme.USERNAME_ROOT_BG
|
||||
else:
|
||||
bgcolor = powerline.theme.USERNAME_BG
|
||||
|
||||
powerline.append(user_prompt, powerline.theme.USERNAME_FG, bgcolor)
|
||||
15
powerline_shell/segments/virtual_env.py
Normal file
15
powerline_shell/segments/virtual_env.py
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import os
|
||||
from ..utils import BasicSegment
|
||||
|
||||
|
||||
class Segment(BasicSegment):
|
||||
def add_to_powerline(self):
|
||||
env = os.getenv('VIRTUAL_ENV') \
|
||||
or os.getenv('CONDA_ENV_PATH') \
|
||||
or os.getenv('CONDA_DEFAULT_ENV')
|
||||
if not env:
|
||||
return
|
||||
env_name = os.path.basename(env)
|
||||
bg = self.powerline.theme.VIRTUAL_ENV_BG
|
||||
fg = self.powerline.theme.VIRTUAL_ENV_FG
|
||||
self.powerline.append(" " + env_name + " ", fg, bg)
|
||||
0
powerline_shell/themes/__init__.py
Normal file
0
powerline_shell/themes/__init__.py
Normal file
|
|
@ -1,6 +1,8 @@
|
|||
# Basic theme which only uses colors in 0-15 range
|
||||
from .default import DefaultColor
|
||||
|
||||
|
||||
class Color(DefaultColor):
|
||||
"""Basic theme which only uses colors in 0-15 range"""
|
||||
USERNAME_FG = 8
|
||||
USERNAME_BG = 15
|
||||
USERNAME_ROOT_BG = 1
|
||||
|
|
@ -1,8 +1,13 @@
|
|||
class DefaultColor:
|
||||
class DefaultColor(object):
|
||||
"""
|
||||
This class should have the default colors for every segment.
|
||||
Please test every new segment with this theme first.
|
||||
"""
|
||||
# RESET is not a real color code. It is used as in indicator
|
||||
# within the code that any foreground / background color should
|
||||
# be cleared
|
||||
RESET = -1
|
||||
|
||||
USERNAME_FG = 250
|
||||
USERNAME_BG = 240
|
||||
USERNAME_ROOT_BG = 124
|
||||
|
|
@ -56,10 +61,14 @@ class DefaultColor:
|
|||
VIRTUAL_ENV_BG = 35 # a mid-tone green
|
||||
VIRTUAL_ENV_FG = 00
|
||||
|
||||
BATTERY_NORMAL_BG = 22
|
||||
BATTERY_NORMAL_FG = 7
|
||||
BATTERY_LOW_BG = 196
|
||||
BATTERY_LOW_FG = 7
|
||||
|
||||
AWS_PROFILE_FG = 39
|
||||
AWS_PROFILE_BG = 238
|
||||
|
||||
|
||||
class Color(DefaultColor):
|
||||
"""
|
||||
This subclass is required when the user chooses to use 'default' theme.
|
||||
|
|
@ -1,3 +1,6 @@
|
|||
from .default import DefaultColor
|
||||
|
||||
|
||||
class Color(DefaultColor):
|
||||
USERNAME_FG = 15
|
||||
USERNAME_BG = 4
|
||||
38
powerline_shell/themes/solarized_light.py
Normal file
38
powerline_shell/themes/solarized_light.py
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
from .default import DefaultColor
|
||||
|
||||
|
||||
class Color(DefaultColor):
|
||||
USERNAME_FG = 15
|
||||
USERNAME_BG = 4
|
||||
USERNAME_ROOT_BG = 1
|
||||
|
||||
HOSTNAME_FG = 15
|
||||
HOSTNAME_BG = 10
|
||||
|
||||
HOME_SPECIAL_DISPLAY = False
|
||||
PATH_FG = 10
|
||||
PATH_BG = 7
|
||||
CWD_FG = 0
|
||||
SEPARATOR_FG = 14
|
||||
|
||||
READONLY_BG = 1
|
||||
READONLY_FG = 7
|
||||
|
||||
REPO_CLEAN_FG = 0
|
||||
REPO_CLEAN_BG = 15
|
||||
REPO_DIRTY_FG = 1
|
||||
REPO_DIRTY_BG = 15
|
||||
|
||||
JOBS_FG = 4
|
||||
JOBS_BG = 7
|
||||
|
||||
CMD_PASSED_FG = 15
|
||||
CMD_PASSED_BG = 2
|
||||
CMD_FAILED_FG = 15
|
||||
CMD_FAILED_BG = 1
|
||||
|
||||
SVN_CHANGES_FG = REPO_DIRTY_FG
|
||||
SVN_CHANGES_BG = REPO_DIRTY_BG
|
||||
|
||||
VIRTUAL_ENV_BG = 15
|
||||
VIRTUAL_ENV_FG = 2
|
||||
|
|
@ -1,3 +1,6 @@
|
|||
from .default import DefaultColor
|
||||
|
||||
|
||||
class Color(DefaultColor):
|
||||
USERNAME_FG = 8
|
||||
USERNAME_BG = 251
|
||||
95
powerline_shell/utils.py
Normal file
95
powerline_shell/utils.py
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
import sys
|
||||
import threading
|
||||
|
||||
py3 = sys.version_info[0] == 3
|
||||
|
||||
if py3:
|
||||
def unicode(x):
|
||||
return str(x)
|
||||
|
||||
|
||||
class RepoStats(object):
|
||||
symbols = {
|
||||
'detached': u'\u2693',
|
||||
'ahead': u'\u2B06',
|
||||
'behind': u'\u2B07',
|
||||
'staged': u'\u2714',
|
||||
'changed': u'\u270E',
|
||||
'new': u'\u2753',
|
||||
'conflicted': u'\u273C'
|
||||
}
|
||||
|
||||
def __init__(self, ahead=0, behind=0, new=0, changed=0, staged=0, conflicted=0):
|
||||
self.ahead = ahead
|
||||
self.behind = behind
|
||||
self.new = new
|
||||
self.changed = changed
|
||||
self.staged = staged
|
||||
self.conflicted = conflicted
|
||||
|
||||
def __eq__(self, other):
|
||||
return (
|
||||
self.ahead == other.ahead and
|
||||
self.behind == other.behind and
|
||||
self.new == other.new and
|
||||
self.changed == other.changed and
|
||||
self.staged == other.staged and
|
||||
self.conflicted == other.conflicted
|
||||
)
|
||||
|
||||
@property
|
||||
def dirty(self):
|
||||
qualifiers = [
|
||||
self.new,
|
||||
self.changed,
|
||||
self.staged,
|
||||
self.conflicted,
|
||||
]
|
||||
return sum(qualifiers) > 0
|
||||
|
||||
def __getitem__(self, _key):
|
||||
return getattr(self, _key)
|
||||
|
||||
def n_or_empty(self, _key):
|
||||
"""Given a string name of one of the properties of this class, returns
|
||||
the value of the property as a string when the value is greater than
|
||||
1. When it is not greater than one, returns an empty string.
|
||||
|
||||
As an example, if you want to show an icon for new files, but you only
|
||||
want a number to appear next to the icon when there are more than one
|
||||
new file, you can do:
|
||||
|
||||
segment = repo_stats.n_or_empty("new") + icon_string
|
||||
"""
|
||||
return unicode(self[_key]) if int(self[_key]) > 1 else u''
|
||||
|
||||
def add_to_powerline(self, powerline):
|
||||
def add(_key, fg, bg):
|
||||
if self[_key]:
|
||||
s = u" {}{} ".format(self.n_or_empty(_key), self.symbols[_key])
|
||||
powerline.append(s, fg, bg)
|
||||
color = powerline.theme
|
||||
add('ahead', color.GIT_AHEAD_FG, color.GIT_AHEAD_BG)
|
||||
add('behind', color.GIT_BEHIND_FG, color.GIT_BEHIND_BG)
|
||||
add('staged', color.GIT_STAGED_FG, color.GIT_STAGED_BG)
|
||||
add('changed', color.GIT_NOTSTAGED_FG, color.GIT_NOTSTAGED_BG)
|
||||
add('new', color.GIT_UNTRACKED_FG, color.GIT_UNTRACKED_BG)
|
||||
add('conflicted', color.GIT_CONFLICTED_FG, color.GIT_CONFLICTED_BG)
|
||||
|
||||
|
||||
def warn(msg):
|
||||
print('[powerline-bash] ', msg)
|
||||
|
||||
|
||||
class BasicSegment(object):
|
||||
def __init__(self, powerline):
|
||||
self.powerline = powerline
|
||||
|
||||
def start(self):
|
||||
pass
|
||||
|
||||
|
||||
class ThreadedSegment(threading.Thread):
|
||||
def __init__(self, powerline):
|
||||
super(ThreadedSegment, self).__init__()
|
||||
self.powerline = powerline
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
def add_exit_code_segment(powerline):
|
||||
if powerline.args.prev_error == 0:
|
||||
return
|
||||
fg = Color.CMD_FAILED_FG
|
||||
bg = Color.CMD_FAILED_BG
|
||||
powerline.append(' %s ' % str(powerline.args.prev_error), fg, bg)
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
import os
|
||||
import subprocess
|
||||
|
||||
def get_fossil_status():
|
||||
has_modified_files = False
|
||||
has_untracked_files = False
|
||||
has_missing_files = False
|
||||
output = os.popen('fossil changes 2>/dev/null').read().strip()
|
||||
has_untracked_files = True if os.popen("fossil extras 2>/dev/null").read().strip() else False
|
||||
has_missing_files = 'MISSING' in output
|
||||
has_modified_files = 'EDITED' in output
|
||||
|
||||
return has_modified_files, has_untracked_files, has_missing_files
|
||||
|
||||
def _add_fossil_segment(powerline):
|
||||
subprocess.Popen(['fossil'], stdout=subprocess.PIPE).communicate()[0]
|
||||
branch = ''.join([i.replace('*','').strip() for i in os.popen("fossil branch 2> /dev/null").read().strip().split("\n") if i.startswith('*')])
|
||||
if len(branch) == 0:
|
||||
return
|
||||
|
||||
bg = Color.REPO_CLEAN_BG
|
||||
fg = Color.REPO_CLEAN_FG
|
||||
has_modified_files, has_untracked_files, has_missing_files = get_fossil_status()
|
||||
if has_modified_files or has_untracked_files or has_missing_files:
|
||||
bg = Color.REPO_DIRTY_BG
|
||||
fg = Color.REPO_DIRTY_FG
|
||||
extra = ''
|
||||
if has_untracked_files:
|
||||
extra += '+'
|
||||
if has_missing_files:
|
||||
extra += '!'
|
||||
branch += (' ' + extra if extra != '' else '')
|
||||
powerline.append(' %s ' % branch, fg, bg)
|
||||
|
||||
def add_fossil_segment(powerline):
|
||||
"""Wraps _add_fossil_segment in exception handling."""
|
||||
|
||||
# FIXME This function was added when introducing a testing framework,
|
||||
# during which the 'powerline' object was passed into the
|
||||
# `add_[segment]_segment` functions instead of being a global variable. At
|
||||
# that time it was unclear whether the below exceptions could actually be
|
||||
# thrown. It would be preferable to find out whether they ever will. If so,
|
||||
# write a comment explaining when. Otherwise remove.
|
||||
|
||||
try:
|
||||
_add_fossil_segment(powerline)
|
||||
except OSError:
|
||||
pass
|
||||
except subprocess.CalledProcessError:
|
||||
pass
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
import os
|
||||
import subprocess
|
||||
|
||||
def get_hg_status():
|
||||
has_modified_files = False
|
||||
has_untracked_files = False
|
||||
has_missing_files = False
|
||||
|
||||
p = subprocess.Popen(['hg', 'status'], stdout=subprocess.PIPE)
|
||||
output = p.communicate()[0].decode("utf-8")
|
||||
|
||||
for line in output.split('\n'):
|
||||
if line == '':
|
||||
continue
|
||||
elif line[0] == '?':
|
||||
has_untracked_files = True
|
||||
elif line[0] == '!':
|
||||
has_missing_files = True
|
||||
else:
|
||||
has_modified_files = True
|
||||
return has_modified_files, has_untracked_files, has_missing_files
|
||||
|
||||
def add_hg_segment(powerline):
|
||||
branch = os.popen('hg branch 2> /dev/null').read().rstrip()
|
||||
if len(branch) == 0:
|
||||
return False
|
||||
bg = Color.REPO_CLEAN_BG
|
||||
fg = Color.REPO_CLEAN_FG
|
||||
has_modified_files, has_untracked_files, has_missing_files = get_hg_status()
|
||||
if has_modified_files or has_untracked_files or has_missing_files:
|
||||
bg = Color.REPO_DIRTY_BG
|
||||
fg = Color.REPO_DIRTY_FG
|
||||
extra = ''
|
||||
if has_untracked_files:
|
||||
extra += '+'
|
||||
if has_missing_files:
|
||||
extra += '!'
|
||||
branch += (' ' + extra if extra != '' else '')
|
||||
return powerline.append(' %s ' % branch, fg, bg)
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
def add_hostname_segment(powerline):
|
||||
if powerline.args.colorize_hostname:
|
||||
from lib.color_compliment import stringToHashToColorAndOpposite
|
||||
from lib.colortrans import rgb2short
|
||||
from socket import gethostname
|
||||
hostname = gethostname()
|
||||
FG, BG = stringToHashToColorAndOpposite(hostname)
|
||||
FG, BG = (rgb2short(*color) for color in [FG, BG])
|
||||
host_prompt = ' %s ' % hostname.split('.')[0]
|
||||
|
||||
powerline.append(host_prompt, FG, BG)
|
||||
else:
|
||||
if powerline.args.shell == 'bash':
|
||||
host_prompt = ' \\h '
|
||||
elif powerline.args.shell == 'zsh':
|
||||
host_prompt = ' %m '
|
||||
else:
|
||||
import socket
|
||||
host_prompt = ' %s ' % socket.gethostname().split('.')[0]
|
||||
|
||||
powerline.append(host_prompt, Color.HOSTNAME_FG, Color.HOSTNAME_BG)
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
import os
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
def add_jobs_segment(powerline):
|
||||
pppid_proc = subprocess.Popen(['ps', '-p', str(os.getppid()), '-oppid='],
|
||||
stdout=subprocess.PIPE)
|
||||
pppid = pppid_proc.communicate()[0].decode("utf-8").strip()
|
||||
|
||||
output_proc = subprocess.Popen(['ps', '-a', '-o', 'ppid'],
|
||||
stdout=subprocess.PIPE)
|
||||
output = output_proc.communicate()[0].decode("utf-8")
|
||||
|
||||
num_jobs = len(re.findall(str(pppid), output)) - 1
|
||||
|
||||
if num_jobs > 0:
|
||||
powerline.append(' %d ' % num_jobs, Color.JOBS_FG, Color.JOBS_BG)
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
import subprocess
|
||||
|
||||
|
||||
def add_node_version_segment(powerline):
|
||||
try:
|
||||
p1 = subprocess.Popen(["node", "--version"], stdout=subprocess.PIPE)
|
||||
version = p1.communicate()[0].decode("utf-8").rstrip()
|
||||
version = "node " + version
|
||||
powerline.append(version, 15, 18)
|
||||
except OSError:
|
||||
return
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
import subprocess
|
||||
|
||||
|
||||
def add_php_version_segment(powerline):
|
||||
try:
|
||||
output = subprocess.check_output(['php', '-r', 'echo PHP_VERSION;'], stderr=subprocess.STDOUT)
|
||||
if '-' in output:
|
||||
version = ' %s ' % output.split('-')[0]
|
||||
else:
|
||||
version = ' %s ' % output
|
||||
|
||||
powerline.append(version, 15, 4)
|
||||
except OSError:
|
||||
return
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
import os
|
||||
|
||||
def add_read_only_segment(powerline):
|
||||
cwd = powerline.cwd or os.getenv('PWD')
|
||||
|
||||
if not os.access(cwd, os.W_OK):
|
||||
powerline.append(' %s ' % powerline.lock, Color.READONLY_FG, Color.READONLY_BG)
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
def add_root_segment(powerline):
|
||||
root_indicators = {
|
||||
'bash': ' \\$ ',
|
||||
'zsh': ' %# ',
|
||||
'bare': ' $ ',
|
||||
}
|
||||
bg = Color.CMD_PASSED_BG
|
||||
fg = Color.CMD_PASSED_FG
|
||||
if powerline.args.prev_error != 0:
|
||||
fg = Color.CMD_FAILED_FG
|
||||
bg = Color.CMD_FAILED_BG
|
||||
powerline.append(root_indicators[powerline.args.shell], fg, bg)
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
import subprocess
|
||||
|
||||
|
||||
def add_ruby_version_segment(powerline):
|
||||
try:
|
||||
p1 = subprocess.Popen(["ruby", "-v"], stdout=subprocess.PIPE)
|
||||
p2 = subprocess.Popen(["sed", "s/ (.*//"], stdin=p1.stdout, stdout=subprocess.PIPE)
|
||||
version = p2.communicate()[0].decode("utf-8").rstrip()
|
||||
if os.environ.has_key("GEM_HOME"):
|
||||
gem = os.environ["GEM_HOME"].split("@")
|
||||
if len(gem) > 1:
|
||||
version += " " + gem[1]
|
||||
powerline.append(version, 15, 1)
|
||||
except OSError:
|
||||
return
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
def add_set_term_title_segment(powerline):
|
||||
term = os.getenv('TERM')
|
||||
if not (('xterm' in term) or ('rxvt' in term)):
|
||||
return
|
||||
|
||||
if powerline.args.shell == 'bash':
|
||||
set_title = '\\[\\e]0;\\u@\\h: \\w\\a\\]'
|
||||
elif powerline.args.shell == 'zsh':
|
||||
set_title = '\033]0;%n@%m: %~\007'
|
||||
else:
|
||||
import socket
|
||||
set_title = '\033]0;%s@%s: %s\007' % (os.getenv('USER'), socket.gethostname().split('.')[0], powerline.cwd or os.getenv('PWD'))
|
||||
|
||||
powerline.append(set_title, None, None, '')
|
||||
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
import os
|
||||
|
||||
def add_ssh_segment(powerline):
|
||||
|
||||
if os.getenv('SSH_CLIENT'):
|
||||
powerline.append(' %s ' % powerline.network, Color.SSH_FG, Color.SSH_BG)
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
import subprocess
|
||||
|
||||
|
||||
def _add_svn_segment(powerline):
|
||||
is_svn = subprocess.Popen(['svn', 'status'],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
is_svn_output = is_svn.communicate()[1].decode("utf-8").strip()
|
||||
if len(is_svn_output) != 0:
|
||||
return
|
||||
|
||||
#"svn status | grep -c "^[ACDIMRX\\!\\~]"
|
||||
p1 = subprocess.Popen(['svn', 'status'], stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
p2 = subprocess.Popen(['grep', '-c', '^[ACDIMR\\!\\~]'],
|
||||
stdin=p1.stdout, stdout=subprocess.PIPE)
|
||||
output = p2.communicate()[0].decode("utf-8").strip()
|
||||
if len(output) > 0 and int(output) > 0:
|
||||
changes = output.strip()
|
||||
powerline.append(' %s ' % changes, Color.SVN_CHANGES_FG, Color.SVN_CHANGES_BG)
|
||||
|
||||
|
||||
def add_svn_segment(powerline):
|
||||
"""Wraps _add_svn_segment in exception handling."""
|
||||
|
||||
# FIXME This function was added when introducing a testing framework,
|
||||
# during which the 'powerline' object was passed into the
|
||||
# `add_[segment]_segment` functions instead of being a global variable. At
|
||||
# that time it was unclear whether the below exceptions could actually be
|
||||
# thrown. It would be preferable to find out whether they ever will. If so,
|
||||
# write a comment explaining when. Otherwise remove.
|
||||
|
||||
try:
|
||||
_add_svn_segment(powerline)
|
||||
except OSError:
|
||||
pass
|
||||
except subprocess.CalledProcessError:
|
||||
pass
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
def add_time_segment(powerline):
|
||||
if powerline.args.shell == 'bash':
|
||||
time = ' \\t '
|
||||
elif powerline.args.shell == 'zsh':
|
||||
time = ' %* '
|
||||
else:
|
||||
import time
|
||||
time = ' %s ' % time.strftime('%H:%M:%S')
|
||||
|
||||
powerline.append(time, Color.HOSTNAME_FG, Color.HOSTNAME_BG)
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
import subprocess
|
||||
import re
|
||||
|
||||
def add_uptime_segment(powerline):
|
||||
try:
|
||||
output = subprocess.check_output(['uptime'], stderr=subprocess.STDOUT)
|
||||
raw_uptime = re.search('(?<=up).+(?=,\s+\d+\s+user)', output).group(0)
|
||||
day_search = re.search('\d+(?=\s+day)', output)
|
||||
days = '' if not day_search else '%sd ' % day_search.group(0)
|
||||
hour_search = re.search('\d{1,2}(?=\:)', raw_uptime)
|
||||
hours = '' if not hour_search else '%sh ' % hour_search.group(0)
|
||||
minutes = re.search('(?<=\:)\d{1,2}|\d{1,2}(?=\s+min)', raw_uptime).group(0)
|
||||
uptime = u' %s%s%sm \u2191 ' % (days, hours, minutes)
|
||||
powerline.append(uptime, Color.CWD_FG, Color.PATH_BG)
|
||||
except OSError:
|
||||
return
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
|
||||
def add_username_segment(powerline):
|
||||
import os
|
||||
if powerline.args.shell == 'bash':
|
||||
user_prompt = ' \\u '
|
||||
elif powerline.args.shell == 'zsh':
|
||||
user_prompt = ' %n '
|
||||
else:
|
||||
user_prompt = ' %s ' % os.getenv('USER')
|
||||
|
||||
if os.getenv('USER') == 'root':
|
||||
bgcolor = Color.USERNAME_ROOT_BG
|
||||
else:
|
||||
bgcolor = Color.USERNAME_BG
|
||||
|
||||
powerline.append(user_prompt, Color.USERNAME_FG, bgcolor)
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
import os
|
||||
|
||||
def add_virtual_env_segment(powerline):
|
||||
env = os.getenv('VIRTUAL_ENV') or os.getenv('CONDA_ENV_PATH')
|
||||
if env is None:
|
||||
return
|
||||
|
||||
env_name = os.path.basename(env)
|
||||
bg = Color.VIRTUAL_ENV_BG
|
||||
fg = Color.VIRTUAL_ENV_FG
|
||||
powerline.append(' %s ' % env_name, fg, bg)
|
||||
5
setup.cfg
Normal file
5
setup.cfg
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
[bdist_wheel]
|
||||
universal = 1
|
||||
|
||||
[metadata]
|
||||
description-file = README.md
|
||||
22
setup.py
Executable file
22
setup.py
Executable file
|
|
@ -0,0 +1,22 @@
|
|||
#!/usr/bin/env python
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
setup(name="powerline-shell",
|
||||
version="0.3.0",
|
||||
description="A pretty prompt for your shell",
|
||||
author="Buck Ryan",
|
||||
url="https://github.com/banga/powerline-shell",
|
||||
classifiers=[],
|
||||
packages=[
|
||||
"powerline_shell",
|
||||
"powerline_shell.segments",
|
||||
"powerline_shell.themes",
|
||||
],
|
||||
install_requires=[
|
||||
"argparse",
|
||||
],
|
||||
entry_points="""
|
||||
[console_scripts]
|
||||
powerline-shell=powerline_shell:main
|
||||
""",
|
||||
)
|
||||
|
|
@ -3,7 +3,7 @@ import mock
|
|||
import os
|
||||
import tempfile
|
||||
import shutil
|
||||
import powerline_shell_base as p
|
||||
import powerline_shell as p
|
||||
|
||||
|
||||
class CwdTest(unittest.TestCase):
|
||||
|
|
@ -15,14 +15,14 @@ class CwdTest(unittest.TestCase):
|
|||
shutil.rmtree(self.dirname)
|
||||
|
||||
@mock.patch('os.getenv')
|
||||
@mock.patch('powerline_shell_base.warn')
|
||||
@mock.patch('powerline_shell.warn')
|
||||
def test_normal(self, warn, getenv):
|
||||
getenv.return_value = self.dirname
|
||||
self.assertEqual(p.get_valid_cwd(), self.dirname)
|
||||
self.assertEqual(warn.call_count, 0)
|
||||
|
||||
@mock.patch('os.getenv')
|
||||
@mock.patch('powerline_shell_base.warn')
|
||||
@mock.patch('powerline_shell.warn')
|
||||
def test_nonexistent_warns(self, warn, getenv):
|
||||
subdir = os.path.join(self.dirname, 'subdir')
|
||||
getenv.return_value = subdir
|
||||
|
|
@ -30,7 +30,7 @@ class CwdTest(unittest.TestCase):
|
|||
self.assertEqual(warn.call_count, 1)
|
||||
|
||||
@mock.patch('os.getenv')
|
||||
@mock.patch('powerline_shell_base.warn')
|
||||
@mock.patch('powerline_shell.warn')
|
||||
def test_falls_back_to_getcwd(self, warn, getenv):
|
||||
getenv.return_value = None
|
||||
os.chdir(self.dirname)
|
||||
|
|
@ -38,7 +38,7 @@ class CwdTest(unittest.TestCase):
|
|||
self.assertEqual(warn.call_count, 0)
|
||||
|
||||
@mock.patch('os.getenv')
|
||||
@mock.patch('powerline_shell_base.warn')
|
||||
@mock.patch('powerline_shell.warn')
|
||||
def test_nonexistent_getcwd_warns(self, warn, getenv):
|
||||
subdir = os.path.join(self.dirname, 'subdir')
|
||||
getenv.return_value = None
|
||||
|
|
|
|||
25
test/repo_stats_test.py
Normal file
25
test/repo_stats_test.py
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import unittest
|
||||
from powerline_shell.utils import RepoStats
|
||||
|
||||
|
||||
class RepoStatsTest(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.repo_stats = RepoStats()
|
||||
self.repo_stats.changed = 1
|
||||
self.repo_stats.conflicted = 4
|
||||
|
||||
def test_dirty(self):
|
||||
self.assertTrue(self.repo_stats.dirty)
|
||||
|
||||
def test_simple(self):
|
||||
self.assertEqual(self.repo_stats.new, 0)
|
||||
|
||||
def test_n_or_empty__empty(self):
|
||||
self.assertEqual(self.repo_stats.n_or_empty("changed"), u"")
|
||||
|
||||
def test_n_or_empty__n(self):
|
||||
self.assertEqual(self.repo_stats.n_or_empty("conflicted"), u"4")
|
||||
|
||||
def test_index(self):
|
||||
self.assertEqual(self.repo_stats["changed"], 1)
|
||||
63
test/segments_test/fossil_test.py
Normal file
63
test/segments_test/fossil_test.py
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
import unittest
|
||||
import mock
|
||||
import tempfile
|
||||
import shutil
|
||||
import sh
|
||||
import powerline_shell.segments.fossil as fossil
|
||||
from powerline_shell.utils import RepoStats
|
||||
|
||||
test_cases = {
|
||||
"EXTRA new-file": RepoStats(new=1),
|
||||
"EDITED modified-file": RepoStats(changed=1),
|
||||
"CONFLICT conflicted-file": RepoStats(conflicted=1),
|
||||
"ADDED added-file": RepoStats(staged=1),
|
||||
}
|
||||
|
||||
|
||||
class FossilTest(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.powerline = mock.MagicMock()
|
||||
|
||||
self.dirname = tempfile.mkdtemp()
|
||||
sh.cd(self.dirname)
|
||||
sh.fossil("init", "test.fossil")
|
||||
sh.fossil("open", "test.fossil")
|
||||
|
||||
self.segment = fossil.Segment(self.powerline)
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self.dirname)
|
||||
|
||||
def _add_and_commit(self, filename):
|
||||
sh.touch(filename)
|
||||
sh.fossil("add", filename)
|
||||
sh.fossil("commit", "-m", "add file " + filename)
|
||||
|
||||
def _checkout_new_branch(self, branch):
|
||||
sh.fossil("branch", "new", branch, "trunk")
|
||||
|
||||
@mock.patch("powerline_shell.segments.fossil.get_PATH")
|
||||
def test_fossil_not_installed(self, get_PATH):
|
||||
get_PATH.return_value = "" # so fossil can't be found
|
||||
self.segment.start()
|
||||
self.segment.add_to_powerline()
|
||||
self.assertEqual(self.powerline.append.call_count, 0)
|
||||
|
||||
def test_non_fossil_directory(self):
|
||||
sh.fossil("close", "--force")
|
||||
self.segment.start()
|
||||
self.segment.add_to_powerline()
|
||||
self.assertEqual(self.powerline.append.call_count, 0)
|
||||
|
||||
def test_standard(self):
|
||||
self._add_and_commit("foo")
|
||||
self.segment.start()
|
||||
self.segment.add_to_powerline()
|
||||
self.assertEqual(self.powerline.append.call_args[0][0], " trunk ")
|
||||
|
||||
@mock.patch('powerline_shell.segments.fossil._get_fossil_status')
|
||||
def test_all(self, check_output):
|
||||
for stdout, result in test_cases.items():
|
||||
stats = fossil.parse_fossil_stats([stdout])
|
||||
self.assertEquals(result, stats)
|
||||
|
|
@ -3,19 +3,20 @@ import mock
|
|||
import tempfile
|
||||
import shutil
|
||||
import sh
|
||||
import segments.git as git
|
||||
import powerline_shell.segments.git as git
|
||||
|
||||
|
||||
class GitTest(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.powerline = mock.MagicMock()
|
||||
git.Color = mock.MagicMock()
|
||||
|
||||
self.dirname = tempfile.mkdtemp()
|
||||
sh.cd(self.dirname)
|
||||
sh.git("init", ".")
|
||||
|
||||
self.segment = git.Segment(self.powerline)
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self.dirname)
|
||||
|
||||
|
|
@ -24,36 +25,41 @@ class GitTest(unittest.TestCase):
|
|||
sh.git("add", filename)
|
||||
sh.git("commit", "-m", "add file " + filename)
|
||||
|
||||
def _new_branch(self, branch):
|
||||
def _checkout_new_branch(self, branch):
|
||||
sh.git("checkout", "-b", branch)
|
||||
|
||||
def _get_commit_hash(self):
|
||||
return sh.git("rev-parse", "HEAD")
|
||||
|
||||
@mock.patch('segments.git.get_PATH')
|
||||
@mock.patch('powerline_shell.segments.git.get_PATH')
|
||||
def test_git_not_installed(self, get_PATH):
|
||||
get_PATH.return_value = "" # so git can't be found
|
||||
git.add_git_segment(self.powerline)
|
||||
self.segment.start()
|
||||
self.segment.add_to_powerline()
|
||||
self.assertEqual(self.powerline.append.call_count, 0)
|
||||
|
||||
def test_non_git_directory(self):
|
||||
shutil.rmtree(".git")
|
||||
git.add_git_segment(self.powerline)
|
||||
self.segment.start()
|
||||
self.segment.add_to_powerline()
|
||||
self.assertEqual(self.powerline.append.call_count, 0)
|
||||
|
||||
def test_big_bang(self):
|
||||
git.add_git_segment(self.powerline)
|
||||
self.segment.start()
|
||||
self.segment.add_to_powerline()
|
||||
self.assertEqual(self.powerline.append.call_args[0][0], ' Big Bang ')
|
||||
|
||||
def test_master_branch(self):
|
||||
self._add_and_commit("foo")
|
||||
git.add_git_segment(self.powerline)
|
||||
self.segment.start()
|
||||
self.segment.add_to_powerline()
|
||||
self.assertEqual(self.powerline.append.call_args[0][0], ' master ')
|
||||
|
||||
def test_different_branch(self):
|
||||
self._add_and_commit("foo")
|
||||
self._new_branch("bar")
|
||||
git.add_git_segment(self.powerline)
|
||||
self._checkout_new_branch("bar")
|
||||
self.segment.start()
|
||||
self.segment.add_to_powerline()
|
||||
self.assertEqual(self.powerline.append.call_args[0][0], ' bar ')
|
||||
|
||||
def test_detached(self):
|
||||
|
|
@ -61,7 +67,8 @@ class GitTest(unittest.TestCase):
|
|||
commit_hash = self._get_commit_hash()
|
||||
self._add_and_commit("bar")
|
||||
sh.git("checkout", "HEAD^")
|
||||
git.add_git_segment(self.powerline)
|
||||
self.segment.start()
|
||||
self.segment.add_to_powerline()
|
||||
|
||||
# In detached mode, we output a unicode symbol and then the shortened
|
||||
# commit hash.
|
||||
|
|
|
|||
48
test/segments_test/hg_test.py
Normal file
48
test/segments_test/hg_test.py
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
import unittest
|
||||
import mock
|
||||
import tempfile
|
||||
import shutil
|
||||
import sh
|
||||
import powerline_shell.segments.hg as hg
|
||||
|
||||
|
||||
class HgTest(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.powerline = mock.MagicMock()
|
||||
|
||||
self.dirname = tempfile.mkdtemp()
|
||||
sh.cd(self.dirname)
|
||||
sh.hg("init", ".")
|
||||
|
||||
self.segment = hg.Segment(self.powerline)
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self.dirname)
|
||||
|
||||
def _add_and_commit(self, filename):
|
||||
sh.touch(filename)
|
||||
sh.hg("add", filename)
|
||||
sh.hg("commit", "-m", "add file " + filename)
|
||||
|
||||
def _checkout_new_branch(self, branch):
|
||||
sh.hg("branch", branch)
|
||||
|
||||
@mock.patch("powerline_shell.segments.hg.get_PATH")
|
||||
def test_hg_not_installed(self, get_PATH):
|
||||
get_PATH.return_value = "" # so hg can"t be found
|
||||
self.segment.start()
|
||||
self.segment.add_to_powerline()
|
||||
self.assertEqual(self.powerline.append.call_count, 0)
|
||||
|
||||
def test_non_hg_directory(self):
|
||||
shutil.rmtree(".hg")
|
||||
self.segment.start()
|
||||
self.segment.add_to_powerline()
|
||||
self.assertEqual(self.powerline.append.call_count, 0)
|
||||
|
||||
def test_standard(self):
|
||||
self._add_and_commit("foo")
|
||||
self.segment.start()
|
||||
self.segment.add_to_powerline()
|
||||
self.assertEqual(self.powerline.append.call_args[0][0], " default ")
|
||||
21
test/segments_test/hostname_test.py
Normal file
21
test/segments_test/hostname_test.py
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import unittest
|
||||
import mock
|
||||
import powerline_shell.segments.hostname as hostname
|
||||
from powerline_shell.themes.default import Color
|
||||
from argparse import Namespace
|
||||
|
||||
|
||||
class HostnameTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.powerline = mock.MagicMock()
|
||||
self.powerline.theme = Color
|
||||
self.segment = hostname.Segment(self.powerline)
|
||||
|
||||
def test_colorize(self):
|
||||
self.powerline.segment_conf.return_value = True
|
||||
self.segment.start()
|
||||
self.segment.add_to_powerline()
|
||||
args = self.powerline.append.call_args[0]
|
||||
self.assertNotEqual(args[0], r" \h ")
|
||||
self.assertNotEqual(args[1], Color.HOSTNAME_FG)
|
||||
self.assertNotEqual(args[2], Color.HOSTNAME_BG)
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import unittest
|
||||
import mock
|
||||
import segments.uptime as uptime
|
||||
import powerline_shell.segments.uptime as uptime
|
||||
|
||||
test_cases = {
|
||||
# linux test cases
|
||||
|
|
@ -19,11 +19,12 @@ class UptimeTest(unittest.TestCase):
|
|||
|
||||
def setUp(self):
|
||||
self.powerline = mock.MagicMock()
|
||||
uptime.Color = mock.MagicMock()
|
||||
self.segment = uptime.Segment(self.powerline)
|
||||
|
||||
@mock.patch('subprocess.check_output')
|
||||
def test_all(self, check_output):
|
||||
for stdout, result in test_cases.items():
|
||||
check_output.return_value = stdout
|
||||
uptime.add_uptime_segment(self.powerline)
|
||||
self.segment.start()
|
||||
self.segment.add_to_powerline()
|
||||
self.assertEqual(self.powerline.append.call_args[0][0].split()[0], result)
|
||||
|
|
|
|||
Loading…
Reference in a new issue