Powerline-shell
Posted on Fri 14 August 2020 in Shell
Update 13/nov/2021 After spending a few minutes reading the docs, I realize you can override the default segments without modifying the existing ones. Check my segments for an example. I give more details at the end of this post (Better customization section).
A few days ago, I found this gem in Github: Powerline-shell. This application is written in Python. Powerline-shell allows you to customize your prompt by adding several pieces of information (called segments), like:
- Name of the virtual environment
- Git status
- User name and host name
- Current working directory
- etc.
It is similar to Powerline, other application for the same purpose. Although, I find Powerline-shell so much easier to customize. This post explains how to install poweline-shell
and customize your shell so that it will look like this:
After configuring powerline-shell
, your prompt will look like this:
master 2⬆ 1✔ 7✎ 4? [dev] auraham@rocket ~/git/repo $
This means that:
- We are in the
master
branch. - There are 2 pending commits.
On branch master
Your branch is ahead of 'origin/master' by 2 commits.
(use "git push" to publish your local commits)
- There is 1 staged file (i.e., one file ready to be committed):
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: sample
- There are 7 modified files (i.e., changes not staged for commit):
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: git_commands.md
modified: learninggit.md
modified: ../themes/Flex-minimal/templates/author.html
modified: ../themes/Flex-minimal/templates/categories.html
modified: ../themes/Flex-minimal/templates/category.html
modified: ../themes/Flex-minimal/templates/tag.html
modified: ../themes/Flex-minimal/templates/tags.html
- There are 4 untracked files:
Untracked files:
(use "git add <file>..." to include in what will be committed)
build_model_v1.ipynb
build_model_v1.nbdata
ml_notes.md
pages/index_prev.md
Installation
First, install powerline-shell
and its dependencies as follows:
sudo apt-get install fonts-powerline
pip3 install powerline-shell
Then, add the following to your .bashrc
file:
function _update_ps1() {
PS1=$(powerline-shell $?)
}
if [[ $TERM != linux && ! $PROMPT_COMMAND =~ _update_ps1 ]]; then
PROMPT_COMMAND="_update_ps1; $PROMPT_COMMAND"
fi
If you use other shell (fish
, zsh
, tcsh
), please check the documentation.
Customization
Initialize the configuration files as follows:
mkdir -p ~/.config/powerline-shell && \
powerline-shell --generate-config > ~/.config/powerline-shell/config.json
config.json
specifies the segments and the theme. This is my current setup:
{
"theme": "/home/auraham/.config/powerline-shell/themes/rocket.py", # custom theme
"mode": "flat", # do not use unicode characters
"segments": [
"git",
"virtual_env",
"username",
"hostname",
"ssh",
"cwd",
"hg",
"jobs",
"root"
],
"cwd": {
"full_cwd": true, # shows full path
"max_depth": 10, # how many dirs to show before using "..."
"mode": "plain" # do not split the path into individual segments
}
}
The "segments"
option determines the segments that will be in your shell and their corresponding position. For instance, I prefer to put "git"
before anything else. Otherwise, the git segment would change as I move among directories with cd
. By default, powerline-shell
uses a Unicode character like ">"
at the end of each segment. Personally, I do not like that symbol. To change this, you can use the "mode": "flat"
option. Then, I define the theme using the "theme"
option (my theme is shown below). Finally, I changed the way the current working directory is displayed. Here, "full_cwd"
shows the full path. Also, "mode": "plain"
allows us to show the path as a single string, otherwise, the path will be divided into individual segments. Finally, "max_depth": 10
indicates the number of directories to show in the prompt before using "..."
to shorten it.
~/Desktop $ mkdir -p a/b/c/d/f/g/h/i/j/k/l/m
~/Desktop $ cd a/b/c/d/f/g/h/i/j/k/l/m/
~/Desktop/…/f/g/h/i/j/k/l/m $
The themes are located in ~/.config/powerline-shell/themes
. This is my custom theme called rocket.py
:
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
# change
USERNAME_FG = 162
USERNAME_BG = 232
USERNAME_ROOT_BG = 124
HOSTNAME_FG = 250
HOSTNAME_BG = 238
# change
HOSTNAME_FG = 39
HOSTNAME_BG = 232
HOME_SPECIAL_DISPLAY = True
HOME_BG = 31 # blueish
HOME_FG = 15 # white
PATH_BG = 232
PATH_FG = 250
CWD_FG = 67
SEPARATOR_FG = 244
READONLY_BG = 124
READONLY_FG = 254
SSH_BG = 166 # medium orange
SSH_FG = 254
REPO_CLEAN_BG = 35
REPO_CLEAN_FG = 0
REPO_DIRTY_BG = 88
REPO_DIRTY_FG = 15
# change
REPO_CLEAN_BG = 232
REPO_CLEAN_FG = 35
REPO_DIRTY_BG = 232
REPO_DIRTY_FG = 162
JOBS_FG = 39
JOBS_BG = 238
CMD_PASSED_BG = 232
CMD_PASSED_FG = 245
CMD_FAILED_BG = 161
CMD_FAILED_FG = 197
CMD_FAILED_BG = 232
SVN_CHANGES_BG = 148
SVN_CHANGES_FG = 22
GIT_AHEAD_BG = 240
GIT_AHEAD_FG = 250
GIT_BEHIND_BG = 240
GIT_BEHIND_FG = 250
GIT_STAGED_BG = 2
GIT_STAGED_FG = 15
GIT_NOTSTAGED_BG = 4
GIT_NOTSTAGED_FG = 15
GIT_UNTRACKED_BG = 52
GIT_UNTRACKED_FG = 15
GIT_CONFLICTED_BG = 9
GIT_CONFLICTED_FG = 15
# change
GIT_NOTSTAGED_BG = 232
GIT_NOTSTAGED_FG = 30
# change
GIT_AHEAD_BG = 232
GIT_AHEAD_FG = 61
# change
GIT_UNTRACKED_BG = 232
GIT_UNTRACKED_FG = 244
# change
GIT_STAGED_BG = 232
GIT_STAGED_FG = 2
GIT_STASH_BG = 221
GIT_STASH_FG = 0
VIRTUAL_ENV_BG = 35
VIRTUAL_ENV_FG = 00
# change
VIRTUAL_ENV_BG = 232
VIRTUAL_ENV_FG = 35
BATTERY_NORMAL_BG = 22
BATTERY_NORMAL_FG = 7
BATTERY_LOW_BG = 196
BATTERY_LOW_FG = 7
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.
Because the segments require a 'Color' class for every theme.
"""
pass
As it can be seen, it is just a Python class with a bunch of variables that define the color of each segment. The colors must be specified using Xterm-256 color codes.
Additional changes
Many of the segments use an empty space as separator. However, I decided to remove them. To do so, you must edit the Python scripts. You can get the location of these scripts using:
pip3 show powerline-shell
Location: /home/auraham/.virtualenvs/dev/lib/python3.5/site-packages
Thus, the scripts that define the segments are here:
/home/auraham/.virtualenvs/dev/lib/python3.5/site-packages/powerline_shell/segments
Below, you will find the scripts and the changes made on each file:
segments/jobs.py:29: self.powerline.append('%d ' % self.num_jobs, # change
segments/virtual_env.py:18: self.powerline.append(" [" + env_name + "] ", fg, bg) # change
segments/hostname.py:18: host_prompt = r"@\h" # change
segments/git.py:83: self.powerline.append("" + symbol + self.branch + "", fg, bg) # change
segments/root.py:8: 'bash': '\\$', # change
segments/username.py:10: user_prompt = r"\u" # change
utils.py:76: return unicode_(self[_key]) if int(self[_key]) >= 1 else u'' # change
utils.py:81: s = u" {}{}".format(self.n_or_empty(_key), self.symbols[_key]) # change
Better customization
In the previous section we took the long and error-prone way for customizing the segments. The documentation explains we can define our own segments. In the following, we explain how to create a custom segment.
Let's copy root.py
from this path
$ cp /home/auraham/.virtualenvs/dev/lib/python3.5/site-packages/powerline_shell/segments/root.py ~/git/segments
We need to update the relative path for importing packages. For example, we need to change this line:
from ..utils import BasicSegment
as follows:
from powerlinr_shell.utils import BasicSegment
Next, we can customize the segment. In my setup, I like to use >
instead of $
. We can specify that marker as follows:
class Segment(BasicSegment):
def add_to_powerline(self):
powerline = self.powerline
root_indicators = {
'bash': '>', # '\\$',
'tcsh': ' %# ',
'zsh': ' %# ',
'bare': ' $ ',
}
# ...
Now, we need to specify the location of our segments in the configuration. To do so, update ~/.config/powerline-shell/config.json
as shown below:
{
"theme": "~/git/segments/rocket.py",
"mode": "flat",
"segments": [
"~/git/segments/time.py",
"~/git/segments/git.py",
"~/git/segments/virtual_env.py",
"~/git/segments/username.py",
"~/git/segments/hostname.py",
"~/git/segments/ssh.py",
"~/git/segments/cwd.py",
"~/git/segments/hg.py",
"~/git/segments/jobs.py",
"~/git/segments/newline.py",
"~/git/segments/root.py"
],
"cwd": {
"full_cwd": true,
"max_depth": 10,
"mode": "plain"
},
"time": {
"format": "%H:%M:%S"
}
}
Notice that segments
contains paths. If you want to use the default root
, then include root
in segments
.
On the other hand, if you want to use your own implementation of root
, then provide its path.
A nice thing of this approach is that ~/git/segments
contains all our custom segments and our theme.