Compare commits

...

111 commits

Author SHA1 Message Date
Buck Ryan 4b19aa47f1
Merge pull request #521 from pmbauer/master
add nord theme
2022-09-22 14:12:11 -04:00
Buck Ryan f091bdc61c Switch CYGWIN job counting code from map to list comprehension
Closes #516
2022-09-22 14:08:37 -04:00
Buck Ryan 0c9ccee860
Merge pull request #536 from conr2d/readme-zsh
Update README.md (zsh example)
2022-09-22 14:03:24 -04:00
Buck Ryan 0055f7c2b7 MINGW condition in job count
Closes #330
2022-09-22 14:01:08 -04:00
Buck Ryan 5763a35cc0 add note about testing on zsh 2022-09-22 13:55:46 -04:00
Buck Ryan db35d233d1 Fix jobs segment for bash 5, fish 3 2022-09-22 13:52:42 -04:00
Buck Ryan 70edbd062d Merge commit '33d1ae1ae9a147ecfbd4f33d3b346e4f4767a027' into fix-jobs 2022-09-22 13:29:02 -04:00
Jeeyong Um 7adadf1e04 Update README.md 2022-07-28 20:17:28 +09:00
Buck Ryan 4b681d8318
Merge pull request #531 from blcsntb/patch-1
Update README.md
2022-03-16 14:10:09 -04:00
Binh Nguyen 3433b92e86
Update README.md 2022-03-09 14:50:46 +07:00
Paul Bauer 56f78ca049 add nord theme 2021-05-17 12:44:49 -04:00
Thomas Cherry 33d1ae1ae9 removing need to explicity call out fish from the command line 2019-07-03 23:23:08 -04:00
Thomas Cherry fd0b3a8ec4 removing need to explicity call out fish from the command line 2019-07-03 23:21:33 -04:00
Thomas Cherry 256888344a fixing names as suggested 2019-07-03 23:03:52 -04:00
Buck Ryan a9b8c9bb39 update metadata homepage 2018-09-15 20:24:03 -04:00
Buck Ryan 7332357af6 prepare 0.7.0 2018-09-15 19:17:33 -04:00
Buck Ryan 09fd45d6fc doc formatting 2018-09-15 19:13:48 -04:00
Buck Ryan feb9c8550e fix bug in svn segment 2018-07-01 21:13:15 -04:00
Buck Ryan 067202f71a prepare 0.7.0-rc1 2018-06-21 21:29:37 -04:00
Buck Ryan e8a86cf8ff Merge branch 'master' into develop 2018-06-21 21:28:39 -04:00
Buck Ryan 9d15bf7040
Merge pull request #365 from b-ryan/stdout-segment
Generic stdout and environment variable segments
2018-06-21 21:28:15 -04:00
Buck Ryan d095a2f3d5 fix tests and new test dockerfile 2018-06-21 21:26:40 -04:00
Buck Ryan 54f7b90052 Merge branch 'develop' into stdout-segment 2018-06-21 18:17:52 -04:00
Buck Ryan 0ea47cc115 date the 0.6.0 release 2018-06-20 10:29:30 -04:00
Buck Ryan 3d46c135dc
Merge pull request #416 from b-ryan/develop
Develop
2018-06-20 10:28:59 -04:00
Buck Ryan 7935d7ad11 readme updates for custom segments 2018-06-20 10:26:22 -04:00
Buck Ryan 3cf55e7b60 get ready for 0.6.0 2018-06-20 10:18:58 -04:00
Buck Ryan af919e1772 Custom segment support
Closes #407

The changes in 407 were on the right track, but didn't take it all the
way. Some issues it had:

- Did not call `expanduser` to handle paths like `~/segment.py`
- Did not appear to work on both Python 2 and Python 3
- Did not show a meaningful message when a segment cannot be found

This commit repurposes the code written to import custom themes for
segments.
2018-06-20 10:18:06 -04:00
Buck Ryan 3b95178400 fix issues with config file path
fixes #409
2018-06-04 14:45:30 -04:00
Buck Ryan ee5776f10c
Merge pull request #386 from jamessimas/master
Fix filename for macOS
2018-05-07 10:54:50 -04:00
Buck Ryan 36486483eb changelog for #383 2018-05-07 10:53:02 -04:00
Buck Ryan c2932e7e8f
Merge pull request #383 from dundalek/feature/time-format
Add format option for time segment
2018-05-07 10:51:49 -04:00
Buck Ryan b53337c215 Merge branch 'develop' into stdout-segment 2018-04-25 09:55:50 -04:00
Buck Ryan 73b01d6597 Revert "implement fix for #249"
This reverts commit 86fd04c7a8.

Closes #389
2018-04-22 12:13:10 -04:00
James Simas c64da3dde4 Update macOS section 2018-04-21 19:33:56 -07:00
Buck Ryan 08c07fa1f1 prepare 0.5.3 2018-04-21 17:50:42 -04:00
Buck Ryan bbb7354068
Merge pull request #388 from monicaycli/master
add gruvbox theme
2018-04-21 17:14:21 -04:00
Buck Ryan 5563655d82 prepare 0.5.2 2018-04-21 17:06:37 -04:00
Buck Ryan b2797c77cd README update including clarification of relation to powerline
Closes #329
2018-04-21 17:00:41 -04:00
Buck Ryan ac3be5f7b3 Better handling of invalid JSON config files
Closes #371
2018-04-21 16:44:48 -04:00
Buck Ryan 86fd04c7a8 implement fix for #249
closes #249
2018-04-21 16:15:12 -04:00
Buck Ryan 668a964291 update changes from #354 for py3 2018-04-21 15:59:39 -04:00
Buck Ryan 6eff2101be
Merge pull request #354 from comagnaw/fix_hostname_colorize
Fix hostname colorize
2018-04-21 15:59:07 -04:00
Monica Li 4e74b9a12a add gruvbox theme 2018-04-21 13:55:56 -04:00
Buck Ryan c9a1ea7f9f
Merge pull request #387 from AlvaroBernalG/master
Fix segment git_stash test failure
2018-04-20 11:05:13 -04:00
Alvaro Bernal 31bd259e9d Fix git_stash segment test failure 2018-04-20 14:13:58 +01:00
James Simas 8b9c0f2b80 Fix filename for macOS 2018-04-19 22:22:48 -07:00
Buck Ryan 8ff0806ac8 prepare 0.5.1 2018-04-13 10:14:42 -04:00
Buck Ryan e828f264be python3 compat for git_stash
fixes #384

tested py2 & py3
2018-04-13 10:13:25 -04:00
Buck Ryan 095dc37dd0 fix symbol for untracked 2018-04-10 16:16:48 -04:00
Buck Ryan e163b7aaeb prepare 0.5.0 2018-04-10 16:16:12 -04:00
Buck Ryan 15654cb79a Merge branch 'release-0.5.0' 2018-04-10 16:13:59 -04:00
Buck Ryan 404d3fff56
Merge pull request #379 from apinkney97/master
Add git stash segment
2018-04-10 16:12:23 -04:00
Alex Pinkney 15a6172a2c Move git stash symbol definition to utils.RepoStats.symbols 2018-04-10 06:21:23 -04:00
Jakub Dundalek 7f72c1b031 Add format option for time segment 2018-03-29 16:28:37 +02:00
Alex Pinkney 709c5ba215 Add git_stash segment 2018-03-20 13:16:28 +00:00
Alex Pinkney fc62b0f888 Move get_PATH and x_subprocess_env functions into utils.py 2018-03-20 13:09:48 +00:00
Buck Ryan ae33f7e7cf
Merge pull request #312 from amkarthik/master
Real Virtual env name while using "pipenv"
2018-02-26 10:05:46 -05:00
Buck Ryan d0dec6ce64 new repo path 2018-02-23 23:31:21 -05:00
Buck Ryan a209e6b12d 0.5.0 is upcoming 2018-02-23 23:17:43 -05:00
Buck Ryan 755ba297aa take out ~/.config notes 2018-02-23 23:14:40 -05:00
Buck Ryan cf6a804fd4
Merge pull request #334 from kc9jud/xdg-base-directory
config: Support config in $XDG_CONFIG_HOME
2018-02-23 23:12:27 -05:00
Buck Ryan 599f145208 changelog for #336 2018-02-22 20:16:02 -05:00
Buck Ryan da8d923f86
Merge pull request #366 from Blue-Dog-Archolite/master
Ruby Segment changes for Python 2/3:
2018-02-22 20:08:19 -05:00
Blue-Dog-Archolite 6ff4b50376 Ruby Segment changes:
- use "GEM_HOME" in keys
- removal of python2 specific code
- verification of python2 / python3 functionality
- use of format in append to replace string join
2018-02-22 15:39:11 -07:00
Buck Ryan f6c7eaa10a additional changelog for pending release 2018-02-22 10:36:18 -05:00
Buck Ryan 9a9ce2ac79
Merge pull request #364 from b-ryan/respect-max-plain
respect max dir setting for plain cwd
2018-02-22 10:31:17 -05:00
Buck Ryan 389080f5bf prepare 0.4.10.rc1 2018-02-22 10:30:49 -05:00
Buck Ryan b07c8ef4cb Patch environment for VCS rather than creating new one
Closes #240
2018-02-22 10:24:24 -05:00
Buck Ryan a494cd4a45 prepare 0.4.9 2018-02-19 10:45:27 -05:00
Buck Ryan 27574cc79b Fix tests and some py2/py3 issues 2018-02-19 10:45:02 -05:00
Buck Ryan 3ba8376175
Merge pull request #362 from TiGR/patch-1
Fix double-escape of user/root ($/#) indicator (fixes #315)
2018-02-19 10:09:22 -05:00
Buck Ryan 47ca2df524 nevermind on extra theme variables 2018-02-18 22:04:43 -05:00
Buck Ryan 84a6b215c1 docs for stdout and env 2018-02-18 22:02:44 -05:00
Buck Ryan f0caebd26f segment that gets an environment variable 2018-02-18 21:52:51 -05:00
Buck Ryan 9703379d58 create an stdout segment that just plops in outputs of commands 2018-02-18 21:42:02 -05:00
Buck Ryan b7dc34572c
Merge pull request #349 from emansije/fix-svn-segment
Fixes and enhances svn segment
2018-02-18 21:23:25 -05:00
Buck Ryan a9050d0f61 respect max dir setting for plain cwd 2018-02-18 21:09:22 -05:00
Igor Tarasov c413236ee6 Move escaping back to append and make it optional 2018-02-16 00:43:42 +04:00
Igor Tarasov 235d3a8fda
Fix double-escape of user/root ($/#) indicator (fixes #315)
If our segment is ' \\$ ' then it is already sanitized and should not be escaped again, so we avoid it.
2018-02-12 00:16:04 +04:00
comagnaw 81653f4c0c
Fixing indent 2018-02-03 23:11:55 -05:00
comagnaw 0bca50bb18
Adding getOppositeColor unittest. 2018-02-03 23:08:36 -05:00
comagnaw 15c4aee277
Add conversion to float before pass to rgb_to_hls 2018-02-01 22:29:06 -05:00
Buck Ryan 87b176037f Change bash instructions for ps1 to not duplicate
Fixes #331
2018-01-29 12:18:03 -05:00
Buck Ryan e7964d1682 prepare 0.4.8 2018-01-29 12:01:32 -05:00
Buck Ryan 3c3062e3ce
Merge pull request #352 from b-ryan/fix-custom-themes
A possible solution for allowing custom themes
2018-01-29 11:48:20 -05:00
Buck Ryan 4b26d19907 default time vars 2018-01-29 11:45:31 -05:00
Gaurav Nelson f0293999c7 added seperate variables for customizing colors for time segment 2018-01-29 14:00:34 +10:00
Buck Ryan bcaa7e6e4d A possible solution for allowing custom themes 2018-01-28 22:37:46 -05:00
Buck Ryan 5db48c3014
Merge pull request #326 from mikewaters/master
Added a note about theme color codes.
2018-01-28 22:30:41 -05:00
Emanuel Angelo a1b536b85b Fixes and enhances svn segment
Uses the 'info' command with XML output to make it localization independent.
Prepares the segment for testing.
2018-01-18 00:29:32 +00:00
Buck Ryan ad27ed4ccc 0.4.7 2018-01-15 12:10:11 -05:00
Buck Ryan 4d4241fba0 Add back SVN symbol 2018-01-15 12:02:50 -05:00
Buck Ryan ef5b837aef Merge remote-tracking branch 'emansije/vcs-symbols' into emansije-merge 2018-01-15 12:00:45 -05:00
Emanuel de Jesus bbaacc1a3c
Merge branch 'master' into vcs-symbols 2018-01-13 21:55:29 +00:00
Buck Ryan 8e2b00e7ff
Merge pull request #348 from ypresto/patch-1
Fix wrong filename in README.md
2018-01-13 10:18:53 -05:00
Yuya Tanaka f8649ee985
Fix wrong filename in README.md 2018-01-13 19:27:15 +09:00
Emanuel de Jesus 235e02b831
Merge branch 'master' into vcs-symbols 2017-12-14 23:17:29 +00:00
Patrick Fasano 88e3d6bcf8
config: Use ~/.config as default for 2017-11-28 18:18:46 -05:00
Emanuel de Jesus d80fc8af82
Merge branch 'master' into vcs-symbols 2017-11-27 23:01:24 +00:00
Patrick Fasano e6c730c7ba
config: Support config in $XDG_CONFIG_HOME 2017-11-25 21:41:34 -05:00
mikewaters 8d33e5542e
Added a note about theme color codes. 2017-11-10 12:03:10 -05:00
Thomas Cherry eb0f462717 adding a way to force fish mode for testing and to be more explicit 2017-11-05 12:05:39 -05:00
Thomas Cherry 006be7777f got this to work with fish 2017-11-05 12:05:39 -05:00
Emanuel Angelo dee6ef0ded Applied symbols \u2B61\u20DF and \u2332 for bzr and fossil, respectively 2017-10-26 01:53:03 +01:00
Emanuel de Jesus 7c7e900bf0 Merge branch 'master' into vcs-symbols 2017-10-26 01:38:14 +01:00
Karthik 21cfded8aa Real Virtual env name while using "pipenv".
pipenv is an officially recomended tool for managing python packages
dependencies.
In pipenv we have an option to create virtual env inside the project it
self.
The created virutal env name is .venv.

The normal bash display the name of the virual env as the parent folder
name.
Ex: new_shell/.venv then the virual env name displayed in base is
new_shell.

In powerline_shell the virtual env name is displayed as .venv.

This PR is a fix for displaying the parent folder as virtual env name.
2017-10-17 15:43:56 +05:30
Emanuel Angelo 538bd54fc7 Displays branch name for the svn segment
SVN implements the branch notion at server level and the working copies don't
hold that information. This implementation gets the working copy root path and
extracts the basename, using it as a local branch name.
2017-10-07 18:39:46 +01:00
Emanuel Angelo b76f20d6bd Updates README.md with the latest VCS' segments modifications 2017-10-04 23:22:38 +01:00
Emanuel Angelo 4942ad51e5 Makes the svn segment a threaded one and makes it use the VCS symbol 2017-10-04 22:36:11 +01:00
Emanuel Angelo ef9c8f3e33 Adds VCS symbol before branch name in each VCS segment
The configuration file has an extra `vcs` option with a `show_symbol` boolean
sub-option to toggle the use of the symbol.
2017-10-04 22:33:55 +01:00
44 changed files with 936 additions and 259 deletions

View file

@ -1,5 +1,71 @@
# Changes
2018-09-15 (version 0.7.0)
* New generic `stdout` and `env` segments
2018-06-20 (version 0.6.0)
* Support for custom themes
* New option for the `time` segment to specify format of the displayed time
([@dundalek](https://github.com/b-ryan/powerline-shell/pull/383))
2018-04-22 (version 0.5.4)
* Reverted fix for
([#249](https://github.com/b-ryan/powerline-shell/issues/249)) because it
caused issues on Mac.
2018-04-21 (version 0.5.3)
* New theme! (gruvbox)
([@monicaycli](https://github.com/b-ryan/powerline-shell/pull/388))
2018-04-21 (version 0.5.2)
* Fix hostname colorize bug
([@comagnaw](https://github.com/b-ryan/powerline-shell/issues/353))
* Fix issue with prompt bleeding behavior
([@bytebeast](https://github.com/b-ryan/powerline-shell/issues/249))
* Better error message when config file cannot be decoded (Closes
[#371](https://github.com/b-ryan/powerline-shell/issues/371))
2018-04-13 (version 0.5.1)
* Fix Python 3 compatibility of `git_stash` segment
2018-04-10 (version 0.5.0)
* Patch environment for VCS subprocesses rather than generating a new one
* Fix `cwd` segment so it respects `max_depth` configuration
* Fix Ruby segment for Python 3 compatibility
([@Blue-Dog-Archolite](https://github.com/b-ryan/powerline-shell/pull/366))
* Configuration is now expected to be at
`~/.config/powerline-shell/config.json` ([@emansije and
@kc9jud](https://github.com/b-ryan/powerline-shell/pull/334))
* New `git_stash` segment
([@apinkney97](https://github.com/b-ryan/powerline-shell/pull/379))
2018-02-19 (version 0.4.9)
* Fix root user segment
([@TiGR](https://github.com/b-ryan/powerline-shell/pull/362))
* Fixes and enhancements for SVN segment
([@emansije](https://github.com/b-ryan/powerline-shell/pull/349))
2018-01-29 (version 0.4.8)
* Bring back the ability to create custom themes
([@b-ryan](https://github.com/b-ryan/powerline-shell/pull/352))
* Add the ability to customize the `time` segment in themes
([@gaurav-nelson](https://github.com/b-ryan/powerline-shell/pull/338))
2018-01-15 (version 0.4.7)
* VCS segments (git, hg, etc.) can now show a symbol identifying what VPS the
current directory uses
([@emansije](https://github.com/b-ryan/powerline-shell/pull/298))
2018-01-11 (version 0.4.6)
* Fix bug in SVN segment

View file

@ -1,6 +1,6 @@
FROM aa8y/core:python2
FROM python:2-alpine
MAINTAINER github.com/banga/powerline-shell
MAINTAINER github.com/b-ryan/powerline-shell
USER root
RUN apk add --no-cache --update \
@ -9,25 +9,23 @@ RUN apk add --no-cache --update \
git \
mercurial \
php5 \
subversion && \
subversion \
&& \
rm -rf /var/cache/apk/*
# Cache the dev requirements. Directory is set in the base image.
WORKDIR $APP_DIR
RUN mkdir /code
WORKDIR /code
COPY requirements-dev.txt .
RUN pip install -r requirements-dev.txt && \
rm -rf requirements-dev.txt
rm requirements-dev.txt
# 'USER' is set in the base image. It points to a non-root user called 'docker'.
USER $USER
RUN bzr whoami "$USERNAME <$USER@example.com>" && \
git config --global user.email "$USER@example.com" && \
git config --global user.name "$USERNAME"
RUN bzr whoami "root <root@example.com>" && \
git config --global user.email "root@example.com" && \
git config --global user.name "root"
COPY . ./
USER root
RUN ./setup.py install && \
chown -R $USER:$USER .
# COPY . ./
# RUN ./setup.py install
USER $USER
ENTRYPOINT ["/bin/bash"]
ENV USER root
CMD ["nosetests"]

182
README.md
View file

@ -1,9 +1,8 @@
# A Powerline style prompt for your shell
A [Powerline](https://github.com/Lokaltog/vim-powerline) like prompt for Bash,
ZSH, Fish, and tcsh:
A beautiful and useful prompt generator for Bash, ZSH, Fish, and tcsh:
![MacVim+Solarized+Powerline+CtrlP](https://raw.github.com/banga/powerline-shell/master/bash-powerline-screenshot.png)
![MacVim+Solarized+Powerline+CtrlP](https://raw.github.com/b-ryan/powerline-shell/master/bash-powerline-screenshot.png)
- Shows some important details about the git/svn/hg/fossil branch (see below)
- Changes color if the last command exited with a failure code
@ -11,6 +10,10 @@ ZSH, Fish, and tcsh:
- Shows the current Python [virtualenv](http://www.virtualenv.org/) environment
- It's easy to customize and extend. See below for details.
The generated prompts are designed to resemble
[powerline](https://github.com/powerline/powerline), but otherwise this project
has no relation to powerline.
<!-- 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)*
@ -20,9 +23,11 @@ ZSH, Fish, and tcsh:
- [Bash](#bash)
- [ZSH](#zsh)
- [Fish](#fish)
- [tcsh](#tcsh)
- [Customization](#customization)
- [Config File](#config-file)
- [Adding, Removing and Re-arranging segments](#adding-removing-and-re-arranging-segments)
- [Generic Segments](#generic-segments)
- [Segment Separator](#segment-separator)
- [Themes](#themes)
- [Segment Configuration](#segment-configuration)
@ -42,24 +47,26 @@ quick look into the state of your repo:
of commits is shown along with `⇡` or `⇣` indicating whether a git push
or pull is pending.
In addition, git has a few extra symbols:
If files are modified or in conflict, the situation is summarized with the
following symbols:
- `✎` -- a file has been modified, but not staged for commit
- `✔` -- a file is staged for commit
- `✎` -- a file has been modified (but not staged for commit, in git)
- `✔` -- a file is staged for commit (git) or added for tracking
- `✼` -- a file has conflicts
FIXME
- A `+` appears when untracked files are present (except for git, which uses
`?` instead)
- `?` -- a file is untracked
Each of these will have a number next to it if more than one file matches.
The segment can start with a symbol representing the version control system in
use. To show that symbol, the configuration file must have a variable `vcs`
with an option `show_symbol` set to `true` (see
[Segment Configuration](#segment-configuration)).
## 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.
setting your $TERM to `xterm-256color`.
- Patch the font you use for your terminal: see
[powerline-fonts](https://github.com/Lokaltog/powerline-fonts)
@ -84,7 +91,7 @@ install for just your user, if you'd like. But you may need to fiddle with your
- Or, install from the git repository:
```
git clone https://github.com/banga/powerline-shell
git clone https://github.com/b-ryan/powerline-shell
cd powerline-shell
python setup.py install
```
@ -93,18 +100,23 @@ python setup.py install
### Bash
Add the following to your `.bashrc` (or `.profile` on Mac):
Add the following to your `.bashrc` file:
```
function _update_ps1() {
PS1="$(powerline-shell $?)"
PS1=$(powerline-shell $?)
}
if [ "$TERM" != "linux" ]; then
if [[ $TERM != linux && ! $PROMPT_COMMAND =~ _update_ps1 ]]; then
PROMPT_COMMAND="_update_ps1; $PROMPT_COMMAND"
fi
```
**Note:** On macOS, you must add this to one of `.bash_profile`, `.bash_login`,
or `.profile`. macOS will execute the files in the aforementioned order and
will stop execution at the first file it finds. For more information on the
order of precedence, see the section **INVOCATION** in `man bash`.
### ZSH
Add the following to your `.zshrc`:
@ -123,7 +135,7 @@ function install_powerline_precmd() {
precmd_functions+=(powerline_precmd)
}
if [ "$TERM" != "linux" ]; then
if [ "$TERM" != "linux" -a -x "$(command -v powerline-shell)" ]; then
install_powerline_precmd
fi
```
@ -151,53 +163,74 @@ alias precmd 'set prompt="`powerline-shell --shell tcsh $?`"'
### 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:
expected to be located at `~/.config/powerline-shell/config.json`. You can
generate the default config at this location using:
```
powerline-shell --generate-config > ~/.powerline-shell.json
mkdir -p ~/.config/powerline-shell && \
powerline-shell --generate-config > ~/.config/powerline-shell/config.json
```
(You can see an example config file
[here](https://github.com/b-ryan/dotfiles/blob/master/home/powerline-shell.json))
(As an example, my config file is located here:
[here](https://github.com/b-ryan/dotfiles/blob/master/home/config/powerline-shell/config.json))
### Adding, Removing and Re-arranging segments
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:
can be seen
[here](https://github.com/b-ryan/powerline-shell/tree/master/powerline_shell/segments).
- `aws_profile` - Show which AWS profile is in use. See the
[AWS](http://docs.aws.amazon.com/cli/latest/userguide/cli-multiple-profiles.html)
documentation.
- `battery` - See percentage of battery charged and an icon when the battery is
charging.
- `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 exit 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.
You can also create custom segments. Start by copying an existing segment like
[this](https://github.com/b-ryan/powerline-shell/blob/master/powerline_shell/segments/aws_profile.py).
Make sure to change any relative imports to absolute imports. Ie. change things
like:
```python
from ..utils import BasicSegment
```
to
```python
from powerline_shell.utils import BasicSegment
```
Then change the `add_to_powerline` function to do what you want. You can then
use this segment in your configuration by putting the path to your segment in
the segments section, like:
```json
"segments": [
"~/path/to/segment.py"
]
```
### Generic Segments
There are two special segments available. `stdout` accepts an arbitrary command
and the output of the command will be put into your prompt. `env` takes an
environment variable and the value of the variable will be set in your prompt.
For example, your config could look like this:
```
{
"segments": [
"cwd",
"git",
{
"type": "stdout",
"command": ["echo", "hi"],
"fg_color": 22,
"bg_color": 161
},
{
"type": "env",
"var": "DOCKER_MACHINE_NAME"
},
]
}
```
### Segment Separator
@ -216,9 +249,20 @@ file. The available modes are:
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.
they miss colors for any segments.
If you want to create a custom theme, start by copying one of the existing
themes, like the
[basic](https://github.com/b-ryan/powerline-shell/blob/master/powerline_shell/themes/basic.py).
and update your `~/.config/powerline-shell/config.json`, setting the `"theme"`
to the path of the file. For example your configuration might have:
```
"theme": "~/mythemes/my-great-theme.py"
```
You can then modify the color codes to your liking. Theme colors are specified
using [Xterm-256 color codes](https://jonasjacek.github.io/colors/).
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
@ -229,7 +273,7 @@ settings.
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:
for the `cwd` segment are set in `~/.config/powerline-shell/config.json` like:
```
{
@ -237,13 +281,17 @@ for the `cwd` segment are set in `~/.powerline-shell.py` like:
"cwd": {
options go here
}
"theme": "theme-name",
"vcs": {
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
- `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
@ -256,11 +304,21 @@ The `hostname` segment provides one option:
- `colorize`: If true, the hostname will be colorized based on a hash of
itself.
The `vcs` segment provides one option:
- `show_symbol`: If `true`, the version control system segment will start with
a symbol representing the specific version control system in use in the
current directory.
The options for the `battery` segment are:
- `always_show_percentage`: If true, show percentage when fully charged on AC.
- `low_threshold`: Threshold percentage for low-battery indicator color.
The options for the `time` segment are:
- `format`: Format string as used by strftime function, e.g. `%H:%M`.
### Contributing new types of segments
The `powerline_shell/segments` directory contains python scripts which are
@ -284,6 +342,6 @@ requirements in `requirements-dev.txt`.
## Troubleshooting
See the [FAQ](https://github.com/banga/powerline-shell/wiki/FAQ). If you
See the [FAQ](https://github.com/b-ryan/powerline-shell/wiki/FAQ). If you
continue to have issues, please open an
[issue](https://github.com/banga/powerline-shell/issues/new).
[issue](https://github.com/b-ryan/powerline-shell/issues/new).

View file

@ -6,7 +6,7 @@ import os
import sys
import importlib
import json
from .utils import warn, py3
from .utils import warn, py3, import_file
import re
@ -114,7 +114,9 @@ class Powerline(object):
def bgcolor(self, code):
return self.color('48', code)
def append(self, content, fg, bg, separator=None, separator_fg=None):
def append(self, content, fg, bg, separator=None, separator_fg=None, sanitize=True):
if self.args.shell == "bash" and sanitize:
content = re.sub(r"([`$])", r"\\\1", content)
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))
@ -129,16 +131,12 @@ class Powerline(object):
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,
segment[0],
self.bgcolor(next_segment[2]) if next_segment else self.reset,
self.fgcolor(segment[4]),
segment[3]))
@ -148,6 +146,7 @@ def find_config():
for location in [
"powerline-shell.json",
"~/.powerline-shell.json",
os.path.join(os.environ.get("XDG_CONFIG_HOME", "~/.config"), "powerline-shell", "config.json"),
]:
full = os.path.expanduser(location)
if os.path.exists(full):
@ -168,6 +167,28 @@ DEFAULT_CONFIG = {
}
class ModuleNotFoundException(Exception):
pass
class CustomImporter(object):
def __init__(self):
self.file_import_count = 0
def import_(self, module_prefix, module_or_file, description):
try:
mod = importlib.import_module(module_prefix + module_or_file)
except ImportError:
try:
module_name = "_custom_mod_{0}".format(self.file_import_count)
mod = import_file(module_name, os.path.expanduser(module_or_file))
self.file_import_count += 1
except (ImportError, IOError):
msg = "{0} {1} cannot be found".format(description, module_or_file)
raise ModuleNotFoundException( msg)
return mod
def main():
arg_parser = argparse.ArgumentParser()
arg_parser.add_argument('--generate-config', action='store_true',
@ -186,19 +207,33 @@ def main():
config_path = find_config()
if config_path:
with open(config_path) as f:
config = json.loads(f.read())
try:
config = json.loads(f.read())
except Exception as e:
warn("Config file ({0}) could not be decoded! Error: {1}"
.format(config_path, e))
config = DEFAULT_CONFIG
else:
config = DEFAULT_CONFIG
theme_name = config.get("theme", "default")
mod = importlib.import_module("powerline_shell.themes." + theme_name)
theme = getattr(mod, "Color")
custom_importer = CustomImporter()
theme_mod = custom_importer.import_(
"powerline_shell.themes.",
config.get("theme", "default"),
"Theme")
theme = getattr(theme_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)
for seg_conf in config["segments"]:
if not isinstance(seg_conf, dict):
seg_conf = {"type": seg_conf}
seg_name = seg_conf["type"]
seg_mod = custom_importer.import_(
"powerline_shell.segments.",
seg_name,
"Segment")
segment = getattr(seg_mod, "Segment")(powerline, seg_conf)
segment.start()
segments.append(segment)
for segment in segments:

View file

@ -10,6 +10,7 @@ from .utils import py3
def getOppositeColor(r,g,b):
r, g, b = [x/255.0 for x in [r, g, b]] # convert to float before getting hls value
hls = rgb_to_hls(r,g,b)
opp = list(hls[:])
opp[0] = (opp[0]+0.2)%1 # shift hue (a.k.a. color)

View file

@ -1,23 +1,11 @@
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()}
from ..utils import RepoStats, ThreadedSegment, get_subprocess_env
def _get_bzr_branch():
p = subprocess.Popen(['bzr', 'nick'],
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
env=bzr_subprocess_env())
env=get_subprocess_env())
branch = p.communicate()[0].decode("utf-8").rstrip('\n')
return branch
@ -47,7 +35,7 @@ def build_stats():
try:
p = subprocess.Popen(['bzr', 'status'],
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
env=bzr_subprocess_env())
env=get_subprocess_env())
except OSError:
# Popen will throw an OSError if bzr is not found
return (None, None)
@ -73,6 +61,9 @@ class Segment(ThreadedSegment):
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)
if self.powerline.segment_conf("vcs", "show_symbol"):
symbol = RepoStats().symbols["bzr"] + " "
else:
symbol = ""
self.powerline.append(" " + symbol + self.branch + " ", fg, bg)
self.stats.add_to_powerline(self.powerline)

View file

@ -58,10 +58,6 @@ def add_cwd_segment(powerline):
cwd = cwd.decode("utf-8")
cwd = replace_home_dir(cwd)
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)
full_cwd = powerline.segment_conf("cwd", "full_cwd", False)
@ -84,6 +80,12 @@ def add_cwd_segment(powerline):
# displayed, so chop everything else off
names = names[-1:]
elif powerline.segment_conf("cwd", "mode") == "plain":
joined = os.path.sep.join(names)
powerline.append(" %s " % (joined,), powerline.theme.CWD_FG,
powerline.theme.PATH_BG)
return
for i, name in enumerate(names):
is_last_dir = (i == len(names) - 1)
fg, bg = get_fg_bg(powerline, name, is_last_dir)

View file

@ -0,0 +1,10 @@
import os
from ..utils import BasicSegment
class Segment(BasicSegment):
def add_to_powerline(self):
self.powerline.append(
" %s " % os.getenv(self.segment_def["var"]),
self.segment_def.get("fg_color", self.powerline.theme.PATH_FG),
self.segment_def.get("bg_color", self.powerline.theme.PATH_BG))

View file

@ -1,17 +1,6 @@
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()}
from ..utils import RepoStats, ThreadedSegment, get_subprocess_env
def _get_fossil_branch():
@ -49,7 +38,7 @@ def build_stats():
try:
subprocess.Popen(['fossil'], stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env=fossil_subprocess_env()).communicate()
env=get_subprocess_env()).communicate()
except OSError:
# Popen will throw an OSError if fossil is not found
return (None, None)
@ -74,6 +63,9 @@ class Segment(ThreadedSegment):
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)
if self.powerline.segment_conf("vcs", "show_symbol"):
symbol = RepoStats().symbols["fossil"] + " "
else:
symbol = ""
self.powerline.append(" " + symbol + self.branch + " ", fg, bg)
self.stats.add_to_powerline(self.powerline)

View file

@ -1,28 +1,6 @@
import re
import subprocess
import os
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 git_subprocess_env():
return {
# LANG is specified to ensure git always uses a language we are expecting.
# Otherwise we may be unable to parse the output.
"LANG": "C",
# https://github.com/milkbikis/powerline-shell/pull/126
"HOME": os.getenv("HOME"),
# https://github.com/milkbikis/powerline-shell/pull/153
"PATH": get_PATH(),
}
from ..utils import RepoStats, ThreadedSegment, get_git_subprocess_env
def parse_git_branch_info(status):
@ -33,7 +11,7 @@ def parse_git_branch_info(status):
def _get_git_detached_branch():
p = subprocess.Popen(['git', 'describe', '--tags', '--always'],
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
env=git_subprocess_env())
env=get_git_subprocess_env())
detached_ref = p.communicate()[0].decode("utf-8").rstrip('\n')
if p.returncode == 0:
branch = u'{} {}'.format(RepoStats.symbols['detached'], detached_ref)
@ -63,7 +41,7 @@ def build_stats():
try:
p = subprocess.Popen(['git', 'status', '--porcelain', '-b'],
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
env=git_subprocess_env())
env=get_git_subprocess_env())
except OSError:
# Popen will throw an OSError if git is not found
return (None, None)
@ -98,6 +76,9 @@ class Segment(ThreadedSegment):
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)
if self.powerline.segment_conf("vcs", "show_symbol"):
symbol = RepoStats().symbols["git"] + " "
else:
symbol = ""
self.powerline.append(" " + symbol + self.branch + " ", fg, bg)
self.stats.add_to_powerline(self.powerline)

View file

@ -0,0 +1,34 @@
import subprocess
from ..utils import RepoStats, ThreadedSegment, get_git_subprocess_env
def get_stash_count():
try:
p = subprocess.Popen(['git', 'stash', 'list'],
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
env=get_git_subprocess_env())
except OSError:
return 0
pdata = p.communicate()
if p.returncode != 0:
return 0
return pdata[0].count(b'\n')
class Segment(ThreadedSegment):
def run(self):
self.stash_count = get_stash_count()
def add_to_powerline(self):
self.join()
if not self.stash_count:
return
bg = self.powerline.theme.GIT_STASH_BG
fg = self.powerline.theme.GIT_STASH_FG
sc = self.stash_count if self.stash_count > 1 else ''
stash_str = u' {}{} '.format(sc, RepoStats.symbols['stash'])
self.powerline.append(stash_str, fg, bg)

View file

@ -1,24 +1,12 @@
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 hg_subprocess_env():
return {"PATH": get_PATH()}
from ..utils import RepoStats, ThreadedSegment, get_subprocess_env
def _get_hg_branch():
p = subprocess.Popen(["hg", "branch"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env=hg_subprocess_env())
env=get_subprocess_env())
branch = p.communicate()[0].decode("utf-8").rstrip('\n')
return branch
@ -46,7 +34,7 @@ def build_stats():
p = subprocess.Popen(["hg", "status"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env=hg_subprocess_env())
env=get_subprocess_env())
except OSError:
# Will be thrown if hg cannot be found
return None, None
@ -72,5 +60,9 @@ class Segment(ThreadedSegment):
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)
if self.powerline.segment_conf("vcs", "show_symbol"):
symbol = RepoStats().symbols["hg"] + " "
else:
symbol = ""
self.powerline.append(" " + symbol + self.branch + " ", fg, bg)
self.stats.add_to_powerline(self.powerline)

View file

@ -6,26 +6,30 @@ from ..utils import ThreadedSegment
class Segment(ThreadedSegment):
def run(self):
self.num_jobs = 0
if platform.system().startswith('CYGWIN'):
system = platform.system()
if system.startswith("CYGWIN") or system.startswith("MINGW"):
# 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:])
output_proc = subprocess.Popen(["ps", "-af"], stdout=subprocess.PIPE)
output = [int(l.split()[2].strip()) for l in 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)
# The following logic was tested on:
# - fish, version 3.3.1
# - GNU bash, version 5.1.16(1)-release (x86_64-pc-linux-gnu)
# - zsh 5.8.1 (x86_64-ubuntu-linux-gnu)
# If you change the behavior to account for another shell's
# behavior, please provide details of the shell version you tested
# on in this comment.
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
self.num_jobs = len(re.findall(str(os.getppid()), output)) - 1
def add_to_powerline(self):
self.join()
if self.num_jobs > 0:
self.powerline.append(' %d ' % self.num_jobs,
self.powerline.append(" %d " % self.num_jobs,
self.powerline.theme.JOBS_FG,
self.powerline.theme.JOBS_BG)

View file

@ -1,12 +1,14 @@
import subprocess
from ..utils import ThreadedSegment
from ..utils import ThreadedSegment, decode
class Segment(ThreadedSegment):
def run(self):
self.version = None
try:
output = subprocess.check_output(['php', '-r', 'echo PHP_VERSION;'],
stderr=subprocess.STDOUT)
output = decode(
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

View file

@ -15,4 +15,4 @@ class Segment(BasicSegment):
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)
powerline.append(root_indicators[powerline.args.shell], fg, bg, sanitize=False)

View file

@ -6,14 +6,17 @@ 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)
p1 = subprocess.Popen(['ruby', '-v'], stdout=subprocess.PIPE)
p2 = subprocess.Popen(['sed', "s/ (.*//"], stdin=p1.stdout, stdout=subprocess.PIPE)
ruby_and_gemset = p2.communicate()[0].decode('utf-8').rstrip()
gem_set = os.environ.get('GEM_HOME', '@').split('@')
if len(gem_set) > 1:
ruby_and_gemset += "@{}".format(gem_set.pop())
powerline.append(ruby_and_gemset, 15, 1)
except OSError:
return

View file

@ -0,0 +1,17 @@
import subprocess
from ..utils import ThreadedSegment
class Segment(ThreadedSegment):
def run(self):
cmd = self.segment_def["command"]
self.output = subprocess.check_output(cmd).decode("utf-8").strip()
# TODO handle OSError
# TODO handle no command defined or malformed
def add_to_powerline(self):
self.join()
self.powerline.append(
" %s " % self.output,
self.segment_def.get("fg_color", self.powerline.theme.PATH_FG),
self.segment_def.get("bg_color", self.powerline.theme.PATH_BG))

View file

@ -1,41 +1,57 @@
import subprocess
from ..utils import ThreadedSegment, RepoStats
from ..utils import ThreadedSegment, RepoStats, get_subprocess_env
def _get_svn_revision():
p = subprocess.Popen(["svn", "info", "--xml"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env=get_subprocess_env())
for line in p.communicate()[0].decode("utf-8").splitlines():
if "revision" in line:
revision = line.split("=")[1].split('"')[1]
break
return revision
def parse_svn_stats(status):
stats = RepoStats()
for line in status:
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
return stats
def _get_svn_status(output):
"""This function exists to enable mocking the `svn status` output in tests.
"""
return output[0].decode("utf-8").splitlines()
def build_stats():
try:
p = subprocess.Popen(['svn', 'status'],
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
env=get_subprocess_env())
except OSError:
# Popen will throw an OSError if svn is not found
return None, None
pdata = p.communicate()
if p.returncode != 0 or pdata[1][:22] == b'svn: warning: W155007:':
return None, None
status = _get_svn_status(pdata)
stats = parse_svn_stats(status)
revision = _get_svn_revision()
return stats, revision
class Segment(ThreadedSegment):
def __init__(self, powerline):
super(Segment, self).__init__(powerline)
self.stats = None
self.revision = ""
def run(self):
try:
svn_status = subprocess.Popen(["svn", "status"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
svn_info = subprocess.Popen(["svn", "info"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
svn_stdout, svn_stderr = svn_status.communicate()
svn_info, _ = svn_info.communicate()
except OSError:
return
if len(svn_stderr.decode("utf-8").strip()) != 0:
return
self.stats = RepoStats()
for line in svn_stdout.splitlines():
line = line.decode("utf-8").strip()
if line[0] == "?":
self.stats.new += 1
elif line[0] == "C":
self.stats.conflicted += 1
elif line[0] in ["A", "D", "I", "M", "R", "!", "~"]:
self.stats.changed += 1
for line in svn_info.splitlines():
line = line.decode("utf-8").strip()
if "Revision: " in line:
self.revision = line.split(" ", 1)[1]
self.stats, self.revision = build_stats()
def add_to_powerline(self):
self.join()
@ -46,6 +62,9 @@ class Segment(ThreadedSegment):
if self.stats.dirty:
bg = self.powerline.theme.REPO_DIRTY_BG
fg = self.powerline.theme.REPO_DIRTY_FG
self.powerline.append(" rev " + self.revision + " ", fg, bg)
if self.powerline.segment_conf("vcs", "show_symbol"):
symbol = " " + RepoStats().symbols["svn"]
else:
symbol = ""
self.powerline.append(symbol + " rev " + self.revision + " ", fg, bg)
self.stats.add_to_powerline(self.powerline)

View file

@ -6,12 +6,15 @@ import time
class Segment(BasicSegment):
def add_to_powerline(self):
powerline = self.powerline
if powerline.args.shell == 'bash':
format = powerline.segment_conf('time', 'format')
if format:
time_ = ' %s ' % time.strftime(format)
elif 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)
powerline.theme.TIME_FG,
powerline.theme.TIME_BG)

View file

@ -1,13 +1,13 @@
import subprocess
import re
from ..utils import BasicSegment
from ..utils import BasicSegment, decode
class Segment(BasicSegment):
def add_to_powerline(self):
powerline = self.powerline
try:
output = subprocess.check_output(['uptime'], stderr=subprocess.STDOUT).decode("utf-8")
output = decode(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)

View file

@ -7,6 +7,9 @@ class Segment(BasicSegment):
env = os.getenv('VIRTUAL_ENV') \
or os.getenv('CONDA_ENV_PATH') \
or os.getenv('CONDA_DEFAULT_ENV')
if os.getenv('VIRTUAL_ENV') \
and os.path.basename(env) == '.venv':
env = os.path.basename(os.path.dirname(env))
if not env:
return
env_name = os.path.basename(env)

View file

@ -1,4 +1,4 @@
from .default import DefaultColor
from powerline_shell.themes.default import DefaultColor
class Color(DefaultColor):
@ -40,3 +40,6 @@ class Color(DefaultColor):
AWS_PROFILE_FG = 14
AWS_PROFILE_BG = 8
TIME_FG = 8
TIME_BG = 7

View file

@ -58,6 +58,9 @@ class DefaultColor(object):
GIT_CONFLICTED_BG = 9
GIT_CONFLICTED_FG = 15
GIT_STASH_BG = 221
GIT_STASH_FG = 0
VIRTUAL_ENV_BG = 35 # a mid-tone green
VIRTUAL_ENV_FG = 00
@ -69,6 +72,10 @@ class DefaultColor(object):
AWS_PROFILE_FG = 39
AWS_PROFILE_BG = 238
TIME_FG = 250
TIME_BG = 238
class Color(DefaultColor):
"""
This subclass is required when the user chooses to use 'default' theme.

View file

@ -0,0 +1,111 @@
from powerline_shell.themes.default import DefaultColor
"""
absolute colors based on
https://github.com/morhetz/gruvbox/blob/master/colors/gruvbox.vim
"""
dark0 = 235
dark1 = 237
dark2 = 239
dark3 = 241
dark4 = 243
light0 = 229
light1 = 223
light2 = 250
light3 = 248
light4 = 246
dark_gray = 245
light_gray = 244
neutral_red = 124
neutral_green = 106
neutral_yellow = 172
neutral_blue = 66
neutral_purple = 132
neutral_aqua = 72
neutral_orange = 166
bright_red = 167
bright_green = 142
bright_yellow = 214
bright_blue = 109
bright_purple = 175
bright_aqua = 108
bright_orange = 208
faded_red = 88
faded_green = 100
faded_yellow = 136
faded_blue = 24
faded_purple = 96
faded_aqua = 66
faded_orange = 130
class Color(DefaultColor):
USERNAME_ROOT_BG = faded_red
USERNAME_BG = dark2
USERNAME_FG = bright_purple
HOSTNAME_BG = dark1
HOSTNAME_FG = bright_purple
HOME_SPECIAL_DISPLAY = True
HOME_BG = neutral_blue
HOME_FG = light2
PATH_BG = dark3
PATH_FG = light3
CWD_FG = light2
SEPARATOR_FG = dark_gray
READONLY_BG = bright_red
READONLY_FG = light0
SSH_BG = faded_purple
SSH_FG = light0
REPO_CLEAN_BG = faded_green
REPO_CLEAN_FG = dark1
REPO_DIRTY_BG = faded_orange
REPO_DIRTY_FG = light0
JOBS_FG = neutral_aqua
JOBS_BG = dark1
CMD_PASSED_FG = light4
CMD_PASSED_BG = dark1
CMD_FAILED_FG = light0
CMD_FAILED_BG = neutral_red
SVN_CHANGES_FG = REPO_DIRTY_FG
SVN_CHANGES_BG = REPO_DIRTY_BG
GIT_AHEAD_BG = dark2
GIT_AHEAD_FG = light3
GIT_BEHIND_BG = dark2
GIT_BEHIND_FG = light3
GIT_STAGED_BG = neutral_green
GIT_STAGED_FG = light0
GIT_NOTSTAGED_BG = neutral_orange
GIT_NOTSTAGED_FG = light0
GIT_UNTRACKED_BG = faded_red
GIT_UNTRACKED_FG = light0
GIT_CONFLICTED_BG = neutral_red
GIT_CONFLICTED_FG = light0
GIT_STASH_BG = neutral_yellow
GIT_STASH_FG = dark0
VIRTUAL_ENV_BG = faded_green
VIRTUAL_ENV_FG = light0
BATTERY_NORMAL_BG = neutral_green
BATTERY_NORMAL_FG = dark2
BATTERY_LOW_BG = neutral_red
BATTERY_LOW_FG = light1
AWS_PROFILE_FG = neutral_aqua
AWS_PROFILE_BG = dark1
TIME_FG = light2
TIME_BG = dark4

View file

@ -0,0 +1,89 @@
from powerline_shell.themes.default import DefaultColor
"""
colors from https://www.nordtheme.com/docs/colors-and-palettes
"""
night0 = 236 # nord0
night1 = 237 # nord1
night2 = 238 # nord2
night3 = 239 # nord3
snow0 = 253 # nord4
snow1 = 254 # nord5
snow2 = 255 # nord6
frost0 = 109 # nord7
frost1 = 111 # nord8
frost2 = 110 # nord9
frost3 = 68 # nord10
red = 167 # nord11
orange = 173 # nord12
yellow = 179 # nord13
green = 150 # nord14
purple = 139 # nord15
class Color(DefaultColor):
USERNAME_BG = night3
USERNAME_FG = snow0
HOSTNAME_FG = snow0
HOSTNAME_BG = night0
HOME_BG = frost2
HOME_FG = snow2
PATH_BG = night0
PATH_FG = snow0
CWD_FG = snow0
SEPARATOR_FG = night3
READONLY_BG = red
READONLY_FG = snow2
SSH_BG = orange
SSH_FG = snow2
REPO_CLEAN_BG = green
REPO_CLEAN_FG = night1
REPO_DIRTY_BG = red
REPO_DIRTY_FG = snow2
JOBS_FG = frost3
JOBS_BG = night0
CMD_PASSED_BG = night0
CMD_PASSED_FG = snow2
CMD_FAILED_BG = yellow
CMD_FAILED_FG = snow2
SVN_CHANGES_BG = REPO_DIRTY_FG
SVN_CHANGES_FG = REPO_DIRTY_BG
GIT_AHEAD_BG = night3
GIT_AHEAD_FG = snow0
GIT_BEHIND_BG = night3
GIT_BEHIND_FG = snow0
GIT_STAGED_BG = frost0
GIT_STAGED_FG = night1
GIT_NOTSTAGED_BG = orange
GIT_NOTSTAGED_FG = snow2
GIT_UNTRACKED_BG = purple
GIT_UNTRACKED_FG = snow2
GIT_CONFLICTED_BG = red
GIT_CONFLICTED_FG = snow2
GIT_STASH_BG = yellow
GIT_STASH_FG = night1
VIRTUAL_ENV_BG = green
VIRTUAL_ENV_FG = night1
BATTERY_NORMAL_BG = green
BATTERY_NORMAL_FG = night1
BATTERY_LOW_BG = red
BATTERY_LOW_FG = snow2
AWS_PROFILE_FG = frost3
AWS_PROFILE_BG = night0
TIME_BG = night3
TIME_FG = snow0

View file

@ -1,4 +1,4 @@
from .default import DefaultColor
from powerline_shell.themes.default import DefaultColor
class Color(DefaultColor):
@ -39,3 +39,6 @@ class Color(DefaultColor):
AWS_PROFILE_FG = 7
AWS_PROFILE_BG = 2
TIME_FG = 15
TIME_BG = 10

View file

@ -1,4 +1,4 @@
from .default import DefaultColor
from powerline_shell.themes.default import DefaultColor
class Color(DefaultColor):
@ -36,3 +36,6 @@ class Color(DefaultColor):
VIRTUAL_ENV_BG = 15
VIRTUAL_ENV_FG = 2
TIME_FG = 15
TIME_BG = 10

View file

@ -1,4 +1,4 @@
from .default import DefaultColor
from powerline_shell.themes.default import DefaultColor
class Color(DefaultColor):
@ -39,3 +39,6 @@ class Color(DefaultColor):
AWS_PROFILE_FG = 0
AWS_PROFILE_BG = 7
TIME_FG = 8
TIME_BG = 7

View file

@ -1,11 +1,17 @@
import sys
import os
import threading
py3 = sys.version_info[0] == 3
if py3:
def unicode(x):
def unicode_(x):
return str(x)
def decode(x):
return x.decode("utf-8")
else:
unicode_ = unicode
decode = unicode
class RepoStats(object):
@ -16,7 +22,13 @@ class RepoStats(object):
'staged': u'\u2714',
'changed': u'\u270E',
'new': u'?',
'conflicted': u'\u273C'
'conflicted': u'\u273C',
'stash': u'\u2398',
'git': u'\uE0A0',
'hg': u'\u263F',
'bzr': u'\u2B61\u20DF',
'fossil': u'\u2332',
'svn': u'\u2446'
}
def __init__(self, ahead=0, behind=0, new=0, changed=0, staged=0, conflicted=0):
@ -61,7 +73,7 @@ class RepoStats(object):
segment = repo_stats.n_or_empty("new") + icon_string
"""
return unicode(self[_key]) if int(self[_key]) > 1 else u''
return unicode_(self[_key]) if int(self[_key]) > 1 else u''
def add_to_powerline(self, powerline):
def add(_key, fg, bg):
@ -82,14 +94,59 @@ def warn(msg):
class BasicSegment(object):
def __init__(self, powerline):
def __init__(self, powerline, segment_def):
self.powerline = powerline
self.segment_def = segment_def # type: dict
def start(self):
pass
class ThreadedSegment(threading.Thread):
def __init__(self, powerline):
def __init__(self, powerline, segment_def):
super(ThreadedSegment, self).__init__()
self.powerline = powerline
self.segment_def = segment_def # type: dict
def import_file(module_name, path):
# An implementation of https://stackoverflow.com/a/67692/683436
if py3 and sys.version_info[1] >= 5:
import importlib.util
spec = importlib.util.spec_from_file_location(module_name, path)
if not spec:
raise ImportError()
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
return mod
elif py3:
from importlib.machinery import SourceFileLoader
return SourceFileLoader(module_name, path).load_module()
else:
import imp
return imp.load_source(module_name, path)
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 get_subprocess_env(**envs):
defaults = {
# https://github.com/milkbikis/powerline-shell/pull/153
"PATH": get_PATH(),
}
defaults.update(envs)
env = dict(os.environ)
env.update(defaults)
return env
def get_git_subprocess_env():
# LANG is specified to ensure git always uses a language we are expecting.
# Otherwise we may be unable to parse the output.
return get_subprocess_env(LANG="C")

View file

@ -1,3 +1,4 @@
nose>=1.3.7
mock>=1.3.0
sh>=1.11
parameterized>=0.6.1

View file

@ -3,11 +3,20 @@ from setuptools import setup, find_packages
setup(
name="powerline-shell",
version="0.4.6",
version="0.7.0",
description="A pretty prompt for your shell",
author="Buck Ryan",
url="https://github.com/banga/powerline-shell",
classifiers=[],
author_email="buck@buckryan.com",
license="MIT",
url="https://github.com/b-ryan/powerline-shell",
classifiers=[
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
],
packages=[
"powerline_shell",
"powerline_shell.segments",

View file

@ -1,4 +1,6 @@
#!/bin/sh
set -eu
docker build -t powerline-shell .
docker run --rm -it powerline-shell -c nosetests
docker run --rm --interactive --tty \
--volume $PWD:/code \
powerline-shell "$@"

0
test/__init__.py Normal file
View file

View file

@ -0,0 +1,49 @@
import unittest
from parameterized import parameterized
from powerline_shell.color_compliment import getOppositeColor
def build_inputs():
# Build 768 hex/rgb values to test against getOppositeColor
input_bytes = map(hex, xrange(pow(2,8)))
input_list = []
for x in input_bytes:
#Building hex range of [00-ff]:00:00
combined1 = hex((int(x,16)<<16)| ((int(input_bytes[0],16)<<8)|int(input_bytes[0],16)))
test_input1 = tuple((int(x,16), int(input_bytes[0],16), int(input_bytes[0],16)))
#Building hex range of 00:[00-ff]:00
combined2 = hex((int(input_bytes[0],16)<<16)| ((int(x,16)<<8)|int(input_bytes[0],16)))
test_input2 = tuple((int(input_bytes[0],16), int(x,16), int(input_bytes[0],16)))
#Building hex range of 00:00:[00-ff]
combined3 = hex((int(input_bytes[0],16)<<16)| ((int(input_bytes[0],16)<<8)|int(x,16)))
test_input3 = tuple((int(input_bytes[0],16), int(input_bytes[0],16), int(x,16)))
input_list.append(tuple((combined1, test_input1)))
input_list.append(tuple((combined2, test_input2)))
input_list.append(tuple((combined3, test_input3)))
return input_list
class getOppositeColorTestCase(unittest.TestCase):
'''
Test only runs against 768 combinations of rgb values.
Trying to run parameterized unittest against 16.77M rgb values
was near impossible (need lots of memory and time). Of the 768
values tested, the test has proven to catch 192 exceptions (and 3
ZeroDivisionError exceptions from rgb_to_hls). This can be tested
by commenting out the first line of getOppositeColor, which
converts the rgb values to float.
'''
@parameterized.expand(build_inputs)
def test_rgb_input_get_opposite_not_negative(self, name, test_input):
negative = -1
self.assertNotIn(negative, getOppositeColor(*test_input), u'{0:#08x} returns negative number in rgb tuple'.format(int(name,16)))

View file

View file

@ -5,6 +5,7 @@ import shutil
import sh
import powerline_shell.segments.bzr as bzr
from powerline_shell.utils import RepoStats
from ..testing_utils import dict_side_effect_fn
test_cases = (
@ -22,6 +23,9 @@ class BzrTest(unittest.TestCase):
def setUp(self):
self.powerline = mock.MagicMock()
self.powerline.segment_conf.side_effect = dict_side_effect_fn({
("vcs", "show_symbol"): False,
})
self.dirname = tempfile.mkdtemp()
sh.cd(self.dirname)
@ -30,7 +34,7 @@ class BzrTest(unittest.TestCase):
sh.cd("trunk")
sh.bzr("init")
self.segment = bzr.Segment(self.powerline)
self.segment = bzr.Segment(self.powerline, {})
def tearDown(self):
shutil.rmtree(self.dirname)
@ -45,7 +49,7 @@ class BzrTest(unittest.TestCase):
sh.bzr("branch", "trunk", branch)
sh.cd(branch)
@mock.patch("powerline_shell.segments.bzr.get_PATH")
@mock.patch("powerline_shell.utils.get_PATH")
def test_bzr_not_installed(self, get_PATH):
get_PATH.return_value = "" # so bzr can't be found
self.segment.start()

View file

@ -5,6 +5,7 @@ import shutil
import sh
import powerline_shell.segments.fossil as fossil
from powerline_shell.utils import RepoStats
from ..testing_utils import dict_side_effect_fn
test_cases = {
"EXTRA new-file": RepoStats(new=1),
@ -18,13 +19,16 @@ class FossilTest(unittest.TestCase):
def setUp(self):
self.powerline = mock.MagicMock()
self.powerline.segment_conf.side_effect = dict_side_effect_fn({
("vcs", "show_symbol"): False,
})
self.dirname = tempfile.mkdtemp()
sh.cd(self.dirname)
sh.fossil("init", "test.fossil")
sh.fossil("open", "test.fossil")
self.segment = fossil.Segment(self.powerline)
self.segment = fossil.Segment(self.powerline, {})
def tearDown(self):
shutil.rmtree(self.dirname)
@ -38,7 +42,7 @@ class FossilTest(unittest.TestCase):
sh.fossil("branch", "new", branch, "trunk")
sh.fossil("checkout", branch)
@mock.patch("powerline_shell.segments.fossil.get_PATH")
@mock.patch("powerline_shell.utils.get_PATH")
def test_fossil_not_installed(self, get_PATH):
get_PATH.return_value = "" # so fossil can't be found
self.segment.start()

View file

@ -0,0 +1,77 @@
import unittest
import mock
import tempfile
import shutil
import sh
import powerline_shell.segments.git_stash as git_stash
from powerline_shell.utils import RepoStats
class GitStashTest(unittest.TestCase):
def setUp(self):
self.powerline = mock.MagicMock()
self.dirname = tempfile.mkdtemp()
sh.cd(self.dirname)
sh.git("init", ".")
self.segment = git_stash.Segment(self.powerline, {})
def tearDown(self):
shutil.rmtree(self.dirname)
def _add_and_commit(self, filename):
sh.touch(filename)
sh.git("add", filename)
sh.git("commit", "-m", "add file " + filename)
def _overwrite_file(self, filename, content):
sh.echo(content, _out=filename)
def _stash(self):
sh.git("stash")
@mock.patch('powerline_shell.utils.get_PATH')
def test_git_not_installed(self, get_PATH):
get_PATH.return_value = "" # so git can't be found
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")
self.segment.start()
self.segment.add_to_powerline()
self.assertEqual(self.powerline.append.call_count, 0)
def test_no_stashes(self):
self._add_and_commit("foo")
self.segment.start()
self.segment.add_to_powerline()
self.assertEqual(self.powerline.append.call_count, 0)
def test_one_stash(self):
self._add_and_commit("foo")
self._overwrite_file("foo", "some new content")
self._stash()
self.segment.start()
self.segment.add_to_powerline()
expected = u' {} '.format(RepoStats.symbols["stash"])
self.assertEqual(self.powerline.append.call_args[0][0], expected)
def test_multiple_stashes(self):
self._add_and_commit("foo")
self._overwrite_file("foo", "some new content")
self._stash()
self._overwrite_file("foo", "some different content")
self._stash()
self._overwrite_file("foo", "more different content")
self._stash()
self.segment.start()
self.segment.add_to_powerline()
expected = u' 3{} '.format(RepoStats.symbols["stash"])
self.assertEqual(self.powerline.append.call_args[0][0], expected)

View file

@ -4,18 +4,22 @@ import tempfile
import shutil
import sh
import powerline_shell.segments.git as git
from ..testing_utils import dict_side_effect_fn
class GitTest(unittest.TestCase):
def setUp(self):
self.powerline = mock.MagicMock()
self.powerline.segment_conf.side_effect = dict_side_effect_fn({
("vcs", "show_symbol"): False,
})
self.dirname = tempfile.mkdtemp()
sh.cd(self.dirname)
sh.git("init", ".")
self.segment = git.Segment(self.powerline)
self.segment = git.Segment(self.powerline, {})
def tearDown(self):
shutil.rmtree(self.dirname)
@ -31,7 +35,7 @@ class GitTest(unittest.TestCase):
def _get_commit_hash(self):
return sh.git("rev-parse", "HEAD")
@mock.patch('powerline_shell.segments.git.get_PATH')
@mock.patch('powerline_shell.utils.get_PATH')
def test_git_not_installed(self, get_PATH):
get_PATH.return_value = "" # so git can't be found
self.segment.start()

View file

@ -5,6 +5,7 @@ import shutil
import sh
import powerline_shell.segments.hg as hg
from powerline_shell.utils import RepoStats
from ..testing_utils import dict_side_effect_fn
test_cases = {
@ -20,12 +21,15 @@ class HgTest(unittest.TestCase):
def setUp(self):
self.powerline = mock.MagicMock()
self.powerline.segment_conf.side_effect = dict_side_effect_fn({
("vcs", "show_symbol"): False,
})
self.dirname = tempfile.mkdtemp()
sh.cd(self.dirname)
sh.hg("init", ".")
self.segment = hg.Segment(self.powerline)
self.segment = hg.Segment(self.powerline, {})
def tearDown(self):
shutil.rmtree(self.dirname)
@ -38,7 +42,7 @@ class HgTest(unittest.TestCase):
def _checkout_new_branch(self, branch):
sh.hg("branch", branch)
@mock.patch("powerline_shell.segments.hg.get_PATH")
@mock.patch("powerline_shell.utils.get_PATH")
def test_hg_not_installed(self, get_PATH):
get_PATH.return_value = "" # so hg can"t be found
self.segment.start()

View file

@ -9,7 +9,7 @@ class HostnameTest(unittest.TestCase):
def setUp(self):
self.powerline = mock.MagicMock()
self.powerline.theme = Color
self.segment = hostname.Segment(self.powerline)
self.segment = hostname.Segment(self.powerline, {})
def test_colorize(self):
self.powerline.segment_conf.return_value = True

View file

@ -0,0 +1,32 @@
import tempfile
import unittest
import shutil
import mock
import sh
import powerline_shell.segments.svn as svn
from ..testing_utils import dict_side_effect_fn
class SvnTest(unittest.TestCase):
def setUp(self):
self.powerline = mock.MagicMock()
self.powerline.segment_conf.side_effect = dict_side_effect_fn({
("vcs", "show_symbol"): False,
})
self.dirname = tempfile.mkdtemp()
sh.cd(self.dirname)
# sh.svn("init", ".")
self.segment = svn.Segment(self.powerline, {})
def tearDown(self):
shutil.rmtree(self.dirname)
@mock.patch("powerline_shell.utils.get_PATH")
def test_svn_not_installed(self, get_PATH):
get_PATH.return_value = "" # so svn can't be found
self.segment.start()
self.segment.add_to_powerline()
self.assertEqual(self.powerline.append.call_count, 0)

View file

@ -19,7 +19,7 @@ class UptimeTest(unittest.TestCase):
def setUp(self):
self.powerline = mock.MagicMock()
self.segment = uptime.Segment(self.powerline)
self.segment = uptime.Segment(self.powerline, {})
@mock.patch('subprocess.check_output')
def test_all(self, check_output):

4
test/testing_utils.py Normal file
View file

@ -0,0 +1,4 @@
def dict_side_effect_fn(dict_):
def func(*args):
return dict_[args]
return func