From 5aa4dced98b8fcf233ce82c70b419162c9946af8 Mon Sep 17 00:00:00 2001 From: Brian Enigma Date: Tue, 5 Feb 2013 09:59:01 -0800 Subject: [PATCH 001/366] svn externals shouldn't be considered modifications --- powerline-shell.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/powerline-shell.py b/powerline-shell.py index ca2f6bfd..1608ad09 100755 --- a/powerline-shell.py +++ b/powerline-shell.py @@ -238,7 +238,7 @@ def add_svn_segment(powerline, cwd): 'I' Ignored 'M' Modified 'R' Replaced - 'X' an unversioned directory created by an externals definition + 'X' a directory pulled in by an svn:externals definition '?' item is not under version control '!' item is missing (removed by non-svn command) or incomplete '~' versioned item obstructed by some item of a different kind @@ -248,7 +248,7 @@ def add_svn_segment(powerline, cwd): #cmd = '"svn status | grep -c "^[ACDIMRX\\!\\~]"' p1 = subprocess.Popen(['svn', 'status'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - p2 = subprocess.Popen(['grep', '-c', '^[ACDIMRX\\!\\~]'], + p2 = subprocess.Popen(['grep', '-c', '^[ACDIMR\\!\\~]'], stdin=p1.stdout, stdout=subprocess.PIPE) output = p2.communicate()[0].strip() if len(output) > 0 and int(output) > 0: From 225576b8fb287993901211b644539455a398f1d0 Mon Sep 17 00:00:00 2001 From: William Broach Date: Fri, 8 Feb 2013 22:21:29 -0500 Subject: [PATCH 002/366] Default python virtual env color is completley unreadbable --- powerline-shell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerline-shell.py b/powerline-shell.py index 1608ad09..0c99ed56 100755 --- a/powerline-shell.py +++ b/powerline-shell.py @@ -35,7 +35,7 @@ class Color: SVN_CHANGES_FG = 22 # dark green VIRTUAL_ENV_BG = 35 # a mid-tone green - VIRTUAL_ENV_FG = 22 + VIRTUAL_ENV_FG = 00 class Powerline: From c864aff95eae14633734ad35dc7b7e87bbf15da4 Mon Sep 17 00:00:00 2001 From: Shrey Banga Date: Sat, 9 Feb 2013 17:29:55 -0500 Subject: [PATCH 003/366] Use python instead of python2 --- powerline-shell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerline-shell.py b/powerline-shell.py index 0c99ed56..be0c5fe4 100755 --- a/powerline-shell.py +++ b/powerline-shell.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python # -*- coding: utf-8 -*- import os From 9b3cf0b5728a9dfc0c3f0b479b169859176eda01 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Wed, 20 Feb 2013 11:41:16 -0500 Subject: [PATCH 004/366] add a flat mode --- powerline-shell.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/powerline-shell.py b/powerline-shell.py index be0c5fe4..9aad34c6 100755 --- a/powerline-shell.py +++ b/powerline-shell.py @@ -47,7 +47,11 @@ class Powerline: 'patched': { 'separator': u'\u2B80', 'separator_thin': u'\u2B81' - } + }, + 'flat': { + 'separator': '', + 'separator_thin': '' + }, } color_templates = { From fe2bfacc683a7dff20eb5ee8c6f88f3e6b1a2d86 Mon Sep 17 00:00:00 2001 From: cd01 Date: Sun, 24 Mar 2013 21:54:45 +0900 Subject: [PATCH 005/366] Change directory separator --- powerline-shell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerline-shell.py b/powerline-shell.py index 9aad34c6..acbe900e 100755 --- a/powerline-shell.py +++ b/powerline-shell.py @@ -130,7 +130,7 @@ def add_cwd_segment(powerline, cwd, maxdepth, cwd_only=False): if cwd[0] == '/': cwd = cwd[1:] - names = cwd.split('/') + names = cwd.split(os.sep) if len(names) > maxdepth: names = names[:2] + [u'\u2026'] + names[2 - maxdepth:] From ad7d873fc64e474f10416998fcb92c13e0579733 Mon Sep 17 00:00:00 2001 From: Shrey Banga Date: Sat, 13 Apr 2013 19:14:16 -0400 Subject: [PATCH 006/366] Making user, host work in zsh --- powerline-shell.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/powerline-shell.py b/powerline-shell.py index be0c5fe4..c850e3f5 100755 --- a/powerline-shell.py +++ b/powerline-shell.py @@ -62,6 +62,16 @@ class Powerline: 'bare': ' $ ', } + user_prompt = { + 'bash': ' \\u', + 'zsh': ' %n' + } + + host_prompt = { + 'bash': ' \\h', + 'zsh': ' %m' + } + def __init__(self, mode, shell): self.shell = shell self.color_template = self.color_templates[shell] @@ -329,8 +339,8 @@ def get_valid_cwd(): p = Powerline(mode=args.mode, shell=args.shell) cwd = get_valid_cwd() add_virtual_env_segment(p, cwd) - #p.append(Segment(p, ' \\u ', 250, 240)) - #p.append(Segment(p, ' \\h ', 250, 238)) + #p.append(Segment(p, p.user_prompt[p.shell], 250, 240)) + #p.append(Segment(p, p.host_prompt[p.shell], 250, 238)) add_cwd_segment(p, cwd, 5, args.cwd_only) add_repo_segment(p, cwd) add_root_indicator(p, args.prev_error) From 6349420b427f04852edc124f481bf4d3ccb99b45 Mon Sep 17 00:00:00 2001 From: caetanus Date: Sun, 21 Apr 2013 10:57:20 -0300 Subject: [PATCH 007/366] added fossil segment and hostname segment --- powerline-shell.py | 62 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 5 deletions(-) diff --git a/powerline-shell.py b/powerline-shell.py index a57cb033..5a78078f 100755 --- a/powerline-shell.py +++ b/powerline-shell.py @@ -1,6 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +import socket import os import subprocess import sys @@ -119,6 +120,15 @@ def draw(self, next_segment=None): else: separator_bg = self.powerline.reset + try: + self.content = self.content.decode('utf-8') + except: + try: + self.content = self.content.decode('latin1') + except: + pass + + return ''.join(( self.powerline.fgcolor(self.fg), self.powerline.bgcolor(self.bg), @@ -127,8 +137,15 @@ def draw(self, next_segment=None): self.powerline.fgcolor(self.separator_fg), self.separator)) +def add_hostname_segment(powerline): + hostname = socket.gethostname() + user = os.getenv("USER") + #powerline.append(Segment(powerline, ' %s@%s ' % (user, hostname), Color.CWD_FG, Color.PATH_BG)) -def add_cwd_segment(powerline, cwd, maxdepth, cwd_only=False): + powerline.append(Segment(powerline, '⌂⁂ ', Color.CWD_FG, Color.PATH_BG)) + + +def add_cwd_segment(powerline, cwd, maxdepth, cwd_only = False): #powerline.append(' \\w ', 15, 237) home = os.getenv('HOME') cwd = cwd or os.getenv('PWD') @@ -169,6 +186,17 @@ def get_hg_status(): has_modified_files = True return has_modified_files, has_untracked_files, has_missing_files +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_hg_segment(powerline, cwd): branch = os.popen('hg branch 2> /dev/null').read().rstrip() @@ -189,6 +217,27 @@ def add_hg_segment(powerline, cwd): powerline.append(Segment(powerline, ' %s ' % branch, fg, bg)) return True +def add_fossil_segment(powerline, cwd): + 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 False + + 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(Segment(powerline, ' %s ' % branch, fg, bg)) + return True + def get_git_status(): has_pending_commits = True @@ -215,7 +264,7 @@ def get_git_status(): def add_git_segment(powerline, cwd): #cmd = "git branch 2> /dev/null | grep -e '\\*'" - p1 = subprocess.Popen(['git', 'branch'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + p1 = subprocess.Popen(['git', 'branch', '--no-color'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) p2 = subprocess.Popen(['grep', '-e', '\\*'], stdin=p1.stdout, stdout=subprocess.PIPE) output = p2.communicate()[0].strip() if not output: @@ -277,7 +326,7 @@ def add_svn_segment(powerline, cwd): def add_repo_segment(powerline, cwd): - for add_repo_segment in (add_git_segment, add_svn_segment, add_hg_segment): + for add_repo_segment in (add_git_segment, add_svn_segment, add_fossil_segment, add_hg_segment): try: if add_repo_segment(p, cwd): return @@ -342,9 +391,12 @@ def get_valid_cwd(): p = Powerline(mode=args.mode, shell=args.shell) cwd = get_valid_cwd() + add_hostname_segment(p) + add_virtual_env_segment(p, cwd) - #p.append(Segment(p, p.user_prompt[p.shell], 250, 240)) - #p.append(Segment(p, p.host_prompt[p.shell], 250, 238)) + #p.append(Segment(powerline, ' \\u ', 250, 240)) + #p.append(Segment(powerline, ' \\h ', 250, 238)) + add_cwd_segment(p, cwd, 5, args.cwd_only) add_repo_segment(p, cwd) add_root_indicator(p, args.prev_error) From cac5ba85c21f9bb681f7b4eb55239f45dc403635 Mon Sep 17 00:00:00 2001 From: caetanus Date: Sun, 21 Apr 2013 10:59:27 -0300 Subject: [PATCH 008/366] removed local information --- powerline-shell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerline-shell.py b/powerline-shell.py index 5a78078f..a5afe29a 100755 --- a/powerline-shell.py +++ b/powerline-shell.py @@ -142,7 +142,7 @@ def add_hostname_segment(powerline): user = os.getenv("USER") #powerline.append(Segment(powerline, ' %s@%s ' % (user, hostname), Color.CWD_FG, Color.PATH_BG)) - powerline.append(Segment(powerline, '⌂⁂ ', Color.CWD_FG, Color.PATH_BG)) + powerline.append(Segment(powerline, Color.CWD_FG, Color.PATH_BG)) def add_cwd_segment(powerline, cwd, maxdepth, cwd_only = False): From b0e83c2692cfc36f3034c33d5564cd2af1ce542b Mon Sep 17 00:00:00 2001 From: caetanus Date: Mon, 29 Apr 2013 17:43:20 -0300 Subject: [PATCH 009/366] fixed somethings, added LC_MESSAGES to git to work on newer ubuntus. --- powerline-shell.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/powerline-shell.py b/powerline-shell.py index a5afe29a..aca5db96 100755 --- a/powerline-shell.py +++ b/powerline-shell.py @@ -140,12 +140,10 @@ def draw(self, next_segment=None): def add_hostname_segment(powerline): hostname = socket.gethostname() user = os.getenv("USER") - #powerline.append(Segment(powerline, ' %s@%s ' % (user, hostname), Color.CWD_FG, Color.PATH_BG)) + powerline.append(Segment(powerline, ' %s@%s ' % (user, hostname), Color.CWD_FG, Color.PATH_BG)) - powerline.append(Segment(powerline, Color.CWD_FG, Color.PATH_BG)) - -def add_cwd_segment(powerline, cwd, maxdepth, cwd_only = False): +def add_cwd_segment(powerline, cwd, maxdepth, cwd_only=False): #powerline.append(' \\w ', 15, 237) home = os.getenv('HOME') cwd = cwd or os.getenv('PWD') @@ -326,7 +324,8 @@ def add_svn_segment(powerline, cwd): def add_repo_segment(powerline, cwd): - for add_repo_segment in (add_git_segment, add_svn_segment, add_fossil_segment, add_hg_segment): + for add_repo_segment in (add_git_segment, add_svn_segment, add_hg_segment, + add_fossil_segment): try: if add_repo_segment(p, cwd): return From 136477aa3f2a41d239f71d014a1dd54d448fd70a Mon Sep 17 00:00:00 2001 From: caetanus Date: Mon, 29 Apr 2013 17:45:59 -0300 Subject: [PATCH 010/366] LC_MESSAGES=C in git to work well on newer ubuntu translations. --- powerline-shell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerline-shell.py b/powerline-shell.py index aca5db96..d0e8e8df 100755 --- a/powerline-shell.py +++ b/powerline-shell.py @@ -242,7 +242,7 @@ def get_git_status(): has_untracked_files = False origin_position = "" output = subprocess.Popen(['git', 'status', '--ignore-submodules'], - stdout=subprocess.PIPE).communicate()[0] + stdout=subprocess.PIPE, env={'LC_MESSAGES':'C'}).communicate()[0] for line in output.split('\n'): origin_status = re.findall( r"Your branch is (ahead|behind).*?(\d+) comm", line) From 252a8c3f61282fc1bf7e3bc58c646c8518a1f091 Mon Sep 17 00:00:00 2001 From: caetanus Date: Mon, 29 Apr 2013 19:35:49 -0300 Subject: [PATCH 011/366] commented add hostname segment to not show as default. --- powerline-shell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerline-shell.py b/powerline-shell.py index d0e8e8df..3fbb7a12 100755 --- a/powerline-shell.py +++ b/powerline-shell.py @@ -390,7 +390,7 @@ def get_valid_cwd(): p = Powerline(mode=args.mode, shell=args.shell) cwd = get_valid_cwd() - add_hostname_segment(p) + #add_hostname_segment(p) add_virtual_env_segment(p, cwd) #p.append(Segment(powerline, ' \\u ', 250, 240)) From cef9f57a6c0198d65668a65ce4ca5a3aa71439e2 Mon Sep 17 00:00:00 2001 From: Shrey Banga Date: Fri, 3 May 2013 19:17:18 -0400 Subject: [PATCH 012/366] Cleaning up to make configuration easier I'm planning to refactor the script into multiple files and a configure script, which can be run to add/remove segments. This will make the entire thing faster and make it easier to create new segments and themes. --- powerline-shell.py | 109 +++++++++++++++++++-------------------------- 1 file changed, 47 insertions(+), 62 deletions(-) diff --git a/powerline-shell.py b/powerline-shell.py index 3fbb7a12..995cd107 100755 --- a/powerline-shell.py +++ b/powerline-shell.py @@ -1,14 +1,12 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -import socket import os import subprocess import sys import re import argparse - def warn(msg): print '[powerline-bash] ', msg @@ -120,15 +118,6 @@ def draw(self, next_segment=None): else: separator_bg = self.powerline.reset - try: - self.content = self.content.decode('utf-8') - except: - try: - self.content = self.content.decode('latin1') - except: - pass - - return ''.join(( self.powerline.fgcolor(self.fg), self.powerline.bgcolor(self.bg), @@ -143,8 +132,7 @@ def add_hostname_segment(powerline): powerline.append(Segment(powerline, ' %s@%s ' % (user, hostname), Color.CWD_FG, Color.PATH_BG)) -def add_cwd_segment(powerline, cwd, maxdepth, cwd_only=False): - #powerline.append(' \\w ', 15, 237) +def add_cwd_segment(powerline, cwd, args): home = os.getenv('HOME') cwd = cwd or os.getenv('PWD') cwd = cwd.decode('utf-8') @@ -156,16 +144,21 @@ def add_cwd_segment(powerline, cwd, maxdepth, cwd_only=False): cwd = cwd[1:] names = cwd.split(os.sep) - if len(names) > maxdepth: - names = names[:2] + [u'\u2026'] + names[2 - maxdepth:] + if len(names) > args.cwd_max_depth: + names = names[:2] + [u'\u2026'] + names[2 - args.cwd_max_depth:] - if not cwd_only: + if not args.cwd_only: for n in names[:-1]: powerline.append(Segment(powerline, ' %s ' % n, Color.PATH_FG, Color.PATH_BG, powerline.separator_thin, Color.SEPARATOR_FG)) powerline.append(Segment(powerline, ' %s ' % names[-1], Color.CWD_FG, Color.PATH_BG)) +def add_username_segment(p, cwd, args): + p.append(Segment(p, p.user_prompt[p.shell], 250, 240)) + +def add_hostname_segment(p, cwd, args): + p.append(Segment(p, p.host_prompt[p.shell], 250, 238)) def get_hg_status(): has_modified_files = False @@ -196,7 +189,7 @@ def get_fossil_status(): return has_modified_files, has_untracked_files, has_missing_files -def add_hg_segment(powerline, cwd): +def add_hg_segment(powerline, cwd, args): branch = os.popen('hg branch 2> /dev/null').read().rstrip() if len(branch) == 0: return False @@ -215,7 +208,7 @@ def add_hg_segment(powerline, cwd): powerline.append(Segment(powerline, ' %s ' % branch, fg, bg)) return True -def add_fossil_segment(powerline, cwd): +def add_fossil_segment(powerline, cwd, args): 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: @@ -260,7 +253,7 @@ def get_git_status(): return has_pending_commits, has_untracked_files, origin_position -def add_git_segment(powerline, cwd): +def add_git_segment(powerline, cwd, args): #cmd = "git branch 2> /dev/null | grep -e '\\*'" p1 = subprocess.Popen(['git', 'branch', '--no-color'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) p2 = subprocess.Popen(['grep', '-e', '\\*'], stdin=p1.stdout, stdout=subprocess.PIPE) @@ -284,29 +277,14 @@ def add_git_segment(powerline, cwd): return True -def add_svn_segment(powerline, cwd): +def add_svn_segment(powerline, cwd, args): is_svn = subprocess.Popen(['svn', 'status'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) is_svn_output = is_svn.communicate()[1].strip() if len(is_svn_output) != 0: return - '''svn info: - First column: Says if item was added, deleted, or otherwise changed - ' ' no modifications - 'A' Added - 'C' Conflicted - 'D' Deleted - 'I' Ignored - 'M' Modified - 'R' Replaced - 'X' a directory pulled in by an svn:externals definition - '?' item is not under version control - '!' item is missing (removed by non-svn command) or incomplete - '~' versioned item obstructed by some item of a different kind - ''' - #TODO: Color segment based on above status codes try: - #cmd = '"svn status | grep -c "^[ACDIMRX\\!\\~]"' + #"svn status | grep -c "^[ACDIMRX\\!\\~]" p1 = subprocess.Popen(['svn', 'status'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) p2 = subprocess.Popen(['grep', '-c', '^[ACDIMR\\!\\~]'], @@ -323,19 +301,7 @@ def add_svn_segment(powerline, cwd): return True -def add_repo_segment(powerline, cwd): - for add_repo_segment in (add_git_segment, add_svn_segment, add_hg_segment, - add_fossil_segment): - try: - if add_repo_segment(p, cwd): - return - except subprocess.CalledProcessError: - pass - except OSError: - pass - - -def add_virtual_env_segment(powerline, cwd): +def add_virtual_env_segment(powerline, cwd, args): env = os.getenv("VIRTUAL_ENV") if env is None: return False @@ -347,10 +313,10 @@ def add_virtual_env_segment(powerline, cwd): return True -def add_root_indicator(powerline, error): +def add_root_indicator(powerline, cwd, args): bg = Color.CMD_PASSED_BG fg = Color.CMD_PASSED_FG - if int(error) != 0: + if int(args.prev_error) != 0: fg = Color.CMD_FAILED_FG bg = Color.CMD_FAILED_BG powerline.append(Segment(powerline, powerline.root_indicator, fg, bg)) @@ -382,23 +348,42 @@ def get_valid_cwd(): if __name__ == '__main__': arg_parser = argparse.ArgumentParser() - arg_parser.add_argument('--cwd-only', action='store_true') - arg_parser.add_argument('--mode', action='store', default='patched') - arg_parser.add_argument('--shell', action='store', default='bash') - arg_parser.add_argument('prev_error', nargs='?', default=0) + arg_parser.add_argument('--cwd-only', action='store_true', + help='Only show the current directory') + 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('--mode', action='store', default='patched', + help='The characters used to make separators between segments', + choices=['patched', 'compatible', 'flat']) + arg_parser.add_argument('--shell', action='store', default='bash', + help='Set this to your shell type', choices=['bash', 'zsh']) + arg_parser.add_argument('prev_error', nargs='?', default=0, + help='Error code returned by the last command') args = arg_parser.parse_args() p = Powerline(mode=args.mode, shell=args.shell) cwd = get_valid_cwd() - #add_hostname_segment(p) - add_virtual_env_segment(p, cwd) - #p.append(Segment(powerline, ' \\u ', 250, 240)) - #p.append(Segment(powerline, ' \\h ', 250, 238)) + # Comment or uncomment segments that you do not want: + PROMPT_SEGMENTS = ( + add_virtual_env_segment, + add_username_segment, + add_hostname_segment, + add_cwd_segment, + add_git_segment, + add_svn_segment, + add_hg_segment, + add_fossil_segment, + add_root_indicator, + ) - add_cwd_segment(p, cwd, 5, args.cwd_only) - add_repo_segment(p, cwd) - add_root_indicator(p, args.prev_error) + try: + for add_segment in PROMPT_SEGMENTS: + add_segment(p, cwd, args) + except subprocess.CalledProcessError: + pass + except OSError: + pass sys.stdout.write(p.draw()) # vim: set expandtab: From 112f4112c17bd1507cdde3861f6d19d758d25201 Mon Sep 17 00:00:00 2001 From: Shrey Banga Date: Fri, 3 May 2013 22:29:13 -0400 Subject: [PATCH 013/366] Refactoring segments to individual files The idea is to have an install script that generates the promp generation script, so that processing for segments that are not needed is avoided. The script was getting too slow for many people due to all the checks for the git, hg, svn etc. Also, this will make it cleaner to add new segments. --- .config | 28 +++ README.md | 6 +- install.py | 32 +++ powerline-shell.py | 389 ------------------------------------ powerline-shell.py.template | 135 +++++++++++++ segments/cwd.py | 25 +++ segments/fossil.py | 40 ++++ segments/git.py | 54 +++++ segments/hg.py | 39 ++++ segments/hostname.py | 6 + segments/root.py | 14 ++ segments/svn.py | 24 +++ segments/username.py | 8 + segments/virtual_env.py | 13 ++ 14 files changed, 422 insertions(+), 391 deletions(-) create mode 100644 .config create mode 100644 install.py delete mode 100755 powerline-shell.py create mode 100755 powerline-shell.py.template create mode 100644 segments/cwd.py create mode 100644 segments/fossil.py create mode 100644 segments/git.py create mode 100644 segments/hg.py create mode 100644 segments/hostname.py create mode 100644 segments/root.py create mode 100644 segments/svn.py create mode 100644 segments/username.py create mode 100644 segments/virtual_env.py diff --git a/.config b/.config new file mode 100644 index 00000000..f0924365 --- /dev/null +++ b/.config @@ -0,0 +1,28 @@ +# 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 the current directory. If the path is too long, the middle part is +# replaced with ellipsis ('...') +cwd + +# 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 + +# Shows a '#' if the current user is root, '$' otherwise +# Also, changes color if the last command exited with a non-zero error code +root diff --git a/README.md b/README.md index 7a922b7c..23ed4d28 100644 --- a/README.md +++ b/README.md @@ -24,13 +24,15 @@ A [Powerline](https://github.com/Lokaltog/vim-powerline) like prompt for Bash/ZS git clone https://github.com/milkbikis/powerline-shell +* Configure the segments you want by editing the `.config` file and run `install.py` to generate `powerline-shell.py` + * Create a symlink to the python script in your home: ln -s ~/powerline-shell.py If you don't want the symlink, just modify the path in the commands below -* Now add the following to your .bashrc: +* Now add the following to your `.bashrc`: function _update_ps1() { export PS1="$(~/powerline-shell.py $?)" @@ -38,7 +40,7 @@ A [Powerline](https://github.com/Lokaltog/vim-powerline) like prompt for Bash/ZS export PROMPT_COMMAND="_update_ps1" -* ZSH fans, add the following to your .zshrc: +* ZSH fans, add the following to your `.zshrc`: function powerline_precmd() { export PS1="$(~/powerline-shell.py $? --shell zsh)" diff --git a/install.py b/install.py new file mode 100644 index 00000000..b3b75b9c --- /dev/null +++ b/install.py @@ -0,0 +1,32 @@ +import os + +CONFIG_FILE = '.config' +TEMPLATE_FILE = 'powerline-shell.py.template' +OUTPUT_FILE = 'powerline-shell.py' +SEGMENTS_DIR = 'segments' + +def load_source(srcfile): + try: + return ''.join(open(srcfile).readlines()) + except IOError: + print 'Could not open ' + srcfile + return '' + +if __name__ == "__main__": + source = load_source(TEMPLATE_FILE) + source += '\n#--- Code inserted by configure.py ---' + for line in open(CONFIG_FILE): + line = line.strip() + if len(line) > 0 and line[0] != '#': + srcfile = os.path.join(SEGMENTS_DIR, line + '.py') + source += '\n# ' + srcfile + '\n' + source += load_source(srcfile) + source += '\n# end of ' + srcfile + '\n' + source += '\n#--- End of code inserted by configure.py ---' + source += '\nsys.stdout.write(powerline.draw())\n' + + try: + open(OUTPUT_FILE, 'w').write(source) + print OUTPUT_FILE, 'saved successfully' + except IOError: + print 'ERROR: Could not write to powerline-shell.py. Make sure it is writable' diff --git a/powerline-shell.py b/powerline-shell.py deleted file mode 100755 index 995cd107..00000000 --- a/powerline-shell.py +++ /dev/null @@ -1,389 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import os -import subprocess -import sys -import re -import argparse - -def warn(msg): - print '[powerline-bash] ', msg - - -class Color: - # The following link is a pretty good resources for color values: - # http://www.calmar.ws/vim/color-output.png - - PATH_BG = 237 # dark grey - PATH_FG = 250 # light grey - CWD_FG = 254 # nearly-white grey - SEPARATOR_FG = 244 - - REPO_CLEAN_BG = 148 # a light green color - REPO_CLEAN_FG = 0 # black - REPO_DIRTY_BG = 161 # pink/red - REPO_DIRTY_FG = 15 # white - - CMD_PASSED_BG = 236 - CMD_PASSED_FG = 15 - CMD_FAILED_BG = 161 - CMD_FAILED_FG = 15 - - SVN_CHANGES_BG = 148 - SVN_CHANGES_FG = 22 # dark green - - VIRTUAL_ENV_BG = 35 # a mid-tone green - VIRTUAL_ENV_FG = 00 - - -class Powerline: - symbols = { - 'compatible': { - 'separator': u'\u25B6', - 'separator_thin': u'\u276F' - }, - 'patched': { - 'separator': u'\u2B80', - 'separator_thin': u'\u2B81' - }, - 'flat': { - 'separator': '', - 'separator_thin': '' - }, - } - - color_templates = { - 'bash': '\\[\\e%s\\]', - 'zsh': '%%{%s%%}', - 'bare': '%s', - } - - root_indicators = { - 'bash': ' \\$ ', - 'zsh': ' \\$ ', - 'bare': ' $ ', - } - - user_prompt = { - 'bash': ' \\u', - 'zsh': ' %n' - } - - host_prompt = { - 'bash': ' \\h', - 'zsh': ' %m' - } - - def __init__(self, mode, shell): - self.shell = shell - self.color_template = self.color_templates[shell] - self.root_indicator = self.root_indicators[shell] - self.reset = self.color_template % '[0m' - self.separator = Powerline.symbols[mode]['separator'] - self.separator_thin = Powerline.symbols[mode]['separator_thin'] - self.segments = [] - - def color(self, prefix, code): - 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, segment): - self.segments.append(segment) - - def draw(self): - shifted = self.segments[1:] + [None] - return (''.join((c.draw(n) for c, n in zip(self.segments, shifted))) - + self.reset).encode('utf-8') - - -class Segment: - def __init__(self, powerline, content, fg, bg, separator=None, - separator_fg=None): - self.powerline = powerline - self.content = content - self.fg = fg - self.bg = bg - self.separator = separator or powerline.separator - self.separator_fg = separator_fg or bg - - def draw(self, next_segment=None): - if next_segment: - separator_bg = self.powerline.bgcolor(next_segment.bg) - else: - separator_bg = self.powerline.reset - - return ''.join(( - self.powerline.fgcolor(self.fg), - self.powerline.bgcolor(self.bg), - self.content, - separator_bg, - self.powerline.fgcolor(self.separator_fg), - self.separator)) - -def add_hostname_segment(powerline): - hostname = socket.gethostname() - user = os.getenv("USER") - powerline.append(Segment(powerline, ' %s@%s ' % (user, hostname), Color.CWD_FG, Color.PATH_BG)) - - -def add_cwd_segment(powerline, cwd, args): - home = os.getenv('HOME') - cwd = cwd or os.getenv('PWD') - cwd = cwd.decode('utf-8') - - if cwd.find(home) == 0: - cwd = cwd.replace(home, '~', 1) - - if cwd[0] == '/': - cwd = cwd[1:] - - names = cwd.split(os.sep) - if len(names) > args.cwd_max_depth: - names = names[:2] + [u'\u2026'] + names[2 - args.cwd_max_depth:] - - if not args.cwd_only: - for n in names[:-1]: - powerline.append(Segment(powerline, ' %s ' % n, Color.PATH_FG, - Color.PATH_BG, powerline.separator_thin, Color.SEPARATOR_FG)) - powerline.append(Segment(powerline, ' %s ' % names[-1], Color.CWD_FG, - Color.PATH_BG)) - -def add_username_segment(p, cwd, args): - p.append(Segment(p, p.user_prompt[p.shell], 250, 240)) - -def add_hostname_segment(p, cwd, args): - p.append(Segment(p, p.host_prompt[p.shell], 250, 238)) - -def get_hg_status(): - has_modified_files = False - has_untracked_files = False - has_missing_files = False - output = subprocess.Popen(['hg', 'status'], - stdout=subprocess.PIPE).communicate()[0] - 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 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_hg_segment(powerline, cwd, args): - 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 '') - powerline.append(Segment(powerline, ' %s ' % branch, fg, bg)) - return True - -def add_fossil_segment(powerline, cwd, args): - 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 False - - 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(Segment(powerline, ' %s ' % branch, fg, bg)) - return True - - -def get_git_status(): - has_pending_commits = True - has_untracked_files = False - origin_position = "" - output = subprocess.Popen(['git', 'status', '--ignore-submodules'], - stdout=subprocess.PIPE, env={'LC_MESSAGES':'C'}).communicate()[0] - for line in output.split('\n'): - origin_status = re.findall( - r"Your branch is (ahead|behind).*?(\d+) comm", line) - if origin_status: - origin_position = " %d" % int(origin_status[0][1]) - if origin_status[0][0] == 'behind': - origin_position += u'\u21E3' - if origin_status[0][0] == 'ahead': - origin_position += u'\u21E1' - - if line.find('nothing to commit') >= 0: - has_pending_commits = False - if line.find('Untracked files') >= 0: - has_untracked_files = True - return has_pending_commits, has_untracked_files, origin_position - - -def add_git_segment(powerline, cwd, args): - #cmd = "git branch 2> /dev/null | grep -e '\\*'" - p1 = subprocess.Popen(['git', 'branch', '--no-color'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - p2 = subprocess.Popen(['grep', '-e', '\\*'], stdin=p1.stdout, stdout=subprocess.PIPE) - output = p2.communicate()[0].strip() - if not output: - return False - - branch = output.rstrip()[2:] - has_pending_commits, has_untracked_files, origin_position = get_git_status() - branch += origin_position - if has_untracked_files: - branch += ' +' - - bg = Color.REPO_CLEAN_BG - fg = Color.REPO_CLEAN_FG - if has_pending_commits: - bg = Color.REPO_DIRTY_BG - fg = Color.REPO_DIRTY_FG - - powerline.append(Segment(powerline, ' %s ' % branch, fg, bg)) - return True - - -def add_svn_segment(powerline, cwd, args): - is_svn = subprocess.Popen(['svn', 'status'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - is_svn_output = is_svn.communicate()[1].strip() - if len(is_svn_output) != 0: - return - - try: - #"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].strip() - if len(output) > 0 and int(output) > 0: - changes = output.strip() - powerline.append(Segment(powerline, ' %s ' % changes, - Color.SVN_CHANGES_FG, Color.SVN_CHANGES_BG)) - except OSError: - return False - except subprocess.CalledProcessError: - return False - return True - - -def add_virtual_env_segment(powerline, cwd, args): - env = os.getenv("VIRTUAL_ENV") - if env is None: - return False - - env_name = os.path.basename(env) - bg = Color.VIRTUAL_ENV_BG - fg = Color.VIRTUAL_ENV_FG - powerline.append(Segment(powerline, ' %s ' % env_name, fg, bg)) - return True - - -def add_root_indicator(powerline, cwd, args): - bg = Color.CMD_PASSED_BG - fg = Color.CMD_PASSED_FG - if int(args.prev_error) != 0: - fg = Color.CMD_FAILED_FG - bg = Color.CMD_FAILED_BG - powerline.append(Segment(powerline, powerline.root_indicator, fg, bg)) - - -def get_valid_cwd(): - """ We check if the current working directory is valid or not. Typically - happens when you checkout a different branch on git that doesn't have - this directory. - We return the original cwd because the shell still considers that to be - the working directory, so returning our guess will confuse people - """ - try: - cwd = os.getcwd() - except: - cwd = os.getenv('PWD') # This is where the OS thinks we are - parts = cwd.split(os.sep) - up = cwd - while parts and not os.path.exists(up): - parts.pop() - up = os.sep.join(parts) - try: - os.chdir(up) - except: - warn("Your current directory is invalid.") - sys.exit(1) - warn("Your current directory is invalid. Lowest valid directory: " + up) - return cwd - -if __name__ == '__main__': - arg_parser = argparse.ArgumentParser() - arg_parser.add_argument('--cwd-only', action='store_true', - help='Only show the current directory') - 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('--mode', action='store', default='patched', - help='The characters used to make separators between segments', - choices=['patched', 'compatible', 'flat']) - arg_parser.add_argument('--shell', action='store', default='bash', - help='Set this to your shell type', choices=['bash', 'zsh']) - arg_parser.add_argument('prev_error', nargs='?', default=0, - help='Error code returned by the last command') - args = arg_parser.parse_args() - - p = Powerline(mode=args.mode, shell=args.shell) - cwd = get_valid_cwd() - - # Comment or uncomment segments that you do not want: - PROMPT_SEGMENTS = ( - add_virtual_env_segment, - add_username_segment, - add_hostname_segment, - add_cwd_segment, - add_git_segment, - add_svn_segment, - add_hg_segment, - add_fossil_segment, - add_root_indicator, - ) - - try: - for add_segment in PROMPT_SEGMENTS: - add_segment(p, cwd, args) - except subprocess.CalledProcessError: - pass - except OSError: - pass - sys.stdout.write(p.draw()) - -# vim: set expandtab: diff --git a/powerline-shell.py.template b/powerline-shell.py.template new file mode 100755 index 00000000..71872491 --- /dev/null +++ b/powerline-shell.py.template @@ -0,0 +1,135 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import argparse +import os +import sys + +def warn(msg): + print '[powerline-bash] ', msg + +class Color: + PATH_BG = 237 # dark grey + PATH_FG = 250 # light grey + CWD_FG = 254 # nearly-white grey + SEPARATOR_FG = 244 + + REPO_CLEAN_BG = 148 # a light green color + REPO_CLEAN_FG = 0 # black + REPO_DIRTY_BG = 161 # pink/red + REPO_DIRTY_FG = 15 # white + + CMD_PASSED_BG = 236 + CMD_PASSED_FG = 15 + CMD_FAILED_BG = 161 + CMD_FAILED_FG = 15 + + SVN_CHANGES_BG = 148 + SVN_CHANGES_FG = 22 # dark green + + VIRTUAL_ENV_BG = 35 # a mid-tone green + VIRTUAL_ENV_FG = 00 + + +class Powerline: + symbols = { + 'compatible': { + 'separator': u'\u25B6', + 'separator_thin': u'\u276F' + }, + 'patched': { + 'separator': u'\u2B80', + 'separator_thin': u'\u2B81' + }, + 'flat': { + '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.separator = Powerline.symbols[mode]['separator'] + self.separator_thin = Powerline.symbols[mode]['separator_thin'] + self.segments = [] + + def color(self, prefix, code): + 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 or self.separator, + separator_fg or bg)) + + def draw(self): + return (''.join(self.draw_segment(i) for i in range(len(self.segments))) + + self.reset).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 + happens when you checkout a different branch on git that doesn't have + this directory. + We return the original cwd because the shell still considers that to be + the working directory, so returning our guess will confuse people + """ + try: + cwd = os.getcwd() + except: + cwd = os.getenv('PWD') # This is where the OS thinks we are + parts = cwd.split(os.sep) + up = cwd + while parts and not os.path.exists(up): + parts.pop() + up = os.sep.join(parts) + try: + os.chdir(up) + except: + warn("Your current directory is invalid.") + sys.exit(1) + warn("Your current directory is invalid. Lowest valid directory: " + up) + return cwd + + +if __name__ == "__main__": + arg_parser = argparse.ArgumentParser() + arg_parser.add_argument('--cwd-only', action='store_true', + help='Only show the current directory') + 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('--mode', action='store', default='patched', + help='The characters used to make separators between segments', + choices=['patched', 'compatible', 'flat']) + arg_parser.add_argument('--shell', action='store', default='bash', + help='Set this to your shell type', choices=['bash', 'zsh']) + arg_parser.add_argument('prev_error', nargs='?', type=int, default=0, + help='Error code returned by the last command') + args = arg_parser.parse_args() + + powerline = Powerline(args, get_valid_cwd()) diff --git a/segments/cwd.py b/segments/cwd.py new file mode 100644 index 00000000..b4f70873 --- /dev/null +++ b/segments/cwd.py @@ -0,0 +1,25 @@ +import os + +def add_cwd_segment(): + home = os.getenv('HOME') + cwd = powerline.cwd or os.getenv('PWD') + cwd = cwd.decode('utf-8') + + if cwd.find(home) == 0: + cwd = cwd.replace(home, '~', 1) + + if cwd[0] == '/': + cwd = cwd[1:] + + names = cwd.split(os.sep) + max_depth = powerline.args.cwd_max_depth + if len(names) > max_depth: + names = names[:2] + [u'\u2026'] + names[2 - max_depth:] + + if not powerline.args.cwd_only: + for n in names[:-1]: + powerline.append(' %s ' % n, Color.PATH_FG, Color.PATH_BG, + powerline.separator_thin, Color.SEPARATOR_FG) + powerline.append(' %s ' % names[-1], Color.CWD_FG, Color.PATH_BG) + +add_cwd_segment() diff --git a/segments/fossil.py b/segments/fossil.py new file mode 100644 index 00000000..bffc10f3 --- /dev/null +++ b/segments/fossil.py @@ -0,0 +1,40 @@ +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(): + 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) + +try: + add_fossil_segment() +except OSError: + pass +except subprocess.CalledProcessError: + pass diff --git a/segments/git.py b/segments/git.py new file mode 100644 index 00000000..ca2a97f2 --- /dev/null +++ b/segments/git.py @@ -0,0 +1,54 @@ +import re +import subprocess + +def get_git_status(): + has_pending_commits = True + has_untracked_files = False + origin_position = "" + output = subprocess.Popen(['git', 'status', '--ignore-submodules'], + stdout=subprocess.PIPE, env={'LC_MESSAGES':'C'}).communicate()[0] + for line in output.split('\n'): + origin_status = re.findall( + r"Your branch is (ahead|behind).*?(\d+) comm", line) + if origin_status: + origin_position = " %d" % int(origin_status[0][1]) + if origin_status[0][0] == 'behind': + origin_position += u'\u21E3' + if origin_status[0][0] == 'ahead': + origin_position += u'\u21E1' + + if line.find('nothing to commit') >= 0: + has_pending_commits = False + if line.find('Untracked files') >= 0: + has_untracked_files = True + return has_pending_commits, has_untracked_files, origin_position + + +def add_git_segment(): + #cmd = "git branch 2> /dev/null | grep -e '\\*'" + p1 = subprocess.Popen(['git', 'branch', '--no-color'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + p2 = subprocess.Popen(['grep', '-e', '\\*'], stdin=p1.stdout, stdout=subprocess.PIPE) + output = p2.communicate()[0].strip() + if not output: + return + + branch = output.rstrip()[2:] + has_pending_commits, has_untracked_files, origin_position = get_git_status() + branch += origin_position + if has_untracked_files: + branch += ' +' + + bg = Color.REPO_CLEAN_BG + fg = Color.REPO_CLEAN_FG + if has_pending_commits: + bg = Color.REPO_DIRTY_BG + fg = Color.REPO_DIRTY_FG + + powerline.append(' %s ' % branch, fg, bg) + +try: + add_git_segment() +except OSError: + pass +except subprocess.CalledProcessError: + pass diff --git a/segments/hg.py b/segments/hg.py new file mode 100644 index 00000000..8b95000b --- /dev/null +++ b/segments/hg.py @@ -0,0 +1,39 @@ +import os +import subprocess + +def get_hg_status(): + has_modified_files = False + has_untracked_files = False + has_missing_files = False + output = subprocess.Popen(['hg', 'status'], + stdout=subprocess.PIPE).communicate()[0] + 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(): + 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) + +add_hg_segment() diff --git a/segments/hostname.py b/segments/hostname.py new file mode 100644 index 00000000..231b396c --- /dev/null +++ b/segments/hostname.py @@ -0,0 +1,6 @@ +def add_hostname_segment(): + host_prompts = { + 'bash': ' \\h', + 'zsh': ' %m' + } + powerline.append(host_prompts[powerline.args.shell], 250, 238) diff --git a/segments/root.py b/segments/root.py new file mode 100644 index 00000000..c2d939c8 --- /dev/null +++ b/segments/root.py @@ -0,0 +1,14 @@ +def add_root_indicator_segment(): + 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) + +add_root_indicator_segment() diff --git a/segments/svn.py b/segments/svn.py new file mode 100644 index 00000000..f634a45e --- /dev/null +++ b/segments/svn.py @@ -0,0 +1,24 @@ +import subprocess + +def add_svn_segment(): + is_svn = subprocess.Popen(['svn', 'status'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + is_svn_output = is_svn.communicate()[1].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].strip() + if len(output) > 0 and int(output) > 0: + changes = output.strip() + powerline.append(' %s ' % changes, Color.SVN_CHANGES_FG, Color.SVN_CHANGES_BG) + +try: + add_svn_segment() +except OSError: + pass +except subprocess.CalledProcessError: + pass diff --git a/segments/username.py b/segments/username.py new file mode 100644 index 00000000..5adb28d8 --- /dev/null +++ b/segments/username.py @@ -0,0 +1,8 @@ +def add_username_segment(): + user_prompts = { + 'bash': ' \\u', + 'zsh': ' %n' + } + powerline.append(user_prompts[powerline.args.shell], 250, 240) + +add_username_segment() diff --git a/segments/virtual_env.py b/segments/virtual_env.py new file mode 100644 index 00000000..71b0ee8d --- /dev/null +++ b/segments/virtual_env.py @@ -0,0 +1,13 @@ +import os + +def add_virtual_env_segment(): + env = os.getenv('VIRTUAL_ENV') + 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) + +add_virtual_env_segment() From 35182ab22ba49228718e4eae2f948e066410e1b5 Mon Sep 17 00:00:00 2001 From: Shrey Banga Date: Fri, 3 May 2013 22:31:26 -0400 Subject: [PATCH 014/366] Changing execution permission on install.py --- install.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 install.py diff --git a/install.py b/install.py old mode 100644 new mode 100755 From 0c480e723a1b14bb502fcfd6dd39dc0e26a32de7 Mon Sep 17 00:00:00 2001 From: Shrey Banga Date: Fri, 3 May 2013 22:32:21 -0400 Subject: [PATCH 015/366] Adding shebang line to install.py --- install.py | 1 + 1 file changed, 1 insertion(+) diff --git a/install.py b/install.py index b3b75b9c..7627d262 100755 --- a/install.py +++ b/install.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python import os CONFIG_FILE = '.config' From 30cf5c68602bf47c0b1e79e8f8aa62f372c38572 Mon Sep 17 00:00:00 2001 From: Shrey Banga Date: Fri, 3 May 2013 22:38:51 -0400 Subject: [PATCH 016/366] Make the generate script executable --- install.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/install.py b/install.py index 7627d262..0d041e5f 100755 --- a/install.py +++ b/install.py @@ -1,5 +1,6 @@ #!/usr/bin/env python import os +import stat CONFIG_FILE = '.config' TEMPLATE_FILE = 'powerline-shell.py.template' @@ -28,6 +29,8 @@ def load_source(srcfile): 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' From 05b7b3b5eb23cde569038c3a75c3ce1c27ca73a5 Mon Sep 17 00:00:00 2001 From: Shrey Banga Date: Fri, 3 May 2013 22:49:13 -0400 Subject: [PATCH 017/366] Adding some documentation --- .config | 10 ++++++++++ README.md | 15 ++++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/.config b/.config index f0924365..c428d895 100644 --- a/.config +++ b/.config @@ -1,3 +1,13 @@ +# This config file is a list of segments which are added to your powerline-shell +# prompt in the order in which they appear. Any line starting with # is ignored +# so you can simply comment out segments you don't like, or rearrange the lines +# if you want them to appear in a different order +# +# Every time you make a change to this file, run install.py to update the +# powerline-shell.py script +# +# For instructions on how to use the powerline-shell.py script, see the README + # Show current virtual environment (see http://www.virtualenv.org/) virtual_env diff --git a/README.md b/README.md index 23ed4d28..21d8ebbb 100644 --- a/README.md +++ b/README.md @@ -5,14 +5,14 @@ A [Powerline](https://github.com/Lokaltog/vim-powerline) like prompt for Bash/ZS ![MacVim+Solarized+Powerline+CtrlP](https://raw.github.com/milkbikis/dotfiles-mac/master/bash-powerline-screenshot.png) -* Shows some important details about the git branch: - * Displays the current git branch which changes background color when the branch is dirty +* Shows some important details about the git/svn/hg/fossil branch: + * Displays the current branch which changes background color when the branch is dirty * A '+' appears when untracked files are present * 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 * 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 all done in a Python script, so you could go nuts with it +* It's easy to customize and extend. See below for details. # Setup @@ -62,3 +62,12 @@ A [Powerline](https://github.com/Lokaltog/vim-powerline) like prompt for Bash/ZS function fish_prompt ~/powerline-shell.py $status --shell bare end + +# Customization + +The `segments` directory contains python scripts which are injected as is into +a single file `powerline-shell.py.template`. 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` file at the appropriate location. Make sure that your script +does not introduce new globals which might conflict with other scripts. From 392a2ab83b0a2e60eba6c6ed20e4fe702c235534 Mon Sep 17 00:00:00 2001 From: Shrey Banga Date: Fri, 3 May 2013 22:51:53 -0400 Subject: [PATCH 018/366] Updating the title --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 21d8ebbb..3d62d00d 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -Powerline style prompt for Bash (and now, ZSH) -============================================== +A Powerline style prompt for your shell +======================================= -A [Powerline](https://github.com/Lokaltog/vim-powerline) like prompt for Bash/ZSH: +A [Powerline](https://github.com/Lokaltog/vim-powerline) like prompt for Bash, ZSH and Fish: ![MacVim+Solarized+Powerline+CtrlP](https://raw.github.com/milkbikis/dotfiles-mac/master/bash-powerline-screenshot.png) From 3a1a453ab91b13f7ded4905b23d863a8bee5d24a Mon Sep 17 00:00:00 2001 From: Shrey Banga Date: Fri, 3 May 2013 22:59:38 -0400 Subject: [PATCH 019/366] Adding text about contributing --- README.md | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3d62d00d..20595606 100644 --- a/README.md +++ b/README.md @@ -65,9 +65,29 @@ A [Powerline](https://github.com/Lokaltog/vim-powerline) like prompt for Bash, Z # Customization +## Adding, Removing and Disabling segments + +The `.config` 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 the `.config` file, run `install.py`, which will generate a new +`powerline-shell.py` customized to your configuration. You should see the new +prompt immediately. + +## Contributing new types of segments + The `segments` directory contains python scripts which are injected as is into a single file `powerline-shell.py.template`. 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` file at the appropriate location. Make sure that your script -does not introduce new globals which might conflict with other scripts. +to the `.config` file at the appropriate location. + +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 +scenario. + +## Themes + +The script currently uses a single theme, but it's easy enough to change the +colors by editing the `Color` class in `powerline-shell.py.template`. I'm going +to refactor the code to allow choosing between different themes and allowing +people to contribute themes in separate files. From 2e338ca159c305794c2eafed0cd61d8de01de04a Mon Sep 17 00:00:00 2001 From: Shrey Banga Date: Fri, 3 May 2013 23:03:50 -0400 Subject: [PATCH 020/366] Fixing typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 20595606..1a7ca539 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ A [Powerline](https://github.com/Lokaltog/vim-powerline) like prompt for Bash, Z # Customization -## Adding, Removing and Disabling segments +## Adding, Removing and Re-arranging segments The `.config` file defines which segments are drawn and in which order. Simply comment out and rearrange segment names to get your desired arrangement. Every From 44d9ab539b9c40e1b82155d58bdacc0476171bbd Mon Sep 17 00:00:00 2001 From: Shrey Banga Date: Fri, 3 May 2013 23:07:10 -0400 Subject: [PATCH 021/366] Reformatting readme --- README.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1a7ca539..97ccf6f9 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,9 @@ A [Powerline](https://github.com/Lokaltog/vim-powerline) like prompt for Bash, Z # 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. +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/vim-powerline/wiki/Patched-fonts @@ -32,7 +34,8 @@ A [Powerline](https://github.com/Lokaltog/vim-powerline) like prompt for Bash, Z If you don't want the symlink, just modify the path in the commands below -* Now add the following to your `.bashrc`: +## Bash: +Add the following to your `.bashrc`: function _update_ps1() { export PS1="$(~/powerline-shell.py $?)" @@ -40,7 +43,8 @@ A [Powerline](https://github.com/Lokaltog/vim-powerline) like prompt for Bash, Z export PROMPT_COMMAND="_update_ps1" -* ZSH fans, add the following to your `.zshrc`: +## ZSH: +Add the following to your `.zshrc`: function powerline_precmd() { export PS1="$(~/powerline-shell.py $? --shell zsh)" @@ -57,7 +61,8 @@ A [Powerline](https://github.com/Lokaltog/vim-powerline) like prompt for Bash, Z install_powerline_precmd -* Fish users, redefine `fish_prompt` in ~/.config/fish/config.fish: +## Fish: +Redefine `fish_prompt` in ~/.config/fish/config.fish: function fish_prompt ~/powerline-shell.py $status --shell bare From df3127bf284e189de867aa7e7610a16890024834 Mon Sep 17 00:00:00 2001 From: Shrey Banga Date: Sat, 4 May 2013 00:09:25 -0300 Subject: [PATCH 022/366] Fixing the heading sizes --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 97ccf6f9..493e6a45 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ setting your $TERM to xterm-256color, because that works for me. If you don't want the symlink, just modify the path in the commands below -## Bash: +### Bash: Add the following to your `.bashrc`: function _update_ps1() { @@ -43,7 +43,7 @@ Add the following to your `.bashrc`: export PROMPT_COMMAND="_update_ps1" -## ZSH: +### ZSH: Add the following to your `.zshrc`: function powerline_precmd() { @@ -61,7 +61,7 @@ Add the following to your `.zshrc`: install_powerline_precmd -## Fish: +### Fish: Redefine `fish_prompt` in ~/.config/fish/config.fish: function fish_prompt @@ -70,7 +70,7 @@ Redefine `fish_prompt` in ~/.config/fish/config.fish: # Customization -## Adding, Removing and Re-arranging segments +### Adding, Removing and Re-arranging segments The `.config` file defines which segments are drawn and in which order. Simply comment out and rearrange segment names to get your desired arrangement. Every @@ -78,7 +78,7 @@ time you change the `.config` file, run `install.py`, which will generate a new `powerline-shell.py` customized to your configuration. You should see the new prompt immediately. -## Contributing new types of segments +### Contributing new types of segments The `segments` directory contains python scripts which are injected as is into a single file `powerline-shell.py.template`. Each segment script defines a @@ -90,7 +90,7 @@ 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 scenario. -## Themes +### Themes The script currently uses a single theme, but it's easy enough to change the colors by editing the `Color` class in `powerline-shell.py.template`. I'm going From 7dcc352acaed11671d2b81a298446f7d30a8ab47 Mon Sep 17 00:00:00 2001 From: Shrey Banga Date: Sat, 4 May 2013 03:49:55 -0400 Subject: [PATCH 023/366] Adding theme-ing capabilities The config file is now a python file so that it may be easily extended. Themes can be added to the themes/ directory and applied in config.py. --- .config => config.py | 35 +++++++++++++++++++---------------- install.py | 19 +++++++------------ powerline-shell.py.template | 23 ----------------------- themes/default.py | 21 +++++++++++++++++++++ 4 files changed, 47 insertions(+), 51 deletions(-) rename .config => config.py (57%) create mode 100644 themes/default.py diff --git a/.config b/config.py similarity index 57% rename from .config rename to config.py index c428d895..38d08b21 100644 --- a/.config +++ b/config.py @@ -1,38 +1,41 @@ -# This config file is a list of segments which are added to your powerline-shell -# prompt in the order in which they appear. Any line starting with # is ignored -# so you can simply comment out segments you don't like, or rearrange the lines -# if you want them to appear in a different order -# -# Every time you make a change to this file, run install.py to update the -# powerline-shell.py script +# 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 = [ # Show current virtual environment (see http://www.virtualenv.org/) -virtual_env + 'virtual_env', # Show the current user's username as in ordinary prompts -username + 'username', # Show the machine's hostname. Mostly used when ssh-ing into other machines -hostname + 'hostname', # Show the current directory. If the path is too long, the middle part is # replaced with ellipsis ('...') -cwd + 'cwd', # Show the current git branch and status -git + 'git', # Show the current mercurial branch and status -hg + 'hg', # Show the current svn branch and status -svn + 'svn', # Show the current fossil branch and status -fossil + 'fossil', # Shows a '#' if the current user is root, '$' otherwise # Also, changes color if the last command exited with a non-zero error code -root + 'root', +] + +# Change the colors used to draw individual segments in your prompt +THEME = 'default' diff --git a/install.py b/install.py index 0d041e5f..e878f7ff 100755 --- a/install.py +++ b/install.py @@ -1,31 +1,26 @@ #!/usr/bin/env python import os import stat +import config -CONFIG_FILE = '.config' TEMPLATE_FILE = 'powerline-shell.py.template' OUTPUT_FILE = 'powerline-shell.py' SEGMENTS_DIR = 'segments' +THEMES_DIR = 'themes' def load_source(srcfile): try: - return ''.join(open(srcfile).readlines()) + return ''.join(open(srcfile).readlines()) + '\n\n' except IOError: print 'Could not open ' + srcfile return '' if __name__ == "__main__": source = load_source(TEMPLATE_FILE) - source += '\n#--- Code inserted by configure.py ---' - for line in open(CONFIG_FILE): - line = line.strip() - if len(line) > 0 and line[0] != '#': - srcfile = os.path.join(SEGMENTS_DIR, line + '.py') - source += '\n# ' + srcfile + '\n' - source += load_source(srcfile) - source += '\n# end of ' + srcfile + '\n' - source += '\n#--- End of code inserted by configure.py ---' - source += '\nsys.stdout.write(powerline.draw())\n' + 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')) + source += 'sys.stdout.write(powerline.draw())\n' try: open(OUTPUT_FILE, 'w').write(source) diff --git a/powerline-shell.py.template b/powerline-shell.py.template index 71872491..a5deb2cb 100755 --- a/powerline-shell.py.template +++ b/powerline-shell.py.template @@ -8,29 +8,6 @@ import sys def warn(msg): print '[powerline-bash] ', msg -class Color: - PATH_BG = 237 # dark grey - PATH_FG = 250 # light grey - CWD_FG = 254 # nearly-white grey - SEPARATOR_FG = 244 - - REPO_CLEAN_BG = 148 # a light green color - REPO_CLEAN_FG = 0 # black - REPO_DIRTY_BG = 161 # pink/red - REPO_DIRTY_FG = 15 # white - - CMD_PASSED_BG = 236 - CMD_PASSED_FG = 15 - CMD_FAILED_BG = 161 - CMD_FAILED_FG = 15 - - SVN_CHANGES_BG = 148 - SVN_CHANGES_FG = 22 # dark green - - VIRTUAL_ENV_BG = 35 # a mid-tone green - VIRTUAL_ENV_FG = 00 - - class Powerline: symbols = { 'compatible': { diff --git a/themes/default.py b/themes/default.py new file mode 100644 index 00000000..e064e8c8 --- /dev/null +++ b/themes/default.py @@ -0,0 +1,21 @@ +class Color: + PATH_BG = 237 # dark grey + PATH_FG = 250 # light grey + CWD_FG = 254 # nearly-white grey + SEPARATOR_FG = 244 + + REPO_CLEAN_BG = 148 # a light green color + REPO_CLEAN_FG = 0 # black + REPO_DIRTY_BG = 161 # pink/red + REPO_DIRTY_FG = 15 # white + + CMD_PASSED_BG = 236 + CMD_PASSED_FG = 15 + CMD_FAILED_BG = 161 + CMD_FAILED_FG = 15 + + SVN_CHANGES_BG = 148 + SVN_CHANGES_FG = 22 # dark green + + VIRTUAL_ENV_BG = 35 # a mid-tone green + VIRTUAL_ENV_FG = 00 From 6861fcb18da2c612d58203c5790555ba42013b99 Mon Sep 17 00:00:00 2001 From: Shrey Banga Date: Sat, 4 May 2013 04:59:10 -0300 Subject: [PATCH 024/366] Updated readme about config.py and themes --- README.md | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 493e6a45..a6e3db6c 100644 --- a/README.md +++ b/README.md @@ -26,9 +26,13 @@ setting your $TERM to xterm-256color, because that works for me. git clone https://github.com/milkbikis/powerline-shell -* Configure the segments you want by editing the `.config` file and run `install.py` to generate `powerline-shell.py` +* Configure the segments you want by editing `config.py`. Then run -* Create a symlink to the python script in your home: + ./install.py + + This will generate `powerline-shell.py` + +* Create a symlink to this python script in your home: ln -s ~/powerline-shell.py @@ -72,9 +76,9 @@ Redefine `fish_prompt` in ~/.config/fish/config.fish: ### Adding, Removing and Re-arranging segments -The `.config` file defines which segments are drawn and in which order. Simply +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 the `.config` file, run `install.py`, which will generate a new +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. @@ -84,7 +88,7 @@ The `segments` directory contains python scripts which are injected as is into a single file `powerline-shell.py.template`. 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` file at the appropriate location. +to the `config.py` file at the appropriate location. 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 @@ -92,7 +96,7 @@ scenario. ### Themes -The script currently uses a single theme, but it's easy enough to change the -colors by editing the `Color` class in `powerline-shell.py.template`. I'm going -to refactor the code to allow choosing between different themes and allowing -people to contribute themes in separate files. +The `themes` directory stores themes for your prompt, which are basically color +values used by segments. Create a new theme by copying `themes/default.py` and +changing the values. To use a theme, set the `THEME` variable in `config.py` to +the name of your theme. From 18fd1fec6e0da6552da22afee5a1e55b215fa51e Mon Sep 17 00:00:00 2001 From: Shrey Banga Date: Sat, 4 May 2013 05:53:18 -0300 Subject: [PATCH 025/366] Adding info about color testing script --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index a6e3db6c..82d932e3 100644 --- a/README.md +++ b/README.md @@ -100,3 +100,8 @@ The `themes` directory stores themes for your prompt, which are basically color values used by segments. Create a new theme by copying `themes/default.py` 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. From c77d7d7ce73432ba028586c4feb3995c31d4cba6 Mon Sep 17 00:00:00 2001 From: Shrey Banga Date: Sat, 4 May 2013 04:51:20 -0400 Subject: [PATCH 026/366] Adding a script to test color combinations for themes --- themes/colortest.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100755 themes/colortest.py diff --git a/themes/colortest.py b/themes/colortest.py new file mode 100755 index 00000000..1ac2972c --- /dev/null +++ b/themes/colortest.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python +import sys + +ESCAPE = chr(27) + +def fg(color): + return ESCAPE + '[38;5;{0}m'.format(color) + +def bg(color): + return ESCAPE + '[48;5;{0}m'.format(color) + +def reset(): + return ESCAPE + '[48;0m' + +if __name__ == "__main__": + if len(sys.argv) < 5: + print 'Usage: colortest.py fg_start fg_end bg_start bg_end test_string' + sys.exit(1) + + fg_start, fg_end, bg_start, bg_end = map(int, sys.argv[1:5]) + test_string = sys.argv[5] + + print ' ' * len(str(bg_start)), + for fg_color in range(fg_start, fg_end + 1): + print ' ' * (len(test_string) - len(str(fg_color))), fg_color, + print + + for bg_color in range(bg_start, bg_end + 1): + print bg_color, bg(bg_color), + for fg_color in range(fg_start, fg_end + 1): + print fg(fg_color), test_string, + print reset() From 5dedc3943163374b1532c261597c0639fff2b655 Mon Sep 17 00:00:00 2001 From: Shrey Banga Date: Sat, 4 May 2013 04:59:17 -0400 Subject: [PATCH 027/366] Fixed argument count --- themes/colortest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/themes/colortest.py b/themes/colortest.py index 1ac2972c..e3beca46 100755 --- a/themes/colortest.py +++ b/themes/colortest.py @@ -13,7 +13,7 @@ def reset(): return ESCAPE + '[48;0m' if __name__ == "__main__": - if len(sys.argv) < 5: + if len(sys.argv) < 6: print 'Usage: colortest.py fg_start fg_end bg_start bg_end test_string' sys.exit(1) From 6b5d7c621e133e3a67e973b156c166717a05cd40 Mon Sep 17 00:00:00 2001 From: Shrey Banga Date: Sat, 4 May 2013 05:24:45 -0400 Subject: [PATCH 028/366] Fixing git segment. Was always showing as dirty --- segments/git.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/segments/git.py b/segments/git.py index ca2a97f2..6d9cad25 100644 --- a/segments/git.py +++ b/segments/git.py @@ -6,7 +6,7 @@ def get_git_status(): has_untracked_files = False origin_position = "" output = subprocess.Popen(['git', 'status', '--ignore-submodules'], - stdout=subprocess.PIPE, env={'LC_MESSAGES':'C'}).communicate()[0] + stdout=subprocess.PIPE).communicate()[0] for line in output.split('\n'): origin_status = re.findall( r"Your branch is (ahead|behind).*?(\d+) comm", line) From 5360cc7196faf70153daff496d9a2b87192180c3 Mon Sep 17 00:00:00 2001 From: Shrey Banga Date: Sat, 4 May 2013 05:25:30 -0400 Subject: [PATCH 029/366] Adding hostname and username colors to the theme --- segments/hostname.py | 5 ++++- segments/username.py | 3 ++- themes/basic.py | 29 +++++++++++++++++++++++++++++ themes/default.py | 6 ++++++ 4 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 themes/basic.py diff --git a/segments/hostname.py b/segments/hostname.py index 231b396c..4f338983 100644 --- a/segments/hostname.py +++ b/segments/hostname.py @@ -3,4 +3,7 @@ def add_hostname_segment(): 'bash': ' \\h', 'zsh': ' %m' } - powerline.append(host_prompts[powerline.args.shell], 250, 238) + powerline.append(host_prompts[powerline.args.shell], Color.HOSTNAME_FG, + Color.HOSTNAME_BG) + +add_hostname_segment() diff --git a/segments/username.py b/segments/username.py index 5adb28d8..e220acc3 100644 --- a/segments/username.py +++ b/segments/username.py @@ -3,6 +3,7 @@ def add_username_segment(): 'bash': ' \\u', 'zsh': ' %n' } - powerline.append(user_prompts[powerline.args.shell], 250, 240) + powerline.append(user_prompts[powerline.args.shell], Color.USERNAME_FG, + Color.USERNAME_BG) add_username_segment() diff --git a/themes/basic.py b/themes/basic.py new file mode 100644 index 00000000..06f2f676 --- /dev/null +++ b/themes/basic.py @@ -0,0 +1,29 @@ +# Basic theme which only uses colors in 0-15 range + +class Color: + USERNAME_FG = 8 + USERNAME_BG = 15 + + HOSTNAME_FG = 8 + HOSTNAME_BG = 7 + + PATH_BG = 8 # dark grey + PATH_FG = 7 # light grey + CWD_FG = 15 # white + SEPARATOR_FG = 7 + + REPO_CLEAN_BG = 2 # green + REPO_CLEAN_FG = 0 # black + REPO_DIRTY_BG = 1 # red + REPO_DIRTY_FG = 15 # white + + CMD_PASSED_BG = 8 + CMD_PASSED_FG = 15 + CMD_FAILED_BG = 11 + CMD_FAILED_FG = 0 + + SVN_CHANGES_BG = REPO_DIRTY_BG + SVN_CHANGES_FG = REPO_DIRTY_FG + + VIRTUAL_ENV_BG = 15 + VIRTUAL_ENV_FG = 0 diff --git a/themes/default.py b/themes/default.py index e064e8c8..c0a43e0f 100644 --- a/themes/default.py +++ b/themes/default.py @@ -1,4 +1,10 @@ class Color: + USERNAME_FG = 250 + USERNAME_BG = 240 + + HOSTNAME_FG = 250 + HOSTNAME_BG = 238 + PATH_BG = 237 # dark grey PATH_FG = 250 # light grey CWD_FG = 254 # nearly-white grey From cf42b52f2be0f2861a4402c93f7e1bf9b62c3d5c Mon Sep 17 00:00:00 2001 From: Shrey Banga Date: Sat, 4 May 2013 05:38:46 -0400 Subject: [PATCH 030/366] Adding solarized-dark theme and gitignore --- .gitignore | 2 ++ themes/solarized-dark.py | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 .gitignore create mode 100644 themes/solarized-dark.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..25a014d8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +powerline-shell.py +*.py[co] diff --git a/themes/solarized-dark.py b/themes/solarized-dark.py new file mode 100644 index 00000000..0ce78670 --- /dev/null +++ b/themes/solarized-dark.py @@ -0,0 +1,27 @@ +class Color: + USERNAME_FG = 15 + USERNAME_BG = 4 + + HOSTNAME_FG = 15 + HOSTNAME_BG = 10 + + PATH_FG = 7 + PATH_BG = 10 + CWD_FG = 15 + SEPARATOR_FG = 14 + + REPO_CLEAN_FG = 14 + REPO_CLEAN_BG = 0 + REPO_DIRTY_FG = 3 + REPO_DIRTY_BG = 0 + + 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 From e5562d55271b4428d68f8c00baef77dc60f875d7 Mon Sep 17 00:00:00 2001 From: Shrey Banga Date: Sun, 5 May 2013 02:59:28 -0400 Subject: [PATCH 031/366] Updating the virtual_env color for basic theme --- themes/basic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/themes/basic.py b/themes/basic.py index 06f2f676..8db1a93c 100644 --- a/themes/basic.py +++ b/themes/basic.py @@ -25,5 +25,5 @@ class Color: SVN_CHANGES_BG = REPO_DIRTY_BG SVN_CHANGES_FG = REPO_DIRTY_FG - VIRTUAL_ENV_BG = 15 + VIRTUAL_ENV_BG = 2 VIRTUAL_ENV_FG = 0 From cf67d78daf242dca75ce24c327936cfdabbfe1b3 Mon Sep 17 00:00:00 2001 From: Shrey Banga Date: Sun, 5 May 2013 03:35:03 -0400 Subject: [PATCH 032/366] Recognize home directory in cwd even if it differs from $HOME --- segments/cwd.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/segments/cwd.py b/segments/cwd.py index b4f70873..fedb1649 100644 --- a/segments/cwd.py +++ b/segments/cwd.py @@ -1,17 +1,21 @@ import os -def add_cwd_segment(): +def get_short_path(cwd): home = os.getenv('HOME') - cwd = powerline.cwd or os.getenv('PWD') - cwd = cwd.decode('utf-8') + names = cwd.split(os.sep) + if names[0] == '': names = names[1:] + path = '' + for i in range(len(names)): + path += os.sep + names[i] + if os.path.samefile(path, home): + return ['~'] + names[i+1:] + return names - if cwd.find(home) == 0: - cwd = cwd.replace(home, '~', 1) - if cwd[0] == '/': - cwd = cwd[1:] +def add_cwd_segment(): + cwd = powerline.cwd or os.getenv('PWD') + names = get_short_path(cwd.decode('utf-8')) - names = cwd.split(os.sep) max_depth = powerline.args.cwd_max_depth if len(names) > max_depth: names = names[:2] + [u'\u2026'] + names[2 - max_depth:] From 1a898bbec2b5a71246dac9d08ffeb513143f7b3a Mon Sep 17 00:00:00 2001 From: Shrey Banga Date: Fri, 17 May 2013 18:12:33 -0400 Subject: [PATCH 033/366] Fixes #74 --- powerline-shell.py.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerline-shell.py.template b/powerline-shell.py.template index a5deb2cb..e2518fd4 100755 --- a/powerline-shell.py.template +++ b/powerline-shell.py.template @@ -104,7 +104,7 @@ if __name__ == "__main__": help='The characters used to make separators between segments', choices=['patched', 'compatible', 'flat']) arg_parser.add_argument('--shell', action='store', default='bash', - help='Set this to your shell type', choices=['bash', 'zsh']) + 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') args = arg_parser.parse_args() From b3f09ea8e1ac1f6daf6da6dc05462e6b25a492f8 Mon Sep 17 00:00:00 2001 From: lhl Date: Sun, 19 May 2013 23:51:35 -0700 Subject: [PATCH 034/366] Added 'bare' options for hostname and username (required for fish compatibility) --- segments/hostname.py | 5 ++++- segments/username.py | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/segments/hostname.py b/segments/hostname.py index 4f338983..a44832fc 100644 --- a/segments/hostname.py +++ b/segments/hostname.py @@ -1,7 +1,10 @@ +import socket + def add_hostname_segment(): host_prompts = { 'bash': ' \\h', - 'zsh': ' %m' + 'zsh': ' %m', + 'bare': ' %s' % socket.gethostname().split('.')[0] } powerline.append(host_prompts[powerline.args.shell], Color.HOSTNAME_FG, Color.HOSTNAME_BG) diff --git a/segments/username.py b/segments/username.py index e220acc3..a48bf74a 100644 --- a/segments/username.py +++ b/segments/username.py @@ -1,7 +1,10 @@ +import os + def add_username_segment(): user_prompts = { 'bash': ' \\u', - 'zsh': ' %n' + 'zsh': ' %n', + 'bare': ' %s' % os.getenv('USER') } powerline.append(user_prompts[powerline.args.shell], Color.USERNAME_FG, Color.USERNAME_BG) From 491388f948b883a2a512a7d443f499189c0a8ef3 Mon Sep 17 00:00:00 2001 From: Shrey Banga Date: Mon, 20 May 2013 01:14:30 -0700 Subject: [PATCH 035/366] Performance improvements in username, hostname segments --- segments/hostname.py | 18 +++++++++--------- segments/username.py | 17 +++++++++-------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/segments/hostname.py b/segments/hostname.py index a44832fc..4b5f24ee 100644 --- a/segments/hostname.py +++ b/segments/hostname.py @@ -1,12 +1,12 @@ -import socket - def add_hostname_segment(): - host_prompts = { - 'bash': ' \\h', - 'zsh': ' %m', - 'bare': ' %s' % socket.gethostname().split('.')[0] - } - powerline.append(host_prompts[powerline.args.shell], Color.HOSTNAME_FG, - Color.HOSTNAME_BG) + 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) add_hostname_segment() diff --git a/segments/username.py b/segments/username.py index a48bf74a..8dd438f6 100644 --- a/segments/username.py +++ b/segments/username.py @@ -1,12 +1,13 @@ -import os def add_username_segment(): - user_prompts = { - 'bash': ' \\u', - 'zsh': ' %n', - 'bare': ' %s' % os.getenv('USER') - } - powerline.append(user_prompts[powerline.args.shell], Color.USERNAME_FG, - Color.USERNAME_BG) + if powerline.args.shell == 'bash': + user_prompt = ' \\u' + elif powerline.args.shell == 'zsh': + user_prompt = ' %n' + else: + import os + user_prompt = ' %s' % os.getenv('USER') + + powerline.append(user_prompt, Color.USERNAME_FG, Color.USERNAME_BG) add_username_segment() From 1bcb583d48ac54d2fa1cd6e50676d3a775b15604 Mon Sep 17 00:00:00 2001 From: Shrey Banga Date: Mon, 20 May 2013 03:02:12 -0700 Subject: [PATCH 036/366] Adding jobs segment --- config.py | 3 +++ segments/jobs.py | 13 +++++++++++++ themes/basic.py | 3 +++ themes/default.py | 3 +++ themes/solarized-dark.py | 3 +++ 5 files changed, 25 insertions(+) create mode 100644 segments/jobs.py diff --git a/config.py b/config.py index 38d08b21..a191d5ad 100644 --- a/config.py +++ b/config.py @@ -32,6 +32,9 @@ # Show the current fossil branch and status 'fossil', +# Show number of running jobs + 'jobs', + # Shows a '#' if the current user is root, '$' otherwise # Also, changes color if the last command exited with a non-zero error code 'root', diff --git a/segments/jobs.py b/segments/jobs.py new file mode 100644 index 00000000..b0069fd0 --- /dev/null +++ b/segments/jobs.py @@ -0,0 +1,13 @@ +import os +import re +import subprocess + +def add_jobs_segment(): + ppid = os.getppid() + output = subprocess.Popen(['ps', '-a', '-o', 'ppid'], stdout=subprocess.PIPE).communicate()[0] + num_jobs = len(re.findall(str(ppid), output)) - 1 + + if num_jobs > 0: + powerline.append(' %d ' % num_jobs, Color.JOBS_FG, Color.JOBS_BG) + +add_jobs_segment() diff --git a/themes/basic.py b/themes/basic.py index 8db1a93c..92aad22a 100644 --- a/themes/basic.py +++ b/themes/basic.py @@ -17,6 +17,9 @@ class Color: REPO_DIRTY_BG = 1 # red REPO_DIRTY_FG = 15 # white + JOBS_FG = 14 + JOBS_BG = 8 + CMD_PASSED_BG = 8 CMD_PASSED_FG = 15 CMD_FAILED_BG = 11 diff --git a/themes/default.py b/themes/default.py index c0a43e0f..e8a681aa 100644 --- a/themes/default.py +++ b/themes/default.py @@ -15,6 +15,9 @@ class Color: REPO_DIRTY_BG = 161 # pink/red REPO_DIRTY_FG = 15 # white + JOBS_FG = 39 + JOBS_BG = 238 + CMD_PASSED_BG = 236 CMD_PASSED_FG = 15 CMD_FAILED_BG = 161 diff --git a/themes/solarized-dark.py b/themes/solarized-dark.py index 0ce78670..de9b1ce1 100644 --- a/themes/solarized-dark.py +++ b/themes/solarized-dark.py @@ -15,6 +15,9 @@ class Color: REPO_DIRTY_FG = 3 REPO_DIRTY_BG = 0 + JOBS_FG = 4 + JOBS_BG = 8 + CMD_PASSED_FG = 15 CMD_PASSED_BG = 2 CMD_FAILED_FG = 15 From 935e9c01f47df72c00f8e48d1d86d94d8c1ffb6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20=C5=9Awi=C4=99cicki?= Date: Sat, 15 Jun 2013 20:18:52 +0300 Subject: [PATCH 037/366] Update README.md Info about powerline-shell under python2.6 --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 82d932e3..82a505bc 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,10 @@ setting your $TERM to xterm-256color, because that works for me. 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 + ### Bash: Add the following to your `.bashrc`: From 4f0ac7a3b17a076c3b1617208198b48bef1005a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rcio=20Almada?= Date: Sun, 16 Jun 2013 15:36:24 -0300 Subject: [PATCH 038/366] Adding php_version segment --- segments/php_version.py | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 segments/php_version.py diff --git a/segments/php_version.py b/segments/php_version.py new file mode 100644 index 00000000..ae166324 --- /dev/null +++ b/segments/php_version.py @@ -0,0 +1,11 @@ +import subprocess + + +def add_php_version_segment(): + try: + version = ' %s ' % subprocess.check_output(['php', '--version'], stderr=subprocess.STDOUT).split(' ')[1] + powerline.append(version, 15, 4) + except OSError: + return + +add_php_version_segment() From 7afba0fdf47d95a070816d3340c5731fb2f5e1cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rcio=20Almada?= Date: Sun, 16 Jun 2013 17:35:51 -0300 Subject: [PATCH 039/366] Improving php_version segment: better way to get version number --- segments/php_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/segments/php_version.py b/segments/php_version.py index ae166324..2b89f304 100644 --- a/segments/php_version.py +++ b/segments/php_version.py @@ -3,7 +3,7 @@ def add_php_version_segment(): try: - version = ' %s ' % subprocess.check_output(['php', '--version'], stderr=subprocess.STDOUT).split(' ')[1] + version = ' %s ' % subprocess.check_output(['php', '-r', 'echo PHP_VERSION;'], stderr=subprocess.STDOUT) powerline.append(version, 15, 4) except OSError: return From b03c98f53eb1e5d33e84dc4fe1619b8155ca1b17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rcio=20Almada?= Date: Sun, 16 Jun 2013 17:36:31 -0300 Subject: [PATCH 040/366] Adding ruby_version segment --- segments/ruby_version.py | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 segments/ruby_version.py diff --git a/segments/ruby_version.py b/segments/ruby_version.py new file mode 100644 index 00000000..fd76593b --- /dev/null +++ b/segments/ruby_version.py @@ -0,0 +1,11 @@ +import subprocess + + +def add_php_version_segment(): + try: + version = ' %s ' % subprocess.check_output(['ruby', '-e', 'print RUBY_VERSION'], stderr=subprocess.STDOUT) + powerline.append(version, 15, 1) + except OSError: + return + +add_php_version_segment() From df4dc2e443949f202dca4922930e04ae7b694478 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rcio=20Almada?= Date: Mon, 17 Jun 2013 10:58:14 -0300 Subject: [PATCH 041/366] Fixed php_version segment: wrong php version number when running on Ubuntu with system wide PHP installation --- segments/php_version.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/segments/php_version.py b/segments/php_version.py index 2b89f304..ee174047 100644 --- a/segments/php_version.py +++ b/segments/php_version.py @@ -3,7 +3,12 @@ def add_php_version_segment(): try: - version = ' %s ' % subprocess.check_output(['php', '-r', 'echo PHP_VERSION;'], stderr=subprocess.STDOUT) + 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 From 2a84ecc29d78813f7e4d8357d17f1312f151756c Mon Sep 17 00:00:00 2001 From: Jon San Miguel Date: Wed, 10 Jul 2013 15:37:42 -0700 Subject: [PATCH 042/366] Update patched character codes --- powerline-shell.py.template | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/powerline-shell.py.template b/powerline-shell.py.template index e2518fd4..6c1cb403 100755 --- a/powerline-shell.py.template +++ b/powerline-shell.py.template @@ -15,8 +15,8 @@ class Powerline: 'separator_thin': u'\u276F' }, 'patched': { - 'separator': u'\u2B80', - 'separator_thin': u'\u2B81' + 'separator': u'\uE0B0', + 'separator_thin': u'\uE0B1' }, 'flat': { 'separator': '', From ab35ff5cffbcc27c07c9b7316256caca8f8f3b5f Mon Sep 17 00:00:00 2001 From: Shrey Banga Date: Thu, 11 Jul 2013 13:38:40 -0700 Subject: [PATCH 043/366] Fixing #79 --- install.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.py b/install.py index e878f7ff..70f96f39 100755 --- a/install.py +++ b/install.py @@ -12,7 +12,7 @@ def load_source(srcfile): try: return ''.join(open(srcfile).readlines()) + '\n\n' except IOError: - print 'Could not open ' + srcfile + print 'Could not open', srcfile return '' if __name__ == "__main__": From 261ab159df20b8046680aff8ccccc3213b3a5b6d Mon Sep 17 00:00:00 2001 From: ascherger Date: Mon, 15 Jul 2013 18:43:00 -0500 Subject: [PATCH 044/366] updated method naming and now supports showing patch levels --- segments/ruby_version.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/segments/ruby_version.py b/segments/ruby_version.py index fd76593b..e6598287 100644 --- a/segments/ruby_version.py +++ b/segments/ruby_version.py @@ -1,11 +1,13 @@ import subprocess -def add_php_version_segment(): +def add_ruby_version_segment(): try: - version = ' %s ' % subprocess.check_output(['ruby', '-e', 'print RUBY_VERSION'], stderr=subprocess.STDOUT) + p1 = subprocess.Popen(["ruby", "-v"], stdout=subprocess.PIPE) + p2 = subprocess.Popen(["sed", "s/ (.*//"], stdin=p1.stdout, stdout=subprocess.PIPE) + version = p2.communicate()[0].rstrip() powerline.append(version, 15, 1) except OSError: return -add_php_version_segment() +add_ruby_version_segment() From 5d4e38b9a55185223a90a32382f853ab8dc9f400 Mon Sep 17 00:00:00 2001 From: flyinprogramer Date: Tue, 16 Jul 2013 10:06:28 -0500 Subject: [PATCH 045/366] added support for gemsets which are a thing for RVM --- segments/ruby_version.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/segments/ruby_version.py b/segments/ruby_version.py index e6598287..64b5551b 100644 --- a/segments/ruby_version.py +++ b/segments/ruby_version.py @@ -6,6 +6,10 @@ def add_ruby_version_segment(): p1 = subprocess.Popen(["ruby", "-v"], stdout=subprocess.PIPE) p2 = subprocess.Popen(["sed", "s/ (.*//"], stdin=p1.stdout, stdout=subprocess.PIPE) version = p2.communicate()[0].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 From 1b538b83ab487db6521416b1ca4461fe00edf66a Mon Sep 17 00:00:00 2001 From: "H. Ryan Jones" Date: Sat, 20 Jul 2013 05:22:06 -0700 Subject: [PATCH 046/366] initial commit of colorizing by hostname feature --- lib/__init__.py | 0 lib/color_compliment.py | 25 +++ lib/colortrans.py | 321 +++++++++++++++++++++++++++++++++ segments/hostname_colorized.py | 12 ++ 4 files changed, 358 insertions(+) create mode 100644 lib/__init__.py create mode 100755 lib/color_compliment.py create mode 100755 lib/colortrans.py create mode 100644 segments/hostname_colorized.py diff --git a/lib/__init__.py b/lib/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/lib/color_compliment.py b/lib/color_compliment.py new file mode 100755 index 00000000..5fc39814 --- /dev/null +++ b/lib/color_compliment.py @@ -0,0 +1,25 @@ +#! /usr/bin/env python + +from colortrans import * +from colorsys import hls_to_rgb, rgb_to_hls +from md5 import md5 +from sys import argv + + +def getOppositeColor(r,g,b): + hls = rgb_to_hls(r,g,b) + opp = list(hls[:]) + opp[0] = 255-opp[0] # reverse 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 + else: + opp[1] += 255/2 + opp[1], 255-opp[2] + opp = ( int(x) for x in opp) + return hls_to_rgb(*opp) + +def stringToHashToColorAndOpposite(string): + string = md5(string).hexdigest()[:6] # get a random color + color1 = rgbstring2tuple(string) + color2 = getOppositeColor(*color1) + return color1, color2 diff --git a/lib/colortrans.py b/lib/colortrans.py new file mode 100755 index 00000000..cea78919 --- /dev/null +++ b/lib/colortrans.py @@ -0,0 +1,321 @@ +#! /usr/bin/env python + +""" Convert values between RGB hex codes and xterm-256 color codes. + +Nice long listing of all 256 colors and their codes. Useful for +developing console color themes, or even script output schemes. + +Resources: +* http://en.wikipedia.org/wiki/8-bit_color +* http://en.wikipedia.org/wiki/ANSI_escape_code +* /usr/share/X11/rgb.txt + +I'm not sure where this script was inspired from. I think I must have +written it from scratch, though it's been several years now. +""" + +__author__ = 'Micah Elliott http://MicahElliott.com' +__version__ = '0.1' +__copyright__ = 'Copyright (C) 2011 Micah Elliott. All rights reserved.' +__license__ = 'WTFPL http://sam.zoy.org/wtfpl/' + +#--------------------------------------------------------------------- + + +def hexstr2num(hexstr): + return int(hexstr, 16) + +def rgbstring2tuple(s): + return tuple([hexstr2num(h) for h in (s[:2], s[2:4], s[4:])]) + +RGB2SHORT_DICT = { + (0, 0, 0): 16, + (0, 0, 95): 17, + (0, 0, 128): 4, + (0, 0, 135): 18, + (0, 0, 175): 19, + (0, 0, 215): 20, + (0, 0, 255): 12, + (0, 95, 0): 22, + (0, 95, 95): 23, + (0, 95, 135): 24, + (0, 95, 175): 25, + (0, 95, 215): 26, + (0, 95, 255): 27, + (0, 128, 0): 2, + (0, 128, 128): 6, + (0, 135, 0): 28, + (0, 135, 95): 29, + (0, 135, 135): 30, + (0, 135, 175): 31, + (0, 135, 215): 32, + (0, 135, 255): 33, + (0, 175, 0): 34, + (0, 175, 95): 35, + (0, 175, 135): 36, + (0, 175, 175): 37, + (0, 175, 215): 38, + (0, 175, 255): 39, + (0, 215, 0): 40, + (0, 215, 95): 41, + (0, 215, 135): 42, + (0, 215, 175): 43, + (0, 215, 215): 44, + (0, 215, 255): 45, + (0, 255, 0): 46, + (0, 255, 95): 47, + (0, 255, 135): 48, + (0, 255, 175): 49, + (0, 255, 215): 50, + (0, 255, 255): 14, + (8, 8, 8): 232, + (18, 18, 18): 233, + (28, 28, 28): 234, + (38, 38, 38): 235, + (48, 48, 48): 236, + (58, 58, 58): 237, + (68, 68, 68): 238, + (78, 78, 78): 239, + (88, 88, 88): 240, + (95, 0, 0): 52, + (95, 0, 95): 53, + (95, 0, 135): 54, + (95, 0, 175): 55, + (95, 0, 215): 56, + (95, 0, 255): 57, + (95, 95, 0): 58, + (95, 95, 95): 59, + (95, 95, 135): 60, + (95, 95, 175): 61, + (95, 95, 215): 62, + (95, 95, 255): 63, + (95, 135, 0): 64, + (95, 135, 95): 65, + (95, 135, 135): 66, + (95, 135, 175): 67, + (95, 135, 215): 68, + (95, 135, 255): 69, + (95, 175, 0): 70, + (95, 175, 95) : 71, + (95, 175, 135): 72, + (95, 175, 175): 73, + (95, 175, 215): 74, + (95, 175, 255): 75, + (95, 215, 0): 76, + (95, 215, 95) : 77, + (95, 215, 135): 78, + (95, 215, 175): 79, + (95, 215, 215): 80, + (95, 215, 255): 81, + (95, 255, 0): 82, + (95, 255, 95) : 83, + (95, 255, 135): 84, + (95, 255, 175): 85, + (95, 255, 215): 86, + (95, 255, 255): 87, + (98, 98, 98): 241, + (108, 108, 108): 242, + (118, 118, 118): 243, + (128, 0, 0): 1, + (128, 0, 128): 5, + (128, 128, 0): 3, + (128, 128, 128): 244, + (135, 0, 0): 88, + (135, 0, 95): 89, + (135, 0, 135): 90, + (135, 0, 175): 91, + (135, 0, 215): 92, + (135, 0, 255): 93, + (135, 95, 0): 94, + (135, 95, 95): 95, + (135, 95, 135): 96, + (135, 95, 175): 97, + (135, 95, 215): 98, + (135, 95, 255): 99, + (135, 135, 0): 100, + (135, 135, 95): 101, + (135, 135, 135): 102, + (135, 135, 175): 103, + (135, 135, 215): 104, + (135, 135, 255): 105, + (135, 175, 0): 106, + (135, 175, 95): 107, + (135, 175, 135): 108, + (135, 175, 175): 109, + (135, 175, 215): 110, + (135, 175, 255): 111, + (135, 215, 0): 112, + (135, 215, 95): 113, + (135, 215, 135): 114, + (135, 215, 175): 115, + (135, 215, 215): 116, + (135, 215, 255): 117, + (135, 255, 0): 118, + (135, 255, 95): 119, + (135, 255, 135): 120, + (135, 255, 175): 121, + (135, 255, 215): 122, + (135, 255, 255): 123, + (138, 138, 138): 245, + (148, 148, 148): 246, + (158, 158, 158): 247, + (168, 168, 168): 248, + (175, 0, 0): 124, + (175, 0, 95): 125, + (175, 0, 135): 126, + (175, 0, 175): 127, + (175, 0, 215): 128, + (175, 0, 255): 129, + (175, 95, 0): 130, + (175, 95, 95): 131, + (175, 95, 135): 132, + (175, 95, 175): 133, + (175, 95, 215): 134, + (175, 95, 255): 135, + (175, 135, 0): 136, + (175, 135, 95): 137, + (175, 135, 135): 138, + (175, 135, 175): 139, + (175, 135, 215): 140, + (175, 135, 255): 141, + (175, 175, 0): 142, + (175, 175, 95): 143, + (175, 175, 135): 144, + (175, 175, 175): 145, + (175, 175, 215): 146, + (175, 175, 255): 147, + (175, 215, 0): 148, + (175, 215, 95): 149, + (175, 215, 135): 150, + (175, 215, 175): 151, + (175, 215, 215): 152, + (175, 215, 255): 153, + (175, 255, 0): 154, + (175, 255, 95): 155, + (175, 255, 135): 156, + (175, 255, 175): 157, + (175, 255, 215): 158, + (175, 255, 255): 159, + (178, 178, 178): 249, + (188, 188, 188): 250, + (192, 192, 192): 7, + (198, 198, 198): 251, + (208, 208, 208): 252, + (215, 0, 0): 160, + (215, 0, 95): 161, + (215, 0, 135): 162, + (215, 0, 175): 163, + (215, 0, 215): 164, + (215, 0, 255): 165, + (215, 95, 0): 166, + (215, 95, 95): 167, + (215, 95, 135): 168, + (215, 95, 175): 169, + (215, 95, 215): 170, + (215, 95, 255): 171, + (215, 135, 0): 172, + (215, 135, 95): 173, + (215, 135, 135): 174, + (215, 135, 175): 175, + (215, 135, 215): 176, + (215, 135, 255): 177, + (215, 175, 0): 178, + (215, 175, 95): 179, + (215, 175, 135): 180, + (215, 175, 175): 181, + (215, 175, 215): 182, + (215, 175, 255): 183, + (215, 215, 0): 184, + (215, 215, 95): 185, + (215, 215, 135): 186, + (215, 215, 175): 187, + (215, 215, 215): 188, + (215, 215, 255): 189, + (215, 255, 0): 190, + (215, 255, 95): 191, + (215, 255, 135): 192, + (215, 255, 175): 193, + (215, 255, 215): 194, + (215, 255, 255): 195, + (218, 218, 218): 253, + (228, 228, 228): 254, + (238, 238, 238): 255, + (255, 0, 0): 196, + (255, 0, 95): 197, + (255, 0, 135): 198, + (255, 0, 175): 199, + (255, 0, 215): 200, + (255, 0, 255): 13, + (255, 95, 0): 202, + (255, 95, 95): 203, + (255, 95, 135): 204, + (255, 95, 175): 205, + (255, 95, 215): 206, + (255, 95, 255): 207, + (255, 135, 0): 208, + (255, 135, 95): 209, + (255, 135, 135): 210, + (255, 135, 175): 211, + (255, 135, 215): 212, + (255, 135, 255): 213, + (255, 175, 0): 214, + (255, 175, 95): 215, + (255, 175, 135): 216, + (255, 175, 175): 217, + (255, 175, 215): 218, + (255, 175, 255): 219, + (255, 215, 0): 220, + (255, 215, 95): 221, + (255, 215, 135): 222, + (255, 215, 175): 223, + (255, 215, 215): 224, + (255, 215, 255): 225, + (255, 255, 0): 11, + (255, 255, 95): 227, + (255, 255, 135): 228, + (255, 255, 175): 229, + (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 + @returns: integer between 0 and 255, compatible with xterm. + >>> rgb2short(18, 52, 86) + 23 + >>> rgb2short(255, 255, 255) + 231 + >>> rgb2short(13, 173, 214) # vimeo logo + 38 + """ + incs = (0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff) + # Break 6-char RGB code into 3 integer vals. + parts = [ r, g, b] + res = [] + for part in parts: + i = 0 + while i < len(incs)-1: + s, b = incs[i], incs[i+1] # smaller, bigger + if s <= part <= b: + s1 = abs(s - part) + b1 = abs(b - part) + if s1 < b1: closest = s + else: closest = b + res.append(closest) + break + i += 1 + #print '***', res + #res = ''.join([ ('%02.x' % i) for i in res ]) + #equiv = RGB2SHORT_DICT[ res ] + #print '***', res, equiv + return RGB2SHORT_DICT[tuple(res)] + +#--------------------------------------------------------------------- + +if __name__ == '__main__': + import doctest + doctest.testmod() diff --git a/segments/hostname_colorized.py b/segments/hostname_colorized.py new file mode 100644 index 00000000..152283e1 --- /dev/null +++ b/segments/hostname_colorized.py @@ -0,0 +1,12 @@ +def add_hostname_segment(): + 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) + +add_hostname_segment() From 5eae65004c7f1aa0b421a59caafe6732a58a26f5 Mon Sep 17 00:00:00 2001 From: "H. Ryan Jones" Date: Sat, 20 Jul 2013 05:48:27 -0700 Subject: [PATCH 047/366] testing hostname coloring on other machines --- config.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config.py b/config.py index a191d5ad..0286a4ad 100644 --- a/config.py +++ b/config.py @@ -14,7 +14,8 @@ 'username', # Show the machine's hostname. Mostly used when ssh-ing into other machines - 'hostname', + #'hostname', + 'hostname_colorized', # colorize based on a hash of the hostname # Show the current directory. If the path is too long, the middle part is # replaced with ellipsis ('...') From 7e289bedcc5e9c5966a0ef7d200ea04091fc5787 Mon Sep 17 00:00:00 2001 From: "H. Ryan Jones" Date: Sat, 20 Jul 2013 06:46:50 -0700 Subject: [PATCH 048/366] Tweaking of opposite color picker, also fixed a bug causing RGB values to go over 255 --- lib/color_compliment.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/lib/color_compliment.py b/lib/color_compliment.py index 5fc39814..988684ca 100755 --- a/lib/color_compliment.py +++ b/lib/color_compliment.py @@ -8,15 +8,23 @@ def getOppositeColor(r,g,b): hls = rgb_to_hls(r,g,b) + #print "hls is" + #print hls opp = list(hls[:]) - opp[0] = 255-opp[0] # reverse hue (a.k.a. color) + #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 else: opp[1] += 255/2 - opp[1], 255-opp[2] - opp = ( int(x) for x in opp) - return hls_to_rgb(*opp) + 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 + opp = [ x*254/m for x in opp] + return tuple([ int(x) for x in opp]) def stringToHashToColorAndOpposite(string): string = md5(string).hexdigest()[:6] # get a random color From 5900b364e06d1e4f6162ef5e23f3b42caeba1d2c Mon Sep 17 00:00:00 2001 From: "H. Ryan Jones" Date: Sat, 20 Jul 2013 07:30:43 -0700 Subject: [PATCH 049/366] Small update to the doc string at the top --- lib/colortrans.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/colortrans.py b/lib/colortrans.py index cea78919..0e2922cb 100755 --- a/lib/colortrans.py +++ b/lib/colortrans.py @@ -1,6 +1,10 @@ #! /usr/bin/env python -""" Convert values between RGB hex codes and xterm-256 color codes. +""" +Code is modified (fairly heavily) by hryanjones@gmail.com from +https://gist.github.com/MicahElliott/719710 + +Convert values between RGB tuples and xterm-256 color codes. Nice long listing of all 256 colors and their codes. Useful for developing console color themes, or even script output schemes. @@ -309,9 +313,6 @@ def rgb2short(r, g, b): break i += 1 #print '***', res - #res = ''.join([ ('%02.x' % i) for i in res ]) - #equiv = RGB2SHORT_DICT[ res ] - #print '***', res, equiv return RGB2SHORT_DICT[tuple(res)] #--------------------------------------------------------------------- From f68e02d17f80da29f812037fc9925038cf947724 Mon Sep 17 00:00:00 2001 From: "H. Ryan Jones" Date: Sat, 20 Jul 2013 07:43:26 -0700 Subject: [PATCH 050/366] actually had meant to make the normal hostname the default --- config.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.py b/config.py index 0286a4ad..8f5b8cd4 100644 --- a/config.py +++ b/config.py @@ -14,8 +14,8 @@ 'username', # Show the machine's hostname. Mostly used when ssh-ing into other machines - #'hostname', - 'hostname_colorized', # colorize based on a hash of the hostname + 'hostname', + #'hostname_colorized', # colorize based on a hash of the hostname # Show the current directory. If the path is too long, the middle part is # replaced with ellipsis ('...') From 291023283de57767fb63d5d570e99580bbc43a88 Mon Sep 17 00:00:00 2001 From: David Stoline Date: Mon, 22 Jul 2013 14:34:52 -0400 Subject: [PATCH 051/366] Don't clobber customizations when an update is made to config.py upstream. --- .gitignore | 1 + config.py => config.py.dist | 0 install.py | 5 +++++ 3 files changed, 6 insertions(+) rename config.py => config.py.dist (100%) diff --git a/.gitignore b/.gitignore index 25a014d8..59291234 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ powerline-shell.py *.py[co] +config.py diff --git a/config.py b/config.py.dist similarity index 100% rename from config.py rename to config.py.dist diff --git a/install.py b/install.py index 70f96f39..a152877d 100755 --- a/install.py +++ b/install.py @@ -16,6 +16,11 @@ def load_source(srcfile): return '' if __name__ == "__main__": + try: + with open('config.py'): pass + except IOError: + print 'Please copy config.py.dist to config.py and retry.' + exit(1) source = load_source(TEMPLATE_FILE) source += load_source(os.path.join(THEMES_DIR, config.THEME + '.py')) for segment in config.SEGMENTS: From c81d075dd11591e6b68f3f1444d80200db24bfad Mon Sep 17 00:00:00 2001 From: David Stoline Date: Mon, 22 Jul 2013 21:01:50 -0400 Subject: [PATCH 052/366] Create a config.py rather than having people do it manually. --- install.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/install.py b/install.py index a152877d..6e534d6b 100755 --- a/install.py +++ b/install.py @@ -2,6 +2,7 @@ import os import stat import config +import shutil TEMPLATE_FILE = 'powerline-shell.py.template' OUTPUT_FILE = 'powerline-shell.py' @@ -19,8 +20,8 @@ def load_source(srcfile): try: with open('config.py'): pass except IOError: - print 'Please copy config.py.dist to config.py and retry.' - exit(1) + print 'Created personal config.py for your customizations' + shutil.copyfile('config.py.dist', 'config.py') source = load_source(TEMPLATE_FILE) source += load_source(os.path.join(THEMES_DIR, config.THEME + '.py')) for segment in config.SEGMENTS: @@ -34,3 +35,4 @@ def load_source(srcfile): print OUTPUT_FILE, 'saved successfully' except IOError: print 'ERROR: Could not write to powerline-shell.py. Make sure it is writable' + exit(1) From 4a3194dd96ec1c948d1ccaac30ece7924019ca4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20=C5=9Awi=C4=99cicki?= Date: Wed, 24 Jul 2013 12:11:45 +0200 Subject: [PATCH 053/366] Fix ImportError for config --- install.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/install.py b/install.py index 6e534d6b..0fa1942b 100755 --- a/install.py +++ b/install.py @@ -1,8 +1,14 @@ #!/usr/bin/env python import os import stat -import config -import shutil + +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.py.template' OUTPUT_FILE = 'powerline-shell.py' @@ -17,11 +23,6 @@ def load_source(srcfile): return '' if __name__ == "__main__": - try: - with open('config.py'): pass - except IOError: - print 'Created personal config.py for your customizations' - shutil.copyfile('config.py.dist', 'config.py') source = load_source(TEMPLATE_FILE) source += load_source(os.path.join(THEMES_DIR, config.THEME + '.py')) for segment in config.SEGMENTS: From 401bb9d0938b58bb137e8112007e61923cf1ecc5 Mon Sep 17 00:00:00 2001 From: "H. Ryan Jones" Date: Fri, 26 Jul 2013 23:49:03 -0700 Subject: [PATCH 054/366] Reworked method for enabling colorized hostname feature, updated README --- README.md | 21 ++++++++++++++++++--- config.py | 1 - powerline-shell.py.template | 2 ++ segments/hostname.py | 26 +++++++++++++++++++------- segments/hostname_colorized.py | 12 ------------ 5 files changed, 39 insertions(+), 23 deletions(-) delete mode 100644 segments/hostname_colorized.py diff --git a/README.md b/README.md index 82a505bc..e2300821 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,8 @@ setting your $TERM to xterm-256color, because that works for me. * Patch the font you use for your terminal: see https://github.com/Lokaltog/vim-powerline/wiki/Patched-fonts + * If you struggle too much to get working fonts in your terminal, you can use "compatible" mode. + * Clone this repository somewhere: git clone https://github.com/milkbikis/powerline-shell @@ -30,18 +32,31 @@ setting your $TERM to xterm-256color, because that works for me. ./install.py - This will generate `powerline-shell.py` + * This will generate `powerline-shell.py` -* Create a symlink to this python script in your home: +* (optional) Create a symlink to this python script in your home: ln -s ~/powerline-shell.py - If you don't want the symlink, just modify the path in the commands below + * 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`. + +``` + --cwd-only Only show the current directory + --cwd-max-depth CWD_MAX_DEPTH + Maximum number of directories to show in path + --colorize-hostname Colorize the hostname based on a hash of itself. + --mode {patched,compatible,flat} + The characters used to make separators between + segments +``` + ### Bash: Add the following to your `.bashrc`: diff --git a/config.py b/config.py index 8f5b8cd4..a191d5ad 100644 --- a/config.py +++ b/config.py @@ -15,7 +15,6 @@ # Show the machine's hostname. Mostly used when ssh-ing into other machines 'hostname', - #'hostname_colorized', # colorize based on a hash of the hostname # Show the current directory. If the path is too long, the middle part is # replaced with ellipsis ('...') diff --git a/powerline-shell.py.template b/powerline-shell.py.template index 6c1cb403..66087a4d 100755 --- a/powerline-shell.py.template +++ b/powerline-shell.py.template @@ -100,6 +100,8 @@ if __name__ == "__main__": help='Only show the current directory') 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('--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']) diff --git a/segments/hostname.py b/segments/hostname.py index 4b5f24ee..7b90b28f 100644 --- a/segments/hostname.py +++ b/segments/hostname.py @@ -1,12 +1,24 @@ def add_hostname_segment(): - if powerline.args.shell == 'bash': - host_prompt = ' \\h' - elif powerline.args.shell == 'zsh': - host_prompt = ' %m' + 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: - import socket - host_prompt = ' %s' % socket.gethostname().split('.')[0] + 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) - powerline.append(host_prompt, Color.HOSTNAME_FG, Color.HOSTNAME_BG) add_hostname_segment() diff --git a/segments/hostname_colorized.py b/segments/hostname_colorized.py deleted file mode 100644 index 152283e1..00000000 --- a/segments/hostname_colorized.py +++ /dev/null @@ -1,12 +0,0 @@ -def add_hostname_segment(): - 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) - -add_hostname_segment() From 1641d543bfb0870d02d3e8c4c0860fd8b22bb8d9 Mon Sep 17 00:00:00 2001 From: Shrey Banga Date: Thu, 8 Aug 2013 17:02:38 -0700 Subject: [PATCH 055/366] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e2300821..21b90e30 100644 --- a/README.md +++ b/README.md @@ -20,9 +20,10 @@ 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/vim-powerline/wiki/Patched-fonts +* Patch the font you use for your terminal: see 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 * Clone this repository somewhere: From be1489feac1ccae5b167592b5bf8b578a6fc1135 Mon Sep 17 00:00:00 2001 From: Emmanuel Touzery Date: Sat, 31 Aug 2013 00:13:38 +0200 Subject: [PATCH 056/366] ability to color differently the home directly, inspired by powerline --- segments/cwd.py | 10 ++++++++-- themes/default.py | 2 ++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/segments/cwd.py b/segments/cwd.py index fedb1649..fb447b0e 100644 --- a/segments/cwd.py +++ b/segments/cwd.py @@ -22,8 +22,14 @@ def add_cwd_segment(): if not powerline.args.cwd_only: for n in names[:-1]: - powerline.append(' %s ' % n, Color.PATH_FG, Color.PATH_BG, + if n == '~': + powerline.append(' %s ' % n, Color.HOME_FG, Color.HOME_BG) + else: + powerline.append(' %s ' % n, Color.PATH_FG, Color.PATH_BG, powerline.separator_thin, Color.SEPARATOR_FG) - powerline.append(' %s ' % names[-1], Color.CWD_FG, Color.PATH_BG) + if names[-1] == '~': + powerline.append(' %s ' % names[-1], Color.HOME_FG, Color.HOME_BG) + else: + powerline.append(' %s ' % names[-1], Color.CWD_FG, Color.PATH_BG) add_cwd_segment() diff --git a/themes/default.py b/themes/default.py index e8a681aa..2cdb6408 100644 --- a/themes/default.py +++ b/themes/default.py @@ -5,6 +5,8 @@ class Color: HOSTNAME_FG = 250 HOSTNAME_BG = 238 + HOME_BG = 31 # blueish + HOME_FG = 15 # white PATH_BG = 237 # dark grey PATH_FG = 250 # light grey CWD_FG = 254 # nearly-white grey From 166f975a922f0a6b583e6000beb61de691e54d36 Mon Sep 17 00:00:00 2001 From: Emmanuel Touzery Date: Sat, 31 Aug 2013 07:08:34 +0200 Subject: [PATCH 057/366] make other themes behave properly after the special coloring for the home dir feature --- segments/cwd.py | 4 ++-- themes/basic.py | 1 + themes/default.py | 1 + themes/solarized-dark.py | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/segments/cwd.py b/segments/cwd.py index fb447b0e..d1d0aca2 100644 --- a/segments/cwd.py +++ b/segments/cwd.py @@ -22,12 +22,12 @@ def add_cwd_segment(): if not powerline.args.cwd_only: for n in names[:-1]: - if n == '~': + if n == '~' and Color.HOME_SPECIAL_DISPLAY: powerline.append(' %s ' % n, Color.HOME_FG, Color.HOME_BG) else: powerline.append(' %s ' % n, Color.PATH_FG, Color.PATH_BG, powerline.separator_thin, Color.SEPARATOR_FG) - if names[-1] == '~': + if names[-1] == '~' and Color.HOME_SPECIAL_DISPLAY: powerline.append(' %s ' % names[-1], Color.HOME_FG, Color.HOME_BG) else: powerline.append(' %s ' % names[-1], Color.CWD_FG, Color.PATH_BG) diff --git a/themes/basic.py b/themes/basic.py index 92aad22a..9fe97add 100644 --- a/themes/basic.py +++ b/themes/basic.py @@ -7,6 +7,7 @@ class Color: HOSTNAME_FG = 8 HOSTNAME_BG = 7 + HOME_SPECIAL_DISPLAY = False PATH_BG = 8 # dark grey PATH_FG = 7 # light grey CWD_FG = 15 # white diff --git a/themes/default.py b/themes/default.py index 2cdb6408..0f11fa97 100644 --- a/themes/default.py +++ b/themes/default.py @@ -5,6 +5,7 @@ class Color: HOSTNAME_FG = 250 HOSTNAME_BG = 238 + HOME_SPECIAL_DISPLAY = True HOME_BG = 31 # blueish HOME_FG = 15 # white PATH_BG = 237 # dark grey diff --git a/themes/solarized-dark.py b/themes/solarized-dark.py index de9b1ce1..fc90d564 100644 --- a/themes/solarized-dark.py +++ b/themes/solarized-dark.py @@ -5,6 +5,7 @@ class Color: HOSTNAME_FG = 15 HOSTNAME_BG = 10 + HOME_SPECIAL_DISPLAY = False PATH_FG = 7 PATH_BG = 10 CWD_FG = 15 From 9481d741ee8a04e7f12f89b1dc4dfefd3faca27e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rcio=20Almada?= Date: Mon, 2 Sep 2013 22:43:24 -0300 Subject: [PATCH 058/366] Added whitespace to avoid segment interpenetration in bash --- segments/hostname.py | 2 +- segments/username.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/segments/hostname.py b/segments/hostname.py index 7b90b28f..365872f7 100644 --- a/segments/hostname.py +++ b/segments/hostname.py @@ -11,7 +11,7 @@ def add_hostname_segment(): powerline.append(host_prompt, FG, BG) else: if powerline.args.shell == 'bash': - host_prompt = ' \\h' + host_prompt = ' \\h ' elif powerline.args.shell == 'zsh': host_prompt = ' %m' else: diff --git a/segments/username.py b/segments/username.py index 8dd438f6..73048436 100644 --- a/segments/username.py +++ b/segments/username.py @@ -1,7 +1,7 @@ def add_username_segment(): if powerline.args.shell == 'bash': - user_prompt = ' \\u' + user_prompt = ' \\u ' elif powerline.args.shell == 'zsh': user_prompt = ' %n' else: From 663453d131bdebaf069140085f993ca15d928b79 Mon Sep 17 00:00:00 2001 From: Saswat Padhi Date: Sun, 15 Sep 2013 05:40:37 +0530 Subject: [PATCH 059/366] Added ReadOnly segment + The segment displays a padlock (in patched mode), or 'RO' (in compatibility mode). ! Added a condition for showing / if that is the only path. The CWD segment earlier showed nothing, which I think is not very consistent. --- config.py.dist | 4 ++++ powerline-shell.py.template | 4 ++++ segments/cwd.py | 6 ++++-- segments/read_only.py | 9 +++++++++ themes/basic.py | 3 +++ themes/default.py | 3 +++ themes/solarized-dark.py | 3 +++ 7 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 segments/read_only.py diff --git a/config.py.dist b/config.py.dist index a191d5ad..95ecdf77 100644 --- a/config.py.dist +++ b/config.py.dist @@ -20,6 +20,10 @@ SEGMENTS = [ # 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', diff --git a/powerline-shell.py.template b/powerline-shell.py.template index 66087a4d..c8dbedfb 100755 --- a/powerline-shell.py.template +++ b/powerline-shell.py.template @@ -11,14 +11,17 @@ def warn(msg): class Powerline: symbols = { 'compatible': { + 'lock': 'RO', 'separator': u'\u25B6', 'separator_thin': u'\u276F' }, 'patched': { + 'lock': u'\uE0A2', 'separator': u'\uE0B0', 'separator_thin': u'\uE0B1' }, 'flat': { + 'lock': '', 'separator': '', 'separator_thin': '' }, @@ -36,6 +39,7 @@ class Powerline: 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.separator = Powerline.symbols[mode]['separator'] self.separator_thin = Powerline.symbols[mode]['separator_thin'] self.segments = [] diff --git a/segments/cwd.py b/segments/cwd.py index d1d0aca2..70724b00 100644 --- a/segments/cwd.py +++ b/segments/cwd.py @@ -9,9 +9,10 @@ def get_short_path(cwd): path += os.sep + names[i] if os.path.samefile(path, home): return ['~'] + names[i+1:] + if not names[0]: + return ['/'] return names - def add_cwd_segment(): cwd = powerline.cwd or os.getenv('PWD') names = get_short_path(cwd.decode('utf-8')) @@ -22,11 +23,12 @@ def add_cwd_segment(): if not powerline.args.cwd_only: for n in names[:-1]: - if n == '~' and Color.HOME_SPECIAL_DISPLAY: + if n == '~' and Color.HOME_SPECIAL_DISPLAY: powerline.append(' %s ' % n, Color.HOME_FG, Color.HOME_BG) else: powerline.append(' %s ' % n, Color.PATH_FG, Color.PATH_BG, powerline.separator_thin, Color.SEPARATOR_FG) + if names[-1] == '~' and Color.HOME_SPECIAL_DISPLAY: powerline.append(' %s ' % names[-1], Color.HOME_FG, Color.HOME_BG) else: diff --git a/segments/read_only.py b/segments/read_only.py new file mode 100644 index 00000000..bcb28f4c --- /dev/null +++ b/segments/read_only.py @@ -0,0 +1,9 @@ +import os + +def add_read_only_segment(): + 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) + +add_read_only_segment() diff --git a/themes/basic.py b/themes/basic.py index 9fe97add..ebf003ac 100644 --- a/themes/basic.py +++ b/themes/basic.py @@ -13,6 +13,9 @@ class Color: CWD_FG = 15 # white SEPARATOR_FG = 7 + READONLY_BG = 1 + READONLY_FG = 15 + REPO_CLEAN_BG = 2 # green REPO_CLEAN_FG = 0 # black REPO_DIRTY_BG = 1 # red diff --git a/themes/default.py b/themes/default.py index 0f11fa97..11ea3806 100644 --- a/themes/default.py +++ b/themes/default.py @@ -13,6 +13,9 @@ class Color: CWD_FG = 254 # nearly-white grey SEPARATOR_FG = 244 + READONLY_BG = 124 + READONLY_FG = 254 + REPO_CLEAN_BG = 148 # a light green color REPO_CLEAN_FG = 0 # black REPO_DIRTY_BG = 161 # pink/red diff --git a/themes/solarized-dark.py b/themes/solarized-dark.py index fc90d564..a14920c2 100644 --- a/themes/solarized-dark.py +++ b/themes/solarized-dark.py @@ -11,6 +11,9 @@ class Color: CWD_FG = 15 SEPARATOR_FG = 14 + READONLY_BG = 1 + READONLY_FG = 7 + REPO_CLEAN_FG = 14 REPO_CLEAN_BG = 0 REPO_DIRTY_FG = 3 From 86c8407f12939398e109652b1160645ebf08f9fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rcio=20Almada?= Date: Sat, 14 Sep 2013 21:40:19 -0300 Subject: [PATCH 060/366] New theme: washed --- themes/washed.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 themes/washed.py diff --git a/themes/washed.py b/themes/washed.py new file mode 100644 index 00000000..2b805c4c --- /dev/null +++ b/themes/washed.py @@ -0,0 +1,31 @@ +class Color: + USERNAME_FG = 8 + USERNAME_BG = 251 + + HOSTNAME_FG = 8 + HOSTNAME_BG = 7 + + HOME_SPECIAL_DISPLAY = False + PATH_BG = 15 + PATH_FG = 8 + CWD_FG = 8 + SEPARATOR_FG = 251 + + REPO_CLEAN_BG = 150 # pale green + REPO_CLEAN_FG = 0 + REPO_DIRTY_BG = 203 # pale red + REPO_DIRTY_FG = 15 + + JOBS_FG = 14 + JOBS_BG = 8 + + CMD_PASSED_BG = 7 + CMD_PASSED_FG = 8 + CMD_FAILED_BG = 9 + CMD_FAILED_FG = 15 + + SVN_CHANGES_BG = REPO_DIRTY_BG + SVN_CHANGES_FG = REPO_DIRTY_FG + + VIRTUAL_ENV_BG = 150 + VIRTUAL_ENV_FG = 0 From b36051265ef1111141eb47eca0714f2e41824e1c Mon Sep 17 00:00:00 2001 From: Saswat Padhi Date: Sun, 15 Sep 2013 06:45:46 +0530 Subject: [PATCH 061/366] Added error redirection to avoid stack traces. --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 21b90e30..567505df 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ There are a few optional arguments which can be seen by running `powerline-shell Add the following to your `.bashrc`: function _update_ps1() { - export PS1="$(~/powerline-shell.py $?)" + export PS1="$(~/powerline-shell.py $? 2> /dev/null)" } export PROMPT_COMMAND="_update_ps1" @@ -71,7 +71,7 @@ Add the following to your `.bashrc`: Add the following to your `.zshrc`: function powerline_precmd() { - export PS1="$(~/powerline-shell.py $? --shell zsh)" + export PS1="$(~/powerline-shell.py $? --shell zsh 2> /dev/null)" } function install_powerline_precmd() { @@ -89,7 +89,7 @@ Add the following to your `.zshrc`: Redefine `fish_prompt` in ~/.config/fish/config.fish: function fish_prompt - ~/powerline-shell.py $status --shell bare + ~/powerline-shell.py $status --shell bare ^/dev/null end # Customization From 719fe90845c20d57bbf609dd7fef8d70bb540967 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rcio=20Almada?= Date: Sun, 15 Sep 2013 20:33:38 -0300 Subject: [PATCH 062/366] minor color adjustment: green repo segment looks even more... washed --- themes/washed.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/themes/washed.py b/themes/washed.py index 2b805c4c..7025cb40 100644 --- a/themes/washed.py +++ b/themes/washed.py @@ -12,7 +12,7 @@ class Color: SEPARATOR_FG = 251 REPO_CLEAN_BG = 150 # pale green - REPO_CLEAN_FG = 0 + REPO_CLEAN_FG = 235 REPO_DIRTY_BG = 203 # pale red REPO_DIRTY_FG = 15 From b50642791293d65007afc96f68a2efba332aff9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rcio=20Almada?= Date: Sun, 15 Sep 2013 20:47:17 -0300 Subject: [PATCH 063/366] keeping spaces consistent across different terminals --- segments/hostname.py | 4 ++-- segments/username.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/segments/hostname.py b/segments/hostname.py index 365872f7..d19296e8 100644 --- a/segments/hostname.py +++ b/segments/hostname.py @@ -13,10 +13,10 @@ def add_hostname_segment(): if powerline.args.shell == 'bash': host_prompt = ' \\h ' elif powerline.args.shell == 'zsh': - host_prompt = ' %m' + host_prompt = ' %m ' else: import socket - host_prompt = ' %s' % socket.gethostname().split('.')[0] + host_prompt = ' %s ' % socket.gethostname().split('.')[0] powerline.append(host_prompt, Color.HOSTNAME_FG, Color.HOSTNAME_BG) diff --git a/segments/username.py b/segments/username.py index 73048436..30fd9635 100644 --- a/segments/username.py +++ b/segments/username.py @@ -3,10 +3,10 @@ def add_username_segment(): if powerline.args.shell == 'bash': user_prompt = ' \\u ' elif powerline.args.shell == 'zsh': - user_prompt = ' %n' + user_prompt = ' %n ' else: import os - user_prompt = ' %s' % os.getenv('USER') + user_prompt = ' %s ' % os.getenv('USER') powerline.append(user_prompt, Color.USERNAME_FG, Color.USERNAME_BG) From 51fbcf1dfbd1528b0739999c88b67243ab88c5b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rcio=20Almada?= Date: Sun, 15 Sep 2013 21:15:04 -0300 Subject: [PATCH 064/366] washed now supports read_only segment --- themes/washed.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/themes/washed.py b/themes/washed.py index 7025cb40..b2c6d685 100644 --- a/themes/washed.py +++ b/themes/washed.py @@ -11,6 +11,9 @@ class Color: CWD_FG = 8 SEPARATOR_FG = 251 + READONLY_BG = 209 + READONLY_FG = 15 + REPO_CLEAN_BG = 150 # pale green REPO_CLEAN_FG = 235 REPO_DIRTY_BG = 203 # pale red From fd331d0461a6c36c3fe6bcea9dc2484ad6d7e75f Mon Sep 17 00:00:00 2001 From: Saswat Padhi Date: Tue, 17 Sep 2013 01:39:53 +0530 Subject: [PATCH 065/366] Themes fall back to default.py for missing segment --- README.md | 9 +++++++-- install.py | 1 + themes/basic.py | 2 +- themes/default.py | 13 ++++++++++++- themes/solarized-dark.py | 2 +- 5 files changed, 22 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 567505df..5a7177d7 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ A [Powerline](https://github.com/Lokaltog/vim-powerline) like prompt for Bash, Z 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`, because that works for me. * Patch the font you use for your terminal: see https://github.com/Lokaltog/powerline-fonts @@ -114,10 +114,15 @@ 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 scenario. +Make sure you introduce new default colors in `themes/default.py` for every new +segment you create. Test your segment with this theme first. + ### Themes The `themes` directory stores themes for your prompt, which are basically color -values used by segments. Create a new theme by copying `themes/default.py` and +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. diff --git a/install.py b/install.py index 0fa1942b..6f239b69 100755 --- a/install.py +++ b/install.py @@ -24,6 +24,7 @@ def load_source(srcfile): if __name__ == "__main__": source = load_source(TEMPLATE_FILE) + source += load_source(os.path.join(THEMES_DIR, 'default.py')) 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')) diff --git a/themes/basic.py b/themes/basic.py index ebf003ac..846ad637 100644 --- a/themes/basic.py +++ b/themes/basic.py @@ -1,6 +1,6 @@ # Basic theme which only uses colors in 0-15 range -class Color: +class Color(DefaultColor): USERNAME_FG = 8 USERNAME_BG = 15 diff --git a/themes/default.py b/themes/default.py index 11ea3806..23413b2f 100644 --- a/themes/default.py +++ b/themes/default.py @@ -1,4 +1,8 @@ -class Color: +class DefaultColor: + """ + This class should have the default colors for every segment. + Please test every new segment with this theme first. + """ USERNAME_FG = 250 USERNAME_BG = 240 @@ -34,3 +38,10 @@ class Color: VIRTUAL_ENV_BG = 35 # a mid-tone green VIRTUAL_ENV_FG = 00 + +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 diff --git a/themes/solarized-dark.py b/themes/solarized-dark.py index a14920c2..48d0aedc 100644 --- a/themes/solarized-dark.py +++ b/themes/solarized-dark.py @@ -1,4 +1,4 @@ -class Color: +class Color(DefaultColor): USERNAME_FG = 15 USERNAME_BG = 4 From 714d687137c468676923ed094d8c41792454516a Mon Sep 17 00:00:00 2001 From: Saswat Padhi Date: Tue, 17 Sep 2013 16:38:48 +0530 Subject: [PATCH 066/366] Fixed jobs count for current shell We generate the entire prompt by evaluating the python script in a $() which creates a separate subprocess which is the parent of the Python process. The original shell is the parent of the $() subprocess. So, we need to get the grand parent id. --- segments/jobs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/segments/jobs.py b/segments/jobs.py index b0069fd0..3fae3dff 100644 --- a/segments/jobs.py +++ b/segments/jobs.py @@ -3,9 +3,9 @@ import subprocess def add_jobs_segment(): - ppid = os.getppid() + pppid = subprocess.Popen(['ps', '-p', str(os.getppid()), '-oppid='], stdout=subprocess.PIPE).communicate()[0].strip() output = subprocess.Popen(['ps', '-a', '-o', 'ppid'], stdout=subprocess.PIPE).communicate()[0] - num_jobs = len(re.findall(str(ppid), output)) - 1 + num_jobs = len(re.findall(str(pppid), output)) - 1 if num_jobs > 0: powerline.append(' %d ' % num_jobs, Color.JOBS_FG, Color.JOBS_BG) From 7df4e0888a7649510f30e8361b084d47b072cc8c Mon Sep 17 00:00:00 2001 From: Shrey Banga Date: Thu, 19 Sep 2013 04:29:26 -0700 Subject: [PATCH 067/366] Update washed.py --- themes/washed.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/themes/washed.py b/themes/washed.py index b2c6d685..32455d81 100644 --- a/themes/washed.py +++ b/themes/washed.py @@ -1,4 +1,4 @@ -class Color: +class Color(DefaultColor): USERNAME_FG = 8 USERNAME_BG = 251 From 3a07df1877cd56aa22a1cc83efa66e7145d0ef9e Mon Sep 17 00:00:00 2001 From: Alex Charron Date: Sun, 29 Sep 2013 16:43:17 -0400 Subject: [PATCH 068/366] Explicit Python 2. --- install.py | 2 +- themes/colortest.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/install.py b/install.py index 6f239b69..98db7617 100755 --- a/install.py +++ b/install.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 import os import stat diff --git a/themes/colortest.py b/themes/colortest.py index e3beca46..291966f9 100755 --- a/themes/colortest.py +++ b/themes/colortest.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 import sys ESCAPE = chr(27) From 60cf330b8c65dcb0bb653d167474eb232cc4b3d6 Mon Sep 17 00:00:00 2001 From: Shrey Banga Date: Thu, 10 Oct 2013 14:09:46 -0700 Subject: [PATCH 069/366] Update readme to mention config.py.dist --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5a7177d7..ed63c3cd 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ setting your $TERM to `xterm-256color`, because that works for me. git clone https://github.com/milkbikis/powerline-shell -* Configure the segments you want by editing `config.py`. Then run +* Copy `config.py.dist` to `config.py` and edit it to configure the segments you want. Then run ./install.py From 837ad970fadf11a2d0867c84c3968b1ad7a352fe Mon Sep 17 00:00:00 2001 From: Xfennec Date: Wed, 13 Nov 2013 18:25:51 +0100 Subject: [PATCH 070/366] Adding an SSH segment --- config.py.dist | 3 +++ powerline-shell.py.template | 4 ++++ segments/ssh.py | 8 ++++++++ themes/default.py | 3 +++ 4 files changed, 18 insertions(+) create mode 100644 segments/ssh.py diff --git a/config.py.dist b/config.py.dist index 95ecdf77..bad4143d 100644 --- a/config.py.dist +++ b/config.py.dist @@ -16,6 +16,9 @@ SEGMENTS = [ # 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', diff --git a/powerline-shell.py.template b/powerline-shell.py.template index c8dbedfb..6ddeb78e 100755 --- a/powerline-shell.py.template +++ b/powerline-shell.py.template @@ -12,16 +12,19 @@ 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': '' }, @@ -40,6 +43,7 @@ class Powerline: 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 = [] diff --git a/segments/ssh.py b/segments/ssh.py new file mode 100644 index 00000000..e90397a3 --- /dev/null +++ b/segments/ssh.py @@ -0,0 +1,8 @@ +import os + +def add_ssh_segment(): + + if os.getenv('SSH_CLIENT'): + powerline.append(' %s ' % powerline.network, Color.SSH_FG, Color.SSH_BG) + +add_ssh_segment() diff --git a/themes/default.py b/themes/default.py index 23413b2f..7b602aff 100644 --- a/themes/default.py +++ b/themes/default.py @@ -20,6 +20,9 @@ class DefaultColor: READONLY_BG = 124 READONLY_FG = 254 + SSH_BG = 166 # medium orange + SSH_FG = 254 + REPO_CLEAN_BG = 148 # a light green color REPO_CLEAN_FG = 0 # black REPO_DIRTY_BG = 161 # pink/red From 5f54301634cd27475b022658db365536962d6225 Mon Sep 17 00:00:00 2001 From: Filipe Barros Date: Thu, 21 Nov 2013 15:32:21 +0000 Subject: [PATCH 071/366] added support for time segment --- config.py.dist | 3 +++ segments/time.py | 12 ++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 segments/time.py diff --git a/config.py.dist b/config.py.dist index bad4143d..a24c592a 100644 --- a/config.py.dist +++ b/config.py.dist @@ -10,6 +10,9 @@ SEGMENTS = [ # Show current virtual environment (see http://www.virtualenv.org/) 'virtual_env', +# Show current time + 'time', + # Show the current user's username as in ordinary prompts 'username', diff --git a/segments/time.py b/segments/time.py new file mode 100644 index 00000000..68431504 --- /dev/null +++ b/segments/time.py @@ -0,0 +1,12 @@ +def add_time_segment(): + 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) + +add_time_segment() From 38ffe8770bd7612976ef0fdabfe0f728f8f3a097 Mon Sep 17 00:00:00 2001 From: Swizzlr Date: Tue, 10 Dec 2013 17:42:49 -0500 Subject: [PATCH 072/366] Edit readme to respect bashrc Term cwd code on Mac --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ed63c3cd..af8cb20d 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ A [Powerline](https://github.com/Lokaltog/vim-powerline) like prompt for Bash, Z # 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 +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 @@ -65,7 +65,7 @@ Add the following to your `.bashrc`: export PS1="$(~/powerline-shell.py $? 2> /dev/null)" } - export PROMPT_COMMAND="_update_ps1" + export PROMPT_COMMAND="_update_ps1; $PROMPT_COMMAND" ### ZSH: Add the following to your `.zshrc`: @@ -105,12 +105,12 @@ prompt immediately. ### Contributing new types of segments The `segments` directory contains python scripts which are injected as is into -a single file `powerline-shell.py.template`. Each segment script defines a +a single file `powerline-shell.py.template`. 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. -Make sure that your script does not introduce new globals which might conflict +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 scenario. From 2af442bfdf0c283af34334bc09c09dcde8572120 Mon Sep 17 00:00:00 2001 From: Shrey Banga Date: Fri, 27 Dec 2013 20:10:12 -0800 Subject: [PATCH 073/366] Make git segment faster --- segments/git.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/segments/git.py b/segments/git.py index 6d9cad25..1c8b5259 100644 --- a/segments/git.py +++ b/segments/git.py @@ -6,10 +6,10 @@ def get_git_status(): has_untracked_files = False origin_position = "" output = subprocess.Popen(['git', 'status', '--ignore-submodules'], - stdout=subprocess.PIPE).communicate()[0] + stdout=subprocess.PIPE).communicate()[0] for line in output.split('\n'): origin_status = re.findall( - r"Your branch is (ahead|behind).*?(\d+) comm", line) + r"Your branch is (ahead|behind).*?(\d+) comm", line) if origin_status: origin_position = " %d" % int(origin_status[0][1]) if origin_status[0][0] == 'behind': @@ -25,14 +25,18 @@ def get_git_status(): def add_git_segment(): - #cmd = "git branch 2> /dev/null | grep -e '\\*'" - p1 = subprocess.Popen(['git', 'branch', '--no-color'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - p2 = subprocess.Popen(['grep', '-e', '\\*'], stdin=p1.stdout, stdout=subprocess.PIPE) - output = p2.communicate()[0].strip() - if not output: + # See http://git-blame.blogspot.com/2013/06/checking-current-branch-programatically.html + p = subprocess.Popen(['git', 'symbolic-ref', '-q', 'HEAD'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out, err = p.communicate() + + if 'Not a git repo' in err: return - branch = output.rstrip()[2:] + if out: + branch = out[len('refs/heads/'):].rstrip() + else: + branch = '(Detached)' + has_pending_commits, has_untracked_files, origin_position = get_git_status() branch += origin_position if has_untracked_files: From a3975a4e42da8ae9c37a5016ea05c8f73a5a83b9 Mon Sep 17 00:00:00 2001 From: Adrian Vondendriesch Date: Sun, 12 Jan 2014 12:38:03 +0100 Subject: [PATCH 074/366] Use LANG='C' to prevent language specific git output. We must be sure we are able to parse the git status output. If we don't use this while calling popen we will get language specific output that we couldn't parse. --- segments/git.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/segments/git.py b/segments/git.py index 1c8b5259..ed7bf680 100644 --- a/segments/git.py +++ b/segments/git.py @@ -6,7 +6,7 @@ def get_git_status(): has_untracked_files = False origin_position = "" output = subprocess.Popen(['git', 'status', '--ignore-submodules'], - stdout=subprocess.PIPE).communicate()[0] + env={"LANG": "C"}, stdout=subprocess.PIPE).communicate()[0] for line in output.split('\n'): origin_status = re.findall( r"Your branch is (ahead|behind).*?(\d+) comm", line) From b656cf95b7b714c3193d2e03b1c3d5629ffc694f Mon Sep 17 00:00:00 2001 From: Shrey Banga Date: Tue, 28 Jan 2014 20:03:39 -0800 Subject: [PATCH 075/366] Create LICENSE --- LICENSE | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..271cb592 --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2014 Shrey Banga and contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. From 6ff6f3095aeedb55859ce1bad2fb39f0b8a93673 Mon Sep 17 00:00:00 2001 From: Jens Kehne Date: Mon, 3 Feb 2014 22:36:38 +0100 Subject: [PATCH 076/366] Show username segment in red if the current user is root --- segments/username.py | 7 ++++++- themes/basic.py | 1 + themes/default.py | 1 + themes/solarized-dark.py | 1 + themes/washed.py | 1 + 5 files changed, 10 insertions(+), 1 deletion(-) diff --git a/segments/username.py b/segments/username.py index 30fd9635..3a44ff8e 100644 --- a/segments/username.py +++ b/segments/username.py @@ -8,6 +8,11 @@ def add_username_segment(): import os user_prompt = ' %s ' % os.getenv('USER') - powerline.append(user_prompt, Color.USERNAME_FG, Color.USERNAME_BG) + if os.getenv('USER') == 'root': + bgcolor = Color.USERNAME_ROOT_BG + else: + bgcolor = Color.USERNAME_BG + + powerline.append(user_prompt, Color.USERNAME_FG, bgcolor) add_username_segment() diff --git a/themes/basic.py b/themes/basic.py index 846ad637..5d076915 100644 --- a/themes/basic.py +++ b/themes/basic.py @@ -3,6 +3,7 @@ class Color(DefaultColor): USERNAME_FG = 8 USERNAME_BG = 15 + USERNAME_ROOT_BG = 1 HOSTNAME_FG = 8 HOSTNAME_BG = 7 diff --git a/themes/default.py b/themes/default.py index 7b602aff..ba4e5511 100644 --- a/themes/default.py +++ b/themes/default.py @@ -5,6 +5,7 @@ class DefaultColor: """ USERNAME_FG = 250 USERNAME_BG = 240 + USERNAME_ROOT_BG = 124 HOSTNAME_FG = 250 HOSTNAME_BG = 238 diff --git a/themes/solarized-dark.py b/themes/solarized-dark.py index 48d0aedc..4e158c8e 100644 --- a/themes/solarized-dark.py +++ b/themes/solarized-dark.py @@ -1,6 +1,7 @@ class Color(DefaultColor): USERNAME_FG = 15 USERNAME_BG = 4 + USERNAME_ROOT_BG = 1 HOSTNAME_FG = 15 HOSTNAME_BG = 10 diff --git a/themes/washed.py b/themes/washed.py index 32455d81..3c455e3d 100644 --- a/themes/washed.py +++ b/themes/washed.py @@ -1,6 +1,7 @@ class Color(DefaultColor): USERNAME_FG = 8 USERNAME_BG = 251 + USERNAME_ROOT_BG = 209 HOSTNAME_FG = 8 HOSTNAME_BG = 7 From e4d1994621f07260e94054eef7a40a4e598cac1f Mon Sep 17 00:00:00 2001 From: "Ruturaj K. Vartak" Date: Tue, 4 Feb 2014 11:40:52 +0530 Subject: [PATCH 077/366] move import os just below the func def --- segments/username.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/segments/username.py b/segments/username.py index 3a44ff8e..4d8e5755 100644 --- a/segments/username.py +++ b/segments/username.py @@ -1,11 +1,11 @@ def add_username_segment(): + import os if powerline.args.shell == 'bash': user_prompt = ' \\u ' elif powerline.args.shell == 'zsh': user_prompt = ' %n ' else: - import os user_prompt = ' %s ' % os.getenv('USER') if os.getenv('USER') == 'root': From 22d54ac05fb399585cdff6867c5240dfc4ab9bee Mon Sep 17 00:00:00 2001 From: jknair Date: Fri, 7 Feb 2014 12:18:35 +0530 Subject: [PATCH 078/366] adding HOME env variable, so that git respects user's configs #123 --- segments/git.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/segments/git.py b/segments/git.py index ed7bf680..092c8096 100644 --- a/segments/git.py +++ b/segments/git.py @@ -5,8 +5,8 @@ def get_git_status(): has_pending_commits = True has_untracked_files = False origin_position = "" - output = subprocess.Popen(['git', 'status', '--ignore-submodules'], - env={"LANG": "C"}, stdout=subprocess.PIPE).communicate()[0] + output = subprocess.Popen(['git', 'st', '--ignore-submodules'], + env={"LANG": "C", "HOME": os.getenv("HOME")}, stdout=subprocess.PIPE).communicate()[0] for line in output.split('\n'): origin_status = re.findall( r"Your branch is (ahead|behind).*?(\d+) comm", line) From 74e3a02f0da46501252dc93e246b41c424cd54c0 Mon Sep 17 00:00:00 2001 From: Jayakrishnan Date: Sat, 8 Feb 2014 15:57:47 +0530 Subject: [PATCH 079/366] corrected typo for git status command --- segments/git.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/segments/git.py b/segments/git.py index 092c8096..230499f1 100644 --- a/segments/git.py +++ b/segments/git.py @@ -5,7 +5,7 @@ def get_git_status(): has_pending_commits = True has_untracked_files = False origin_position = "" - output = subprocess.Popen(['git', 'st', '--ignore-submodules'], + output = subprocess.Popen(['git', 'status', '--ignore-submodules'], env={"LANG": "C", "HOME": os.getenv("HOME")}, stdout=subprocess.PIPE).communicate()[0] for line in output.split('\n'): origin_status = re.findall( From 257762730fffa18be61696c32c9c0c37fd978a24 Mon Sep 17 00:00:00 2001 From: Martin Wetterwald Date: Thu, 20 Feb 2014 17:58:53 +0100 Subject: [PATCH 080/366] Enhances detached head display in git segment. --- segments/git.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/segments/git.py b/segments/git.py index 230499f1..7f1a09b4 100644 --- a/segments/git.py +++ b/segments/git.py @@ -35,7 +35,12 @@ def add_git_segment(): if out: branch = out[len('refs/heads/'):].rstrip() else: - branch = '(Detached)' + p = subprocess.Popen(['git', 'rev-parse', '--short', 'HEAD'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + commit_hash_out, commit_hash_err = (x.rstrip('\n') for x in p.communicate()) + + p = subprocess.Popen(['git', 'describe', '--exact-match', '--tags', commit_hash_out], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + tag_hash_out, tag_hash_err = (x.rstrip('\n') for x in p.communicate()) + branch = '➤ {}'.format(tag_hash_out if p.returncode == 0 else commit_hash_out).decode('utf-8') has_pending_commits, has_untracked_files, origin_position = get_git_status() branch += origin_position From a4ce1022ab1c63c7f204fb64a37ba110cc7520f0 Mon Sep 17 00:00:00 2001 From: Martin Wetterwald Date: Fri, 21 Feb 2014 03:14:29 +0100 Subject: [PATCH 081/366] Enhances git segment with untracked, notstaged, staged and conflicted files. --- segments/git.py | 86 ++++++++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 40 deletions(-) diff --git a/segments/git.py b/segments/git.py index 7f1a09b4..4c27d899 100644 --- a/segments/git.py +++ b/segments/git.py @@ -1,60 +1,66 @@ import re import subprocess -def get_git_status(): - has_pending_commits = True - has_untracked_files = False - origin_position = "" - output = subprocess.Popen(['git', 'status', '--ignore-submodules'], - env={"LANG": "C", "HOME": os.getenv("HOME")}, stdout=subprocess.PIPE).communicate()[0] - for line in output.split('\n'): - origin_status = re.findall( - r"Your branch is (ahead|behind).*?(\d+) comm", line) - if origin_status: - origin_position = " %d" % int(origin_status[0][1]) - if origin_status[0][0] == 'behind': - origin_position += u'\u21E3' - if origin_status[0][0] == 'ahead': - origin_position += u'\u21E1' - - if line.find('nothing to commit') >= 0: - has_pending_commits = False - if line.find('Untracked files') >= 0: - has_untracked_files = True - return has_pending_commits, has_untracked_files, origin_position +def get_git_status(pdata): + status = pdata[0].splitlines() + branchinfo = re.search('^## (?P\S+)(\.{3}(?P\S+)( \[(ahead (?P\d+)(, )?)?(behind (?P\d+))?\])?)?$', status[0]) -def add_git_segment(): - # See http://git-blame.blogspot.com/2013/06/checking-current-branch-programatically.html - p = subprocess.Popen(['git', 'symbolic-ref', '-q', 'HEAD'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = p.communicate() + stats = {'untracked': 0, 'notstaged': 0, 'staged': 0, 'conflicted': 0} + for statusline in status[1:]: + code = statusline[:2] + if code == '??': + stats['untracked'] += 1 + elif code in ('DD', 'AU', 'UD', 'UA', 'DU', 'AA', 'UU'): + stats['conflicted'] += 1 + else: + if code[1] != ' ': + stats['notstaged'] += 1 + if code[0] != ' ': + stats['staged'] += 1 + dirty = (True if sum(stats.values()) > 0 else False) + return dirty, stats, branchinfo.groupdict() if branchinfo else None - if 'Not a git repo' in err: - return - if out: - branch = out[len('refs/heads/'):].rstrip() - else: - p = subprocess.Popen(['git', 'rev-parse', '--short', 'HEAD'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - commit_hash_out, commit_hash_err = (x.rstrip('\n') for x in p.communicate()) +def add_git_segment(): + p = subprocess.Popen(['git', 'status', '--porcelain', '-b'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + pdata = p.communicate() + if p.returncode != 0: + return - p = subprocess.Popen(['git', 'describe', '--exact-match', '--tags', commit_hash_out], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - tag_hash_out, tag_hash_err = (x.rstrip('\n') for x in p.communicate()) - branch = '➤ {}'.format(tag_hash_out if p.returncode == 0 else commit_hash_out).decode('utf-8') + dirty, stats, branchinfo = get_git_status(pdata) - has_pending_commits, has_untracked_files, origin_position = get_git_status() - branch += origin_position - if has_untracked_files: - branch += ' +' + if branchinfo: + branch = branchinfo['local'] + else: + p = subprocess.Popen(['git', 'describe', '--tags', '--always'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + detached_ref = p.communicate()[0].rstrip('\n') + if p.returncode == 0: + branch = '⚓ {}'.format(detached_ref).decode('utf-8') + else: + branch = 'Big Bang' bg = Color.REPO_CLEAN_BG fg = Color.REPO_CLEAN_FG - if has_pending_commits: + if dirty: bg = Color.REPO_DIRTY_BG fg = Color.REPO_DIRTY_FG powerline.append(' %s ' % branch, fg, bg) + if branchinfo: + if branchinfo['ahead']: + powerline.append("{}⬆".format(branchinfo['ahead'] if int(branchinfo['ahead']) > 1 else str('')).decode('utf-8'), 250, 240) + if branchinfo['behind']: + powerline.append("{}⬇".format(branchinfo['behind'] if int(branchinfo['behind']) > 1 else str('')).decode('utf-8'), 250, 240) + if stats['staged']: + powerline.append("{}✔".format(stats['staged'] if stats['staged'] > 1 else str('')).decode('utf-8'), 15, 22) + if stats['notstaged']: + powerline.append("{}✎".format(stats['notstaged'] if stats['notstaged'] > 1 else str('')).decode('utf-8'), 15, 130) + if stats['untracked']: + powerline.append("{}?".format(stats['untracked'] if stats['untracked'] > 1 else str('')), 15, 52) + if stats['conflicted']: + powerline.append("{}✼".format(stats['conflicted'] if stats['conflicted'] > 1 else str('')).decode('utf-8'), 15, 9) try: add_git_segment() except OSError: From daec74bc16f63887d268b63baf7c4716834c561f Mon Sep 17 00:00:00 2001 From: Martin Wetterwald Date: Fri, 21 Feb 2014 13:19:27 +0100 Subject: [PATCH 082/366] Adds Color variables for the git segment. --- segments/git.py | 12 ++++++------ themes/default.py | 13 +++++++++++++ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/segments/git.py b/segments/git.py index 4c27d899..98997705 100644 --- a/segments/git.py +++ b/segments/git.py @@ -50,17 +50,17 @@ def add_git_segment(): if branchinfo: if branchinfo['ahead']: - powerline.append("{}⬆".format(branchinfo['ahead'] if int(branchinfo['ahead']) > 1 else str('')).decode('utf-8'), 250, 240) + powerline.append("{}⬆".format(branchinfo['ahead'] if int(branchinfo['ahead']) > 1 else str('')).decode('utf-8'), Color.GIT_AHEAD_FG, Color.GIT_AHEAD_BG) if branchinfo['behind']: - powerline.append("{}⬇".format(branchinfo['behind'] if int(branchinfo['behind']) > 1 else str('')).decode('utf-8'), 250, 240) + powerline.append("{}⬇".format(branchinfo['behind'] if int(branchinfo['behind']) > 1 else str('')).decode('utf-8'), Color.GIT_BEHIND_FG, Color.GIT_BEHIND_BG) if stats['staged']: - powerline.append("{}✔".format(stats['staged'] if stats['staged'] > 1 else str('')).decode('utf-8'), 15, 22) + powerline.append("{}✔".format(stats['staged'] if stats['staged'] > 1 else str('')).decode('utf-8'), Color.GIT_STAGED_FG, Color.GIT_STAGED_BG) if stats['notstaged']: - powerline.append("{}✎".format(stats['notstaged'] if stats['notstaged'] > 1 else str('')).decode('utf-8'), 15, 130) + powerline.append("{}✎".format(stats['notstaged'] if stats['notstaged'] > 1 else str('')).decode('utf-8'), Color.GIT_NOTSTAGED_FG, Color.GIT_NOTSTAGED_BG) if stats['untracked']: - powerline.append("{}?".format(stats['untracked'] if stats['untracked'] > 1 else str('')), 15, 52) + powerline.append("{}?".format(stats['untracked'] if stats['untracked'] > 1 else str('')), Color.GIT_UNTRACKED_FG, Color.GIT_UNTRACKED_BG) if stats['conflicted']: - powerline.append("{}✼".format(stats['conflicted'] if stats['conflicted'] > 1 else str('')).decode('utf-8'), 15, 9) + powerline.append("{}✼".format(stats['conflicted'] if stats['conflicted'] > 1 else str('')).decode('utf-8'), Color.GIT_CONFLICTED_FG, Color.GIT_CONFLICTED_BG) try: add_git_segment() except OSError: diff --git a/themes/default.py b/themes/default.py index ba4e5511..08b1ff45 100644 --- a/themes/default.py +++ b/themes/default.py @@ -40,6 +40,19 @@ class DefaultColor: SVN_CHANGES_BG = 148 SVN_CHANGES_FG = 22 # dark green + GIT_AHEAD_BG = 240 + GIT_AHEAD_FG = 250 + GIT_BEHIND_BG = 240 + GIT_BEHIND_FG = 250 + GIT_STAGED_BG = 22 + GIT_STAGED_FG = 15 + GIT_NOTSTAGED_BG = 130 + GIT_NOTSTAGED_FG = 15 + GIT_UNTRACKED_BG = 52 + GIT_UNTRACKED_FG = 15 + GIT_CONFLICTED_BG = 9 + GIT_CONFLICTED_FG = 15 + VIRTUAL_ENV_BG = 35 # a mid-tone green VIRTUAL_ENV_FG = 00 From 25e831e816f54297179d407216044174b058220d Mon Sep 17 00:00:00 2001 From: Martin Wetterwald Date: Fri, 21 Feb 2014 13:52:08 +0100 Subject: [PATCH 083/366] Fixes bug causing no display of status when head was detached. --- segments/git.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/segments/git.py b/segments/git.py index 98997705..809d315a 100644 --- a/segments/git.py +++ b/segments/git.py @@ -53,14 +53,14 @@ def add_git_segment(): powerline.append("{}⬆".format(branchinfo['ahead'] if int(branchinfo['ahead']) > 1 else str('')).decode('utf-8'), Color.GIT_AHEAD_FG, Color.GIT_AHEAD_BG) if branchinfo['behind']: powerline.append("{}⬇".format(branchinfo['behind'] if int(branchinfo['behind']) > 1 else str('')).decode('utf-8'), Color.GIT_BEHIND_FG, Color.GIT_BEHIND_BG) - if stats['staged']: - powerline.append("{}✔".format(stats['staged'] if stats['staged'] > 1 else str('')).decode('utf-8'), Color.GIT_STAGED_FG, Color.GIT_STAGED_BG) - if stats['notstaged']: - powerline.append("{}✎".format(stats['notstaged'] if stats['notstaged'] > 1 else str('')).decode('utf-8'), Color.GIT_NOTSTAGED_FG, Color.GIT_NOTSTAGED_BG) - if stats['untracked']: - powerline.append("{}?".format(stats['untracked'] if stats['untracked'] > 1 else str('')), Color.GIT_UNTRACKED_FG, Color.GIT_UNTRACKED_BG) - if stats['conflicted']: - powerline.append("{}✼".format(stats['conflicted'] if stats['conflicted'] > 1 else str('')).decode('utf-8'), Color.GIT_CONFLICTED_FG, Color.GIT_CONFLICTED_BG) + if stats['staged']: + powerline.append("{}✔".format(stats['staged'] if stats['staged'] > 1 else str('')).decode('utf-8'), Color.GIT_STAGED_FG, Color.GIT_STAGED_BG) + if stats['notstaged']: + powerline.append("{}✎".format(stats['notstaged'] if stats['notstaged'] > 1 else str('')).decode('utf-8'), Color.GIT_NOTSTAGED_FG, Color.GIT_NOTSTAGED_BG) + if stats['untracked']: + powerline.append("{}?".format(stats['untracked'] if stats['untracked'] > 1 else str('')), Color.GIT_UNTRACKED_FG, Color.GIT_UNTRACKED_BG) + if stats['conflicted']: + powerline.append("{}✼".format(stats['conflicted'] if stats['conflicted'] > 1 else str('')).decode('utf-8'), Color.GIT_CONFLICTED_FG, Color.GIT_CONFLICTED_BG) try: add_git_segment() except OSError: From 714aa0ed8222cffc533cb37231222d076bc667fc Mon Sep 17 00:00:00 2001 From: Andy Davidoff Date: Fri, 21 Feb 2014 18:23:37 -0500 Subject: [PATCH 084/366] add a conditional segment holding the $? --- config.py.dist | 3 +++ segments/exit_code.py | 8 ++++++++ 2 files changed, 11 insertions(+) create mode 100644 segments/exit_code.py diff --git a/config.py.dist b/config.py.dist index bad4143d..e4a3b413 100644 --- a/config.py.dist +++ b/config.py.dist @@ -42,6 +42,9 @@ SEGMENTS = [ # 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', diff --git a/segments/exit_code.py b/segments/exit_code.py new file mode 100644 index 00000000..49b2cc2b --- /dev/null +++ b/segments/exit_code.py @@ -0,0 +1,8 @@ +def add_status_indicator_segment(): + if powerline.args.prev_error == 0: + return + fg = Color.CMD_FAILED_FG + bg = Color.CMD_FAILED_BG + powerline.append(str(powerline.args.prev_error), fg, bg) + +add_status_indicator_segment() From 64ee1ac9cbfedf706a0b010f6987c75e42c61299 Mon Sep 17 00:00:00 2001 From: Andy Davidoff Date: Fri, 21 Feb 2014 18:36:52 -0500 Subject: [PATCH 085/366] omit exit_code by default --- config.py.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.py.dist b/config.py.dist index e4a3b413..46f74af3 100644 --- a/config.py.dist +++ b/config.py.dist @@ -43,7 +43,7 @@ SEGMENTS = [ 'jobs', # Show the last command's exit code if it was non-zero - 'exit_code', +# '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 From df829476c956f375cdcba0227705caf470650e5a Mon Sep 17 00:00:00 2001 From: Martin Wetterwald Date: Sat, 19 Apr 2014 13:16:21 +0200 Subject: [PATCH 086/366] Fixes bug since Python 2.7.6 (un-greedy quantifiers in the regex). --- segments/git.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/segments/git.py b/segments/git.py index 809d315a..6172d086 100644 --- a/segments/git.py +++ b/segments/git.py @@ -4,7 +4,7 @@ def get_git_status(pdata): status = pdata[0].splitlines() - branchinfo = re.search('^## (?P\S+)(\.{3}(?P\S+)( \[(ahead (?P\d+)(, )?)?(behind (?P\d+))?\])?)?$', status[0]) + branchinfo = re.search('^## (?P\S+?)(\.{3}(?P\S+?)( \[(ahead (?P\d+)(, )?)?(behind (?P\d+))?\])?)?$', status[0]) stats = {'untracked': 0, 'notstaged': 0, 'staged': 0, 'conflicted': 0} for statusline in status[1:]: From d376ef2bf12592e09896ae89857513f010a9a65b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rcio=20Almada?= Date: Mon, 21 Apr 2014 17:02:22 -0300 Subject: [PATCH 087/366] adding uptime segment --- segments/uptime.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 segments/uptime.py diff --git a/segments/uptime.py b/segments/uptime.py new file mode 100644 index 00000000..ff6bb70e --- /dev/null +++ b/segments/uptime.py @@ -0,0 +1,22 @@ +import subprocess +import re + +# uptime output samples +# 1h: 00:00:00 up 1:00, 2 users, load average: 0,00, 0,00, 0,00 +# 10+h: 00:00:00 up 10:00, 2 users, load average: 0,00, 0,00, 0,00 +# 1+d: 00:00:00 up 1 days, 1:00, 2 users, load average: 0,00, 0,00, 0,00 +# 9+d: 00:00:00 up 12 days, 1:00, 2 users, load average: 0,00, 0,00, 0,00 +# mac: 00:00:00 up 233 day(s), 10:00, 2 users, load average: 0,00, 0,00, 0,00 + +def add_uptime_segment(): + try: + output = subprocess.check_output(['uptime'], stderr=subprocess.STDOUT) + day_search = re.search('\d+(?=\s+day)', output) + days = '' if not day_search else '%sd ' % day_search.group(0) + time = re.search('\d{1,2}\:\d{1,2}(?=,)', output).group(0) + uptime = u' %s%s ↑ ' % (days, time) + powerline.append(uptime, Color.CWD_FG, Color.PATH_BG) + except OSError: + return + +add_uptime_segment() \ No newline at end of file From 5c8e33f196640c02761ec6621df15adb4182a260 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rcio=20Almada?= Date: Tue, 22 Apr 2014 12:41:49 -0300 Subject: [PATCH 088/366] better uptime resolution --- segments/uptime.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/segments/uptime.py b/segments/uptime.py index ff6bb70e..2e7811e3 100644 --- a/segments/uptime.py +++ b/segments/uptime.py @@ -6,15 +6,19 @@ # 10+h: 00:00:00 up 10:00, 2 users, load average: 0,00, 0,00, 0,00 # 1+d: 00:00:00 up 1 days, 1:00, 2 users, load average: 0,00, 0,00, 0,00 # 9+d: 00:00:00 up 12 days, 1:00, 2 users, load average: 0,00, 0,00, 0,00 -# mac: 00:00:00 up 233 day(s), 10:00, 2 users, load average: 0,00, 0,00, 0,00 +# -1h 00:00:00 up 120 days, 49 min, 2 users, load average: 0,00, 0,00, 0,00 +# mac: 00:00:00 up 23 3 day(s), 10:00, 2 users, load average: 0,00, 0,00, 0,00 def add_uptime_segment(): 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) - time = re.search('\d{1,2}\:\d{1,2}(?=,)', output).group(0) - uptime = u' %s%s ↑ ' % (days, time) + 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 ↑ ' % (days, hours, minutes) powerline.append(uptime, Color.CWD_FG, Color.PATH_BG) except OSError: return From 4580868391ee2e3ab680fce970aec7d83a0ccdd6 Mon Sep 17 00:00:00 2001 From: Guilherme Chapiewski Date: Mon, 19 May 2014 23:39:27 -0700 Subject: [PATCH 089/366] Added space after hostname to prevent cutting the last character - http://cl.ly/image/1K311W2N132e (and to make it consistent with other segments like username, for instance). --- segments/hostname.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/segments/hostname.py b/segments/hostname.py index d19296e8..baf99191 100644 --- a/segments/hostname.py +++ b/segments/hostname.py @@ -6,7 +6,7 @@ def add_hostname_segment(): hostname = gethostname() FG, BG = stringToHashToColorAndOpposite(hostname) FG, BG = (rgb2short(*color) for color in [FG, BG]) - host_prompt = ' %s' % hostname.split('.')[0] + host_prompt = ' %s ' % hostname.split('.')[0] powerline.append(host_prompt, FG, BG) else: From 4eb373842840e7feeed5e3540a44e7a6b7f0ac99 Mon Sep 17 00:00:00 2001 From: Guilherme Chapiewski Date: Mon, 19 May 2014 23:45:44 -0700 Subject: [PATCH 090/366] Added space after prompt because I didn't like the text touching it. --- powerline-shell.py.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerline-shell.py.template b/powerline-shell.py.template index 6ddeb78e..0d329f9f 100755 --- a/powerline-shell.py.template +++ b/powerline-shell.py.template @@ -63,7 +63,7 @@ class Powerline: def draw(self): return (''.join(self.draw_segment(i) for i in range(len(self.segments))) - + self.reset).encode('utf-8') + + self.reset).encode('utf-8') + ' ' def draw_segment(self, idx): segment = self.segments[idx] From 48303d504bd8ebe4fbc9392358fe9680e0535e27 Mon Sep 17 00:00:00 2001 From: nkcfan Date: Sun, 6 Jul 2014 14:07:45 +0800 Subject: [PATCH 091/366] Fix zsh root_indicator --- segments/root.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/segments/root.py b/segments/root.py index c2d939c8..9cd5e8c2 100644 --- a/segments/root.py +++ b/segments/root.py @@ -1,7 +1,7 @@ def add_root_indicator_segment(): root_indicators = { 'bash': ' \\$ ', - 'zsh': ' \\$ ', + 'zsh': ' %# ', 'bare': ' $ ', } bg = Color.CMD_PASSED_BG From c30307ae72f4df2c3c8212381d3e0b34db743303 Mon Sep 17 00:00:00 2001 From: andrejgl Date: Wed, 9 Jul 2014 23:59:16 +0300 Subject: [PATCH 092/366] get_git_status(): PATH environment variable missing. OSError: if git is installed in non standard path --- segments/git.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/segments/git.py b/segments/git.py index 230499f1..0aedfcbc 100644 --- a/segments/git.py +++ b/segments/git.py @@ -6,7 +6,7 @@ def get_git_status(): has_untracked_files = False origin_position = "" output = subprocess.Popen(['git', 'status', '--ignore-submodules'], - env={"LANG": "C", "HOME": os.getenv("HOME")}, stdout=subprocess.PIPE).communicate()[0] + env={"LANG": "C", "HOME": os.getenv("HOME"), "PATH": os.getenv("PATH")}, stdout=subprocess.PIPE).communicate()[0] for line in output.split('\n'): origin_status = re.findall( r"Your branch is (ahead|behind).*?(\d+) comm", line) From 7bec5e59d9afb5c9cd6b20035fe40569047c1088 Mon Sep 17 00:00:00 2001 From: Pedro Lopes Date: Sat, 12 Jul 2014 17:10:30 +0100 Subject: [PATCH 093/366] Add a "set terminal title" segment. Emmits a non-printing sequence that sets the terminal window title to user@host:dir (This is a common default setting in many linux distros) It was necessary to slightly refactor Powerline methods to distinguish between None and '' passed as parameters. --- config.py.dist | 3 +++ powerline-shell.py.template | 10 +++++++--- segments/set_term_title.py | 17 +++++++++++++++++ 3 files changed, 27 insertions(+), 3 deletions(-) create mode 100644 segments/set_term_title.py diff --git a/config.py.dist b/config.py.dist index bad4143d..1499aa38 100644 --- a/config.py.dist +++ b/config.py.dist @@ -7,6 +7,9 @@ # 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', diff --git a/powerline-shell.py.template b/powerline-shell.py.template index 0d329f9f..42149141 100755 --- a/powerline-shell.py.template +++ b/powerline-shell.py.template @@ -49,7 +49,10 @@ class Powerline: self.segments = [] def color(self, prefix, code): - return self.color_template % ('[%s;5;%sm' % (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) @@ -58,8 +61,9 @@ class Powerline: return self.color('48', code) def append(self, content, fg, bg, separator=None, separator_fg=None): - self.segments.append((content, fg, bg, separator or self.separator, - separator_fg or bg)) + 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): return (''.join(self.draw_segment(i) for i in range(len(self.segments))) diff --git a/segments/set_term_title.py b/segments/set_term_title.py new file mode 100644 index 00000000..5853d0c0 --- /dev/null +++ b/segments/set_term_title.py @@ -0,0 +1,17 @@ +def add_term_title_segment(): + 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 = '\\e]0;%n@%m: %~\\a' + else: + import socket + set_title = '\\e]0;%s@%s: %s\\a' % (os.getenv('USER'), socket.gethostname().split('.')[0], powerline.cwd or os.getenv('PWD')) + + powerline.append(set_title, None, None, '') + + +add_term_title_segment() From becd5c8356a106bddf8549ea8f5c9de15278d518 Mon Sep 17 00:00:00 2001 From: Pedro Lopes Date: Sat, 12 Jul 2014 20:34:08 +0100 Subject: [PATCH 094/366] Add an optional 'plain' mode to the cwd segment. Rationale: A plain path like "~/projects/powerline-shell" can be easily copied&pasted, and also takes up less space in the prompt. The new command line parameter --cwd-mode controls the display of the cwd segment: --cwd-mode=fancy is the same as the current default --cwd-mode=plain is the new mode to display a plain path --cwd-mode=dironly is the same as the old parameter --cwd-only (which is still supported to keep backward compat) --- README.md | 3 ++- powerline-shell.py.template | 5 ++++- segments/cwd.py | 25 ++++++++++++++----------- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index af8cb20d..36ba1661 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,8 @@ setting your $TERM to `xterm-256color`, because that works for me. There are a few optional arguments which can be seen by running `powerline-shell.py --help`. ``` - --cwd-only Only show the current directory + --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 --colorize-hostname Colorize the hostname based on a hash of itself. diff --git a/powerline-shell.py.template b/powerline-shell.py.template index 0d329f9f..dcdc14a4 100755 --- a/powerline-shell.py.template +++ b/powerline-shell.py.template @@ -104,8 +104,11 @@ def get_valid_cwd(): if __name__ == "__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='Only show the current directory') + 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('--colorize-hostname', action='store_true', diff --git a/segments/cwd.py b/segments/cwd.py index 70724b00..ae5a01ff 100644 --- a/segments/cwd.py +++ b/segments/cwd.py @@ -21,17 +21,20 @@ def add_cwd_segment(): if len(names) > max_depth: names = names[:2] + [u'\u2026'] + names[2 - max_depth:] - if not powerline.args.cwd_only: - for n in names[:-1]: - if n == '~' and Color.HOME_SPECIAL_DISPLAY: - powerline.append(' %s ' % n, Color.HOME_FG, Color.HOME_BG) - else: - powerline.append(' %s ' % n, Color.PATH_FG, Color.PATH_BG, - powerline.separator_thin, Color.SEPARATOR_FG) - - if names[-1] == '~' and Color.HOME_SPECIAL_DISPLAY: - powerline.append(' %s ' % names[-1], Color.HOME_FG, Color.HOME_BG) + if powerline.args.cwd_mode=='plain': + powerline.append(' %s ' % '/'.join(names), Color.CWD_FG, Color.PATH_BG) else: - powerline.append(' %s ' % names[-1], Color.CWD_FG, Color.PATH_BG) + if not (powerline.args.cwd_mode=='dironly' or powerline.args.cwd_only): + for n in names[:-1]: + if n == '~' and Color.HOME_SPECIAL_DISPLAY: + powerline.append(' %s ' % n, Color.HOME_FG, Color.HOME_BG) + else: + powerline.append(' %s ' % n, Color.PATH_FG, Color.PATH_BG, + powerline.separator_thin, Color.SEPARATOR_FG) + + if names[-1] == '~' and Color.HOME_SPECIAL_DISPLAY: + powerline.append(' %s ' % names[-1], Color.HOME_FG, Color.HOME_BG) + else: + powerline.append(' %s ' % names[-1], Color.CWD_FG, Color.PATH_BG) add_cwd_segment() From 2e0af6066af4d895015cd20fcaf784060ece397e Mon Sep 17 00:00:00 2001 From: Pedro Lopes Date: Sat, 12 Jul 2014 23:02:57 +0100 Subject: [PATCH 095/366] Fix: include leading / in cwd when in plain mode --- segments/cwd.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/segments/cwd.py b/segments/cwd.py index ae5a01ff..f154f493 100644 --- a/segments/cwd.py +++ b/segments/cwd.py @@ -22,7 +22,8 @@ def add_cwd_segment(): names = names[:2] + [u'\u2026'] + names[2 - max_depth:] if powerline.args.cwd_mode=='plain': - powerline.append(' %s ' % '/'.join(names), Color.CWD_FG, Color.PATH_BG) + powerline.append(' %s%s ' % ('' if names[0] in '/~' else '/', '/'.join(names)), + Color.CWD_FG, Color.PATH_BG) else: if not (powerline.args.cwd_mode=='dironly' or powerline.args.cwd_only): for n in names[:-1]: From 90a724313902e3d95f1a37d9102af1544c9bc61d Mon Sep 17 00:00:00 2001 From: Pedro Lopes Date: Sun, 27 Jul 2014 11:59:46 +0100 Subject: [PATCH 096/366] Fix use of escape characters in "set terminal title" segment. Escape characters were incorrect for non-BASH shells. --- segments/set_term_title.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/segments/set_term_title.py b/segments/set_term_title.py index 5853d0c0..4d1d5cd8 100644 --- a/segments/set_term_title.py +++ b/segments/set_term_title.py @@ -6,10 +6,10 @@ def add_term_title_segment(): if powerline.args.shell == 'bash': set_title = '\\[\\e]0;\\u@\\h: \\w\\a\\]' elif powerline.args.shell == 'zsh': - set_title = '\\e]0;%n@%m: %~\\a' + set_title = '\033]0;%n@%m: %~\007' else: import socket - set_title = '\\e]0;%s@%s: %s\\a' % (os.getenv('USER'), socket.gethostname().split('.')[0], powerline.cwd or os.getenv('PWD')) + 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, '') From 32fe1db984796a0c7b42991636ffed41c36cf497 Mon Sep 17 00:00:00 2001 From: torvatn Date: Thu, 23 Oct 2014 12:43:58 +0200 Subject: [PATCH 097/366] Adds support for git branch divergence syntax --- segments/git.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/segments/git.py b/segments/git.py index 230499f1..84017a1c 100644 --- a/segments/git.py +++ b/segments/git.py @@ -10,12 +10,15 @@ def get_git_status(): for line in output.split('\n'): origin_status = re.findall( r"Your branch is (ahead|behind).*?(\d+) comm", line) + diverged_status = re.findall(r"and have (\d+) and (\d+) different commits each", line) if origin_status: origin_position = " %d" % int(origin_status[0][1]) if origin_status[0][0] == 'behind': origin_position += u'\u21E3' if origin_status[0][0] == 'ahead': origin_position += u'\u21E1' + if diverged_status: + origin_position = " %d%c %d%c" % (int(diverged_status[0][0]), u'\u21E1', int(diverged_status[0][1]), u'\u21E3') if line.find('nothing to commit') >= 0: has_pending_commits = False From 27b342aaa2a79cef11183ca179bf97b778703bc8 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Fri, 12 Jun 2015 16:00:19 -0400 Subject: [PATCH 098/366] added node segment --- segments/node.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 segments/node.py diff --git a/segments/node.py b/segments/node.py new file mode 100644 index 00000000..cf9e4132 --- /dev/null +++ b/segments/node.py @@ -0,0 +1,13 @@ +import subprocess + + +def add_node_version_segment(): + try: + p1 = subprocess.Popen(["node", "--version"], stdout=subprocess.PIPE) + version = p1.communicate()[0].rstrip() + version = "node " + version + powerline.append(version, 15, 18) + except OSError: + return + +add_node_version_segment() From 91b1926ced73589b6a2ae6475873bc365c7267fc Mon Sep 17 00:00:00 2001 From: Dan Church Date: Tue, 7 Jul 2015 09:56:43 -0500 Subject: [PATCH 099/366] Do not export PS1 and PROMPT_COMMAND PS1 and PROMPT_COMMAND are never used outside of bash. There's never a reason to export them into the environment variable arena. --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index af8cb20d..472020e1 100644 --- a/README.md +++ b/README.md @@ -62,16 +62,16 @@ There are a few optional arguments which can be seen by running `powerline-shell Add the following to your `.bashrc`: function _update_ps1() { - export PS1="$(~/powerline-shell.py $? 2> /dev/null)" + PS1="$(~/powerline-shell.py $? 2> /dev/null)" } - export PROMPT_COMMAND="_update_ps1; $PROMPT_COMMAND" + PROMPT_COMMAND="_update_ps1; $PROMPT_COMMAND" ### ZSH: Add the following to your `.zshrc`: function powerline_precmd() { - export PS1="$(~/powerline-shell.py $? --shell zsh 2> /dev/null)" + PS1="$(~/powerline-shell.py $? --shell zsh 2> /dev/null)" } function install_powerline_precmd() { From 874bb61361c3230a5cb2e3991eab445a5ced77e3 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Mon, 27 Jul 2015 21:32:39 -0400 Subject: [PATCH 100/366] Rename node.py to node_version.py --- segments/{node.py => node_version.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename segments/{node.py => node_version.py} (100%) diff --git a/segments/node.py b/segments/node_version.py similarity index 100% rename from segments/node.py rename to segments/node_version.py From 06a51dcaadd241c0dde69eab0fa4c0abfd018e2e Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Mon, 27 Jul 2015 22:25:12 -0400 Subject: [PATCH 101/366] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 472020e1..894cca6a 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ There are a few optional arguments which can be seen by running `powerline-shell ``` ### Bash: -Add the following to your `.bashrc`: +Add the following to your `.bashrc` (or `.profile` on Mac): function _update_ps1() { PS1="$(~/powerline-shell.py $? 2> /dev/null)" From 491f95e7c36cec432f1db98b478e73c6840a4ce3 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Mon, 27 Jul 2015 23:02:25 -0400 Subject: [PATCH 102/366] add a changelog to the README --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 472020e1..459c8044 100644 --- a/README.md +++ b/README.md @@ -130,3 +130,10 @@ 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 + +2015-07-27 + +* Use `python2` instead of `python` in hashbangs +* Add `node_version` segment From fccb91fe187644706a2db7470a1317962879d325 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Tue, 28 Jul 2015 22:19:16 -0400 Subject: [PATCH 103/366] README notes on preventing use of powerline for linux terminal closes #60 --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index eb391f3d..ca0ad9d3 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,9 @@ Add the following to your `.bashrc` (or `.profile` on Mac): PS1="$(~/powerline-shell.py $? 2> /dev/null)" } - PROMPT_COMMAND="_update_ps1; $PROMPT_COMMAND" + if [ "$TERM" != "linux" ]; then + PROMPT_COMMAND="_update_ps1; $PROMPT_COMMAND" + fi ### ZSH: Add the following to your `.zshrc`: @@ -83,7 +85,9 @@ Add the following to your `.zshrc`: precmd_functions+=(powerline_precmd) } - install_powerline_precmd + if [ "$TERM" != "linux" ]; then + install_powerline_precmd + fi ### Fish: Redefine `fish_prompt` in ~/.config/fish/config.fish: From bb0bef32bf2456d44c404439965d60419ba3ce59 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Fri, 31 Jul 2015 00:06:21 -0400 Subject: [PATCH 104/366] change uptime char to unicode byte point and add newline --- segments/uptime.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/segments/uptime.py b/segments/uptime.py index 2e7811e3..8ea229f4 100644 --- a/segments/uptime.py +++ b/segments/uptime.py @@ -18,9 +18,9 @@ def add_uptime_segment(): 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 ↑ ' % (days, hours, minutes) + uptime = u' %s%s%sm \u2191 ' % (days, hours, minutes) powerline.append(uptime, Color.CWD_FG, Color.PATH_BG) except OSError: return -add_uptime_segment() \ No newline at end of file +add_uptime_segment() From 06ca7ab0e1882444952c8230f75246b6f3f79824 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Fri, 31 Jul 2015 00:07:13 -0400 Subject: [PATCH 105/366] add today's changes --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ca0ad9d3..d7b6e9a6 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,12 @@ settings. # Changes +2015-07-30 + +* Fix ZSH root indicator (@nkcfan) +* Add uptime segment (@marcioAlmada) + 2015-07-27 -* Use `python2` instead of `python` in hashbangs -* Add `node_version` segment +* Use `python2` instead of `python` in hashbangs ( +* Add `node_version` segment (@mmilleruva) From 78f39d29519d1db1ad82589d8356c0b83dff8be2 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Fri, 31 Jul 2015 21:16:34 -0400 Subject: [PATCH 106/366] Rewrite the cwd function to not follow symlinks As part of the commit I also set up unit testing --- dev_requirements.txt | 2 + install.py | 2 +- ...ell.py.template => powerline_shell_base.py | 31 ++++++----- test/cwd_test.py | 53 +++++++++++++++++++ 4 files changed, 74 insertions(+), 14 deletions(-) create mode 100644 dev_requirements.txt rename powerline-shell.py.template => powerline_shell_base.py (85%) create mode 100644 test/cwd_test.py diff --git a/dev_requirements.txt b/dev_requirements.txt new file mode 100644 index 00000000..a6786964 --- /dev/null +++ b/dev_requirements.txt @@ -0,0 +1,2 @@ +nose +mock diff --git a/install.py b/install.py index 98db7617..2264093c 100755 --- a/install.py +++ b/install.py @@ -10,7 +10,7 @@ shutil.copyfile('config.py.dist', 'config.py') import config -TEMPLATE_FILE = 'powerline-shell.py.template' +TEMPLATE_FILE = 'powerline_shell_base.py' OUTPUT_FILE = 'powerline-shell.py' SEGMENTS_DIR = 'segments' THEMES_DIR = 'themes' diff --git a/powerline-shell.py.template b/powerline_shell_base.py similarity index 85% rename from powerline-shell.py.template rename to powerline_shell_base.py index 42149141..f1c3455a 100755 --- a/powerline-shell.py.template +++ b/powerline_shell_base.py @@ -88,21 +88,26 @@ def get_valid_cwd(): We return the original cwd because the shell still considers that to be the working directory, so returning our guess will confuse people """ + # Prefer the PDW environment variable. Python's os.getcwd function follows + # symbolic links, which is undesirable. But if PDW is not set then fall + # back to this func try: - cwd = os.getcwd() + cwd = os.getenv('PWD') or os.getcwd() except: - cwd = os.getenv('PWD') # This is where the OS thinks we are - parts = cwd.split(os.sep) - up = cwd - while parts and not os.path.exists(up): - parts.pop() - up = os.sep.join(parts) - try: - os.chdir(up) - except: - warn("Your current directory is invalid.") - sys.exit(1) - warn("Your current directory is invalid. Lowest valid directory: " + up) + warn("Your current directory is invalid. If you open a ticket at " + + "https://github.com/milkbikis/powerline-shell/issues/new " + + "we would love to help fix the issue.") + sys.stdout.write("> ") + sys.exit(1) + + parts = cwd.split(os.sep) + up = cwd + while parts and not os.path.exists(up): + parts.pop() + up = os.sep.join(parts) + if cwd != up: + warn("Your current directory is invalid. Lowest valid directory: " + + up) return cwd diff --git a/test/cwd_test.py b/test/cwd_test.py new file mode 100644 index 00000000..111863e8 --- /dev/null +++ b/test/cwd_test.py @@ -0,0 +1,53 @@ +import unittest +import mock +import os +import tempfile +import shutil +import powerline_shell_base as p + + +class CwdTest(unittest.TestCase): + + def setUp(self): + self.dirname = tempfile.mkdtemp() + + def tearDown(self): + shutil.rmtree(self.dirname) + + @mock.patch('os.getenv') + @mock.patch('powerline_shell_base.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') + def test_nonexistent_warns(self, warn, getenv): + subdir = os.path.join(self.dirname, 'subdir') + getenv.return_value = subdir + self.assertEqual(p.get_valid_cwd(), subdir) + self.assertEqual(warn.call_count, 1) + + @mock.patch('os.getenv') + @mock.patch('powerline_shell_base.warn') + def test_falls_back_to_getcwd(self, warn, getenv): + getenv.return_value = None + os.chdir(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') + def test_nonexistent_getcwd_warns(self, warn, getenv): + subdir = os.path.join(self.dirname, 'subdir') + getenv.return_value = None + + os.mkdir(subdir) + os.chdir(subdir) + os.rmdir(subdir) + + with self.assertRaises(SystemExit) as e: + p.get_valid_cwd() + + self.assertEqual(warn.call_count, 1) From 1fbe9c3e4e8e49366beb177b97574c7391775848 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Fri, 31 Jul 2015 21:20:06 -0400 Subject: [PATCH 107/366] fix typo in comment --- powerline_shell_base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/powerline_shell_base.py b/powerline_shell_base.py index f1c3455a..89442d14 100755 --- a/powerline_shell_base.py +++ b/powerline_shell_base.py @@ -88,8 +88,8 @@ def get_valid_cwd(): We return the original cwd because the shell still considers that to be the working directory, so returning our guess will confuse people """ - # Prefer the PDW environment variable. Python's os.getcwd function follows - # symbolic links, which is undesirable. But if PDW is not set then fall + # Prefer the PWD environment variable. Python's os.getcwd function follows + # symbolic links, which is undesirable. But if PWD is not set then fall # back to this func try: cwd = os.getenv('PWD') or os.getcwd() From 638b6670209e1e3a286da654facd2b8bfe77cb8c Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Fri, 31 Jul 2015 21:24:47 -0400 Subject: [PATCH 108/366] update readme to reflect new template file --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d7b6e9a6..620de282 100644 --- a/README.md +++ b/README.md @@ -109,10 +109,10 @@ prompt immediately. ### Contributing new types of segments The `segments` directory contains python scripts which are injected as is into -a single file `powerline-shell.py.template`. 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. +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. 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 From 354aa0fc5b1c3f055527344237f0c7653a46308a Mon Sep 17 00:00:00 2001 From: Mathieu Comandon Date: Fri, 31 Jul 2015 18:25:21 -0700 Subject: [PATCH 109/366] Use print function instead of statement --- install.py | 7 ++++--- powerline-shell.py.template | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/install.py b/install.py index 98db7617..c4ee2af2 100755 --- a/install.py +++ b/install.py @@ -1,4 +1,5 @@ #!/usr/bin/env python2 +from __future__ import print_function import os import stat @@ -19,7 +20,7 @@ def load_source(srcfile): try: return ''.join(open(srcfile).readlines()) + '\n\n' except IOError: - print 'Could not open', srcfile + print('Could not open', srcfile) return '' if __name__ == "__main__": @@ -34,7 +35,7 @@ def load_source(srcfile): 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' + print(OUTPUT_FILE, 'saved successfully') except IOError: - print 'ERROR: Could not write to powerline-shell.py. Make sure it is writable' + print('ERROR: Could not write to powerline-shell.py. Make sure it is writable') exit(1) diff --git a/powerline-shell.py.template b/powerline-shell.py.template index 42149141..25401316 100755 --- a/powerline-shell.py.template +++ b/powerline-shell.py.template @@ -1,12 +1,13 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +from __future__ import print_function import argparse import os import sys def warn(msg): - print '[powerline-bash] ', msg + print('[powerline-bash] ', msg) class Powerline: symbols = { @@ -61,7 +62,7 @@ class Powerline: return self.color('48', code) def append(self, content, fg, bg, separator=None, separator_fg=None): - self.segments.append((content, fg, bg, + 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)) From f98bf71d1e8af46285975427896d23eff232fe72 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Fri, 31 Jul 2015 21:32:04 -0400 Subject: [PATCH 110/366] update readme with today's change --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 620de282..cafe0e0e 100644 --- a/README.md +++ b/README.md @@ -137,6 +137,10 @@ settings. # Changes +2015-07-31 + +* The current working directory no longer follows symbolic links + 2015-07-30 * Fix ZSH root indicator (@nkcfan) From ad3559481c597a591f27aac58dc02aa039d9208f Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Fri, 31 Jul 2015 21:32:39 -0400 Subject: [PATCH 111/366] remove stray paren --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cafe0e0e..a7976bba 100644 --- a/README.md +++ b/README.md @@ -148,5 +148,5 @@ settings. 2015-07-27 -* Use `python2` instead of `python` in hashbangs ( +* Use `python2` instead of `python` in hashbangs * Add `node_version` segment (@mmilleruva) From 4587f0e958f31970d29558c99ab64d6f7d1a3be0 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Fri, 31 Jul 2015 21:52:55 -0400 Subject: [PATCH 112/366] rename function in exit_code segment to match filename --- segments/exit_code.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/segments/exit_code.py b/segments/exit_code.py index 49b2cc2b..e9ba0886 100644 --- a/segments/exit_code.py +++ b/segments/exit_code.py @@ -1,8 +1,8 @@ -def add_status_indicator_segment(): +def add_exit_code_segment(): if powerline.args.prev_error == 0: return fg = Color.CMD_FAILED_FG bg = Color.CMD_FAILED_BG powerline.append(str(powerline.args.prev_error), fg, bg) -add_status_indicator_segment() +add_exit_code_segment() From 896d3de7d79205535232f9d21b8df71d01817f71 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Fri, 31 Jul 2015 21:59:11 -0400 Subject: [PATCH 113/366] added exit_code segment to readme and link to PRs --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a7976bba..a35e7293 100644 --- a/README.md +++ b/README.md @@ -140,13 +140,14 @@ settings. 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) -* Add uptime segment (@marcioAlmada) +* 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 -* Add `node_version` segment (@mmilleruva) +* 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)) From 763b72ef6143c59f94a4555366cda95601c7cfa8 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Tue, 18 Aug 2015 20:09:30 -0400 Subject: [PATCH 114/366] remove time from default segments --- config.py.dist | 3 --- 1 file changed, 3 deletions(-) diff --git a/config.py.dist b/config.py.dist index a77fc12c..a1e76272 100644 --- a/config.py.dist +++ b/config.py.dist @@ -13,9 +13,6 @@ SEGMENTS = [ # Show current virtual environment (see http://www.virtualenv.org/) 'virtual_env', -# Show current time - 'time', - # Show the current user's username as in ordinary prompts 'username', From 2bbe74c34847eb618634431d0bde27dfa83396ad Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Tue, 18 Aug 2015 20:21:38 -0400 Subject: [PATCH 115/366] add notes about recent changes --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index a35e7293..ec2d732d 100644 --- a/README.md +++ b/README.md @@ -137,6 +137,14 @@ settings. # Changes +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 From 959b7cacff5efa6acde608f137561d44d1f53d8d Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Fri, 7 Feb 2014 18:37:05 +0100 Subject: [PATCH 116/366] [ADD] argument --cwd-max-dir-size This allows to restrict the size of each displayed folder in the path. This is usefull to keep a minimum space usage for longer path. eg: for /usr/lib/python2.7/site-packages with value of 2, the displayed path would be /us/li/py/si Fixes #112 --- README.md | 3 +++ powerline_shell_base.py | 2 ++ segments/cwd.py | 2 ++ 3 files changed, 7 insertions(+) diff --git a/README.md b/README.md index ec2d732d..adcc4c10 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,9 @@ There are a few optional arguments which can be seen by running `powerline-shell --cwd-only Only show 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 diff --git a/powerline_shell_base.py b/powerline_shell_base.py index e2775fe1..c5257997 100755 --- a/powerline_shell_base.py +++ b/powerline_shell_base.py @@ -118,6 +118,8 @@ def get_valid_cwd(): help='Only show the current directory') 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', diff --git a/segments/cwd.py b/segments/cwd.py index 70724b00..cd7d9fd4 100644 --- a/segments/cwd.py +++ b/segments/cwd.py @@ -23,6 +23,8 @@ def add_cwd_segment(): if not powerline.args.cwd_only: for n in names[:-1]: + if powerline.args.cwd_max_dir_size: + n = n[:powerline.args.cwd_max_dir_size] if n == '~' and Color.HOME_SPECIAL_DISPLAY: powerline.append(' %s ' % n, Color.HOME_FG, Color.HOME_BG) else: From 17627e4136c211d698b70a1316a06eaab78c666f Mon Sep 17 00:00:00 2001 From: Pedro Lopes Date: Mon, 24 Aug 2015 16:49:07 +0100 Subject: [PATCH 117/366] Suggested changes for pull request - not tested --- segments/cwd.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/segments/cwd.py b/segments/cwd.py index f154f493..d42124f7 100644 --- a/segments/cwd.py +++ b/segments/cwd.py @@ -22,8 +22,7 @@ def add_cwd_segment(): names = names[:2] + [u'\u2026'] + names[2 - max_depth:] if powerline.args.cwd_mode=='plain': - powerline.append(' %s%s ' % ('' if names[0] in '/~' else '/', '/'.join(names)), - Color.CWD_FG, Color.PATH_BG) + powerline.append(cwd, Color.CWD_FG, Color.PATH_BG) else: if not (powerline.args.cwd_mode=='dironly' or powerline.args.cwd_only): for n in names[:-1]: From 431601e0a890d88c32e788dd8d1234852411d75f Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Wed, 26 Aug 2015 13:03:41 -0400 Subject: [PATCH 118/366] add notes about today's change --- README.md | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index dd8a44cd..dd111204 100644 --- a/README.md +++ b/README.md @@ -138,25 +138,39 @@ settings. # Changes +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)) +* 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)) +* 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)) +* 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)) +* 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)) +* 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)) From dc7b8a3a656d01a737d0901b8c4c382d73a25595 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Wed, 26 Aug 2015 13:17:47 -0400 Subject: [PATCH 119/366] refactor get_short_path into two functions use this to replace the home directory in the new plain mode --- segments/cwd.py | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/segments/cwd.py b/segments/cwd.py index d42124f7..c9a791df 100644 --- a/segments/cwd.py +++ b/segments/cwd.py @@ -1,30 +1,38 @@ import os -def get_short_path(cwd): + +def replace_home_dir(cwd): home = os.getenv('HOME') + if cwd.startswith(home): + return '~' + cwd[len(home):] + return cwd + + +def split_path_into_names(cwd): names = cwd.split(os.sep) - if names[0] == '': names = names[1:] - path = '' - for i in range(len(names)): - path += os.sep + names[i] - if os.path.samefile(path, home): - return ['~'] + names[i+1:] + + if names[0] == '': + names = names[1:] + if not names[0]: return ['/'] + return names + def add_cwd_segment(): - cwd = powerline.cwd or os.getenv('PWD') - names = get_short_path(cwd.decode('utf-8')) + cwd = (powerline.cwd or os.getenv('PWD')).decode('utf-8') + cwd = replace_home_dir(cwd) + names = split_path_into_names(cwd) max_depth = powerline.args.cwd_max_depth if len(names) > max_depth: names = names[:2] + [u'\u2026'] + names[2 - max_depth:] - if powerline.args.cwd_mode=='plain': - powerline.append(cwd, Color.CWD_FG, Color.PATH_BG) + if powerline.args.cwd_mode == 'plain': + powerline.append(' %s ' % (cwd,), Color.CWD_FG, Color.PATH_BG) else: - if not (powerline.args.cwd_mode=='dironly' or powerline.args.cwd_only): + if not (powerline.args.cwd_mode == 'dironly' or powerline.args.cwd_only): for n in names[:-1]: if n == '~' and Color.HOME_SPECIAL_DISPLAY: powerline.append(' %s ' % n, Color.HOME_FG, Color.HOME_BG) From 8a28dee1bc3ca8ec83705cc431768ef18be7798c Mon Sep 17 00:00:00 2001 From: Chris Holden Date: Fri, 4 Sep 2015 15:51:06 -0400 Subject: [PATCH 120/366] Allow venv segment to be from Anaconda --- segments/virtual_env.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/segments/virtual_env.py b/segments/virtual_env.py index 71b0ee8d..d8937e63 100644 --- a/segments/virtual_env.py +++ b/segments/virtual_env.py @@ -1,7 +1,7 @@ import os def add_virtual_env_segment(): - env = os.getenv('VIRTUAL_ENV') + env = os.getenv('VIRTUAL_ENV') or os.getenv('CONDA_ENV_PATH') if env is None: return From 7bf58d1d8235ab40961d4dfae0fd4b89ad696d0d Mon Sep 17 00:00:00 2001 From: Martin Wetterwald Date: Thu, 24 Sep 2015 11:33:26 +0200 Subject: [PATCH 121/366] Uses UTF-8 codes instead of characters in git segment as suggested by @Anarky: https://github.com/milkbikis/powerline-shell/pull/136#discussion_r10820795 --- segments/git.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/segments/git.py b/segments/git.py index 6172d086..db169139 100644 --- a/segments/git.py +++ b/segments/git.py @@ -23,6 +23,15 @@ def get_git_status(pdata): def add_git_segment(): + symbols = { + 'detached': u'\u2693', + 'ahead': u'\u2B06', + 'behind': u'\u2B07', + 'staged': u'\u2714', + 'notstaged': u'\u270E', + 'conflicted': u'\u273C' + } + p = subprocess.Popen(['git', 'status', '--porcelain', '-b'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) pdata = p.communicate() if p.returncode != 0: @@ -36,7 +45,7 @@ def add_git_segment(): p = subprocess.Popen(['git', 'describe', '--tags', '--always'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) detached_ref = p.communicate()[0].rstrip('\n') if p.returncode == 0: - branch = '⚓ {}'.format(detached_ref).decode('utf-8') + branch = '%c %s' % (symbols['detached'], detached_ref.decode('utf-8')) else: branch = 'Big Bang' @@ -50,17 +59,17 @@ def add_git_segment(): if branchinfo: if branchinfo['ahead']: - powerline.append("{}⬆".format(branchinfo['ahead'] if int(branchinfo['ahead']) > 1 else str('')).decode('utf-8'), Color.GIT_AHEAD_FG, Color.GIT_AHEAD_BG) + powerline.append('%s%c' % (branchinfo['ahead'] if int(branchinfo['ahead']) > 1 else str('').decode('utf-8'), symbols['ahead']), Color.GIT_AHEAD_FG, Color.GIT_AHEAD_BG) if branchinfo['behind']: - powerline.append("{}⬇".format(branchinfo['behind'] if int(branchinfo['behind']) > 1 else str('')).decode('utf-8'), Color.GIT_BEHIND_FG, Color.GIT_BEHIND_BG) + powerline.append('%s%c' % (branchinfo['behind'] if int(branchinfo['behind']) > 1 else str('').decode('utf-8'), symbols['behind']), Color.GIT_BEHIND_FG, Color.GIT_BEHIND_BG) if stats['staged']: - powerline.append("{}✔".format(stats['staged'] if stats['staged'] > 1 else str('')).decode('utf-8'), Color.GIT_STAGED_FG, Color.GIT_STAGED_BG) + powerline.append('%s%c' % (stats['staged'] if stats['staged'] > 1 else str('').decode('utf-8'), symbols['staged']), Color.GIT_STAGED_FG, Color.GIT_STAGED_BG) if stats['notstaged']: - powerline.append("{}✎".format(stats['notstaged'] if stats['notstaged'] > 1 else str('')).decode('utf-8'), Color.GIT_NOTSTAGED_FG, Color.GIT_NOTSTAGED_BG) + powerline.append('%s%c' % (stats['notstaged'] if stats['notstaged'] > 1 else str('').decode('utf-8'), symbols['notstaged']), Color.GIT_NOTSTAGED_FG, Color.GIT_NOTSTAGED_BG) if stats['untracked']: - powerline.append("{}?".format(stats['untracked'] if stats['untracked'] > 1 else str('')), Color.GIT_UNTRACKED_FG, Color.GIT_UNTRACKED_BG) + powerline.append('%s?' % (stats['untracked'] if stats['untracked'] > 1 else str('')), Color.GIT_UNTRACKED_FG, Color.GIT_UNTRACKED_BG) if stats['conflicted']: - powerline.append("{}✼".format(stats['conflicted'] if stats['conflicted'] > 1 else str('')).decode('utf-8'), Color.GIT_CONFLICTED_FG, Color.GIT_CONFLICTED_BG) + powerline.append('%s%c' % (stats['conflicted'] if stats['conflicted'] > 1 else str('').decode('utf-8'), symbols['conflicted']), Color.GIT_CONFLICTED_FG, Color.GIT_CONFLICTED_BG) try: add_git_segment() except OSError: From 284e3bbdc5ebeaa503e317b111e60e271902ff18 Mon Sep 17 00:00:00 2001 From: Martin Wetterwald Date: Thu, 24 Sep 2015 11:41:29 +0200 Subject: [PATCH 122/366] Enhances icon for untracked files in git segment. --- segments/git.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/segments/git.py b/segments/git.py index db169139..7426a127 100644 --- a/segments/git.py +++ b/segments/git.py @@ -29,6 +29,7 @@ def add_git_segment(): 'behind': u'\u2B07', 'staged': u'\u2714', 'notstaged': u'\u270E', + 'untracked': u'\u2753', 'conflicted': u'\u273C' } @@ -67,7 +68,7 @@ def add_git_segment(): if stats['notstaged']: powerline.append('%s%c' % (stats['notstaged'] if stats['notstaged'] > 1 else str('').decode('utf-8'), symbols['notstaged']), Color.GIT_NOTSTAGED_FG, Color.GIT_NOTSTAGED_BG) if stats['untracked']: - powerline.append('%s?' % (stats['untracked'] if stats['untracked'] > 1 else str('')), Color.GIT_UNTRACKED_FG, Color.GIT_UNTRACKED_BG) + powerline.append('%s%c' % (stats['untracked'] if stats['untracked'] > 1 else str('').decode('utf-8'), symbols['untracked']), Color.GIT_UNTRACKED_FG, Color.GIT_UNTRACKED_BG) if stats['conflicted']: powerline.append('%s%c' % (stats['conflicted'] if stats['conflicted'] > 1 else str('').decode('utf-8'), symbols['conflicted']), Color.GIT_CONFLICTED_FG, Color.GIT_CONFLICTED_BG) try: From 1ff9a437608edee96802d96b51e2e8aadc979180 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Fri, 2 Oct 2015 22:05:25 -0400 Subject: [PATCH 123/366] update README --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 29690ae1..d532d7ce 100644 --- a/README.md +++ b/README.md @@ -141,6 +141,13 @@ settings. # Changes +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 From 0bece00c9a936bef77ee4808587a5e789ec80fab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Watteng=C3=A5rd?= Date: Sat, 7 Nov 2015 19:13:52 +0100 Subject: [PATCH 124/366] First commit of battery percentage segment --- segments/battery.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 segments/battery.py diff --git a/segments/battery.py b/segments/battery.py new file mode 100644 index 00000000..17d9fad3 --- /dev/null +++ b/segments/battery.py @@ -0,0 +1,22 @@ +def add_battery_segment(): + f = open('/sys/class/power_supply/BAT0/capacity') + cap = f.read().strip() + f.close() + + f = open('/sys/class/power_supply/BAT0/status') + status = f.read().strip() + f.close() + + if status == 'Charging': + pwr = u' \u21ea ' + else: + pwr = ' ' + + if int(cap) > 20: + bg = Color.HOME_BG + else: + bg = Color.READONLY_BG + + powerline.append(' ' + cap + '%' + pwr, Color.HOME_FG, bg) + +add_battery_segment() From a57ee0fa719781e7f18ed71b3a5d4cee0df8cd7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Watteng=C3=A5rd?= Date: Sat, 7 Nov 2015 19:31:33 +0100 Subject: [PATCH 125/366] Made separate color constants for battery --- segments/battery.py | 18 ++++++++++++------ themes/default.py | 5 +++++ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/segments/battery.py b/segments/battery.py index 17d9fad3..ab12e0af 100644 --- a/segments/battery.py +++ b/segments/battery.py @@ -1,9 +1,13 @@ def add_battery_segment(): - f = open('/sys/class/power_supply/BAT0/capacity') + CAP_FILE = '/sys/class/power_supply/BAT0/capacity' + STATUS_FILE = '/sys/class/power_supply/BAT0/status' + LOW_BATTERY_THRESHOLD = 20 + + f = open(CAP_FILE) cap = f.read().strip() f.close() - f = open('/sys/class/power_supply/BAT0/status') + f = open(STATUS_FILE) status = f.read().strip() f.close() @@ -12,11 +16,13 @@ def add_battery_segment(): else: pwr = ' ' - if int(cap) > 20: - bg = Color.HOME_BG + if int(cap) < LOW_BATTERY_THRESHOLD: + bg = Color.BATTERY_LOW_BG + fg = Color.BATTERY_LOW_FG else: - bg = Color.READONLY_BG + bg = Color.BATTERY_NORMAL_BG + fg = Color.BATTERY_NORMAL_FG - powerline.append(' ' + cap + '%' + pwr, Color.HOME_FG, bg) + powerline.append(' ' + cap + '%' + pwr, fg, bg) add_battery_segment() diff --git a/themes/default.py b/themes/default.py index ba4e5511..4d93a583 100644 --- a/themes/default.py +++ b/themes/default.py @@ -42,6 +42,11 @@ 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 class Color(DefaultColor): """ From 3098ce9f033d11f1bc0534e7e2dc9780ee116f46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Watteng=C3=A5rd?= Date: Sat, 7 Nov 2015 20:08:36 +0100 Subject: [PATCH 126/366] =?UTF-8?q?Replaced=20charging=20symbol=20with=20l?= =?UTF-8?q?ightning=20bolt=20(=E2=9A=A1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- segments/battery.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/segments/battery.py b/segments/battery.py index ab12e0af..10efe1a4 100644 --- a/segments/battery.py +++ b/segments/battery.py @@ -12,7 +12,7 @@ def add_battery_segment(): f.close() if status == 'Charging': - pwr = u' \u21ea ' + pwr = u' \u26A1 ' else: pwr = ' ' From 9610c2434a6dee1465c2aa631bf71015a243fc67 Mon Sep 17 00:00:00 2001 From: Ben Chatelain Date: Mon, 16 Nov 2015 21:26:46 -0700 Subject: [PATCH 127/366] Add padding to exit_code segment --- segments/exit_code.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/segments/exit_code.py b/segments/exit_code.py index e9ba0886..5c936156 100644 --- a/segments/exit_code.py +++ b/segments/exit_code.py @@ -3,6 +3,6 @@ def add_exit_code_segment(): return fg = Color.CMD_FAILED_FG bg = Color.CMD_FAILED_BG - powerline.append(str(powerline.args.prev_error), fg, bg) + powerline.append(' %s ' % str(powerline.args.prev_error), fg, bg) add_exit_code_segment() From 7227babb8cd0ec547b9787ca268d234f6523f854 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Wed, 18 Nov 2015 20:03:09 -0500 Subject: [PATCH 128/366] update README and refactor git.py to merge #136 --- README.md | 28 ++++++++++++-- segments/git.py | 98 ++++++++++++++++++++++++++++--------------------- 2 files changed, 81 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index dd111204..bafa5ff9 100644 --- a/README.md +++ b/README.md @@ -5,15 +5,35 @@ A [Powerline](https://github.com/Lokaltog/vim-powerline) like prompt for Bash, Z ![MacVim+Solarized+Powerline+CtrlP](https://raw.github.com/milkbikis/dotfiles-mac/master/bash-powerline-screenshot.png) -* Shows some important details about the git/svn/hg/fossil branch: - * Displays the current branch which changes background color when the branch is dirty - * A '+' appears when untracked files are present - * 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 +* 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 + +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 + branch is dirty. +* 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 + +FIXME + * 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 This script uses ANSI color codes to display colors in a terminal. These are diff --git a/segments/git.py b/segments/git.py index 7426a127..8f11b4d3 100644 --- a/segments/git.py +++ b/segments/git.py @@ -1,11 +1,35 @@ import re import subprocess -def get_git_status(pdata): - status = pdata[0].splitlines() +GIT_SYMBOLS = { + 'detached': u'\u2693', + 'ahead': u'\u2B06', + 'behind': u'\u2B07', + 'staged': u'\u2714', + 'notstaged': u'\u270E', + 'untracked': u'\u2753', + 'conflicted': u'\u273C' +} + + +def parse_git_branch_info(status): + info = re.search('^## (?P\S+?)''(\.{3}(?P\S+?)( \[(ahead (?P\d+)(, )?)?(behind (?P\d+))?\])?)?$', status[0]) + return info.groupdict() if info else None - branchinfo = re.search('^## (?P\S+?)(\.{3}(?P\S+?)( \[(ahead (?P\d+)(, )?)?(behind (?P\d+))?\])?)?$', status[0]) +def _get_git_detached_branch(): + p = subprocess.Popen(['git', 'describe', '--tags', '--always'], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + detached_ref = p.communicate()[0].rstrip('\n') + if p.returncode == 0: + branch = u'{} {}'.format(GIT_SYMBOLS['detached'], + detached_ref.decode('utf-8')) + else: + branch = 'Big Bang' + return branch + + +def parse_git_stats(status): stats = {'untracked': 0, 'notstaged': 0, 'staged': 0, 'conflicted': 0} for statusline in status[1:]: code = statusline[:2] @@ -18,37 +42,31 @@ def get_git_status(pdata): stats['notstaged'] += 1 if code[0] != ' ': stats['staged'] += 1 - dirty = (True if sum(stats.values()) > 0 else False) - return dirty, stats, branchinfo.groupdict() if branchinfo else None + + return stats + + +def _n_or_empty(_dict, _key): + return _dict[_key] if int(_dict[_key]) > 1 else u'' def add_git_segment(): - symbols = { - 'detached': u'\u2693', - 'ahead': u'\u2B06', - 'behind': u'\u2B07', - 'staged': u'\u2714', - 'notstaged': u'\u270E', - 'untracked': u'\u2753', - 'conflicted': u'\u273C' - } - - p = subprocess.Popen(['git', 'status', '--porcelain', '-b'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + p = subprocess.Popen(['git', 'status', '--porcelain', '-b'], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) pdata = p.communicate() if p.returncode != 0: return - dirty, stats, branchinfo = get_git_status(pdata) + status = pdata[0].splitlines() + + branch_info = parse_git_branch_info(status) + stats = parse_git_stats(status) + dirty = (True if sum(stats.values()) > 0 else False) - if branchinfo: - branch = branchinfo['local'] + if branch_info: + branch = branch_info['local'] else: - p = subprocess.Popen(['git', 'describe', '--tags', '--always'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - detached_ref = p.communicate()[0].rstrip('\n') - if p.returncode == 0: - branch = '%c %s' % (symbols['detached'], detached_ref.decode('utf-8')) - else: - branch = 'Big Bang' + branch = _get_git_detached_branch() bg = Color.REPO_CLEAN_BG fg = Color.REPO_CLEAN_FG @@ -58,22 +76,20 @@ def add_git_segment(): powerline.append(' %s ' % branch, fg, bg) - if branchinfo: - if branchinfo['ahead']: - powerline.append('%s%c' % (branchinfo['ahead'] if int(branchinfo['ahead']) > 1 else str('').decode('utf-8'), symbols['ahead']), Color.GIT_AHEAD_FG, Color.GIT_AHEAD_BG) - if branchinfo['behind']: - powerline.append('%s%c' % (branchinfo['behind'] if int(branchinfo['behind']) > 1 else str('').decode('utf-8'), symbols['behind']), Color.GIT_BEHIND_FG, Color.GIT_BEHIND_BG) - if stats['staged']: - powerline.append('%s%c' % (stats['staged'] if stats['staged'] > 1 else str('').decode('utf-8'), symbols['staged']), Color.GIT_STAGED_FG, Color.GIT_STAGED_BG) - if stats['notstaged']: - powerline.append('%s%c' % (stats['notstaged'] if stats['notstaged'] > 1 else str('').decode('utf-8'), symbols['notstaged']), Color.GIT_NOTSTAGED_FG, Color.GIT_NOTSTAGED_BG) - if stats['untracked']: - powerline.append('%s%c' % (stats['untracked'] if stats['untracked'] > 1 else str('').decode('utf-8'), symbols['untracked']), Color.GIT_UNTRACKED_FG, Color.GIT_UNTRACKED_BG) - if stats['conflicted']: - powerline.append('%s%c' % (stats['conflicted'] if stats['conflicted'] > 1 else str('').decode('utf-8'), symbols['conflicted']), Color.GIT_CONFLICTED_FG, Color.GIT_CONFLICTED_BG) + 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) + + 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) + try: add_git_segment() -except OSError: - pass -except subprocess.CalledProcessError: +except (OSError, subprocess.CalledProcessError): pass From 3570c03bb8dd8f4c1eb6b581c7245bd80093a933 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Wed, 18 Nov 2015 20:39:32 -0500 Subject: [PATCH 129/366] git README note --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index d72f8536..9e693cbf 100644 --- a/README.md +++ b/README.md @@ -161,6 +161,11 @@ settings. # Changes +2015-11-18 + +* The git segment has gotten a makeover + ([MartinWetterwald](https://github.com/milkbikis/powerline-shell/pull/136)) + 2015-10-02 * New option (`--cwd-max-dir-size`) which allows you to limit each directory From 3ecc4611ee649e3ba69c33b7fa2721c37d2ea7f9 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Wed, 18 Nov 2015 21:10:54 -0500 Subject: [PATCH 130/366] release note --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 9e693cbf..fcc9bb36 100644 --- a/README.md +++ b/README.md @@ -165,6 +165,8 @@ settings. * 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)) 2015-10-02 From 337c5eff60442da5a230c00332b3685fb3c31f39 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Wed, 18 Nov 2015 22:36:44 -0500 Subject: [PATCH 131/366] Fixes #148, #157, #158 --- segments/cwd.py | 60 ++++++++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/segments/cwd.py b/segments/cwd.py index 30342626..28b9d326 100644 --- a/segments/cwd.py +++ b/segments/cwd.py @@ -1,5 +1,7 @@ import os +ELLIPSIS = u'\u2026' + def replace_home_dir(cwd): home = os.getenv('HOME') @@ -46,31 +48,43 @@ def get_fg_bg(name): def add_cwd_segment(): cwd = (powerline.cwd or os.getenv('PWD')).decode('utf-8') cwd = replace_home_dir(cwd) - names = split_path_into_names(cwd) - - max_depth = powerline.args.cwd_max_depth - if len(names) > max_depth: - names = names[:2] + [u'\u2026'] + names[2 - max_depth:] if powerline.args.cwd_mode == 'plain': powerline.append(' %s ' % (cwd,), Color.CWD_FG, Color.PATH_BG) - else: - if (powerline.args.cwd_mode == 'dironly' or powerline.args.cwd_only): - # 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) - - 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 = None - separator_fg = None - - powerline.append(' %s ' % maybe_shorten_name(name), fg, bg, - separator, separator_fg) + return + + names = split_path_into_names(cwd) + + max_depth = powerline.args.cwd_max_depth + if max_depth <= 0: + warn("Ignoring --cwd-max-depth argument 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 + # ellipsis. So if you are at ~/a/b/c/d/e and max depth is 4, it will + # show `~ a ... d e`. + # + # max_depth must be greater than n_before or else you end up repeating + # parts of the path with the way the splicing is written below. + 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): + # 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) + + 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 = None + separator_fg = None + + powerline.append(' %s ' % maybe_shorten_name(name), fg, bg, + separator, separator_fg) add_cwd_segment() From c14a274764b9a57ea0f7b53b47090647a7323871 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Wed, 18 Nov 2015 22:44:01 -0500 Subject: [PATCH 132/366] release note --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index fcc9bb36..9242dc95 100644 --- a/README.md +++ b/README.md @@ -167,6 +167,8 @@ settings. ([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)) 2015-10-02 From 1ea9b7f5aef33be3c21425d5a5d128c18ee35c7c Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Wed, 18 Nov 2015 22:56:34 -0500 Subject: [PATCH 133/366] release note --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9242dc95..4ebb7260 100644 --- a/README.md +++ b/README.md @@ -164,11 +164,13 @@ settings. 2015-11-18 * The git segment has gotten a makeover - ([MartinWetterwald](https://github.com/milkbikis/powerline-shell/pull/136)) + ([@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)) + ([@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)) + ([@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 From e28d9b37d46680262b7737d5b052e993fa3404b9 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Thu, 19 Nov 2015 22:31:15 -0500 Subject: [PATCH 134/366] fix python3 compatibility --- powerline_shell_base.py | 12 ++++++++++-- segments/cwd.py | 2 +- segments/git.py | 7 +++---- segments/hg.py | 6 ++++-- segments/jobs.py | 10 ++++++++-- segments/node_version.py | 2 +- segments/ruby_version.py | 2 +- segments/svn.py | 7 ++++--- 8 files changed, 32 insertions(+), 16 deletions(-) diff --git a/powerline_shell_base.py b/powerline_shell_base.py index c4c1e846..8b95fb3a 100755 --- a/powerline_shell_base.py +++ b/powerline_shell_base.py @@ -6,9 +6,13 @@ import os import sys +py3 = sys.version_info.major == 3 + + def warn(msg): print('[powerline-bash] ', msg) + class Powerline: symbols = { 'compatible': { @@ -67,8 +71,12 @@ def append(self, content, fg, bg, separator=None, separator_fg=None): separator_fg if separator_fg is not None else bg)) def draw(self): - return (''.join(self.draw_segment(i) for i in range(len(self.segments))) - + self.reset).encode('utf-8') + ' ' + 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] diff --git a/segments/cwd.py b/segments/cwd.py index 28b9d326..a697a032 100644 --- a/segments/cwd.py +++ b/segments/cwd.py @@ -46,7 +46,7 @@ def get_fg_bg(name): def add_cwd_segment(): - cwd = (powerline.cwd or os.getenv('PWD')).decode('utf-8') + cwd = powerline.cwd or os.getenv('PWD') cwd = replace_home_dir(cwd) if powerline.args.cwd_mode == 'plain': diff --git a/segments/git.py b/segments/git.py index 3fb4749d..cc0787bc 100644 --- a/segments/git.py +++ b/segments/git.py @@ -33,10 +33,9 @@ def _get_git_detached_branch(): p = subprocess.Popen(['git', 'describe', '--tags', '--always'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=git_subprocess_env) - detached_ref = p.communicate()[0].rstrip('\n') + detached_ref = p.communicate()[0].decode("utf-8").rstrip('\n') if p.returncode == 0: - branch = u'{} {}'.format(GIT_SYMBOLS['detached'], - detached_ref.decode('utf-8')) + branch = u'{} {}'.format(GIT_SYMBOLS['detached'], detached_ref) else: branch = 'Big Bang' return branch @@ -71,7 +70,7 @@ def add_git_segment(): if p.returncode != 0: return - status = pdata[0].splitlines() + status = pdata[0].decode("utf-8").splitlines() branch_info = parse_git_branch_info(status) stats = parse_git_stats(status) diff --git a/segments/hg.py b/segments/hg.py index 8b95000b..5a4f40dc 100644 --- a/segments/hg.py +++ b/segments/hg.py @@ -5,8 +5,10 @@ def get_hg_status(): has_modified_files = False has_untracked_files = False has_missing_files = False - output = subprocess.Popen(['hg', 'status'], - stdout=subprocess.PIPE).communicate()[0] + + p = subprocess.Popen(['hg', 'status'], stdout=subprocess.PIPE) + output = p.communicate()[0].decode("utf-8") + for line in output.split('\n'): if line == '': continue diff --git a/segments/jobs.py b/segments/jobs.py index 3fae3dff..5dde3e65 100644 --- a/segments/jobs.py +++ b/segments/jobs.py @@ -3,8 +3,14 @@ import subprocess def add_jobs_segment(): - pppid = subprocess.Popen(['ps', '-p', str(os.getppid()), '-oppid='], stdout=subprocess.PIPE).communicate()[0].strip() - output = subprocess.Popen(['ps', '-a', '-o', 'ppid'], stdout=subprocess.PIPE).communicate()[0] + 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: diff --git a/segments/node_version.py b/segments/node_version.py index cf9e4132..842e487c 100644 --- a/segments/node_version.py +++ b/segments/node_version.py @@ -4,7 +4,7 @@ def add_node_version_segment(): try: p1 = subprocess.Popen(["node", "--version"], stdout=subprocess.PIPE) - version = p1.communicate()[0].rstrip() + version = p1.communicate()[0].decode("utf-8").rstrip() version = "node " + version powerline.append(version, 15, 18) except OSError: diff --git a/segments/ruby_version.py b/segments/ruby_version.py index 64b5551b..82ba7f27 100644 --- a/segments/ruby_version.py +++ b/segments/ruby_version.py @@ -5,7 +5,7 @@ def add_ruby_version_segment(): try: p1 = subprocess.Popen(["ruby", "-v"], stdout=subprocess.PIPE) p2 = subprocess.Popen(["sed", "s/ (.*//"], stdin=p1.stdout, stdout=subprocess.PIPE) - version = p2.communicate()[0].rstrip() + 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: diff --git a/segments/svn.py b/segments/svn.py index f634a45e..a378a87a 100644 --- a/segments/svn.py +++ b/segments/svn.py @@ -1,8 +1,9 @@ import subprocess def add_svn_segment(): - is_svn = subprocess.Popen(['svn', 'status'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - is_svn_output = is_svn.communicate()[1].strip() + 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 @@ -11,7 +12,7 @@ def add_svn_segment(): stderr=subprocess.PIPE) p2 = subprocess.Popen(['grep', '-c', '^[ACDIMR\\!\\~]'], stdin=p1.stdout, stdout=subprocess.PIPE) - output = p2.communicate()[0].strip() + 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) From d781ec4985c312d8f77c5da0dd660836e2defc0c Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 21 Nov 2015 18:55:55 -0500 Subject: [PATCH 135/366] fix unicode issue in cwd --- segments/cwd.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/segments/cwd.py b/segments/cwd.py index a697a032..d5e3a791 100644 --- a/segments/cwd.py +++ b/segments/cwd.py @@ -47,6 +47,8 @@ def get_fg_bg(name): def add_cwd_segment(): cwd = powerline.cwd or os.getenv('PWD') + if not py3: + cwd = cwd.decode("utf-8") cwd = replace_home_dir(cwd) if powerline.args.cwd_mode == 'plain': From b66461fc8e662e1393decae7d46a2bbae8d08ed7 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 21 Nov 2015 19:48:16 -0500 Subject: [PATCH 136/366] release note --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 4ebb7260..6efe6e53 100644 --- a/README.md +++ b/README.md @@ -161,6 +161,11 @@ settings. # Changes +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 From 87b297ac233fb62111ff2be2e69e98415138776b Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sun, 22 Nov 2015 12:20:38 -0500 Subject: [PATCH 137/366] only include the user's theme if it is not the default fixes #121 --- install.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/install.py b/install.py index 6b781497..500f35ae 100755 --- a/install.py +++ b/install.py @@ -26,9 +26,13 @@ def load_source(srcfile): if __name__ == "__main__": source = load_source(TEMPLATE_FILE) source += load_source(os.path.join(THEMES_DIR, 'default.py')) - source += load_source(os.path.join(THEMES_DIR, config.THEME + '.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')) + source += 'sys.stdout.write(powerline.draw())\n' try: From 6db5053e2fce0499fe9279a92a32673669bc2f62 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Wed, 25 Nov 2015 11:23:17 -0500 Subject: [PATCH 138/366] release note --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 6efe6e53..5e29c878 100644 --- a/README.md +++ b/README.md @@ -161,6 +161,11 @@ settings. # Changes +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 From 7686aca6cb74d1f966d1ae3079b5159ea5a51128 Mon Sep 17 00:00:00 2001 From: Philipp Kretzschmar Date: Sat, 28 Nov 2015 00:03:14 +0100 Subject: [PATCH 139/366] Docs: rm indent level in codeblock The indent level didn't allow for copy and paste in my ~/.vimrc, as there were prefixed by 8 spaces. --- README.md | 56 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 5e29c878..40d3ff2e 100644 --- a/README.md +++ b/README.md @@ -85,40 +85,46 @@ There are a few optional arguments which can be seen by running `powerline-shell ### Bash: Add the following to your `.bashrc` (or `.profile` on Mac): - function _update_ps1() { - PS1="$(~/powerline-shell.py $? 2> /dev/null)" - } +``` +function _update_ps1() { + PS1="$(~/powerline-shell.py $? 2> /dev/null)" +} - if [ "$TERM" != "linux" ]; then - PROMPT_COMMAND="_update_ps1; $PROMPT_COMMAND" - fi +if [ "$TERM" != "linux" ]; then + PROMPT_COMMAND="_update_ps1; $PROMPT_COMMAND" +fi +``` ### ZSH: Add the following to your `.zshrc`: - function powerline_precmd() { - PS1="$(~/powerline-shell.py $? --shell zsh 2> /dev/null)" - } - - function install_powerline_precmd() { - for s in "${precmd_functions[@]}"; do - if [ "$s" = "powerline_precmd" ]; then - return - fi - done - precmd_functions+=(powerline_precmd) - } - - if [ "$TERM" != "linux" ]; then - install_powerline_precmd - fi +``` +function powerline_precmd() { + PS1="$(~/powerline-shell.py $? --shell zsh 2> /dev/null)" +} + +function install_powerline_precmd() { + for s in "${precmd_functions[@]}"; do + if [ "$s" = "powerline_precmd" ]; then + return + fi + done + precmd_functions+=(powerline_precmd) +} + +if [ "$TERM" != "linux" ]; then + install_powerline_precmd +fi +``` ### Fish: Redefine `fish_prompt` in ~/.config/fish/config.fish: - function fish_prompt - ~/powerline-shell.py $status --shell bare ^/dev/null - end +``` +function fish_prompt + ~/powerline-shell.py $status --shell bare ^/dev/null +end +``` # Customization From b9845c56f3aa62cd2c6f42a914985f1bc3ff148d Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Wed, 16 Dec 2015 12:36:41 -0500 Subject: [PATCH 140/366] change the install command's hashbang to just python --- install.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.py b/install.py index 500f35ae..9be4b712 100755 --- a/install.py +++ b/install.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python from __future__ import print_function import os import stat From 6bef8fab1dc86739f6073d8dfbacc1fb20dc1edc Mon Sep 17 00:00:00 2001 From: Chris Holden Date: Tue, 22 Dec 2015 01:42:09 -0500 Subject: [PATCH 141/366] Try hashlib over md5 (md5 is deprecated) --- lib/color_compliment.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/color_compliment.py b/lib/color_compliment.py index 988684ca..5d5eec47 100755 --- a/lib/color_compliment.py +++ b/lib/color_compliment.py @@ -2,7 +2,11 @@ from colortrans import * from colorsys import hls_to_rgb, rgb_to_hls -from md5 import md5 +# md5 deprecated since Python 2.5 +try: + from md5 import md5 +except ImportError: + from hashlib import md5 from sys import argv From 1f1acb81cba48e35820c4a88b4c39ab5ff40db42 Mon Sep 17 00:00:00 2001 From: Chris Holden Date: Tue, 22 Dec 2015 01:45:55 -0500 Subject: [PATCH 142/366] Fix py3 ImportError by using relative import --- lib/color_compliment.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/color_compliment.py b/lib/color_compliment.py index 5d5eec47..12b082e9 100755 --- a/lib/color_compliment.py +++ b/lib/color_compliment.py @@ -1,6 +1,4 @@ #! /usr/bin/env python - -from colortrans import * from colorsys import hls_to_rgb, rgb_to_hls # md5 deprecated since Python 2.5 try: @@ -9,6 +7,9 @@ from hashlib import md5 from sys import argv +# Original, non-relative import errors on Python3 +from .colortrans import * + def getOppositeColor(r,g,b): hls = rgb_to_hls(r,g,b) From c07c4be6b4e410a56bc95284bb553f5b1baaa7f7 Mon Sep 17 00:00:00 2001 From: Chris Holden Date: Tue, 22 Dec 2015 01:47:51 -0500 Subject: [PATCH 143/366] Fix unicode digest error on Py3 Encoding works on Py2.7, but will only encode if Py3 in case it breaks earlier Py2.x --- lib/color_compliment.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/color_compliment.py b/lib/color_compliment.py index 12b082e9..0a040d2a 100755 --- a/lib/color_compliment.py +++ b/lib/color_compliment.py @@ -5,11 +5,13 @@ from md5 import md5 except ImportError: from hashlib import md5 -from sys import argv +import sys # Original, non-relative import errors on Python3 from .colortrans import * +py3 = sys.version_info.major == 3 + def getOppositeColor(r,g,b): hls = rgb_to_hls(r,g,b) @@ -32,6 +34,10 @@ 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 color1 = rgbstring2tuple(string) color2 = getOppositeColor(*color1) From d22338fff86ee2885a1156d37aea7eab64d90362 Mon Sep 17 00:00:00 2001 From: Chris Holden Date: Tue, 22 Dec 2015 02:33:00 -0500 Subject: [PATCH 144/366] Fix sys.version_info for Python<=2.6 sys.version_info doesn't have named tuple components prior to Python 2.7 https://docs.python.org/2/library/sys.html#sys.version_info --- lib/color_compliment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/color_compliment.py b/lib/color_compliment.py index 0a040d2a..9e022ddc 100755 --- a/lib/color_compliment.py +++ b/lib/color_compliment.py @@ -10,7 +10,7 @@ # Original, non-relative import errors on Python3 from .colortrans import * -py3 = sys.version_info.major == 3 +py3 = sys.version_info[0] == 3 def getOppositeColor(r,g,b): From b3d914bb00547a5074c9c90c73cca5e08dba5ef7 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 26 Dec 2015 10:32:31 -0500 Subject: [PATCH 145/366] readme note --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 40d3ff2e..91554aec 100644 --- a/README.md +++ b/README.md @@ -167,6 +167,11 @@ settings. # Changes +2015-12-26 + +* 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` From 03e74797ea4eaadf6780fcd011540453f1619fbe Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Fri, 20 Nov 2015 11:07:11 -0500 Subject: [PATCH 146/366] have the install script add each segment so the files can be imported for testing --- install.py | 4 ++++ segments/cwd.py | 8 +++----- segments/exit_code.py | 4 +--- segments/fossil.py | 17 ++++++++--------- segments/git.py | 11 ++++++----- segments/hg.py | 4 +--- segments/hostname.py | 5 +---- segments/jobs.py | 4 +--- segments/node_version.py | 4 +--- segments/php_version.py | 4 +--- segments/read_only.py | 4 +--- segments/root.py | 4 +--- segments/ruby_version.py | 4 +--- segments/set_term_title.py | 4 +--- segments/ssh.py | 4 +--- segments/svn.py | 14 +++++++------- segments/time.py | 4 +--- segments/uptime.py | 4 +--- segments/username.py | 4 +--- segments/virtual_env.py | 4 +--- 20 files changed, 43 insertions(+), 72 deletions(-) diff --git a/install.py b/install.py index 9be4b712..bf36f41e 100755 --- a/install.py +++ b/install.py @@ -33,6 +33,10 @@ def load_source(srcfile): 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: diff --git a/segments/cwd.py b/segments/cwd.py index d5e3a791..3c80b701 100644 --- a/segments/cwd.py +++ b/segments/cwd.py @@ -28,7 +28,7 @@ def requires_special_home_display(name): return (name == '~' and Color.HOME_SPECIAL_DISPLAY) -def maybe_shorten_name(name): +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.""" @@ -45,7 +45,7 @@ def get_fg_bg(name): return (Color.PATH_FG, Color.PATH_BG,) -def add_cwd_segment(): +def add_cwd_segment(powerline): cwd = powerline.cwd or os.getenv('PWD') if not py3: cwd = cwd.decode("utf-8") @@ -86,7 +86,5 @@ def add_cwd_segment(): separator = None separator_fg = None - powerline.append(' %s ' % maybe_shorten_name(name), fg, bg, + powerline.append(' %s ' % maybe_shorten_name(powerline, name), fg, bg, separator, separator_fg) - -add_cwd_segment() diff --git a/segments/exit_code.py b/segments/exit_code.py index 5c936156..e3b320ee 100644 --- a/segments/exit_code.py +++ b/segments/exit_code.py @@ -1,8 +1,6 @@ -def add_exit_code_segment(): +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) - -add_exit_code_segment() diff --git a/segments/fossil.py b/segments/fossil.py index bffc10f3..7ae3eba0 100644 --- a/segments/fossil.py +++ b/segments/fossil.py @@ -12,8 +12,14 @@ def get_fossil_status(): return has_modified_files, has_untracked_files, has_missing_files -def add_fossil_segment(): - subprocess.Popen(['fossil'], stdout=subprocess.PIPE).communicate()[0] +def add_fossil_segment(powerline): + try: + subprocess.Popen(['fossil'], stdout=subprocess.PIPE).communicate()[0] + except OSError: + return + except subprocess.CalledProcessError: + return + 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 @@ -31,10 +37,3 @@ def add_fossil_segment(): extra += '!' branch += (' ' + extra if extra != '' else '') powerline.append(' %s ' % branch, fg, bg) - -try: - add_fossil_segment() -except OSError: - pass -except subprocess.CalledProcessError: - pass diff --git a/segments/git.py b/segments/git.py index cc0787bc..3bf7877e 100644 --- a/segments/git.py +++ b/segments/git.py @@ -1,5 +1,6 @@ import re import subprocess +import os GIT_SYMBOLS = { 'detached': u'\u2693', @@ -62,7 +63,7 @@ def _n_or_empty(_dict, _key): return _dict[_key] if int(_dict[_key]) > 1 else u'' -def add_git_segment(): +def add_git_segment(powerline): p = subprocess.Popen(['git', 'status', '--porcelain', '-b'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=git_subprocess_env) @@ -102,7 +103,7 @@ def _add(_dict, _key, fg, bg): _add(stats, 'untracked', Color.GIT_UNTRACKED_FG, Color.GIT_UNTRACKED_BG) _add(stats, 'conflicted', Color.GIT_CONFLICTED_FG, Color.GIT_CONFLICTED_BG) -try: - add_git_segment() -except (OSError, subprocess.CalledProcessError): - pass +# try: +# add_git_segment() +# except (OSError, subprocess.CalledProcessError): +# pass diff --git a/segments/hg.py b/segments/hg.py index 5a4f40dc..d5f1cf48 100644 --- a/segments/hg.py +++ b/segments/hg.py @@ -20,7 +20,7 @@ def get_hg_status(): has_modified_files = True return has_modified_files, has_untracked_files, has_missing_files -def add_hg_segment(): +def add_hg_segment(powerline): branch = os.popen('hg branch 2> /dev/null').read().rstrip() if len(branch) == 0: return False @@ -37,5 +37,3 @@ def add_hg_segment(): extra += '!' branch += (' ' + extra if extra != '' else '') return powerline.append(' %s ' % branch, fg, bg) - -add_hg_segment() diff --git a/segments/hostname.py b/segments/hostname.py index baf99191..609711e2 100644 --- a/segments/hostname.py +++ b/segments/hostname.py @@ -1,4 +1,4 @@ -def add_hostname_segment(): +def add_hostname_segment(powerline): if powerline.args.colorize_hostname: from lib.color_compliment import stringToHashToColorAndOpposite from lib.colortrans import rgb2short @@ -19,6 +19,3 @@ def add_hostname_segment(): host_prompt = ' %s ' % socket.gethostname().split('.')[0] powerline.append(host_prompt, Color.HOSTNAME_FG, Color.HOSTNAME_BG) - - -add_hostname_segment() diff --git a/segments/jobs.py b/segments/jobs.py index 5dde3e65..a6ff1808 100644 --- a/segments/jobs.py +++ b/segments/jobs.py @@ -2,7 +2,7 @@ import re import subprocess -def add_jobs_segment(): +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() @@ -15,5 +15,3 @@ def add_jobs_segment(): if num_jobs > 0: powerline.append(' %d ' % num_jobs, Color.JOBS_FG, Color.JOBS_BG) - -add_jobs_segment() diff --git a/segments/node_version.py b/segments/node_version.py index 842e487c..466a0864 100644 --- a/segments/node_version.py +++ b/segments/node_version.py @@ -1,7 +1,7 @@ import subprocess -def add_node_version_segment(): +def add_node_version_segment(powerline): try: p1 = subprocess.Popen(["node", "--version"], stdout=subprocess.PIPE) version = p1.communicate()[0].decode("utf-8").rstrip() @@ -9,5 +9,3 @@ def add_node_version_segment(): powerline.append(version, 15, 18) except OSError: return - -add_node_version_segment() diff --git a/segments/php_version.py b/segments/php_version.py index ee174047..7b9b8aa3 100644 --- a/segments/php_version.py +++ b/segments/php_version.py @@ -1,7 +1,7 @@ import subprocess -def add_php_version_segment(): +def add_php_version_segment(powerline): try: output = subprocess.check_output(['php', '-r', 'echo PHP_VERSION;'], stderr=subprocess.STDOUT) if '-' in output: @@ -12,5 +12,3 @@ def add_php_version_segment(): powerline.append(version, 15, 4) except OSError: return - -add_php_version_segment() diff --git a/segments/read_only.py b/segments/read_only.py index bcb28f4c..efbe11ad 100644 --- a/segments/read_only.py +++ b/segments/read_only.py @@ -1,9 +1,7 @@ import os -def add_read_only_segment(): +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) - -add_read_only_segment() diff --git a/segments/root.py b/segments/root.py index 9cd5e8c2..49404ecf 100644 --- a/segments/root.py +++ b/segments/root.py @@ -1,4 +1,4 @@ -def add_root_indicator_segment(): +def add_root_segment(powerline): root_indicators = { 'bash': ' \\$ ', 'zsh': ' %# ', @@ -10,5 +10,3 @@ def add_root_indicator_segment(): fg = Color.CMD_FAILED_FG bg = Color.CMD_FAILED_BG powerline.append(root_indicators[powerline.args.shell], fg, bg) - -add_root_indicator_segment() diff --git a/segments/ruby_version.py b/segments/ruby_version.py index 82ba7f27..040f5334 100644 --- a/segments/ruby_version.py +++ b/segments/ruby_version.py @@ -1,7 +1,7 @@ import subprocess -def add_ruby_version_segment(): +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) @@ -13,5 +13,3 @@ def add_ruby_version_segment(): powerline.append(version, 15, 1) except OSError: return - -add_ruby_version_segment() diff --git a/segments/set_term_title.py b/segments/set_term_title.py index 4d1d5cd8..e9954ae8 100644 --- a/segments/set_term_title.py +++ b/segments/set_term_title.py @@ -1,4 +1,4 @@ -def add_term_title_segment(): +def add_set_term_title_segment(powerline): term = os.getenv('TERM') if not (('xterm' in term) or ('rxvt' in term)): return @@ -13,5 +13,3 @@ def add_term_title_segment(): powerline.append(set_title, None, None, '') - -add_term_title_segment() diff --git a/segments/ssh.py b/segments/ssh.py index e90397a3..5361bc5e 100644 --- a/segments/ssh.py +++ b/segments/ssh.py @@ -1,8 +1,6 @@ import os -def add_ssh_segment(): +def add_ssh_segment(powerline): if os.getenv('SSH_CLIENT'): powerline.append(' %s ' % powerline.network, Color.SSH_FG, Color.SSH_BG) - -add_ssh_segment() diff --git a/segments/svn.py b/segments/svn.py index a378a87a..49594022 100644 --- a/segments/svn.py +++ b/segments/svn.py @@ -1,6 +1,6 @@ import subprocess -def add_svn_segment(): +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() @@ -17,9 +17,9 @@ def add_svn_segment(): changes = output.strip() powerline.append(' %s ' % changes, Color.SVN_CHANGES_FG, Color.SVN_CHANGES_BG) -try: - add_svn_segment() -except OSError: - pass -except subprocess.CalledProcessError: - pass +# try: +# add_svn_segment() +# except OSError: +# pass +# except subprocess.CalledProcessError: +# pass diff --git a/segments/time.py b/segments/time.py index 68431504..8c0313f6 100644 --- a/segments/time.py +++ b/segments/time.py @@ -1,4 +1,4 @@ -def add_time_segment(): +def add_time_segment(powerline): if powerline.args.shell == 'bash': time = ' \\t ' elif powerline.args.shell == 'zsh': @@ -8,5 +8,3 @@ def add_time_segment(): time = ' %s ' % time.strftime('%H:%M:%S') powerline.append(time, Color.HOSTNAME_FG, Color.HOSTNAME_BG) - -add_time_segment() diff --git a/segments/uptime.py b/segments/uptime.py index 8ea229f4..68123c17 100644 --- a/segments/uptime.py +++ b/segments/uptime.py @@ -9,7 +9,7 @@ # -1h 00:00:00 up 120 days, 49 min, 2 users, load average: 0,00, 0,00, 0,00 # mac: 00:00:00 up 23 3 day(s), 10:00, 2 users, load average: 0,00, 0,00, 0,00 -def add_uptime_segment(): +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) @@ -22,5 +22,3 @@ def add_uptime_segment(): powerline.append(uptime, Color.CWD_FG, Color.PATH_BG) except OSError: return - -add_uptime_segment() diff --git a/segments/username.py b/segments/username.py index 4d8e5755..3d73a12c 100644 --- a/segments/username.py +++ b/segments/username.py @@ -1,5 +1,5 @@ -def add_username_segment(): +def add_username_segment(powerline): import os if powerline.args.shell == 'bash': user_prompt = ' \\u ' @@ -14,5 +14,3 @@ def add_username_segment(): bgcolor = Color.USERNAME_BG powerline.append(user_prompt, Color.USERNAME_FG, bgcolor) - -add_username_segment() diff --git a/segments/virtual_env.py b/segments/virtual_env.py index d8937e63..710efc69 100644 --- a/segments/virtual_env.py +++ b/segments/virtual_env.py @@ -1,6 +1,6 @@ import os -def add_virtual_env_segment(): +def add_virtual_env_segment(powerline): env = os.getenv('VIRTUAL_ENV') or os.getenv('CONDA_ENV_PATH') if env is None: return @@ -9,5 +9,3 @@ def add_virtual_env_segment(): bg = Color.VIRTUAL_ENV_BG fg = Color.VIRTUAL_ENV_FG powerline.append(' %s ' % env_name, fg, bg) - -add_virtual_env_segment() From c22d1af48bf2ede8dd8fcd6b8a78e22338e92829 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 21 Nov 2015 12:53:21 -0500 Subject: [PATCH 147/366] add tests for the git segment --- README.md | 4 ++ dev_requirements.txt | 5 ++- segments/__init__.py | 0 segments/fossil.py | 27 +++++++++---- segments/git.py | 43 ++++++++++++--------- segments/svn.py | 26 +++++++++---- test/segments_test/git_test.py | 69 ++++++++++++++++++++++++++++++++++ 7 files changed, 139 insertions(+), 35 deletions(-) create mode 100644 segments/__init__.py create mode 100644 test/segments_test/git_test.py diff --git a/README.md b/README.md index 91554aec..0539539f 100644 --- a/README.md +++ b/README.md @@ -151,6 +151,10 @@ scenario. Make sure you introduce new default colors in `themes/default.py` for every new 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`. + ### Themes The `themes` directory stores themes for your prompt, which are basically color diff --git a/dev_requirements.txt b/dev_requirements.txt index a6786964..47a4588d 100644 --- a/dev_requirements.txt +++ b/dev_requirements.txt @@ -1,2 +1,3 @@ -nose -mock +nose>=1.3.7 +mock>=1.3.0 +sh>=1.11 diff --git a/segments/__init__.py b/segments/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/segments/fossil.py b/segments/fossil.py index 7ae3eba0..6c7818ec 100644 --- a/segments/fossil.py +++ b/segments/fossil.py @@ -12,14 +12,8 @@ def get_fossil_status(): return has_modified_files, has_untracked_files, has_missing_files -def add_fossil_segment(powerline): - try: - subprocess.Popen(['fossil'], stdout=subprocess.PIPE).communicate()[0] - except OSError: - return - except subprocess.CalledProcessError: - return - +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 @@ -37,3 +31,20 @@ def add_fossil_segment(powerline): 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 diff --git a/segments/git.py b/segments/git.py index 3bf7877e..d33a9d39 100644 --- a/segments/git.py +++ b/segments/git.py @@ -12,17 +12,24 @@ 'conflicted': u'\u273C' } -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. - "LANG": "C", +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") - # https://github.com/milkbikis/powerline-shell/pull/126 - "HOME": os.getenv("HOME"), +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/153 - "PATH": os.getenv("PATH"), -} + # https://github.com/milkbikis/powerline-shell/pull/126 + "HOME": os.getenv("HOME"), + + # https://github.com/milkbikis/powerline-shell/pull/153 + "PATH": get_PATH(), + } def parse_git_branch_info(status): @@ -33,7 +40,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=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) @@ -64,9 +71,14 @@ def _n_or_empty(_dict, _key): def add_git_segment(powerline): - p = subprocess.Popen(['git', 'status', '--porcelain', '-b'], - stdout=subprocess.PIPE, stderr=subprocess.PIPE, - env=git_subprocess_env) + 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 + pdata = p.communicate() if p.returncode != 0: return @@ -102,8 +114,3 @@ def _add(_dict, _key, fg, 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) - -# try: -# add_git_segment() -# except (OSError, subprocess.CalledProcessError): -# pass diff --git a/segments/svn.py b/segments/svn.py index 49594022..89168c01 100644 --- a/segments/svn.py +++ b/segments/svn.py @@ -1,6 +1,7 @@ import subprocess -def add_svn_segment(powerline): + +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() @@ -17,9 +18,20 @@ def add_svn_segment(powerline): changes = output.strip() powerline.append(' %s ' % changes, Color.SVN_CHANGES_FG, Color.SVN_CHANGES_BG) -# try: -# add_svn_segment() -# except OSError: -# pass -# except subprocess.CalledProcessError: -# pass + +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 diff --git a/test/segments_test/git_test.py b/test/segments_test/git_test.py new file mode 100644 index 00000000..982289e3 --- /dev/null +++ b/test/segments_test/git_test.py @@ -0,0 +1,69 @@ +import unittest +import mock +import tempfile +import shutil +import sh +import 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", ".") + + 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 _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') + 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.assertEqual(self.powerline.append.call_count, 0) + + def test_non_git_directory(self): + shutil.rmtree(".git") + git.add_git_segment(self.powerline) + self.assertEqual(self.powerline.append.call_count, 0) + + def test_big_bang(self): + git.add_git_segment(self.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.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.assertEqual(self.powerline.append.call_args[0][0], ' bar ') + + def test_detached(self): + self._add_and_commit("foo") + commit_hash = self._get_commit_hash() + self._add_and_commit("bar") + sh.git("checkout", "HEAD^") + git.add_git_segment(self.powerline) + + # In detached mode, we output a unicode symbol and then the shortened + # commit hash. + self.assertIn(self.powerline.append.call_args[0][0].split()[1], + commit_hash) From 9281d907f2e1f2ee6a7f5b9ba490c4c1b48ba615 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 26 Dec 2015 11:37:45 -0500 Subject: [PATCH 148/366] add circle.yml that installs dev_requirements.txt --- circle.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 circle.yml diff --git a/circle.yml b/circle.yml new file mode 100644 index 00000000..7638a893 --- /dev/null +++ b/circle.yml @@ -0,0 +1,5 @@ +dependencies: + pre: + - sudo pip install -r dev_requirements.txt + - git config --global user.email "tester@example.com" + - git config --global user.name "Tester McGee" From acd0e081b6721e6bb68c035fc729aa088530eb6b Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 26 Dec 2015 12:15:02 -0500 Subject: [PATCH 149/366] convert uptime comments into test cases --- segments/uptime.py | 8 -------- test/segments_test/uptime_test.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 8 deletions(-) create mode 100644 test/segments_test/uptime_test.py diff --git a/segments/uptime.py b/segments/uptime.py index 68123c17..4c7711ce 100644 --- a/segments/uptime.py +++ b/segments/uptime.py @@ -1,14 +1,6 @@ import subprocess import re -# uptime output samples -# 1h: 00:00:00 up 1:00, 2 users, load average: 0,00, 0,00, 0,00 -# 10+h: 00:00:00 up 10:00, 2 users, load average: 0,00, 0,00, 0,00 -# 1+d: 00:00:00 up 1 days, 1:00, 2 users, load average: 0,00, 0,00, 0,00 -# 9+d: 00:00:00 up 12 days, 1:00, 2 users, load average: 0,00, 0,00, 0,00 -# -1h 00:00:00 up 120 days, 49 min, 2 users, load average: 0,00, 0,00, 0,00 -# mac: 00:00:00 up 23 3 day(s), 10:00, 2 users, load average: 0,00, 0,00, 0,00 - def add_uptime_segment(powerline): try: output = subprocess.check_output(['uptime'], stderr=subprocess.STDOUT) diff --git a/test/segments_test/uptime_test.py b/test/segments_test/uptime_test.py new file mode 100644 index 00000000..d2dacd2c --- /dev/null +++ b/test/segments_test/uptime_test.py @@ -0,0 +1,29 @@ +import unittest +import mock +import segments.uptime as uptime + +test_cases = { + # linux test cases + "00:00:00 up 1:00, 2 users, load average: 0,00, 0,00, 0,00": "1h", + "00:00:00 up 10:00, 2 users, load average: 0,00, 0,00, 0,00": "10h", + "00:00:00 up 1 days, 1:00, 2 users, load average: 0,00, 0,00, 0,00": "1d", + "00:00:00 up 12 days, 1:00, 2 users, load average: 0,00, 0,00, 0,00": "12d", + "00:00:00 up 120 days, 49 min, 2 users, load average: 0,00, 0,00, 0,00": "120d", + + # mac test cases + "00:00:00 up 23 3 day(s), 10:00, 2 users, load average: 0,00, 0,00, 0,00": "3d", +} + + +class UptimeTest(unittest.TestCase): + + def setUp(self): + self.powerline = mock.MagicMock() + uptime.Color = mock.MagicMock() + + @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.assertEqual(self.powerline.append.call_args[0][0].split()[0], result) From 9fb1c94dfa86e6d6389605e88354cfbec9fd7d30 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 26 Dec 2015 16:51:27 -0500 Subject: [PATCH 150/366] readme note about #212 --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 0539539f..082c1a63 100644 --- a/README.md +++ b/README.md @@ -173,6 +173,12 @@ settings. 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)) From e5a1c749632788548fdac221159378497ab0a3d3 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sun, 27 Dec 2015 13:22:39 -0500 Subject: [PATCH 151/366] Moved all repo stats code from git.py to the base When all of the new code to provide more interesting stats was added to git.py, it was not very re-usable. A few pull requests could use it though. In particular, #105 adds more info to the svn segment and #210 does the same for mercurial. I would rather not create inconsistencies among these segments or have them duplicate code. Moving it into the base file creates a place where each segment can access it and have a consistent behavior. --- powerline_shell_base.py | 59 ++++++++++++++++++++++++++++++++++ segments/git.py | 48 +++++++-------------------- test/repo_stats_test.py | 22 +++++++++++++ test/segments_test/git_test.py | 5 ++- 4 files changed, 96 insertions(+), 38 deletions(-) create mode 100644 test/repo_stats_test.py diff --git a/powerline_shell_base.py b/powerline_shell_base.py index 8b95fb3a..6a51c0de 100755 --- a/powerline_shell_base.py +++ b/powerline_shell_base.py @@ -90,6 +90,65 @@ def draw_segment(self, idx): self.fgcolor(segment[4]), segment[3])) + +class RepoStats: + symbols = { + 'detached': u'\u2693', + 'ahead': u'\u2B06', + 'behind': u'\u2B07', + 'staged': u'\u2714', + 'not_staged': u'\u270E', + 'untracked': u'\u2753', + 'conflicted': u'\u273C' + } + + def __init__(self): + self.ahead = 0 + self.behind = 0 + self.untracked = 0 + self.not_staged = 0 + self.staged = 0 + self.conflicted = 0 + + @property + def dirty(self): + qualifiers = [ + self.untracked, + self.not_staged, + self.staged, + self.conflicted, + ] + return (True if sum(qualifiers) > 0 else False) + + 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 untracked files, but you + only want a number to appear next to the icon when there are more than + one untracked files, you can do: + + segment = repo_stats.n_or_empty("untracked") + icon_string + """ + return unicode(self[_key]) if int(self[_key]) > 1 else u'' + + def add_to_powerline(self, powerline, color): + def add(_key, fg, bg): + if self[_key]: + s = u" {}{} ".format(self.n_or_empty(_key), self.symbols[_key]) + powerline.append(s, fg, bg) + 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('not_staged', color.GIT_NOTSTAGED_FG, color.GIT_NOTSTAGED_BG) + add('untracked', color.GIT_UNTRACKED_FG, color.GIT_UNTRACKED_BG) + add('conflicted', color.GIT_CONFLICTED_FG, color.GIT_CONFLICTED_BG) + + def get_valid_cwd(): """ We check if the current working directory is valid or not. Typically happens when you checkout a different branch on git that doesn't have diff --git a/segments/git.py b/segments/git.py index d33a9d39..0da777f0 100644 --- a/segments/git.py +++ b/segments/git.py @@ -2,16 +2,6 @@ import subprocess import os -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 easily mocking the PATH in tests. @@ -43,33 +33,29 @@ 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.untracked += 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.not_staged += 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): try: p = subprocess.Popen(['git', 'status', '--porcelain', '-b'], @@ -84,33 +70,21 @@ def add_git_segment(powerline): return 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() bg = Color.REPO_CLEAN_BG fg = Color.REPO_CLEAN_FG - if dirty: + if stats.dirty: bg = Color.REPO_DIRTY_BG fg = Color.REPO_DIRTY_FG powerline.append(' %s ' % branch, fg, bg) - - 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) - - 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) + stats.add_to_powerline(powerline, Color) diff --git a/test/repo_stats_test.py b/test/repo_stats_test.py new file mode 100644 index 00000000..bcd206a6 --- /dev/null +++ b/test/repo_stats_test.py @@ -0,0 +1,22 @@ +import unittest +import powerline_shell_base as p + + +class RepoStatsTest(unittest.TestCase): + + def setUp(self): + self.repo_stats = p.RepoStats() + self.repo_stats.not_staged = 1 + self.repo_stats.conflicted = 4 + + def test_simple(self): + self.assertEqual(self.repo_stats.untracked, 0) + + def test_n_or_empty__empty(self): + self.assertEqual(self.repo_stats.n_or_empty("not_staged"), 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["not_staged"], 1) diff --git a/test/segments_test/git_test.py b/test/segments_test/git_test.py index 982289e3..7ca344ab 100644 --- a/test/segments_test/git_test.py +++ b/test/segments_test/git_test.py @@ -3,14 +3,17 @@ import tempfile import shutil import sh +import powerline_shell_base as p import segments.git as git +git.Color = mock.MagicMock() +git.RepoStats = p.RepoStats + class GitTest(unittest.TestCase): def setUp(self): self.powerline = mock.MagicMock() - git.Color = mock.MagicMock() self.dirname = tempfile.mkdtemp() sh.cd(self.dirname) From 334dd0c631294cf773d68e05cadce477de1fdf71 Mon Sep 17 00:00:00 2001 From: Bryan Grimes Date: Thu, 14 Jan 2016 10:50:21 -0500 Subject: [PATCH 152/366] aws_profile segment added --- .gitignore | 3 +++ README.md | 6 ++++++ segments/aws_profile.py | 11 +++++++++++ themes/basic.py | 17 ++++++++++------- themes/default.py | 6 +++++- themes/solarized-dark.py | 3 +++ themes/washed.py | 3 +++ 7 files changed, 41 insertions(+), 8 deletions(-) create mode 100644 segments/aws_profile.py diff --git a/.gitignore b/.gitignore index 59291234..738abd7d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ powerline-shell.py *.py[co] config.py + +.DS_Store +*sublime* diff --git a/README.md b/README.md index 082c1a63..4631be2d 100644 --- a/README.md +++ b/README.md @@ -171,6 +171,12 @@ 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=` + + 2015-12-26 * Beginnings of unit testing for segments. Included in this change was a diff --git a/segments/aws_profile.py b/segments/aws_profile.py new file mode 100644 index 00000000..5de2e100 --- /dev/null +++ b/segments/aws_profile.py @@ -0,0 +1,11 @@ + +def add_aws_profile_segment(powerline): + import os + + aws_profile = os.environ.get('AWS_PROFILE') or \ + os.environ.get('AWS_DEFAULT_PROFILE') + + if aws_profile: + powerline.append(' aws:%s ' % os.path.basename(aws_profile), + Color.AWS_PROFILE_FG, + Color.AWS_PROFILE_BG) diff --git a/themes/basic.py b/themes/basic.py index 5d076915..3c51c35a 100644 --- a/themes/basic.py +++ b/themes/basic.py @@ -9,18 +9,18 @@ class Color(DefaultColor): HOSTNAME_BG = 7 HOME_SPECIAL_DISPLAY = False - PATH_BG = 8 # dark grey - PATH_FG = 7 # light grey - CWD_FG = 15 # white + PATH_BG = 8 # dark grey + PATH_FG = 7 # light grey + CWD_FG = 15 # white SEPARATOR_FG = 7 READONLY_BG = 1 READONLY_FG = 15 - REPO_CLEAN_BG = 2 # green - REPO_CLEAN_FG = 0 # black - REPO_DIRTY_BG = 1 # red - REPO_DIRTY_FG = 15 # white + REPO_CLEAN_BG = 2 # green + REPO_CLEAN_FG = 0 # black + REPO_DIRTY_BG = 1 # red + REPO_DIRTY_FG = 15 # white JOBS_FG = 14 JOBS_BG = 8 @@ -35,3 +35,6 @@ class Color(DefaultColor): VIRTUAL_ENV_BG = 2 VIRTUAL_ENV_FG = 0 + + AWS_PROFILE_FG = 14 + AWS_PROFILE_BG = 8 diff --git a/themes/default.py b/themes/default.py index 08b1ff45..a365a648 100644 --- a/themes/default.py +++ b/themes/default.py @@ -21,7 +21,7 @@ class DefaultColor: READONLY_BG = 124 READONLY_FG = 254 - SSH_BG = 166 # medium orange + SSH_BG = 166 # medium orange SSH_FG = 254 REPO_CLEAN_BG = 148 # a light green color @@ -56,6 +56,10 @@ class DefaultColor: VIRTUAL_ENV_BG = 35 # a mid-tone green VIRTUAL_ENV_FG = 00 + AWS_PROFILE_FG = 39 + AWS_PROFILE_BG = 238 + + class Color(DefaultColor): """ This subclass is required when the user chooses to use 'default' theme. diff --git a/themes/solarized-dark.py b/themes/solarized-dark.py index 4e158c8e..da556bfd 100644 --- a/themes/solarized-dark.py +++ b/themes/solarized-dark.py @@ -33,3 +33,6 @@ class Color(DefaultColor): VIRTUAL_ENV_BG = 15 VIRTUAL_ENV_FG = 2 + + AWS_PROFILE_FG = 7 + AWS_PROFILE_BG = 2 diff --git a/themes/washed.py b/themes/washed.py index 3c455e3d..790c2afc 100644 --- a/themes/washed.py +++ b/themes/washed.py @@ -33,3 +33,6 @@ class Color(DefaultColor): VIRTUAL_ENV_BG = 150 VIRTUAL_ENV_FG = 0 + + AWS_PROFILE_FG = 0 + AWS_PROFILE_BG = 7 From 7681a384bba55736954138a9bda5bb978158fe79 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Fri, 1 Apr 2016 14:25:05 -0400 Subject: [PATCH 153/366] no need for a ternary --- powerline_shell_base.py | 2 +- test/repo_stats_test.py | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/powerline_shell_base.py b/powerline_shell_base.py index 6a51c0de..896693a5 100755 --- a/powerline_shell_base.py +++ b/powerline_shell_base.py @@ -118,7 +118,7 @@ def dirty(self): self.staged, self.conflicted, ] - return (True if sum(qualifiers) > 0 else False) + return sum(qualifiers) > 0 def __getitem__(self, _key): return getattr(self, _key) diff --git a/test/repo_stats_test.py b/test/repo_stats_test.py index bcd206a6..c97a089d 100644 --- a/test/repo_stats_test.py +++ b/test/repo_stats_test.py @@ -9,6 +9,9 @@ def setUp(self): self.repo_stats.not_staged = 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.untracked, 0) From 75b95a3a10a19018f9d75ee40242b0992ab3b9f5 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Fri, 1 Apr 2016 14:31:13 -0400 Subject: [PATCH 154/366] move changelog to own file, add changelog for #221 --- CHANGELOG.md | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 78 ------------------------------------------------- 2 files changed, 82 insertions(+), 78 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..857583e0 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,82 @@ +# Changes + +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)) diff --git a/README.md b/README.md index 082c1a63..1bcec178 100644 --- a/README.md +++ b/README.md @@ -168,81 +168,3 @@ 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 - -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)) From cc05f820df5e63f510cfa21a5ac5b016577eed2b Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 16 Apr 2016 09:55:33 -0400 Subject: [PATCH 155/366] fix unicode issue for py3 --- powerline_shell_base.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/powerline_shell_base.py b/powerline_shell_base.py index 896693a5..38d018cf 100755 --- a/powerline_shell_base.py +++ b/powerline_shell_base.py @@ -13,6 +13,11 @@ def warn(msg): print('[powerline-bash] ', msg) +if py3: + def unicode(x): + return x + + class Powerline: symbols = { 'compatible': { From d48f383112f5520c4c33d69dca0806e127f495d7 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 16 Apr 2016 09:56:12 -0400 Subject: [PATCH 156/366] changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 857583e0..2a1cef31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changes +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. From ce1fb672840268c564652c3d95de972fe73318f4 Mon Sep 17 00:00:00 2001 From: Yasuhiro Inami Date: Sun, 1 May 2016 06:30:37 +0900 Subject: [PATCH 157/366] Use CWD_FG for last path component --- segments/cwd.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/segments/cwd.py b/segments/cwd.py index 3c80b701..9dd38ba6 100644 --- a/segments/cwd.py +++ b/segments/cwd.py @@ -37,12 +37,16 @@ def maybe_shorten_name(powerline, name): return name -def get_fg_bg(name): +def get_fg_bg(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 is_last_dir: + return (Color.CWD_FG, Color.PATH_BG,) + else: + return (Color.PATH_FG, Color.PATH_BG,) def add_cwd_segment(powerline): @@ -77,11 +81,11 @@ def add_cwd_segment(powerline): 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(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 = None separator_fg = None From 168b4a49a36719a2e8abac7e1cd523aee2bcdb4a Mon Sep 17 00:00:00 2001 From: Michael Wild Date: Mon, 24 Oct 2016 17:10:47 +0200 Subject: [PATCH 158/366] Fixes segments/set_term_title.py for ZSH The %{ and %} quoting was missing that instructs ZSH to consider this part to have zero width. This broke history searching and long command lines. See e.g. http://stackoverflow.com/a/11916552/159834 --- segments/set_term_title.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/segments/set_term_title.py b/segments/set_term_title.py index e9954ae8..7c3e8264 100644 --- a/segments/set_term_title.py +++ b/segments/set_term_title.py @@ -6,7 +6,7 @@ def add_set_term_title_segment(powerline): 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' + 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')) From e157d1e57996457f0d76862866c8871aef1efab9 Mon Sep 17 00:00:00 2001 From: Michael Wild Date: Mon, 24 Oct 2016 17:02:34 +0200 Subject: [PATCH 159/366] Adds Cygwin-specific handling in segments/jobs.py --- segments/jobs.py | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/segments/jobs.py b/segments/jobs.py index a6ff1808..2e0f9dc5 100644 --- a/segments/jobs.py +++ b/segments/jobs.py @@ -1,17 +1,30 @@ import os import re import subprocess +import platform 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() + num_jobs = 0 - output_proc = subprocess.Popen(['ps', '-a', '-o', 'ppid'], - stdout=subprocess.PIPE) - output = output_proc.communicate()[0].decode("utf-8") + 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:]) - num_jobs = len(re.findall(str(pppid), output)) - 1 + 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") + + num_jobs = len(re.findall(str(pppid), output)) - 1 if num_jobs > 0: powerline.append(' %d ' % num_jobs, Color.JOBS_FG, Color.JOBS_BG) From 4a2015916604471a93ff0c426644087f3aee3ad0 Mon Sep 17 00:00:00 2001 From: Dror Atariah Date: Tue, 6 Dec 2016 13:30:51 +0100 Subject: [PATCH 160/366] Fixed problem with conda environments See https://github.com/powerline/powerline/issues/1692 --- segments/virtual_env.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/segments/virtual_env.py b/segments/virtual_env.py index 710efc69..35a368f5 100644 --- a/segments/virtual_env.py +++ b/segments/virtual_env.py @@ -1,7 +1,7 @@ import os def add_virtual_env_segment(powerline): - env = os.getenv('VIRTUAL_ENV') or os.getenv('CONDA_ENV_PATH') + env = os.getenv('VIRTUAL_ENV') or os.getenv('CONDA_ENV_PATH') or os.getenv('CONDA_DEFAULT_ENV') if env is None: return From a253a72658bc7df220f0cde17a60020efedc4438 Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Wed, 11 Jan 2017 01:56:29 -0200 Subject: [PATCH 161/366] Add rbenv segment --- config.py.dist | 3 +++ segments/rbenv.py | 13 +++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 segments/rbenv.py diff --git a/config.py.dist b/config.py.dist index a1e76272..55e894c4 100644 --- a/config.py.dist +++ b/config.py.dist @@ -13,6 +13,9 @@ SEGMENTS = [ # Show current virtual environment (see http://www.virtualenv.org/) 'virtual_env', +# Show current ruby environment (see http://rbenv.org/) + 'rbenv', + # Show the current user's username as in ordinary prompts 'username', diff --git a/segments/rbenv.py b/segments/rbenv.py new file mode 100644 index 00000000..70e34a81 --- /dev/null +++ b/segments/rbenv.py @@ -0,0 +1,13 @@ +import subprocess + + +def add_rbenv_segment(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, Color.VIRTUAL_ENV_FG, Color.VIRTUAL_ENV_BG) + except OSError: + return From 724e8303a80f17c83128b5876dbb3d95c106805c Mon Sep 17 00:00:00 2001 From: Lehman Black Date: Tue, 28 Mar 2017 08:41:54 -0500 Subject: [PATCH 162/366] Add segment for npm version --- segments/npm_version.py | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 segments/npm_version.py diff --git a/segments/npm_version.py b/segments/npm_version.py new file mode 100644 index 00000000..0deb5f8d --- /dev/null +++ b/segments/npm_version.py @@ -0,0 +1,11 @@ +import subprocess + + +def add_npm_version_segment(powerline): + try: + p1 = subprocess.Popen(["npm", "--version"], stdout=subprocess.PIPE) + version = p1.communicate()[0].decode("utf-8").rstrip() + version = "npm " + version + powerline.append(version, 15, 18) + except OSError: + return From 400c29a3a8a8396bc1ce650e522ff090fc007c79 Mon Sep 17 00:00:00 2001 From: Florian Friedrich Date: Tue, 4 Apr 2017 14:34:17 +0200 Subject: [PATCH 163/366] Add newline segment --- powerline_shell_base.py | 2 ++ segments/newline.py | 2 ++ 2 files changed, 4 insertions(+) create mode 100644 segments/newline.py diff --git a/powerline_shell_base.py b/powerline_shell_base.py index 38d018cf..8ed28265 100755 --- a/powerline_shell_base.py +++ b/powerline_shell_base.py @@ -61,6 +61,8 @@ def __init__(self, args, cwd): def color(self, prefix, code): if code is None: return '' + elif code is -1: + return self.reset else: return self.color_template % ('[%s;5;%sm' % (prefix, code)) diff --git a/segments/newline.py b/segments/newline.py new file mode 100644 index 00000000..eef4dc7b --- /dev/null +++ b/segments/newline.py @@ -0,0 +1,2 @@ +def add_newline_segment(powerline): + powerline.append("\n", -1, -1, '') From 30f2124db18e2d186ee7b79fbf60aa7d7ab0230a Mon Sep 17 00:00:00 2001 From: Florian Friedrich Date: Tue, 4 Apr 2017 14:35:33 +0200 Subject: [PATCH 164/366] Add example of newline to config.py.dist --- config.py.dist | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config.py.dist b/config.py.dist index a1e76272..c005dea1 100644 --- a/config.py.dist +++ b/config.py.dist @@ -48,6 +48,9 @@ SEGMENTS = [ # Show the last command's exit code if it was non-zero # 'exit_code', +# Adds a line break +# 'newline', + # Shows a '#' if the current user is root, '$' otherwise # Also, changes color if the last command exited with a non-zero error code 'root', From 079cbc6cbf58f06e0ab7a87e2d80452f91cdd0ca Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Mon, 15 May 2017 11:49:21 -0400 Subject: [PATCH 165/366] changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a1cef31..63f3a196 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changes +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 From cbdb5e9547d3db8b22d1d48718bc64605c92b04f Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Tue, 20 Jun 2017 11:07:18 -0400 Subject: [PATCH 166/366] readability improvements for #266 --- powerline_shell_base.py | 2 +- segments/newline.py | 2 +- themes/default.py | 5 +++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/powerline_shell_base.py b/powerline_shell_base.py index 8ed28265..5d367a52 100755 --- a/powerline_shell_base.py +++ b/powerline_shell_base.py @@ -61,7 +61,7 @@ def __init__(self, args, cwd): def color(self, prefix, code): if code is None: return '' - elif code is -1: + elif code == Color.RESET: return self.reset else: return self.color_template % ('[%s;5;%sm' % (prefix, code)) diff --git a/segments/newline.py b/segments/newline.py index eef4dc7b..e9b43452 100644 --- a/segments/newline.py +++ b/segments/newline.py @@ -1,2 +1,2 @@ def add_newline_segment(powerline): - powerline.append("\n", -1, -1, '') + powerline.append("\nabc\n", Color.RESET, Color.RESET, separator='') diff --git a/themes/default.py b/themes/default.py index 08b1ff45..6526158a 100644 --- a/themes/default.py +++ b/themes/default.py @@ -3,6 +3,11 @@ class DefaultColor: 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 From 53fd55760bff3be87b8cc3cf06ef2524d91829f1 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Tue, 20 Jun 2017 11:12:54 -0400 Subject: [PATCH 167/366] changelog for #266 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63f3a196..cc7b03e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changes +2017-06-20 + +* Add `newline` segment + ([@ffried](https://github.com/banga/powerline-shell/pull/266)) + 2017-05-15 * Fix the `set_term_title` segment for ZSH From 0a367b24673f5c16b936f85a8dd3aaad097a7afe Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Tue, 20 Jun 2017 14:25:33 -0400 Subject: [PATCH 168/366] changelog for #265 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc7b03e3..44985304 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ * 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)) 2017-05-15 From 0bf761c5c42f5a516f27e975470105af251d389f Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Tue, 20 Jun 2017 14:32:20 -0400 Subject: [PATCH 169/366] changelog for #257 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 44985304..bfb4de03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ ([@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)) 2017-05-15 From f75286c0df16d053bec64decf9c1661038e91b2b Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Tue, 20 Jun 2017 15:02:32 -0400 Subject: [PATCH 170/366] lint the readme and add TOC --- README.md | 108 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 72 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 1bcec178..36a9658e 100644 --- a/README.md +++ b/README.md @@ -1,72 +1,105 @@ -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: ![MacVim+Solarized+Powerline+CtrlP](https://raw.github.com/milkbikis/dotfiles-mac/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 -* 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 + + +**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* + +- [Version Control](#version-control) +- [Setup](#setup) + - [All Shells](#all-shells) + - [Bash](#bash) + - [ZSH](#zsh) + - [Fish](#fish) +- [Customization](#customization) + - [Adding, Removing and Re-arranging segments](#adding-removing-and-re-arranging-segments) + - [Contributing new types of segments](#contributing-new-types-of-segments) + - [Themes](#themes) + + + +## 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: -* Clone this repository somewhere: +``` +git clone https://github.com/milkbikis/powerline-shell +``` - 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 -* Copy `config.py.dist` to `config.py` and edit it to configure the segments you want. Then run +``` +./install.py +``` - ./install.py +This will generate `powerline-shell.py` - * This will generate `powerline-shell.py` +- (optional) Create a symlink to this python script in your home: -* (optional) Create a symlink to this python script in your home: +``` +ln -s ~/powerline-shell.py +``` - ln -s ~/powerline-shell.py +If you don't want the symlink, just modify the path in the commands below - * If you don't want the symlink, just modify the path in the commands below +- For python2.6 you have to install argparse -* For python2.6 you have to install argparse +``` +pip install argparse +``` - pip install argparse +### All Shells -### All Shells: -There are a few optional arguments which can be seen by running `powerline-shell.py --help`. +There are a few optional arguments which can be seen by running +`powerline-shell.py --help`. ``` --cwd-mode {fancy,plain,dironly} @@ -82,7 +115,8 @@ There are a few optional arguments which can be seen by running `powerline-shell segments ``` -### Bash: +### Bash + Add the following to your `.bashrc` (or `.profile` on Mac): ``` @@ -95,7 +129,8 @@ if [ "$TERM" != "linux" ]; then fi ``` -### ZSH: +### ZSH + Add the following to your `.zshrc`: ``` @@ -117,7 +152,8 @@ if [ "$TERM" != "linux" ]; then fi ``` -### Fish: +### Fish + Redefine `fish_prompt` in ~/.config/fish/config.fish: ``` @@ -126,7 +162,7 @@ function fish_prompt end ``` -# Customization +## Customization ### Adding, Removing and Re-arranging segments From d0db198e82c38199312ae9583191ca262f2cc484 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Tue, 20 Jun 2017 15:06:37 -0400 Subject: [PATCH 171/366] add screenshot back --- README.md | 2 +- bash-powerline-screenshot.png | Bin 0 -> 35843 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 bash-powerline-screenshot.png diff --git a/README.md b/README.md index 36a9658e..1f49b43f 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ A [Powerline](https://github.com/Lokaltog/vim-powerline) like prompt for Bash, ZSH and Fish: -![MacVim+Solarized+Powerline+CtrlP](https://raw.github.com/milkbikis/dotfiles-mac/master/bash-powerline-screenshot.png) +![MacVim+Solarized+Powerline+CtrlP](https://raw.github.com/banga/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 diff --git a/bash-powerline-screenshot.png b/bash-powerline-screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..66a3b244627ee83a4f58bd6e7c5afcef82c24e5a GIT binary patch literal 35843 zcmZ^}b9`mZ5-z-B+vddP#I|kQ&cwDc@x+?gwr$(Co!oiPd5^yP-Sx-*^=?#k^{T3_ zs%M4E%ZkB4V?zS~05}P8VMPD{MD9=92@?3v?-Xn$H~@f&Zy_WkFCipEDDP-zYGG{x z0H{M%Xt<~=Z!~QlN%u1JPjCErD0KoD?x$hl5{Mpr+&FltzPMRUNpE?0{NX$ad2|tnt~D%GsT>m+mdcy?oj%9 zLS6e|R09FWk-ZIx;;gQ%`F-8pdE@eP1sm0JwSLO2e(83jB4VB)0E}Z%-@y7`#R#9N z0Ka9w%q?*Nsd(PR;SMug&yWEczr*|?E7y8@eD@~t&Y#%vUk4mqSwz1p0k%(ujV&1f z{b0g$aoYq@$GOEI0I3Mr9AV-GP{i^h0zr6y-x$Wuu&}W3#kL@*)bmGZ*7jGoaqSi# z=g9uH@Aa0qfF&_phP+{Z-^fUp?k67s(#}m-myh>z9J!8lY9j0HSjaQ&NVfH9kUl&p zMlh)6>U;8%*bo-SXY!N$E=?xVcz}IYP`_65`=HZ}0bK~>p};%Au_`0e$<{}ihzw0g&5ywq8cb!-+f9-qCr>R=Un5m zOt(3bcP}P1fv$7^F_6BAAFF7B`x7$`k6f;o^{lv9woh&J*KdTSEAVDwpUe!8YQ8_L zVZvb?8u|CbCMX8Km)^lcoRCD2hZ&lN>-V$$6og#Zja?_?d|yfxJtTmuD@Kk6+=pl#G4{!=ziozPy+8OA(_E3z* zM7(k{8WU>d&$>InkN9;)dn@PpH6eBL#o%L=lai+f79(CEju`S&;nSk$A!Xs`SME1_ zgJ&Yz5Mu2!-`$%vx_ZoA9hG_{O^h4nT_YBpbeQ2h6~tJayoY$q-^8=N`OjOPBrpL! z?p!-+dcEBc1q4VA{t^zu>cE2vGb759_Ts<%h-x*#M~Z}r)rK8~-m0Xn`Is7}0qb`UvBhNX6$tJk=)(Lk zm~k3CP|to0as1qQp!0rg41l6;=yTx7Zjf_Q3* zbS!d@9ul_GBW_gBkc|05nt=={F_Lm%-e{E}aM&xW$7{&2##-H>oRevlr#g38*_x;k zdo7|P+&e0BuyWh}yX-F(S&SwavB7~IM+dZK({;FY3S00e5V`KVy`*bXH#sj-UL3s$ zyWXc=v75SQ7i>{%1#H@M9TptdMkQ}b2}{F(9T@;RoNh`G~Q&bg3T)0yNs-5k6E zZ;7`genLnj7ASa7Xre@U*=F%(DK{zge3BW78LT%2KT&>87HLFw8j2 zZ_HOll}7l+Sq43|VRh=YLA9vW_0_O-G_?upD(X5KiRxwQRdup8xy${_G%LL;@O3(- zIA(7nlVi5S_`_L4KK|Z6y^{hn`us@ZNV4;j_9%zsWPxOrCK)F4f8qVAYM$0s)P~m% z*CuZPZ$WR?Xl`ivXt`^lcj7zpcQ0_mbysw^bPsV;b$fA}aL;$AcC)*oyRNyxx(>d@ z+dDhRI5In2+AF>$*z4-~Qt(shmM7HC(bnhJSBMjv7G%)9j@qu?ZjEb>i1+Q{pgJ(ekX1u_7s_nnB^=$4B2iutVw`H+upfp>Q%HqItn%$a96MPxu}EA^iZ8im*nCuYbbgpS zu`rSKr%W6V{hMlx%%mutR;AEoWP4b9@w>tc*R2+GDfAAs3p72dM1*R@O2kIQn53fQ zr=*Ic+|Te)(^0I^%uy+-St@@jauqV=G!+{agx`;4wxuOy3JY|_;Py~Ns}zMOUdJT9r{=okD0p1G^1pWYC7m^T?8!{217lj)2ThvChY*2I1Vvt=%p6rn9g{-fL zR0(5Fa&E~~(6q<&XaapgWkPAfPE((zoHj<2yKcYXzR9{?yI!$LvJShtsLr*vvfjsx z#6+m!q%qj0!dl8&Z#8^XWYy&yxQ*sV(z%BTy)A)}?*!19{+0Z}b&tY~L)9K0xhXk8 zF0JLlW7@iD{kSt-oDLobN1Nf*5NthQFG0> zO%2}{2cr= z`OF4}1&#q5hd2dChnNIE0Y`(F06POu0i6mx4*eNIBOgVX^s`Vta#|_3%%H7zGT0`x zEx1W^o5YKxl~^L)ARa`)OF=>*Hoq|6DZkjT-Y{l}MzNygp+>&^hqW0ljN>p~L`v8e z!55nVeJ<6GSf15x5@}Jva6ztd$$tC(3ToZYx{_n%uldi80MEL|P8nutu0;64x56hg zNV9$8apQC|Hscx7U=yBk)nU5H&&DYmy&v#)vZj;wK6f8SPA5(!EmQF31m9f{z2hA1 zzsqq{5!+Go5q|mj3kq2Di01n4dz5@yWIOv)B8}i)qziJbGgCBup*FWPNP|x;7}r9=%WdzNf`|?Zd$*HMSa^ zHd=>AUUUm>7oMe@t=>80N$TnSvDdoE!opU?#)hlR0I=)u7uE&{kZ5VT(bJ?3iom;6R zFZ}QFoMU`z--}t6nC;m3ZXKS6(&T2c7cm_9n7w&#M0Up(x?n%CHJ$Z-Y2?w_&|~-< zyn9?`j5d9uy(KMek#ts79e!=U&r}!HxE>X+O|3li!>x+NwJmVn%<0OFT*)MPQ*8%>RHpE^5257{1r383KSt_7DL@38lY<F4bsT`mfwX!eBuWaWM&v?eFS+S)tyr_xN z--fUU9R|I_ucRoXq9ki2(PcNK-IG^apY+r1T0Ovdn3^h0(9A;5=Ozp$)7G{!v>XZd zb7b+gHcf$A<*($&45CR=Vr`SJ2@-kf)Jo-x)GM`f6-zV=Jp?N>&k9yby5|ne$SgI^ zV5dBm#ImF;hHbc4m0doqovfsmg0(90G5GY*+mXFp3Uq2o+UwfOI^Jd)R1T0j=*Wa%WV1D?;bCAz0W~ri0(px`f6f(#kBFuVsE2oVk&sjd|vI}2kS1wvqo^H z-gNIft-W3DU7m6BDJM$~nnec9aU3^$+hFUSwTW_ydLn!4sclG-p^ zjho7ERgN?EBc7f%381Zpd^%UQ*PXXY*ETn?$i>0^a5%nk690%dy#_)K&CAJPVE+Y2 zpP#3|Hx0oUkSbt}D+~XGwk4+|lOYP3<3!Fm)5iSFILM3^hn*^>?o%CJ=jrs*o_Ck* zcKI6p77hjx3@<1KIyMZsUwQzA^z<8nly{=R&!jk|_$B3OWo6X_9=&tqU)vIm7 zxP!xQS??{>J>A@e9Sb~vYO+vz@E(FUkg^fVvf`ugW!bYa@{X{ieRJnLaI`$sZDYx* zk3HGI3S|yBvi_dM)qgC7SyBC<@{`8szRwUX%e4RF(dFqoAOOCBf+KzF+O`%Ys zXQphbTGqkR7U79k_1-qVDM2Zo$~-B@s?g!0*0^%1%*m~|ai3GI(~mp}j$0JM;G*+x z$@6gWUE6~Y{YjmeV%%*c5uAxEWln%E&?fqr7|VJGTQB!X_Y=Sd|NqSQ*DWKF&j}Y)87sPMmN)Y+;Oe3OTWFp8NIIeMzpww1jU!53-^*M;9K^d$4b z8XomI{GY+v^ zqbmN`huiSM3V{h<^e4K;L_fr}q)z7)^qsGK-epYM3p8;(K%k~AwN>N#_3rR$D`U5D z@LC)4lT7mN5+(#ggTA9(+iYwTdlO?6d`WKr4I*1F#A+M|-5zm+;Z(G6~OgekpO%@!6I+9#U)+&tul(HLQ8e zR?G)1JCYys5{iTtX&f2B!G-=R*)9pRS((8dnSF^Uht`L;+eJHBj;pIMQFc~m}n(!l*U`OoIYU3 zvNYAJIOjRjAJgKPV;^Ehr-fyhrgl_MHh(L7iuN<(Wl@l;gta>(I3`^EXNK81SD_X7y2kV+#KzX^$ zkKD|)nw?r{oZg<+97SNiq*t=7HA**;=@4u4x~LRh_=MUWNj~-9XPw!wufJ}8HUf>> zWO4O9F%kTR^~SBlTj3dHaosEVVrEcy(7qceQ-j!~km+z&d)Det_-U>A)m&2J@~-y&E&i7xxH+hiK1_meUN#h~5DEjj zs{hA!zWAjn*0(4}kpm*Eo+@*Rdiqvio)ClXWqoJ{glge(l1AV+c=AZ8KAzslow{o~ zi*XCOxrk|1q-DsVljUQo@b`WX53pB!aGVhKVfR4)k~Cu}O~XokMgtAg3KJ(2^6Dpt z0{c=2pQF>=$?ckb6EQ>Y%&%qu8i)UHNT=|e_zp8oYeg^RT_i_lU#bty!^HCtZV3U= z8R)c`Z&V$n*$ZGS>nxECqAuz#9S`aEOK=y_>C)!XB;#2c>KdDkjWuc2`O6@oROEO^ zKPp8oU-7Bi=-rjP=e<%sN`VVNv;qnRPlX10u}Stx+VUoh$P7t#YoJ&qLPqQq6KAVW zMAB$9(B6U^H60rexX174{h+5X-0^zwE2wt3T-#CAlGS;&PBd6mFMMv-P6pGvIoDU- zU$5XUqiv2f()Tn6wOHx1+M`;K-Cb%o+Vjh#a@$J8_B|HhUNbDb3G7JW~C`N+Il zTdE&KZs^NIV!y?jv{i9#1*zFnUv>VdGX0$XsA*1qNW8zh=bZ2uf87t65giy@FM2)v zoFLcg)%sbHTrpsibWw0&#dQ-4r>MHR!UGUC3o0Pcv$OL>0|BVPb|21MTs)*-Tuf;0 zC)^<}M8|R;U>hRy@S& zGV+8%c8(^5taOZYOvJpe{(io&9QFaPt8huGZN*`AZ0{>P6WbU&Es>>SPL z896vO=oy&knV4w*%%F90w{KG zUyT0!{BxfsZWjOHWb5>|Sbqeh|7(Pvk&c1>-?aZM<^HReQ{KYO#9Ce0!p6kb=?@Ry z?=0-x|Cs-Ojr@n>f34K`&q_u{*8g7lUn767x1@w6C)&A@;y8t40;lj zuUVb+Vo77a%h2uyo>E09x zjo9GUf`rE4(3Ezjruo)=u%&O+ks(B6KLI0lTn8!=Ja$w&+u1PSBqRJTJ>$zbM@{ky zs`S4V`KV%_DM(7eT~OEr8`~BG4^@gcvn#h zovD_?O%t@KJ~M65YQsavwl6})$LgYfmP8#5j-jRAe>p8@Aox1^GBUx@HGlkSxUu*|%!;MLIF33x(K5#!~&H6+T`& zd}r5Loi^zc-?QYtyvv7g+3R<`ipj8jpEh)f4H)d(D@LKC>mL=cIJ0hN#(41Nnh+qq zMt{8x|2KSppD0P?{Y(m5;9Mx9zV&FoH3aX7 z>l^Q8WIC?pC4aR#woXJ}`{cO!ARz<(-wd47?Ax26lkS%{{=7m3@L61Lp$LrsRIBYz z!5m-ThDcwI9*^%F*8Sgg4#OjOgH>O{6wM%_;xX^NtxZt6Z1`9$&6T#av}5-OsBR&& zGdQ$FF;V(JLX2>d&*^HCa;1e9-|lL0C0*N7!MF#_tTXUdGg@rn-aPmbd8=Cl?GeI3 zBhe3qKt2WypdcZ8Aygsl?i)ktZC7f;d83cICNX%>6>dM-587LCD)q$?dF3%!#*^aI z9Asy5e&yj?o)G1(>vx|j$g1W9x<);HuMB;k2L8V1(w(H6&=NiNw~1^w@#pxi;2Y}) z^JVA7;$x(-X#Uu}pV+LFO?Vz*9z;NDX7=mJu`PMOirEORhN3?V=ZFn~SmYgyq)&vhGzg^qSaN{-VTmS6EF@VpqHFgU4B{XiP*WmotpLDn-LJ8ob?5( z@rp;3v#6#v?_T+aBf0b2xQLkXy6-s&?{Ehx`j4ZSrh1jgkKP;tCMu9kKuQrM@xu{- zb80qasFIw%r=KF5a3RL{8hyZ4;>Qn5y=^YXgMDjD=th1!qat$bJsC@uQw9}O(=5H? z-Msc8+KCr4KE1mm3nuZ+5xd~fD}SkOV}qb=6jFmExTpw*wclXTr{EdaSN{UJuwy;} zfgPM!gWGBn;Hmc=H;#hKt?`$z0m!Jq$>9r@{W3zq978z)+5X-;>4Mp0!+vf9A}E(G zEExDrS}t80&`*s-wW$lNHC($klVP*8Jy`> zDK<1?dqTd(V0suXF>%Erj{X9kj&ePDb;(MU4#vY)7K%_Q@UVkLA%ngh8qFyTl_2iA1ly?#S_Potkh{r=o+E#iEDRO42RxLGqqA!f)CdONxP;xZlSXBBf zI|l%19-t#^Be67#@lTr3ns@>}PM zm<$#J3Iu#O4+`&6e&TKkIAvv-mpP_8EKCvAEz-;4(HS;rx47vnSd%0OEn24&kQicQ z^8C`sK@KLb*lb6O5Q2q$UR)s)JN$X3dX= zqbqojQ_O1g9dj6 zX_+d|M_jmN`V-kqq$b;luAqvE4t2dU6G$&^5%b+sD`iWSI^Axkr>DzTt+T=-W?g z43EnBq1Gqd%Xfzdv}khGFc}l#pr~f^<|=MczL42^dg#5v{@mk#U6)T-z&cAAx_EbR zkx-6H7#OIH>cTrJ!fS>`T$8I!N7>(nBt&6- zGx5vIZuCvkLFle2Es-i77?6p1KWUrop+tBAa+#T=)l=!SQhhIvLZ!4Ek`hmF;7Ur< z;^hL1wOpnz3=$*1jxpBCY@FL*J`2dk-!mhJ2uKcq8*A#G&UCjxqe_s=rZMsh=%}*g zChb~dV^@Or#;c2GHl@Vo`!h#q0fkIT8c?H$hE)TP9rZoNN2 zcw%p~^Oqqfu^ZcIWW#Zj*{mgR&haH6?-b07XEmM=9h`LqH=t2BPQ+mGN;JRO2l4~x z4=<8JdEeiGCF(XKA$!F&SxcFi)ay7MRaG?%bwmWPGM!j+!BOdCf&` zH~a{*{}${#Wf*YHXazx5C4K0Rz7UX7Wg;NT$8>v7W9MAS!an6*2C(n%vJJ1cdpk&J zdFj-pP7!@pQ|Y*M0nzW{>*F*KItuTb{`53@JX6_D8-SuVy)#MIRFCfdTC5>jNinb2c=|)7iV7Nw0Z5-U zr@Py4mGu5WuM_wWt+)_NPI(xcaWR+Aj)SOw?vJqlsrk67>edu{$TP7Z^77>8m!c~2 z{G=MS6!_(Lw6}ML1_lBrqVW}|j6gVB3+4eigOVx|J*uLCQTDG2m>dk$aAkK zb1W}tmxVS<%pxX!{d~C|f9iK{!77t9I+q5gZ%gCn5uk}9YVA)?VB}w|7A}(J$6>|1 zoBJKdS9+-_$s<7$qfypbhM-Y-{^xxM8p7UweaPGymwwinrF*|ezvIY4L?7~pABb8b zFKk5Kc2fH(BNXkuR8Sj2vW3TN_g}ev$@HIgAKXS~t7Rzw4XE>yu0eE>LGS2^xgPEy zs^GW5mf)jS*-ZnsqYdK>d84?jA}re!cnWYYsOu9$#XXwuF$iYRegE=4f3kpXy8yq9 zs!pZ1n~0pr+Hsv?u7qM9CW@0AUoxVTyug%9wpx`}SOWGSyWd<+t#OcJ%cDBu&ADL+ z@%0{W)KX$6Dljnn9wadki8v^_CDWgsyOIrQzTJKavkPU#kv@%jBMQiifGG@JA)9cS zX&UF{nH2--U@Wqrv|mT9;-}|HE@MvXh;_{KI$g^1gS9#HimO4!@Lkyoj6RFw5(s0! zBuYnB_(|6nky<|Ii_0he(icy=GH;s?akd>Ml(Wk_IM8ZaT-~f?)hTTidxJ-OOcPjB z;y8jZ@yy9%C;73bDW+QcguKFGBdf5}>(k!@Rvl5+gNA{HzgJHv+f|YRI_yBF<*y`di36ld&8}pr~>t6H~gjn%0*)%b<%2j zxgZ;7i~X+MdB4cnklvy$y&6r@UyveuL5=18!0S(O#n<#LRejR}JLhJi*IO;e>cP0> zl5MneCX$nF@0UJtg`(Svvu-!eZjk;??bd%lc4ynBDE8b0wxl?fHRwNiuJqg(A%jcK z7k1%~UVM~7eci|6BoZ34W%GG##-QFaX!?TiQpr&zNOWV3v1THc*eHXf;b?x5Cd4jd z_*l7cq8b1$a}C;wSR&$;9A6m1zL5`8HXhI7-7+&U*{GLz1xCl~{Ky-guNa^zikV7@rGyO{MS;z2@apvA(s$la6brB-X8@p5y#dr)S4sR3xD?I!I>^NxT z*q482Us6?y_bkmj8&;K0H-Po}uCTl5z;SoP2~y%$QN1gu5a}Fey?Lwg#pRveq0fMCa35xYTAuq}jV%Qd0g} zx=ui!x`5cKpTqDjS5k6OUi99l@$G`&{nSwB^t#{xtF?nKt14bNMmmjx?`1WTFJS&@ zkw?+-*7s-qR)B=nYLBD%ZnwCRYfN(VN@P1y;KVTso(w#DsEmZ7b)NsL|Gux zx2+9)*B2_o_hHSQ4~iT5CbB9WM=}`1m=(*UYce}W9A$UOtTW2K7*i`7LI z# z9OL4SBytbwUfcWHP%NnTX%8+w``upYY~qhE^>p*xNnwk2O{3$qQwyv6yBK5tMYv71 z*2WVX7)lm=8$EC&tI~ovKf3W$vxEYZ*lQ9in}~EczqF$!^;mi3eI$*Oe*cWCysY8m zwUk2ftmbv>rttiHof9u15K>gehgMA>b1MX#bI^vjb)8%=g72Xm;_Br;nOrMsCLlsO z2f;`0^=Tt;f1i3SQL+=#+TL;W{iK8;4h(B!XChmY>5#mTZjwKAwbX9QBOmlYestZJ z!D7K#W;VS zZdi*FR#B6Hv$ln|(TEOak8*QuQ1_mSCx-2U2xGUjDfqKQ`R7nW)qCNJB(H{@T% zA$d|s(GDP?5%H;=g}3jQGIqKyn?b)>-3#Wy;A;#|Sjp44 z#X0s+l=X~y^z&Q>wIK9uG7FStft@YONh^trK`U5EGBj(`Op1(Fp~hRR()=cFg|SoW zFxQXsm!MfVJ(YVN^1tuuk1znOp+ixJ-faZ?1;Q2S6}#Jf96$X*FbWu}F%T%#g7ua@ zpRHMOYYjGdzjZh{6ne9Z>!Nbsz<+5Ax`NJ>%5vpO@+JT+J7r3UTE_^sqo> z@>GG+u678c_Unp;hqSOq%gWcnX`TdSIw030^Q6FLrba605m9^GhW$hEoUB-JSSP20rhid5Q!+!$ABMrDN8Z2lfTRLN%G?h#K~d6wNfT?xLqXOmtD zzPS0hz{9rN!H1?hnJk+!5+)o%{i>8%r0!;P$tF+Q@G|7zF~L25j@~l<+_Zv@17p|p zz(XOv>_%At#K4rN-;k9F^0Qa-mfk8E<>bkfE~`j^tEXG|L~^Oc=isH(Y$MgLo`0m7 ze+7CSB7f*)HP(D5*ktnDD*lTApdh9?20`;{gzhA_~Om-TPuNm;u)3nGs z#J>yIe}$ZXbXj~^_tp5T#OtxS<}+5*Gk9d+3)9ve%;qb9eueiuGGrL%!wypGpZW3M zuJKw-AZJJi8@K13@-~N3_^Yq)>q-QGZFf0AN!f|vhsg;BR-s>it-IXI_CNc4Cqg{# zd1R46Vb|sApb`Y#9{YLBul2PKZl+x2bnUC@A29JzrMQj$^W&$_wHSK~?#as$_t^%a zPwVwwG!Wkp2B5OUzWEsROewz_VU((U)$=E+OBvAWnJvCA4*Db^dy z_{0n#%ympWaVW2zRIi%{yVQyt<8? z6ff^j^%2f*|Et9GPoaIeK|QK@Vy=%=kosZJ!bEf%uNI@@ecf{zVu7(y+KP1VDH&ef zFzr;y+Toe4?d#_1Q0CiCz~AC_JXyCgE>WVEZb1ct(FgEYxXnBshb5VeXQo8NX-OzTD$w5J=d`}ac zFKq{4<3JK{mW6p}OX+6^Ow_)h$iL0$FKu}4Bc2Ytu)yZ!RRxn>BCEni*YdE@En1@y z06|-*%R5B6zjOSUR$JrXB`Q`m7pt&+tavC6f>Nm<=*joJ^utt!WER;kWp&% zUDjg5FdP#<;=N{pIiOAyc%(T$YztR|H;xN;n z80z{K;m!U>IrTvifk~}n0fW!4VlS11#sM=8vYi^ULRSV>hT97u+f(vd(9&^*SToc@ z28I~#tmU7Eb?@eQU&FKmNLT4*5c^{jDrCc`M8$PdWSoZf)-HK!ff%J=-8gPcv>A6S z`~(xEkJtXPyf9rM^YHAy2L9Vj^+o?!=>|Tp>0$8dEZ273t1T9X{S5l1mO~*BvY-)! z!xluTiSp2^@(}cTSq92xC7Rv?n4{qk9til+YR6A9LUu9G_^d%haiWd05KrAR=w~9d zL*Z+_Goa7G|K{U|WG|efcZ^KxeeWthxvC=MGaHnp!uw9C8C{riyp#C0E>%iyZ39I= zbCVv8OA8CvYkc5pOS2r|)XG}0O4vMu?W+yJe&{mXzK}z-|Dd&V0Iq9fHoUUBf06F_ z2+H5f^X~sIU-g&g-R=?DmNoKJ%>zF+SHp{#?m(`z^^#TWnYyf z3CHux|0}L_wmvA_3UGFyr`KM zE;b|_;{I)^+d=)&+ddS?Gv>b;=VT-1`~mCE$rt1+M(S1|?J8`9*r!&>6SYF)K`3zo zH+L=eBH4iQ&FY|ChukT{08@g(%O_B_y2LOm_QJq){(#A51tYK4aoh&gKj_h0Zcu+ zLKXVG|HrTL2lIDT^RSiiB$pL4xqtoSqwslTH*^ks{m~*xH|+xYK<>&Sq}BC{@8g7d zG5T+LefdFgpDsqIH`|?1m;HsrLc@FMOb@q6b-g{0u;0Y`0(Z^6?mOF5|3V<2WA?Um z4B2Q1l1q-0u8yD;c7!mfm3`;Uz2=^!Pln`nt)#w`0_WuEZg& z7j$4GUsk|%*h>ld9kW?SKn%bkKW)l-$}7KEb^Q|QSQ|wC`-=FZX;45RSJ&>30lX6$ zkD*POb}A~z?Z5{HME8RcA@FxXKkc+MuHf9`N91Ji7CjCmjh4>1J?y}~{V)Eg&9tO6 zOyW2TGltHW_PLyolCbyfqL^M;5G!{0q^e2_HIH(b){2!~Amo$HXudChFk01F`$c30 z!47nhaZS!+c8I-=YtYk^^MgNW`T-xsWt=89nRg%!<*-tVRmAyJKIY-T_osJ}i|*a= zw#)U$g;|UEWs_C>d`Aw^S0kpgx_0-G6L|d*n{Hbj9MTUd1d}5Nu)jSSHzee}k#ZjK zm9PT}qzop`;l`DC^9!hW;f`X}8lyA0k0bc7N$s+{zf)VUMwPX0mpylQ9E*#QsE09O z@uP=C1-4tO7QXZ`9W0{zH7T*K8VWmp_Ebtp$XIVa@b=sBD|tiRnQtUyHu*>0z&N|% zTd|xt_5TZW%+bZmZ}`|o+<}2a6NPvMU$-@1lNyhW3pY9+>{25T2fIwhS3GF`mnPz) zg1)lHD7}wCE%uEVkPMzM$tmAc*3XK)b8_iRPuZ_I#H~Fl<%h66bPPOv|I8)!1?b_P zrv@=z2iSgZG#I%|uvLN6xSBe{H?kRCy)i_;#>}p$^X;DGtM9F(<_44L)&=Pd?S30-Lvgg zVwZdhlTUbi5&$09T6o*V<%-cu)}Bg!$c;_sCuhXQqN2O}b&zXGJsWQ{n-B`W@8AcN zqjstp>273N6pOhJ5jp>$_T<}GmB-%Z{lIMSS{EA|{;&hg<5w^&X%rkz{rQ=K84oe9 zs^)x{$j&QeWY7PUIWI#e@`(Q&J_@+PE5_!Az*V{L)c|5)`T@Wy183~zN z>nq~$&#Ck!hE7u*ErSl;3cmt&OIBau|De+$9X9;O5{cr|Qc9^=ENOr+4gL+=)}Wt& zZHcd?Y%D0`RA$O5OmuHE;_jS|8y1rN5QCKT8ZXl5D{vO7zIVJqro7-egcQhZb!Z5w zEmbA?%PeBMNnY>al2O~Fm>`7z8yQp&d;J#xs4f3D07$Y)1vyJThVd<2#9X%rr7m)T zJOomur@z_VFPMmnXP_oqHn3TKCTkpr{UqmE1kQ=R zGtuen%f|UUJAX?cvN-q5mK;_qE%yhTK@hR3MUs?=_;v}{BgA+lndh()T2oW!4`kq_@pRJGHEbXPr< z%3!ljB^U<4YTSl2v6qKf^dWON3v*h`t(B1n_f>|?GPC7Gz|rSAPOIu^txcC7+;|BC zrzCfio0LnafLe|@GC7SlBZ~~4Y6$c3%pS=gU@%5FGR5L?X%#3k^SmK)pSeh+4Bq8M zOBRGO_-!WE98$I-t~wV76PikRS}`)45W=l99jXE~a!pLN{DQF7ukm6h**Db-s3f^|d5 zq$;6-qwh3_fsig4HkFCdMWsOloW35}q`5*9pK28I`d?__@^9#CVy8q|_Z~voL zpJBlI!vI(?ExPkEcVpwgpzAMz#Vp@lSRVKJxEcrY7zG=x6lrV>cv#jg>s1BwVo4^` zpFe>jd{#eITzLRPrA2g^=osuAx5ZbI5XId45c48jOFx=&6%U) zwAq;fVyx#WioN+LZeq0+vTG-oX)Zl-u{U*zAOcc7AqQIe$CK^#&}bvYa>S&nr@55q6(% zfjrT+x;ZN0qd2uqsme zqIL5P!I&4VBc%cbm|Yqi4v^m3u%a^fn88397T?2Fv+}om@aze}g6t%~`O*J~2|7Uj z;56Ayf-;XnAe4efZs-PHFk@{vN#mi;!0F6^6g2f+%PlcaWG!?|&(!AC%#b3R=lVv5 zK458+s5c39mM0Rb7ecN~Tz$a6{HufU?Sblgd^ZSdjJ6saPLYoe5+BkR`#D7zX`!&;$MrO`RBQfQZJnvqVA0GeYMw=UXRCrY?-F% zTw1PK(TSS{HxyGiSF}i-SB_Ww2%Kr({3?Q z1bbIP|ADC0OfzTEx4W((XXI!cSLfIDsX{YLLo#zrxx~+}P@g3qH4~Yd{ciIq`5kQ{ zP*PYAHG=EImv8u9o|cH83?^DMsmDXLvxd?1zFbi=2a>jWHIVVxaYnS^F{W5h)AvX9 zI)C_CsT$D#&>D)K@-X56tmcE=stwr$(C zb@HyY-?jEW`<#2~-l}`6?w9#t)T~+Knd2Gw|1@a6VYa+1_p~=B*r&3~udFGb&L?Vm z0K|-rNMpc#ud`q%Yt~EPesZ~h3WF-9{zabQJbC1y!n;}$wd81N*rxLP9S+xQgN{1i z(9N!DSmb%GC#)i5)3j?D^Uqn}4OtW3Eurne{XNB^k-w%GI-Wp^Cs(5utZQd7KAr%D zVYaC5%W2NqMrE2q{Wm+=pTCy9K8`$il&3&vUU09JJd|T)K_(2&{O_5w)I7=q*9xze1In6HWOPbiuQp&w70fO*-5rLgk`^;0>W8Wq zYUp2rTu~EVd<(2>APuSzy><(@+&b5gdhg{wMugU!5+w>oej3>VOpLc<@l9YGf(G3x z1v*wm(wbO}eN0p%@!pP%ye2!1yJ)5BtY_*?I3iSkc{BkxHNi+NEivCA4M`Jyt0tSR z*nQC*6#9X-Th0ogTU$+*o8rXJwG-+SZj-ywL3h`(YjK~rvTCj$yI7sb*0sFUte3ba zu_yT>Nqu^Jyu7dgfkX6aL(8p+k$}bRr`#YB6#HqCNw%gHnHw+aq|Y*eTSBW2Y)WeK zP9V$~k-mN7D~OZ94?*!(Bzzmr=EVe?F%Mk5iPKbKeb8B=UH~lm1dAdhmn5b=$=JHy zs0skE_mKaMq;~j&A=IN^@gE5MvtZnEMiN7+XSIwhHK>q znA|2!zHDCK0`v@2135p_*TFRp=S2wdU;2#h{Y9iJn=GZ2o7OyOT08j5kSp|qqvd2C ztit8P0~W<)N+w%3643bW7;EnYGCLNi;KH!^NRAd2HhE@Y8C~WT$N{h#CUeHVGLIE9 zlK9XXF5|~N{$ok`clrDFtiBJI%2|Cu#VpzMFTm&90mV5bda$_kDZkz8=4{vch%p7$ zXHM6vk?0N2=2X?a)h=Q%$E?PZfWG~|Mv#U4e@u|^WRB(d-lS_oQ^+OJHf8U9XV!^= zFAWIT%H(FOp>O?W8z&H+$8WtqA zT_aIA4CQ=sdR0p9x%k-O{0CkR;DtbQR>swFDueb$%m1T|%FD}rYABybWOhCaW+{f^ znHYHLW8U1r7vk&ng`3g4|EfsGrMh9s5$$z%K09yYgdFi=4no?~wRoNrJ{A;_O@ z=m^37Lp6?BfZD|of_qNg`*i`AoGL{5;3Gh)^bf7_A?=isG4+dRaqSn`)jW0sEh5Mt zD>X|hggn%qT{p!Czw$T~D)pNnz{vbrlYC0JH^f>1V7mJ)cKA4UxTw6Lx(cIw?@I;l z5x#c}lZ%9b>Gi71F=J7^`?Nnzt)qXu9s+JADdRFln;^?n`XrwtjkA0>tpyaF(=fD1I+ZlBoahsP7O}E4*5|>jovhR*Q@zBj4a9eUqAzD66 zTEO5CS}yU$TB-fTTI~#2b1f3A#+Vs8$`5ad3IUof&!hxZyp4Cc8r3X8>byJ)yv+SC ze`00bQS$@T#v5!7;;6l9m(O{e#3Dk*qOWyX5WyR^6@LePj=L~v!BsEfZX-vESs4Ut z#nglU4G;PY;DOYI_NP8%CTX-;`npqkbav+jg8`@+GpLHHb<=gG1|Q%bc3oXda7zsZ z$CBLR4E(jt&E?p1WG|$P&{);7-Q$dRq{yy*t7f*e{LZgQzp{OzPLK%qFRAKla~spc zE%EnJPw1*jH;x-2-PTP;KPm>e2|({VHGQ}6NXk;<^IFOh9Sd;l{Pkj$So697y+L~$ zL_6V@Mi4i%RbJm&$8{15ZPBgRKJg>Yge&nsQCam~l93>RG-~>fhs$W$k=nDPx#1&r zV(oZflWTQ$OO?LwuN``OWAhmjr^2YjmoAcjQB)A)FxRW#e3<1QG>@dES|&+yVVRIWyi?Ju##53lNsnQj{(r1#SyYA5Btu}IyvQx*{pV}a7h>UHz{AO-j;vy0}eb; zcd)Co>==i=+GdxpciB%Kh<oMbd;GkX7qjl0@KyBs$++Uufh z|0mXknrHE9C?R3A~W7g;`Gdpmrk!S62@p;?=F596rsF6LM7vzwdl zTh)KVt52lFTSE^Z!a>vi9l*Mbtu4At?*A0hyR|T0A-rFs+>)B?q^x=|i)w6MCjDlJ zdX%W}ed%9$5`OE}?BV~Rbmq3z4<$yV;?XWu48iL*Xt@ljCNK6{*eNf!BmJ+Zd0T+G zGce|U((%cAM~$?f6`==g`XhX?*qcf%-+Z;^-3oc!WG3;2rV*oF3-#}QDcUhzQy63F zB1E9T_+7U~9jdD}FYU1RzZ7;h9>duM|7-L;0|XHpLdMemn~?hZ#Zm?jsZlo+Auy!H z+@I)!6;s^N8z8@ka>8+hFbvd)28i`x-9ya%?|Uv?#_P@jv!u;k*?cvH2FuF`GL=s| zq_`w+>1vE+9j{K`(lYJ3#7<(xS6ohad1BG&4@o4!v_U* z!|c06QyniMgFrv<_|$EupNr5F38pwcg%nynw@;Oyf9f)dk`b*%&Wnxsc4+?w z@A`H-^xlj{c;2TF=eP|UQ_e<1GLi>^Me!_(zfA{Mdk&_O560~1A z)eeR~eKZfWoL^?14UCU&s`u$^8D=SW_YbZ%vgDyvy(Z0044Cr!P*ye}$DXaNc-l-> zs3upD_x4I0FQpGR_8`H=7RbLx=mUvJm&JH|GE^b9T6$y!C_TNyeM&WV)A_K!QW_(| zkK%EsT%BEp?7%^Z>wSNDd)jEFAfx2VZP1i|Vj{#KMmBVYW;uNvdqEx)WefMv*BL0s zq|xQpi--Zn3^Y4P>F0=4-pA!QPo>2PbiR%Pp=5HvZL!|`87j}VqP9l<>}RcZ3; zJSKQlTdKbePQVdwEK7$Wa=jz~hTeUTn*;f*^Y$GaOuIeVDb94*Yz|k1!uCqSl&d!% zaYG71M3g6VZ;U|JS{j|t4TOK|2msOfRzOa+%n~W?98;4W5Eo>5pH-r2IR3qyd{M`; zV3Nk3e*awt3$*&#yseYn!eweJ#SAAzPf$$)gLIi<-i?H#*m(BR_68Ja;H&9|_rr5@ z*r&da(@=bE!9-!`JR0Rvf}UTy<=Y(ATrMDU&!u=B9ZACbDuh%g6>d|!RO{-74T}af zDw3BEwnG4e;xTftuWRb&1oqi8%=mWD`DnDs?KTKlCOB&UxUqZ!zlPh;0*nyvF?%Wi z=dRz^sWmJ^2jxOg%czBQ%2kI&oDH81_jL>bbz(h|Mr7T_x4`^!L3p;T42hz-m4+xTkK zep_vRnhHZ^p>&85mF?OhyqW8Yb6_nH3|2(yw=-v7YW#lme-Rz-ipWG!=l*S%FhuhK z$L{=qQTjbn7_LoJzW{yGubR3wg51ivq7-=1{5B*{p)&k!(7`R2z`F~5WW+d`cs}6y z1>$Z1xb@txrO^$Oo=323fOuIi?(~C7yz7W`h(A(Y%n-(*)(YdccUe$H%Ua=H5kDS6 zbws1|?&|zLyTr=6b~@k)r+^@WKl#0|ibwbYJUN9?uUgRQ0HY{G4a!-Bsxzc&3das?n~t=b?Q$$4q5R%`SLu`bw5gzyj-ji z?ibpDjuPRJJ-^~lrkt70`3i~XxyjWdd&K^xzr_bkAc*WB`8En}{Hsnu54YlLkSIC+ zz*p21Emj2ujl2pNEwBNS+HQONjjcOr(v&cFnSAz3$NfGBPD?cf`xR~KCH5bJ0$*h% z-N;{MC5AnIhr!~V)sTVWj0IlXc>qCeFuxB=TN!QKcqRsG@mmg!8w&&9bz{wW$9;qr zV%Vn{m_gtKJD*N(pg4tiLDuoE7>j-J`p-HMC{y&xL7Y+X{XuD9;;MRS#)U2dtu z{b_^%QxE9(UdTMgf2tV$q4(9wr9rozV9&fn`q$$#zly9fc%A#Ko{M{K(RSW)9ado& z(!y-~bw8V|v$tx-29f#are9l|+MO-S$J`EgeZ`*xEf8I?fNr8wTgt*0AqOhv4*w4Y zahBFuX$gTao`B(lUR%##T%&)Agui%IArT-5Q2@okl)&?NIaoZ!D7ucKQyEr;Pw;#< zP>S10+fc*VM4i+}Xgbqhb-~r^bC!^XygEVi)XI<*@thI~ePqhl^a7oP)i?n3#bF{Cv~* zUH6AHqL22wQN1*7#CyE#t1OFrTB|9A$UARmr+1D0JM7^OfyjpWI{WQEoc#(L zOb?SrHRnDQpQX4MRG)axli_J!;hs5_pX}|P<{wQHAr6YDr?r#CqoPDPc@(tx)*2W2 zl#VrueW+#~$v$LeK-NmF5HPHOXIVmq-_JaKTVMTS{{5G9kqSn9&seTSB|(7QsGnLZ zD?QbNOlCCAzO_i)-JKQnat&mh#m5?z<_>S=$l;cbM3K~9eRxn5quJE(EqW6j;rcoc zn@JRYe4U4L-1y{pre`TXi_dFN_U$e*2Vm9k+qq|F`Lx4O1#DR!QaeUg8_$2c9dwfX zI)%N%)ahz&m4795diTEXth{+3*y8<<6YSTP^8;*Xc_Uzh_DtYkZU5-CA2#rpr7IHl zzqWQ=LIaOI_$cIsz5YuH^$%Sa@>eq+a`)iBrubjLpN|3*C;ys=-t|GITMRzuk2M3O z`~I=F^mDh0@=sRYFG`&dL^tie2T|G^&??d*gLg;=bp`p!W~fLW4Eisg{*f8v9c6V^ zJ+rgu>{lNJ{6lNy^B0wV*q$Qr4-@XHv))Be|LaV>Vc?PerRBZ(Z!w%_gB>_o+2;3Ndq zdF8hh#+W*M?qMct#trsu*a+AsL(?bKC-oj4`N^?godVb$Ud`Gq5ihOB^*l|4XW@Gv zlpE6Sz9yTKzOB(sDdgw&8rlfHizVHsxnnV@mo%6B9{llUmb1R>8JjDyqN?fm!;AzArPKRjFpZ%bqnt(*1U z9Oa-BTC@R0a1V_iuj3b)PqX?qh%c(KZn;g+ffSMO0rvW*hkFO8M2W#N_>8U$n(e3p zT%da_nl@C!G3o7=+hrQ;mHM0;9Yb-+|C3>NG<|L@2$%%%x2VbEccXuE=To#1uaxiN zfs^qc%SH#d)$g-~{MH3>xRboEhzDSVOa`2=X1~exHn&yBZBh9dnFWL?qN{Pu3tg#b z#d`N?Oqbt#ywO@+iHYr`7`E{U^@y|}17=wCj7X~nQ5GPtPJ5yU8lVuSn`S_>I zL+8X4@bJ$nHmflRAOm6YK)pdPz{|xJJnsj0a+fZkU~rY<0zMUQ2a(sCb`>u>xD% z7@$Ov{+NK?YIqsfYC z7Yp=q7z68#p*j=5V>XG{$|Yhx_<9trteg%pTMmmr-f(sS8K}aw6DLcyF@KwtfV&A0 zJ9#O66-ShyA z)g0Qun1=;nh$cH6rUU{rrm|1}hsM-9V2Is=^We+XY=RX5GnRqisim%bcE3NR!IX%p z2FL#)7~qVqa>gI9U4{2t^_z;Ph@CQko{gtK1!9IRT9r%wg#yHT{Q2^YR0zbGVjsOX z_fi%NtB&KhS>PJenew-!nEdN?KXKEP&ff3hbxpU3*vL1QwycR&a@$t3kC?g|%kfv_ z|Bdl~M6nN&&!W>$Aj8Oc{z|9iF}+mD!pb+m?R?Gdd*H@^c`x&&i%cu_D}=QusnEPt zpH>>BEs+`#b0mf|yB6>%<#e?(2_Ms~RJ+_%x;ja;t7x%GW?Z@#76rl6G$>|o){CKM!c>LsI{nO#KCcze7y?q(8FzMO3-#cIPvoeBPVrZ7+ue!Rq&|q3~ zwKz&VFI~6eYUsp)5p+k8>-9Ey|2v=Pz6s#J7qwz_B-gd8TW+d0wJ!OXTc&Oe!Rg<)!!$)VmL$B zb=VGb3M4TTKRL(8i|y64d~sVRU}@gxnl$Mit6(J$aNjJ+PcOgSqQ&^PplteuvFvUj z!a%-p0m_zs?8V=X-fSx%dHBAv_}VP}GRG6S*i&{>E&0z14h;UyKuU~!ICQ2ohW8s8 zpV+tw)QIU3o26Nq!XVf+n%l|Wj8-UM@VZq$O1RF@*d4cbrKUlWTIz~&mDVk9ng4%j ztfNjm=huQKrwW&L@ z_FFt4gYy5OkGtR2D?yiy2A+s4wpmhs_6I3;1y!y7j9O&W5*MvvkBz{;P1F8;bJ&ij zf1YHPR@Ne-Mh;e^CA8PKBQ(f88qm?oYl1_H?*tw*K=cxMM(ha2n)k`CS6fg%3j9$l zJ^Yq*yY}0!CZEu-OY_U%tD27^Am!LNn0#BT7EeRqr=g7o3TjOuVOPkv{dpEgM7xf< z%?0j|*1QLB84RV2AY_4vl!!5ab(z!mdtDS#G1D=Q^^}*E1`J{{v2z{FH1zY7OVjQ_ zez$fuu5VVL0rUV2hLbB6T%b(<1tyUcD9&;XZhcJFLVU?niN(mYyZ7DE?=iSEAn9)& z6?A*A^15hyQX57>mAmNIF1JaN9ILKCs5&s`jErC|6+NZK5D@TxQh{NQj*CpJTG_rp z67=aHRfO_=GMHjM@%Rh36p->K0*ZNH|o6PK#)NU8FEf;O95)UIM?Ax z>57*|%udNd+l49&{qN3p5WyhIV-E>FJ+$}SI+ z@{R=e_g*;(g>##Sw?S~ews!4GM6fzSI+})%VvfL9Z5IBm@I{jnG;2fG{**k=m%Pty zMxHhMy{4!E7C4|h-p9YHg`Xe=Xj7J+gboDimJ6SauVYU}FCJs1`?M}_F;Mp^7#XN+ zsuQ|u<^Qt2t25VJKD?ot9}VXPM@I2D(q-ianangf7!*C5%|;9JpvN)i<-;l7%|2At zoC0&Iv$-7CH8l;#3V3U9bM6xhWHYQZ@0VHuEnU~LDCZa9GZIS;oU5AIJ)fcRmKb&> zpb%ts@xtjN1fmcjY}BC|5_ptNAv={7+aD-R0PiX{2HYa)SR9y(g~t5E#f#b7xm z3At`6p+BE@W~2IZua-w=`_)nj&xS#5urjR$7ftuKqtaytC-u0My>2%N&n$o3f|N_E zZv1LD^=7|Hsk7AvD11sv2gWOtdaTqCCRcu9EU1?)vGbTck!@e}!h-;}an@-Nyj+$e2dYwwnjt`s?q6A+8&rwZ`>*ewXl3M&KJmg_Abx0KcPke$7uO^12JF zp2m&|^Uv9z$Gmy`iY0*3ptu!`u<9PAf+NMj_5dWI1}e#jB^Yony7Lw`FXe_13@~G8 z_c$4>*KUJMJ)B6;$dD)cbhz7*X{)H;TxoOU?6FORqBHwUUeh*$+}zNSto$z|IbBwR zV*dqtJA99dsNKSyH0WVFzR* z>CL?@sQ9E=O|^;g$EixDVDKbh-0llzoCIU$EFm9E4OPk!M|cs+{&enb7IbkQSwZ2v zn56p)sa#q(_KY4qg&dKgfDikPmCp&FNAyc3NbHKY#nf6h??qzy2Z)K6`RjFjS}4U> zDS_17!09RkCo4_tvhL$~cqweBfu0b3u_`574)nT?9Fot^%11ehR5>tMu(E~A)>i6v zsJqaVzbMj*pQAPYw_ENiwi`>Us*m!^EM-Q0!eNl(3~2<2_W0*YXuDP|wC6HH11quXn%F03U+XENe*Y zR9ritLx;F(zKo>!1MTUIaNk*M=oC6_T`qpjLyM3;ZAD@}UphNy9U#tJkTs7y{ER=G zz{UJyjLutDg}20`5hBesey**ms|EJ zR00{FTu<0mWpH;`{$nmYIk=b5DVT@%q;BI)FqHfAXk5W^hUv*z?mpc3zXqO}Wi_|<-v@5XmE_k*Di``R&v*4%j# z)co3>m0IM#HBBFxy1#AdW|^U4ESde8Sj?ZmbTtifg>KBGgB#D<{UaAD)&rMba90}{M6mF{pMk3h^{+z`c+2od$^(dWq!wJuU z$mTIi;5sE=qw|}YaYx%YZCegc01z|bfGwL?{dy5Wz8$GS9fS#CaA_(P_%FtBZFFEJ z!;`J@_^Ex{e%|%ePudLMqG!TV@o@<90CtiY2oBgn$Qj1>O|^7%ns>v1XA2&G*@s(g zAqUwMou`}-=C~@R8>d=GkIk=?2FTg#w*_?OjfT!yokkvEgx%Yg2n{;9NgZo&(&i4M zg?(*qq`oZnxKeu?%bRU@e1@`X;1OpBaD5=YQeIbVWj>3>4&WLsd*lpb(G$x>*Z^ggUJ>P{D0V)-_;Lz)HakXi)2FkTn89)vfANI{s0yKC#5E z)0MU8y@8S2CBbr2-NlHFb~2fdp~-Yc?OTF_nYJM`Gi@E$;yg4=);M9bo~D}blka}z zVKzaxK6JQ~>f$UR<&#Nb9gQ6}ML3UhMG^6IodVyz;<$ngZH;5#HasWHWv7&&W3$)p zVWPPzkqudYTLI@~(ZHxwr{uZvvlL&4ch9o>?EGy{qQ^YuT4?k=9^>~lZ+`6wiNdCP z(~pGsQ@4-SxmgA2H#N4wl6~sf4`-qAWTVamL4dA2d7G2s2q~VV1L+p=G3NXwFFC&~ zjv}>w`OKxi0KJ-;c6yX&s7m@u7XLV5ZF)l1x~~{jzhE0lQ7xVG;&JqzWel7&;4Mo^ zvhIjTNUc~~)7mRI2DgV}E|W`FGSIZFzrv^WpE9ylbVvfX1ikty!3qu&P^xC;=|td* zOWF$6^k>MoUiIbsQh6vPpQa=8*F?MmO~^@1U6JyCBs0uSTYgB@&oL2??eQ*(DVx_% z?WXSrr)1__ycFcJCxI6v%}|iJJ-tVUU)P$+1HNNmrE>e;7X{kuuiY3Uf+v8p)Ne*` zoO>>c)Z8Z(NE(OOQ?<4HpM_+hzoP50vzw7Mp8k6>1JRd%iKSo|qr8f(gEo~tpqO_u zpHLK0CR-wlrA3x1-IUZUSURI6`>!+xV|_!$ANB(lgmQ+%Ga@hKw>=VaVeQ=D)Ds)F z7rfO{&HD$VAuV$3P^Jp+dUi*$i={Zu;XLbfx1t(TAVnk4pDu^B^l9&*V#-F626BXF zC;%+Ig{1KXfybJP28OUZAG%=88(%TZo!nW8pr>zl0!g`2K=`(n$15qoGG&LniMlgw*^V^fy=oE@y6`_ikT=uL%YT9!UA$3!DoEpaGHFUIwGo;DOeqTdVoIU z&%~Ub|!FqPT&zM}ejfLTG;#1{}KXF@OM0uaP8HkCV&mX%<=kIQ}^y{RY z@^(Se#V_7BB!{+xB7pGZMB%nXBXT|YTC5!j_mSoLM zth`zT!NO7ZAw@=5&G@!(^5cjRWQzc2V06M3xFhdR_m`@!^6F)#M4rf+n$K#@xSH;_P&Ci)?+IYpr|shA1RDQ2xB}gGtFk>& zo-0(_431I>Dt6c;w;j7YnRp0~sE{d%2Xrmq0|mNd_3Z%YDm*Yg7(R8L8G!(DCy31E3=062vA!U~r}JywMW^$WGc?+$Em1rs$n&)Z8mCZXjvfj^qBZXL z-{LzDjbeIp^C@-LWEMNYCFpnNZlAghrlhCo-oOfLbx1e`5hXn!)pCbd{ePxQEH_Hr zhWux3-D#Kec@Qw?-Fo7CGrT6wuX-&u!~9QFN4-WE`wn-E_l*^HShw^ew3pioR%^e? zlanY@eHQ^(>XEQ=rv{m(*Eq)w2MJ5&Zo(InM?fZqD8OB7G6IVFUzTuZ4e~?32$b*n7D~fcY{thJR?1aCXkA=f%c_0e}^)Fv+YoBcF} zbNTx(%4=I7_WRXGxP@546g#EVsMPBz7@>7Cey7wuQs-*>_~-B4rCqPWJ{1wi4dP45 zfzo83`>NIQc-ODfjtHv*{vmEjM<(XPd2VM$3nk^v-ma~mUziv7_VWslCS>z z4-$Q^hk=4rpXqqx1*YYflkmncLT1XFp)7)?Zk8DzrT2-)1^wJvs!$85iFZfukMH-f zzVR**vNfEI){n|!7scTfq%6l3ECXF3sN@&;$=`fGJ|8N0E5h>LW57^=p*c`UryL-~ zL}8R;-4**a!u#{Yv`g!)%IhoJ%I&YuueHj{%j+L*M^*s|>a>-7?w0c>3i@*ZhvICa zQ1sYQzgQkgvcN#HH!}`MV3uJBF;VjmNi*{-kKdPG=B|&+=B}=|=<5Y9PH#Od$g5ek zbcWZ2<~RGYjX(m)x%!A`=7$j?xgr=97=&C5RnXzP)!RSp#r0I;8<8etJmfQRO=nq> zFu^KQPv(B?o59-K4CVIUplTKf4;F%u_O3Jfc9IT;>Pw>+W<%%^H33gnhBsQnMP!PO zRmT=zN&X4NoRnFbX?YY#M2OcIaPq4=bKAk@Pf4>*+hSuh=x-Y?q&c27i|%}R*AUkj z6mGy991p9vD52)mDpD3X`AIr`$XH!{jzKSWyo`P>_{*`LnLQ!-*HS8gwKKXu6YbmV z>DqydgwR>E+@yNO>#mW{Gv5G|8po-7n3XQz6OTKCWA4Yd5)BBoB{kZgxAAo@utMKk zHFby_by?i-*fAgud&b=OXI*xFvPb|0qh3p9&Mkm@_X*msY=R_kjEx_>PzxxWwy5Wq zWm&QBnx>ukj^Ghv2}H9G>NY=EpD?rIzyC2A4A%1EsXraKXE5Lx<5}VTh0uqNW*%OU zH^8_Zr@(^*(LY!r{q{4{)wgH;_7%T4^SthQ;dnFY3=?U(2HM$+W4T_z*N!z~o-HFf zLnG)Ks#xXlGK0GkS%XhjSGhztBWJ}Cyr47Z+9+UAb>k_EN9GYjn$w4&a;)m}y>?We zWJCe=WK85^r=<>OEbScK2A)Pf8TDHL#R}hzK({AvXG-JGAb~Zy2Djy_4E$d(oqUwG zb%|Y?tH|LEuxwi}7RM>396Bq~ycy=DRuVD#JFdWn8nlp^d9nUyo!URv=t^e!b&A$Y zM=b1kxJT3WzctHeP1?QeCoR8G6~a;%ydrbLugn(~CQCWRS4C_+%TPBD{ZSBDVCxB( zXK=-Cq*q{f!-$mX8VY6evWvTWxVwk7JX+nfV}uQybo@CpwtC_Tgt-X&`J>aP;>Bc} zk5~l%9aF?mmFuUusz99C{X5Ye(O{uCWTFq5iINvPQ8W){onOa?@O>);;z=imJQ{)D z7Gbx-ED$Lb;(WKc~>c%K6e(2)VU|;$EwW4r^r3Gb!tiaV?{Yg zb2O5xwzUrAlOd@1gT%I>_B{ehdLxE~gv#%+%W;DZd5uUg-wB$1>RjE%I^ z{(JMk^PQ#SN=-Jr`2mx?LS@E=gmYGBoYOGEJF!LI7v`d-?&wr-Q8HZcArFCM` zBR~*T4ozyMGrE$}EH?a*l1S+vV~S8Jj-y7*AP4pA`{QIEyxf3o#yCN4?;5Ixqnj;P zz0^MA_oedOXIzIW@mexBFoh=z~8dF9|D;|`Q#oB9S>|8lVWMxP7eM7PcLE6@uyjI1lsPLikvL8Dsd{g-`&RS4fgH!OkI}}cKT!#IYMcdesT(51>0fn@cPZf za5CmNp4casG)Ci9_@rZYp|G7zcjQ3lWc^wk#I4aSx(?owI6bQu(c16RL_l~#APMNP z-+5AE!@A}fvv>J(!NB-&*pmJj?}m@cyfH4W=-$v2&H1b>2SVR~7`!Y-?1* zdv?sCsY{g!>_!g#arJMD#g!!1c1O z)TU$MN@-;$;L)>@0M!|Aoib4yroLSR+UFRhJSVf^;G2_hhmSaLmoipc%;`Ct7hC$M zn82~X0CX4A_-b1TvmbyX0J?v^>=7LN%FUj%w|5%_z7Xj;BnShCo&h@SFW$KJ5Fw4} zIgasBIO12n7+iHN+IGS$-TiIgjW_u@D+-f;em6-#{M<`6&FFgZ`K*wRuE)J%;>v~B zUT?Z$+DCRJB;6mo3vP`A6qF@i#u*{7LXTG96WQ%P7-r)2!juL^+@`yN0R1;$w8_@v zOowl&Zx#L#N9@2M3|wBsAGmhPp^?dY>MLuZ_E6#M1U`tN7mFDbG2I_H?3@{|?Omb) zGjYvhshoLwL$TY^sP=`lqj_Xd?X%3lw~mj?r9mOncWh_alEIGJ4CtHRS4ZHaARx#Z zDAAKJyUA-~yl`kZ2|;3)=1&QS|N5|R!uXHx@ybF#^sO2<1>Ugr%9!&_+NxB=n z!C_2DOkGHC)1K;g zh{r=MuV5B+iOW_zjm=FEna6`a(>2rRJ_g|oAeca7kU-ZjA3goD^Vyy?z)==BH?TBz z=DA{QaOg4=(sbv5u;>UB-4*vmz$szAb|Tw{b)VWnhl-8hh8N@8k2buSeu1IQek9`( z?-}EX`DDmFI?FZoq^^JbHe#f|KX=SJ^#oOMa!XXqoeR_Uy6uV?bF)%q`@_%2uGjF# zFcsLPxv_XN%>GG(YrmcV8bTUQr6u-Ccqno>kXxwC1DQe&$Q6_D>|7sHp3Ptm)^y4b0VAoqd;(=ACdQw0xGX zN;>cuh*Z2qH#t91g9wul<9Z9}WU1e;;jY0$fTbz8ya-}xAM*>^dB(w;WM3)hZBJo8 z#FY#~CaJ`}|21~*eb`un_J|E_ypMF9i3j-nQSJp5)KV1wjOH3$i*f=PbM_gJ(3euR z5xLe??t&-jY5jYOeasc%nNpO_;% zZoo3SxM=evU}h%5%_pGU>i^K1$oZbFB$}J#rv#$9%jq{*`2^OY!&9M=Y<~sK`NTpd z({suDn7`)=n!AJMThNUz*P7~s1I=!(v7n>Pb6!(8?j7?yaCO{?7uD{(RlpB>T;)MU z-!4#$!MO%ZvV~ezo_&xN2kN|<^hdp~)@bqv5)>7`&miKu;=I4G5KD7=0hN8XvX~Yh z537;g+EeTOw7|9XOtK$!>(4sl*!qb+qG}wLj^74&vAY9 zCM){UXkOfPE|pZB9$EM9ou!7F1XAG%(TNumLWH0YZpjeDvlRn}>0nq~9|n~Tbq%jk zmVr_>##2uJBrOtr{;8vnADd#hb7%(CV?bZ)0+R(CoQ+M4P14s@2U#Fr zoBR~m(L=nR&Q|%nDU}F%Au;~@vcx#U`pilkHcF!bNr zaVFg=?uj8m&|sXU^)XJ33G(E;?00gc*`tM|E1w?s-0*n5(@aGDZLV1yhD?6%537P^ zP*2wDoVaV;1_s0*W(k=JlXP|t58K{P{nAI3(-KQ9K@(|v^6@k&wJ0dU_*?KX=+>;) zaD8Qc@YUURGbJ*q$t7i)-C=|b6wF%vjOmBFvb3!U(DTV`q2m&89MQU@hO9l5_Q-{0 z?RV429>4U@TZSSP7(fs#iY&=?oZaLT7_X`%UsQO8~RNkl##U*YEvHl8~EmEceO=!%R95PRtcd}X{ZIUv=4Q|X8TNfty(D=GBJ0mR9C6k8}w!{-F zDb%O&*U~H!35?ptM|s%=?SCaxxzcB#>`c2gs1Px6Fz2=snS~Qr)}4a%Z5lmvv}5(< zp3$;1-vk#nPm8kX&HF8_RBv#ps%l%xp+(GrP^Yy%C5q0pau zULy~Cps%w|Ii#mY6JTZ3$Tm1sJlE$Rq=hk`HKz_ruvLg@<6<*ws6QQBCEuZVhkTAL zv8qk+5T$*)37=U6aWS!TW_UeVF#TG_;P|C~qmg2%)#uL`!{u~8q4kRbQ(ghM z7?7x}T-&cdCO{$M;v32|V;vNM+78AKrUV^NB(&pH9=-2B9uIN-Z}T;Jho0~h^L-o6 zX}0|(RTk|#RuIIWA%O-pzY_ZEPAqx`c^=Q-o(gwdyI?Z+p-j)tx81T=OJgqAAm{Bp z1emGu30Nq|5_`?7evUtY3RU|k_8GcqIe4KpsgeQbF6`BNRk0o&$!DcbMn#7?1G}j~ zmMFX9`cWkhSrlGxPdHva$=#Ai>rdnss?<`@2d37e`m`|Z7t(DgXo~)Tmt0lmFM$WR z?Yy9qW<~p)1Wf955eOx6Gs&ov$+}OZ*}-Ej3^gh|5hFI9OtChCF@^x|?%2YRuRYn_NYm;zsb`U=I$a zKIhPk5AV1C_TV=1jJy!=lrPQbM_v+I)%2DTz!M46(6x`p7cuBJ^*D;%umN1~aYd(2 zLC4A1BzAu8O*(v6NEAy6WCU|YRd_)_DIac^41LC3E%ti??X2DanZ5}{eO0ZwR_n=A zF941xoN6g(+3vf&}?sse)vEHN>B1sR#%_MWLc8vlzIw zr(rXUK!9tk3(Rs&lL0J(Id>pA%!qV%;*2f9Un*y4$Y;{1x~<<4>|v00L%@KviKG?y zMP)aVvUt3fepZ?xhgEonFlYGTZ*>FB)W~?OyM*faap1mKnD$#umVr$K%R4pT4uc%9 zPNl?aIda4T3yv?}9Yj0k5AI;?$+-W_Smx;n`#A_U4r3=(9!m9l3t(w%P^HlG#h9eU zWyE*lj|HRl{2@2TK=zr<+KO$NGpCDpEhF%&*TWmAIyDiMS9ZJP1s4PY-Vy&Su9|M}>-(1w0!0edX3@J)oVz<S)H*3wVeI)foHY zloqaBB5{9Z1?4hRmIh|r38}@YZYb*8m!Hr1W3+I2yx12rRAS7|xt$qx^Z9*UOD$6p zZmq^%mLmcNG%pS!&3TJpGq2Z^?(|?kG0iHWRb}k#Z`PadEA47{y4v4|s<@JWZFJl# zWsjO9v!8ajP$wMBl5o~zDc=5azr(!57@Ymu`|$gU3S8WL*tMQ<&1 z%#X~WqdV<<0VXHxTB#v5*Q6UJo8Igg$#JigMvpXUVM5clk6?`(MKaJl2)h4WuSf^fXreQvlYg zV5=*dHwIdz$4hf(WONX=2u!5x=bu2Xw8n$1k&tUD6A}ihq~9B3Z6L@F;h_PwEqgRk ze@1Yyw?b(c3AhkQ*|?#VRaP!)TNLAQZTkz zkX^pBd;UuQsek^UoLmfFFbDV34gM;8D}Yoy(!$yrbo>g*l9oqfpMTjo-!QYqGqHh@ zt;Xwzj03?xD==t?B7o;U__`9Uj}Szs=cvOs%Z^D|GfnA_u{J^e?I<+663iZL@5y54 zJR7Zno1b&cz*HOmJ6sx4Nl*HFwljr9=!u}>9$GYc(I}sqFdB}$sw2*V(aXkb4J=P3 zFONPR3Vw}4{nL=6znmgo47|xawukt-c8P23ORA4It_&Q7XlIdEWrrFox#~66oPN5> z+8)6U7+;L_GUj~RYnVhp>7#&YMmE`N$uHC~Z+p+3%8-fSGw&<}0+)|;#+n$DaQExB zK>BjePnBaP4^uiw`Nxmn3{WXkt0-#}PiQ7Owvq7rS)a^IdYCnj^F||c) zMf0j5={5b#htiMmWOGBbvyWaz-?H7wFJ~B%_kT-Q_!>VTcizs|(WZs;XSS~4mD>Ve zFebkz0Dpa#Uh?>xIJ?Fo$;4lWq7?s}9={V7W8?lh zRCs`cLD_GQhvxLuXs@)5KkGS7$(5Lr7vg0jACciYt0Q9wY&3ud7E^blF!e2GR-{-G zJ6((!H0aEBNc9`c{)gbl@K;-KTH>)8faf{?5XKw0`~Krw zOY7+aV%mZ?fR7j*tQ=+obG_L{57ZIGaOz!r(WgU|=MHZH|A!j*+m`&}atEw$%hPkj za{lym>tQrV7adD%W6Qqu%*?HniKU{KA7CDH9d9XC?9Urj8k#3Nb)>-Hl#Xk;7S{TsR`|>6Gv8l{GtciJkrFr52Zzk%-b1z=eo6qC<-2)zKDNw(S{2?VdbkQbfg41Y);IYw_o-9 z375Ga=CvN%u%X5AaNTmTquXCUbz{D@>y>TXja@Hao?gGs|FW*jvvzm$D!*%cO?PZG z4qCqfIQmj`x=;~3)FTnY#-_C`{kbGp?A~LOWL~Y4Q*jD8{T_5FyYi~5&zXfntENQ@ z1aj_-&|3QBW#hkxZ`!Wjztg-eyJ4rC!0+totLoNny!Us}-HXPT<85kx?OlFrU$n@_ zFKbt5y)^f`pr@hvQo1C2oyNi^^D;l0gunRs{MKw%(X+Kvv$emT*-^gtn?j83iYe!o zd@p^LVA<;^eegmXYjsrn`EQ0VZ)MCclb^ftxc-%QOQ-By{^z1gIRC1r%h%RVowb}@ zB6wEyuBs^kiHhJj{-9xKpm0y_tfj%7>l>%epMTzbi$StN#SZl~qMa|l?~3P1JaHo7 zVa=sCi+&{_4UVK#UcaBom?4PDEf&4(88h;BG|=;xA~uDs0$A2GJFhuVb{Ec$TxQ@CB|jDI?F z7;F1at#h7j)oVYkT0SBAPtwY}miO9uV?-epfekbBqqm-|PhAT--zv{%<9-etgfbOi z>t+{`3;7vvu=5cAY1xi)6Zi=~(n~(~u$r;iT8YExr^-69yoA?#X zhYat5#?$zxHr`wPN^VtQ4iDHKkQhwMfqVBDgnO=ni!qQXAYBq6Y#X+lulSPu7{wsA z8H{h<@){hBu!Rl@g3W1kOl7F9ZuYV_>jRD^A{+gq{uw6=pH+}#3Ft;nPgg&ebxsLQ E05 Date: Tue, 20 Jun 2017 15:08:34 -0400 Subject: [PATCH 172/366] link to the FAQ --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 1f49b43f..2154a263 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ ZSH and Fish: - [Adding, Removing and Re-arranging segments](#adding-removing-and-re-arranging-segments) - [Contributing new types of segments](#contributing-new-types-of-segments) - [Themes](#themes) +- [Troubleshooting](#troubleshooting) @@ -204,3 +205,9 @@ 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. + +## Troubleshooting + +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). From 0db94318c5bffd15964a99e919ab64ba21402a9c Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Tue, 20 Jun 2017 15:55:14 -0400 Subject: [PATCH 173/366] changelog for #256 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bfb4de03..b1af8e7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ ([@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 From 2492c8d10b84500040d0760fbb48617e2f0fcfe0 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Wed, 21 Jun 2017 14:12:58 -0400 Subject: [PATCH 174/366] changelog and disable rbenv by default for #260 --- CHANGELOG.md | 5 +++++ config.py.dist | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b1af8e7c..02598c8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changes +2017-06-21 + +* Add `rbenv` segment + ([@dogo](https://github.com/banga/powerline-shell/pull/260)) + 2017-06-20 * Add `newline` segment diff --git a/config.py.dist b/config.py.dist index 196e0c2d..2affa3e5 100644 --- a/config.py.dist +++ b/config.py.dist @@ -14,7 +14,7 @@ SEGMENTS = [ 'virtual_env', # Show current ruby environment (see http://rbenv.org/) - 'rbenv', +# 'rbenv', # Show the current user's username as in ordinary prompts 'username', From f63ab2fd5c20a606046cbe4628637a00c085e74b Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Wed, 21 Jun 2017 17:24:09 -0400 Subject: [PATCH 175/366] changelog for #235 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02598c8c..69fdcf6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ * 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 From 800b9cdac77ff0dccd88b5dfc8c81a478ed1c544 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 24 Jun 2017 08:29:54 -0400 Subject: [PATCH 176/366] fix stupid abc mistake in newline segment --- segments/newline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/segments/newline.py b/segments/newline.py index e9b43452..a3f72617 100644 --- a/segments/newline.py +++ b/segments/newline.py @@ -1,2 +1,2 @@ def add_newline_segment(powerline): - powerline.append("\nabc\n", Color.RESET, Color.RESET, separator='') + powerline.append("\n", Color.RESET, Color.RESET, separator='') From f4908f3ed672b906b04cfa771d322821037cba69 Mon Sep 17 00:00:00 2001 From: Jonathan Dowland Date: Mon, 10 Jul 2017 16:08:22 +0100 Subject: [PATCH 177/366] remove duplicate hexstr2num hexstr2num was defined (identically) twice. --- lib/colortrans.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/colortrans.py b/lib/colortrans.py index 0e2922cb..1c385522 100755 --- a/lib/colortrans.py +++ b/lib/colortrans.py @@ -281,10 +281,6 @@ def rgbstring2tuple(s): (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 From 2989b1e406aab612d6228b869a644947ac6372b7 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 26 Aug 2017 15:49:02 -0400 Subject: [PATCH 178/366] convert all the code into a proper package --- .gitignore | 1 + install.py | 49 ----------- .../__init__.py | 85 +++++-------------- {lib => powerline_shell}/color_compliment.py | 2 +- {lib => powerline_shell}/colortrans.py | 0 powerline_shell/repos.py | 56 ++++++++++++ {lib => powerline_shell/segments}/__init__.py | 0 {segments => powerline_shell/segments}/cwd.py | 24 +++--- .../segments}/exit_code.py | 4 +- .../segments}/fossil.py | 8 +- {segments => powerline_shell/segments}/git.py | 13 +-- {segments => powerline_shell/segments}/hg.py | 8 +- .../segments}/hostname.py | 2 +- .../segments}/jobs.py | 2 +- powerline_shell/segments/newline.py | 2 + .../segments}/node_version.py | 0 .../segments}/npm_version.py | 0 .../segments}/php_version.py | 0 .../segments}/rbenv.py | 2 +- .../segments}/read_only.py | 2 +- .../segments}/root.py | 8 +- .../segments}/ruby_version.py | 0 .../segments}/set_term_title.py | 0 powerline_shell/segments/ssh.py | 6 ++ {segments => powerline_shell/segments}/svn.py | 2 +- .../segments}/time.py | 2 +- .../segments}/uptime.py | 2 +- .../segments}/username.py | 6 +- .../segments}/virtual_env.py | 4 +- .../themes}/__init__.py | 0 {themes => powerline_shell/themes}/basic.py | 0 .../themes}/colortest.py | 0 {themes => powerline_shell/themes}/default.py | 0 .../themes}/solarized-dark.py | 0 {themes => powerline_shell/themes}/washed.py | 0 segments/newline.py | 2 - segments/ssh.py | 6 -- setup.py | 19 +++++ test/repo_stats_test.py | 1 + 39 files changed, 152 insertions(+), 166 deletions(-) delete mode 100755 install.py rename powerline_shell_base.py => powerline_shell/__init__.py (70%) mode change 100755 => 100644 rename {lib => powerline_shell}/color_compliment.py (97%) mode change 100755 => 100644 rename {lib => powerline_shell}/colortrans.py (100%) create mode 100644 powerline_shell/repos.py rename {lib => powerline_shell/segments}/__init__.py (100%) rename {segments => powerline_shell/segments}/cwd.py (77%) rename {segments => powerline_shell/segments}/exit_code.py (67%) rename {segments => powerline_shell/segments}/fossil.py (91%) rename {segments => powerline_shell/segments}/git.py (91%) rename {segments => powerline_shell/segments}/hg.py (87%) rename {segments => powerline_shell/segments}/hostname.py (88%) rename {segments => powerline_shell/segments}/jobs.py (91%) create mode 100644 powerline_shell/segments/newline.py rename {segments => powerline_shell/segments}/node_version.py (100%) rename {segments => powerline_shell/segments}/npm_version.py (100%) rename {segments => powerline_shell/segments}/php_version.py (100%) rename {segments => powerline_shell/segments}/rbenv.py (72%) rename {segments => powerline_shell/segments}/read_only.py (54%) rename {segments => powerline_shell/segments}/root.py (59%) rename {segments => powerline_shell/segments}/ruby_version.py (100%) rename {segments => powerline_shell/segments}/set_term_title.py (100%) create mode 100644 powerline_shell/segments/ssh.py rename {segments => powerline_shell/segments}/svn.py (92%) rename {segments => powerline_shell/segments}/time.py (73%) rename {segments => powerline_shell/segments}/uptime.py (89%) rename {segments => powerline_shell/segments}/username.py (63%) rename {segments => powerline_shell/segments}/virtual_env.py (77%) rename {segments => powerline_shell/themes}/__init__.py (100%) rename {themes => powerline_shell/themes}/basic.py (100%) rename {themes => powerline_shell/themes}/colortest.py (100%) rename {themes => powerline_shell/themes}/default.py (100%) rename {themes => powerline_shell/themes}/solarized-dark.py (100%) rename {themes => powerline_shell/themes}/washed.py (100%) delete mode 100644 segments/newline.py delete mode 100644 segments/ssh.py create mode 100755 setup.py diff --git a/.gitignore b/.gitignore index 59291234..d84c36e5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ powerline-shell.py *.py[co] config.py +powerline_shell.egg-info/ diff --git a/install.py b/install.py deleted file mode 100755 index bf36f41e..00000000 --- a/install.py +++ /dev/null @@ -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) diff --git a/powerline_shell_base.py b/powerline_shell/__init__.py old mode 100755 new mode 100644 similarity index 70% rename from powerline_shell_base.py rename to powerline_shell/__init__.py index 5d367a52..9aea770f --- a/powerline_shell_base.py +++ b/powerline_shell/__init__.py @@ -1,24 +1,29 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import print_function - import argparse import os import sys +import config +import importlib +from .themes.default import DefaultColor py3 = sys.version_info.major == 3 +if py3: + def unicode(x): + return x + def warn(msg): print('[powerline-bash] ', msg) -if py3: - def unicode(x): - return x +def get_default_theme(): + return DefaultColor -class Powerline: +class Powerline(object): symbols = { 'compatible': { 'lock': 'RO', @@ -46,9 +51,10 @@ class Powerline: 'bare': '%s', } - def __init__(self, args, cwd): + def __init__(self, args, cwd, theme=None): self.args = args self.cwd = cwd + self.theme = theme or get_default_theme() mode, shell = args.mode, args.shell self.color_template = self.color_templates[shell] self.reset = self.color_template % '[0m' @@ -61,7 +67,7 @@ def __init__(self, args, cwd): def color(self, prefix, code): if code is None: return '' - elif code == Color.RESET: + elif code == self.theme.RESET: return self.reset else: return self.color_template % ('[%s;5;%sm' % (prefix, code)) @@ -98,64 +104,6 @@ def draw_segment(self, idx): segment[3])) -class RepoStats: - symbols = { - 'detached': u'\u2693', - 'ahead': u'\u2B06', - 'behind': u'\u2B07', - 'staged': u'\u2714', - 'not_staged': u'\u270E', - 'untracked': u'\u2753', - 'conflicted': u'\u273C' - } - - def __init__(self): - self.ahead = 0 - self.behind = 0 - self.untracked = 0 - self.not_staged = 0 - self.staged = 0 - self.conflicted = 0 - - @property - def dirty(self): - qualifiers = [ - self.untracked, - self.not_staged, - 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 untracked files, but you - only want a number to appear next to the icon when there are more than - one untracked files, you can do: - - segment = repo_stats.n_or_empty("untracked") + icon_string - """ - return unicode(self[_key]) if int(self[_key]) > 1 else u'' - - def add_to_powerline(self, powerline, color): - def add(_key, fg, bg): - if self[_key]: - s = u" {}{} ".format(self.n_or_empty(_key), self.symbols[_key]) - powerline.append(s, fg, bg) - 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('not_staged', color.GIT_NOTSTAGED_FG, color.GIT_NOTSTAGED_BG) - add('untracked', color.GIT_UNTRACKED_FG, color.GIT_UNTRACKED_BG) - add('conflicted', color.GIT_CONFLICTED_FG, color.GIT_CONFLICTED_BG) - - def get_valid_cwd(): """ We check if the current working directory is valid or not. Typically happens when you checkout a different branch on git that doesn't have @@ -186,7 +134,7 @@ def get_valid_cwd(): return cwd -if __name__ == "__main__": +def main(): arg_parser = argparse.ArgumentParser() arg_parser.add_argument('--cwd-mode', action='store', help='How to display the current directory', default='fancy', @@ -209,3 +157,8 @@ def get_valid_cwd(): args = arg_parser.parse_args() powerline = Powerline(args, get_valid_cwd()) + for segment in config.SEGMENTS: + mod = importlib.import_module("powerline_shell.segments." + segment) + fn = getattr(mod, "add_" + segment + "_segment") + fn(powerline) + sys.stdout.write(powerline.draw()) diff --git a/lib/color_compliment.py b/powerline_shell/color_compliment.py old mode 100755 new mode 100644 similarity index 97% rename from lib/color_compliment.py rename to powerline_shell/color_compliment.py index 9e022ddc..0a040d2a --- a/lib/color_compliment.py +++ b/powerline_shell/color_compliment.py @@ -10,7 +10,7 @@ # Original, non-relative import errors on Python3 from .colortrans import * -py3 = sys.version_info[0] == 3 +py3 = sys.version_info.major == 3 def getOppositeColor(r,g,b): diff --git a/lib/colortrans.py b/powerline_shell/colortrans.py similarity index 100% rename from lib/colortrans.py rename to powerline_shell/colortrans.py diff --git a/powerline_shell/repos.py b/powerline_shell/repos.py new file mode 100644 index 00000000..fe4e46e9 --- /dev/null +++ b/powerline_shell/repos.py @@ -0,0 +1,56 @@ +class RepoStats(object): + symbols = { + 'detached': u'\u2693', + 'ahead': u'\u2B06', + 'behind': u'\u2B07', + 'staged': u'\u2714', + 'not_staged': u'\u270E', + 'untracked': u'\u2753', + 'conflicted': u'\u273C' + } + + def __init__(self): + self.ahead = 0 + self.behind = 0 + self.untracked = 0 + self.not_staged = 0 + self.staged = 0 + self.conflicted = 0 + + @property + def dirty(self): + qualifiers = [ + self.untracked, + self.not_staged, + 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 untracked files, but you + only want a number to appear next to the icon when there are more than + one untracked files, you can do: + + segment = repo_stats.n_or_empty("untracked") + icon_string + """ + return unicode(self[_key]) if int(self[_key]) > 1 else u'' + + def add_to_powerline(self, powerline, color): + def add(_key, fg, bg): + if self[_key]: + s = u" {}{} ".format(self.n_or_empty(_key), self.symbols[_key]) + powerline.append(s, fg, bg) + 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('not_staged', color.GIT_NOTSTAGED_FG, color.GIT_NOTSTAGED_BG) + add('untracked', color.GIT_UNTRACKED_FG, color.GIT_UNTRACKED_BG) + add('conflicted', color.GIT_CONFLICTED_FG, color.GIT_CONFLICTED_BG) diff --git a/lib/__init__.py b/powerline_shell/segments/__init__.py similarity index 100% rename from lib/__init__.py rename to powerline_shell/segments/__init__.py diff --git a/segments/cwd.py b/powerline_shell/segments/cwd.py similarity index 77% rename from segments/cwd.py rename to powerline_shell/segments/cwd.py index 9dd38ba6..14702cc2 100644 --- a/segments/cwd.py +++ b/powerline_shell/segments/cwd.py @@ -1,6 +1,8 @@ import os +import sys ELLIPSIS = u'\u2026' +py3 = sys.version_info.major == 3 def replace_home_dir(cwd): @@ -22,10 +24,10 @@ 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): @@ -37,16 +39,16 @@ def maybe_shorten_name(powerline, name): return name -def get_fg_bg(name, is_last_dir): +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,) + if requires_special_home_display(powerline, name): + return (powerline.theme.HOME_FG, powerline.theme.HOME_BG,) if is_last_dir: - return (Color.CWD_FG, Color.PATH_BG,) + return (powerline.theme.CWD_FG, powerline.theme.PATH_BG,) else: - return (Color.PATH_FG, Color.PATH_BG,) + return (powerline.theme.PATH_FG, powerline.theme.PATH_BG,) def add_cwd_segment(powerline): @@ -56,7 +58,7 @@ def add_cwd_segment(powerline): cwd = replace_home_dir(cwd) if powerline.args.cwd_mode == 'plain': - powerline.append(' %s ' % (cwd,), Color.CWD_FG, Color.PATH_BG) + powerline.append(' %s ' % (cwd,), powerline.theme.CWD_FG, powerline.theme.PATH_BG) return names = split_path_into_names(cwd) @@ -82,11 +84,11 @@ def add_cwd_segment(powerline): for i, name in enumerate(names): is_last_dir = (i == len(names) - 1) - fg, bg = get_fg_bg(name, is_last_dir) + fg, bg = get_fg_bg(powerline, name, is_last_dir) separator = powerline.separator_thin - separator_fg = Color.SEPARATOR_FG - 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 diff --git a/segments/exit_code.py b/powerline_shell/segments/exit_code.py similarity index 67% rename from segments/exit_code.py rename to powerline_shell/segments/exit_code.py index e3b320ee..00be9b8c 100644 --- a/segments/exit_code.py +++ b/powerline_shell/segments/exit_code.py @@ -1,6 +1,6 @@ def add_exit_code_segment(powerline): if powerline.args.prev_error == 0: return - fg = Color.CMD_FAILED_FG - bg = Color.CMD_FAILED_BG + fg = powerline.theme.CMD_FAILED_FG + bg = powerline.theme.CMD_FAILED_BG powerline.append(' %s ' % str(powerline.args.prev_error), fg, bg) diff --git a/segments/fossil.py b/powerline_shell/segments/fossil.py similarity index 91% rename from segments/fossil.py rename to powerline_shell/segments/fossil.py index 6c7818ec..3183bb6c 100644 --- a/segments/fossil.py +++ b/powerline_shell/segments/fossil.py @@ -18,12 +18,12 @@ def _add_fossil_segment(powerline): if len(branch) == 0: return - bg = Color.REPO_CLEAN_BG - fg = Color.REPO_CLEAN_FG + bg = powerline.theme.REPO_CLEAN_BG + fg = powerline.theme.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 + bg = powerline.theme.REPO_DIRTY_BG + fg = powerline.theme.REPO_DIRTY_FG extra = '' if has_untracked_files: extra += '+' diff --git a/segments/git.py b/powerline_shell/segments/git.py similarity index 91% rename from segments/git.py rename to powerline_shell/segments/git.py index 0da777f0..1774d941 100644 --- a/segments/git.py +++ b/powerline_shell/segments/git.py @@ -1,6 +1,8 @@ import re import subprocess import os +from ..repos import RepoStats + def get_PATH(): """Normally gets the PATH from the OS. This function exists to enable @@ -8,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. @@ -80,11 +83,11 @@ def add_git_segment(powerline): else: branch = _get_git_detached_branch() - bg = Color.REPO_CLEAN_BG - fg = Color.REPO_CLEAN_FG + bg = powerline.theme.REPO_CLEAN_BG + fg = powerline.theme.REPO_CLEAN_FG if stats.dirty: - bg = Color.REPO_DIRTY_BG - fg = Color.REPO_DIRTY_FG + bg = powerline.theme.REPO_DIRTY_BG + fg = powerline.theme.REPO_DIRTY_FG powerline.append(' %s ' % branch, fg, bg) - stats.add_to_powerline(powerline, Color) + stats.add_to_powerline(powerline, powerline.theme) diff --git a/segments/hg.py b/powerline_shell/segments/hg.py similarity index 87% rename from segments/hg.py rename to powerline_shell/segments/hg.py index d5f1cf48..7d7dc6a5 100644 --- a/segments/hg.py +++ b/powerline_shell/segments/hg.py @@ -24,12 +24,12 @@ 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 + bg = powerline.theme.REPO_CLEAN_BG + fg = powerline.theme.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 + bg = powerline.theme.REPO_DIRTY_BG + fg = powerline.theme.REPO_DIRTY_FG extra = '' if has_untracked_files: extra += '+' diff --git a/segments/hostname.py b/powerline_shell/segments/hostname.py similarity index 88% rename from segments/hostname.py rename to powerline_shell/segments/hostname.py index 609711e2..d4c310a5 100644 --- a/segments/hostname.py +++ b/powerline_shell/segments/hostname.py @@ -18,4 +18,4 @@ def add_hostname_segment(powerline): import socket host_prompt = ' %s ' % socket.gethostname().split('.')[0] - powerline.append(host_prompt, Color.HOSTNAME_FG, Color.HOSTNAME_BG) + powerline.append(host_prompt, powerline.theme.HOSTNAME_FG, powerline.theme.HOSTNAME_BG) diff --git a/segments/jobs.py b/powerline_shell/segments/jobs.py similarity index 91% rename from segments/jobs.py rename to powerline_shell/segments/jobs.py index 2e0f9dc5..68662491 100644 --- a/segments/jobs.py +++ b/powerline_shell/segments/jobs.py @@ -27,4 +27,4 @@ def add_jobs_segment(powerline): num_jobs = len(re.findall(str(pppid), output)) - 1 if num_jobs > 0: - powerline.append(' %d ' % num_jobs, Color.JOBS_FG, Color.JOBS_BG) + powerline.append(' %d ' % num_jobs, powerline.theme.JOBS_FG, powerline.theme.JOBS_BG) diff --git a/powerline_shell/segments/newline.py b/powerline_shell/segments/newline.py new file mode 100644 index 00000000..07b13ffe --- /dev/null +++ b/powerline_shell/segments/newline.py @@ -0,0 +1,2 @@ +def add_newline_segment(powerline): + powerline.append("\n", powerline.theme.RESET, powerline.theme.RESET, separator='') diff --git a/segments/node_version.py b/powerline_shell/segments/node_version.py similarity index 100% rename from segments/node_version.py rename to powerline_shell/segments/node_version.py diff --git a/segments/npm_version.py b/powerline_shell/segments/npm_version.py similarity index 100% rename from segments/npm_version.py rename to powerline_shell/segments/npm_version.py diff --git a/segments/php_version.py b/powerline_shell/segments/php_version.py similarity index 100% rename from segments/php_version.py rename to powerline_shell/segments/php_version.py diff --git a/segments/rbenv.py b/powerline_shell/segments/rbenv.py similarity index 72% rename from segments/rbenv.py rename to powerline_shell/segments/rbenv.py index 70e34a81..1208f6c7 100644 --- a/segments/rbenv.py +++ b/powerline_shell/segments/rbenv.py @@ -8,6 +8,6 @@ def add_rbenv_segment(powerline): if len(version) <= 0: return - powerline.append(' %s ' % version, Color.VIRTUAL_ENV_FG, Color.VIRTUAL_ENV_BG) + powerline.append(' %s ' % version, powerline.theme.VIRTUAL_ENV_FG, powerline.theme.VIRTUAL_ENV_BG) except OSError: return diff --git a/segments/read_only.py b/powerline_shell/segments/read_only.py similarity index 54% rename from segments/read_only.py rename to powerline_shell/segments/read_only.py index efbe11ad..c2bf79e8 100644 --- a/segments/read_only.py +++ b/powerline_shell/segments/read_only.py @@ -4,4 +4,4 @@ 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) + powerline.append(' %s ' % powerline.lock, powerline.theme.READONLY_FG, powerline.theme.READONLY_BG) diff --git a/segments/root.py b/powerline_shell/segments/root.py similarity index 59% rename from segments/root.py rename to powerline_shell/segments/root.py index 49404ecf..4900d7f5 100644 --- a/segments/root.py +++ b/powerline_shell/segments/root.py @@ -4,9 +4,9 @@ def add_root_segment(powerline): 'zsh': ' %# ', 'bare': ' $ ', } - bg = Color.CMD_PASSED_BG - fg = Color.CMD_PASSED_FG + bg = powerline.theme.CMD_PASSED_BG + fg = powerline.theme.CMD_PASSED_FG if powerline.args.prev_error != 0: - fg = Color.CMD_FAILED_FG - bg = Color.CMD_FAILED_BG + fg = powerline.theme.CMD_FAILED_FG + bg = powerline.theme.CMD_FAILED_BG powerline.append(root_indicators[powerline.args.shell], fg, bg) diff --git a/segments/ruby_version.py b/powerline_shell/segments/ruby_version.py similarity index 100% rename from segments/ruby_version.py rename to powerline_shell/segments/ruby_version.py diff --git a/segments/set_term_title.py b/powerline_shell/segments/set_term_title.py similarity index 100% rename from segments/set_term_title.py rename to powerline_shell/segments/set_term_title.py diff --git a/powerline_shell/segments/ssh.py b/powerline_shell/segments/ssh.py new file mode 100644 index 00000000..c4291628 --- /dev/null +++ b/powerline_shell/segments/ssh.py @@ -0,0 +1,6 @@ +import os + +def add_ssh_segment(powerline): + + if os.getenv('SSH_CLIENT'): + powerline.append(' %s ' % powerline.network, powerline.theme.SSH_FG, powerline.theme.SSH_BG) diff --git a/segments/svn.py b/powerline_shell/segments/svn.py similarity index 92% rename from segments/svn.py rename to powerline_shell/segments/svn.py index 89168c01..454b96f1 100644 --- a/segments/svn.py +++ b/powerline_shell/segments/svn.py @@ -16,7 +16,7 @@ def _add_svn_segment(powerline): 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) + powerline.append(' %s ' % changes, powerline.theme.SVN_CHANGES_FG, powerline.theme.SVN_CHANGES_BG) def add_svn_segment(powerline): diff --git a/segments/time.py b/powerline_shell/segments/time.py similarity index 73% rename from segments/time.py rename to powerline_shell/segments/time.py index 8c0313f6..dedad803 100644 --- a/segments/time.py +++ b/powerline_shell/segments/time.py @@ -7,4 +7,4 @@ def add_time_segment(powerline): import time time = ' %s ' % time.strftime('%H:%M:%S') - powerline.append(time, Color.HOSTNAME_FG, Color.HOSTNAME_BG) + powerline.append(time, powerline.theme.HOSTNAME_FG, powerline.theme.HOSTNAME_BG) diff --git a/segments/uptime.py b/powerline_shell/segments/uptime.py similarity index 89% rename from segments/uptime.py rename to powerline_shell/segments/uptime.py index 4c7711ce..e53e2587 100644 --- a/segments/uptime.py +++ b/powerline_shell/segments/uptime.py @@ -11,6 +11,6 @@ def add_uptime_segment(powerline): 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) + powerline.append(uptime, powerline.theme.CWD_FG, powerline.theme.PATH_BG) except OSError: return diff --git a/segments/username.py b/powerline_shell/segments/username.py similarity index 63% rename from segments/username.py rename to powerline_shell/segments/username.py index 3d73a12c..d8cc177d 100644 --- a/segments/username.py +++ b/powerline_shell/segments/username.py @@ -9,8 +9,8 @@ def add_username_segment(powerline): user_prompt = ' %s ' % os.getenv('USER') if os.getenv('USER') == 'root': - bgcolor = Color.USERNAME_ROOT_BG + bgcolor = powerline.theme.USERNAME_ROOT_BG else: - bgcolor = Color.USERNAME_BG + bgcolor = powerline.theme.USERNAME_BG - powerline.append(user_prompt, Color.USERNAME_FG, bgcolor) + powerline.append(user_prompt, powerline.theme.USERNAME_FG, bgcolor) diff --git a/segments/virtual_env.py b/powerline_shell/segments/virtual_env.py similarity index 77% rename from segments/virtual_env.py rename to powerline_shell/segments/virtual_env.py index 35a368f5..2b4de48d 100644 --- a/segments/virtual_env.py +++ b/powerline_shell/segments/virtual_env.py @@ -6,6 +6,6 @@ def add_virtual_env_segment(powerline): return env_name = os.path.basename(env) - bg = Color.VIRTUAL_ENV_BG - fg = Color.VIRTUAL_ENV_FG + bg = powerline.theme.VIRTUAL_ENV_BG + fg = powerline.theme.VIRTUAL_ENV_FG powerline.append(' %s ' % env_name, fg, bg) diff --git a/segments/__init__.py b/powerline_shell/themes/__init__.py similarity index 100% rename from segments/__init__.py rename to powerline_shell/themes/__init__.py diff --git a/themes/basic.py b/powerline_shell/themes/basic.py similarity index 100% rename from themes/basic.py rename to powerline_shell/themes/basic.py diff --git a/themes/colortest.py b/powerline_shell/themes/colortest.py similarity index 100% rename from themes/colortest.py rename to powerline_shell/themes/colortest.py diff --git a/themes/default.py b/powerline_shell/themes/default.py similarity index 100% rename from themes/default.py rename to powerline_shell/themes/default.py diff --git a/themes/solarized-dark.py b/powerline_shell/themes/solarized-dark.py similarity index 100% rename from themes/solarized-dark.py rename to powerline_shell/themes/solarized-dark.py diff --git a/themes/washed.py b/powerline_shell/themes/washed.py similarity index 100% rename from themes/washed.py rename to powerline_shell/themes/washed.py diff --git a/segments/newline.py b/segments/newline.py deleted file mode 100644 index a3f72617..00000000 --- a/segments/newline.py +++ /dev/null @@ -1,2 +0,0 @@ -def add_newline_segment(powerline): - powerline.append("\n", Color.RESET, Color.RESET, separator='') diff --git a/segments/ssh.py b/segments/ssh.py deleted file mode 100644 index 5361bc5e..00000000 --- a/segments/ssh.py +++ /dev/null @@ -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) diff --git a/setup.py b/setup.py new file mode 100755 index 00000000..69843b0a --- /dev/null +++ b/setup.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +from setuptools import setup, find_packages + +setup(name="powerline-shell", + version="0.1.0-alpha", + description="A pretty prompt for your shell", + author="Buck Ryan", + url="httpss://github.com/banga/powerline-shell", + classifiers=[], + py_modules=["powerline_shell"], + install_requires=[ + "argparse", + ], + entry_points=""" + [console_scripts] + powerline-shell=powerline_shell:main + """, + packages=["powerline_shell"], +) diff --git a/test/repo_stats_test.py b/test/repo_stats_test.py index c97a089d..a3e2149c 100644 --- a/test/repo_stats_test.py +++ b/test/repo_stats_test.py @@ -1,5 +1,6 @@ import unittest import powerline_shell_base as p +from powerline_shell.repos import RepoStats class RepoStatsTest(unittest.TestCase): From b4a279b0e79c1a1c297710709777ee136e19b517 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 26 Aug 2017 16:00:30 -0400 Subject: [PATCH 179/366] fix missing imports --- powerline_shell/segments/ruby_version.py | 1 + powerline_shell/segments/set_term_title.py | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/powerline_shell/segments/ruby_version.py b/powerline_shell/segments/ruby_version.py index 040f5334..513d10f8 100644 --- a/powerline_shell/segments/ruby_version.py +++ b/powerline_shell/segments/ruby_version.py @@ -1,3 +1,4 @@ +import os import subprocess diff --git a/powerline_shell/segments/set_term_title.py b/powerline_shell/segments/set_term_title.py index 7c3e8264..adaf7075 100644 --- a/powerline_shell/segments/set_term_title.py +++ b/powerline_shell/segments/set_term_title.py @@ -1,3 +1,6 @@ +import os + + def add_set_term_title_segment(powerline): term = os.getenv('TERM') if not (('xterm' in term) or ('rxvt' in term)): @@ -12,4 +15,3 @@ def add_set_term_title_segment(powerline): 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, '') - From fafd37babb0f8825b4121545db668c4a8931d8ea Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 26 Aug 2017 17:46:46 -0400 Subject: [PATCH 180/366] Convert many segments to new class-based code --- powerline_shell/__init__.py | 27 ++++------- powerline_shell/color_compliment.py | 12 +---- powerline_shell/segments.py | 0 powerline_shell/segments/cwd.py | 7 ++- powerline_shell/segments/exit_code.py | 16 ++++--- powerline_shell/segments/git.py | 32 ++++++++----- powerline_shell/segments/hostname.py | 43 ++++++++++-------- powerline_shell/segments/jobs.py | 53 +++++++++++----------- powerline_shell/segments/newline.py | 11 ++++- powerline_shell/segments/root.py | 29 +++++++----- powerline_shell/segments/set_term_title.py | 2 +- powerline_shell/segments/virtual_env.py | 20 ++++---- powerline_shell/{repos.py => utils.py} | 29 +++++++++++- test/repo_stats_test.py | 2 +- 14 files changed, 166 insertions(+), 117 deletions(-) create mode 100644 powerline_shell/segments.py rename powerline_shell/{repos.py => utils.py} (78%) diff --git a/powerline_shell/__init__.py b/powerline_shell/__init__.py index 9aea770f..4b233220 100644 --- a/powerline_shell/__init__.py +++ b/powerline_shell/__init__.py @@ -7,20 +7,7 @@ import config import importlib from .themes.default import DefaultColor - -py3 = sys.version_info.major == 3 - -if py3: - def unicode(x): - return x - - -def warn(msg): - print('[powerline-bash] ', msg) - - -def get_default_theme(): - return DefaultColor +from .utils import warn, py3 class Powerline(object): @@ -54,7 +41,7 @@ class Powerline(object): def __init__(self, args, cwd, theme=None): self.args = args self.cwd = cwd - self.theme = theme or get_default_theme() + self.theme = theme or DefaultColor mode, shell = args.mode, args.shell self.color_template = self.color_templates[shell] self.reset = self.color_template % '[0m' @@ -157,8 +144,10 @@ def main(): args = arg_parser.parse_args() powerline = Powerline(args, get_valid_cwd()) - for segment in config.SEGMENTS: - mod = importlib.import_module("powerline_shell.segments." + segment) - fn = getattr(mod, "add_" + segment + "_segment") - fn(powerline) + segments = [] + for seg_name in config.SEGMENTS: + mod = importlib.import_module("powerline_shell.segments." + seg_name) + segments.append(getattr(mod, "Segment")(powerline)) + for segment in segments: + segment.add_to_powerline() sys.stdout.write(powerline.draw()) diff --git a/powerline_shell/color_compliment.py b/powerline_shell/color_compliment.py index 0a040d2a..08f8bea7 100644 --- a/powerline_shell/color_compliment.py +++ b/powerline_shell/color_compliment.py @@ -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 @@ except ImportError: from hashlib import md5 import sys - -# Original, non-relative import errors on Python3 from .colortrans import * - -py3 = sys.version_info.major == 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 diff --git a/powerline_shell/segments.py b/powerline_shell/segments.py new file mode 100644 index 00000000..e69de29b diff --git a/powerline_shell/segments/cwd.py b/powerline_shell/segments/cwd.py index 14702cc2..a1d7d295 100644 --- a/powerline_shell/segments/cwd.py +++ b/powerline_shell/segments/cwd.py @@ -1,8 +1,8 @@ import os import sys +from ..utils import warn, py3, BasicSegment ELLIPSIS = u'\u2026' -py3 = sys.version_info.major == 3 def replace_home_dir(cwd): @@ -94,3 +94,8 @@ def add_cwd_segment(powerline): 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) diff --git a/powerline_shell/segments/exit_code.py b/powerline_shell/segments/exit_code.py index 00be9b8c..85153ec3 100644 --- a/powerline_shell/segments/exit_code.py +++ b/powerline_shell/segments/exit_code.py @@ -1,6 +1,10 @@ -def add_exit_code_segment(powerline): - if powerline.args.prev_error == 0: - return - fg = powerline.theme.CMD_FAILED_FG - bg = powerline.theme.CMD_FAILED_BG - powerline.append(' %s ' % str(powerline.args.prev_error), fg, bg) +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) diff --git a/powerline_shell/segments/git.py b/powerline_shell/segments/git.py index 1774d941..03dd09fc 100644 --- a/powerline_shell/segments/git.py +++ b/powerline_shell/segments/git.py @@ -1,7 +1,7 @@ import re import subprocess import os -from ..repos import RepoStats +from ..utils import RepoStats, ThreadedSegment def get_PATH(): @@ -59,18 +59,18 @@ def parse_git_stats(status): return stats -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 pdata = p.communicate() if p.returncode != 0: - return + return None status = pdata[0].decode("utf-8").splitlines() stats = parse_git_stats(status) @@ -82,12 +82,22 @@ def add_git_segment(powerline): branch = branch_info['local'] else: branch = _get_git_detached_branch() + return stats, branch - bg = powerline.theme.REPO_CLEAN_BG - fg = powerline.theme.REPO_CLEAN_FG - if stats.dirty: - bg = powerline.theme.REPO_DIRTY_BG - fg = powerline.theme.REPO_DIRTY_FG - powerline.append(' %s ' % branch, fg, bg) - stats.add_to_powerline(powerline, powerline.theme) +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) diff --git a/powerline_shell/segments/hostname.py b/powerline_shell/segments/hostname.py index d4c310a5..ddbaff6d 100644 --- a/powerline_shell/segments/hostname.py +++ b/powerline_shell/segments/hostname.py @@ -1,21 +1,28 @@ -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] +from ..utils import BasicSegment - powerline.append(host_prompt, FG, BG) - else: - if powerline.args.shell == 'bash': - host_prompt = ' \\h ' - elif powerline.args.shell == 'zsh': - host_prompt = ' %m ' + +class Segment(BasicSegment): + def add_to_powerline(self): + powerline = self.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: - import socket - host_prompt = ' %s ' % socket.gethostname().split('.')[0] + 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, powerline.theme.HOSTNAME_FG, powerline.theme.HOSTNAME_BG) + powerline.append(host_prompt, + powerline.theme.HOSTNAME_FG, + powerline.theme.HOSTNAME_BG) diff --git a/powerline_shell/segments/jobs.py b/powerline_shell/segments/jobs.py index 68662491..e5d0551d 100644 --- a/powerline_shell/segments/jobs.py +++ b/powerline_shell/segments/jobs.py @@ -2,29 +2,30 @@ import re import subprocess import platform - -def add_jobs_segment(powerline): - 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:]) - - 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") - - num_jobs = len(re.findall(str(pppid), output)) - 1 - - if num_jobs > 0: - powerline.append(' %d ' % num_jobs, powerline.theme.JOBS_FG, powerline.theme.JOBS_BG) +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) diff --git a/powerline_shell/segments/newline.py b/powerline_shell/segments/newline.py index 07b13ffe..f25cb46b 100644 --- a/powerline_shell/segments/newline.py +++ b/powerline_shell/segments/newline.py @@ -1,2 +1,9 @@ -def add_newline_segment(powerline): - powerline.append("\n", powerline.theme.RESET, powerline.theme.RESET, separator='') +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="") diff --git a/powerline_shell/segments/root.py b/powerline_shell/segments/root.py index 4900d7f5..5b31c602 100644 --- a/powerline_shell/segments/root.py +++ b/powerline_shell/segments/root.py @@ -1,12 +1,17 @@ -def add_root_segment(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) +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) diff --git a/powerline_shell/segments/set_term_title.py b/powerline_shell/segments/set_term_title.py index adaf7075..9846d6c4 100644 --- a/powerline_shell/segments/set_term_title.py +++ b/powerline_shell/segments/set_term_title.py @@ -1,4 +1,5 @@ import os +import socket def add_set_term_title_segment(powerline): @@ -11,7 +12,6 @@ def add_set_term_title_segment(powerline): 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, '') diff --git a/powerline_shell/segments/virtual_env.py b/powerline_shell/segments/virtual_env.py index 2b4de48d..ffbefec6 100644 --- a/powerline_shell/segments/virtual_env.py +++ b/powerline_shell/segments/virtual_env.py @@ -1,11 +1,15 @@ import os +from ..utils import BasicSegment -def add_virtual_env_segment(powerline): - env = os.getenv('VIRTUAL_ENV') or os.getenv('CONDA_ENV_PATH') or os.getenv('CONDA_DEFAULT_ENV') - if env is None: - return - env_name = os.path.basename(env) - bg = powerline.theme.VIRTUAL_ENV_BG - fg = powerline.theme.VIRTUAL_ENV_FG - powerline.append(' %s ' % env_name, fg, bg) +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) diff --git a/powerline_shell/repos.py b/powerline_shell/utils.py similarity index 78% rename from powerline_shell/repos.py rename to powerline_shell/utils.py index fe4e46e9..c8171905 100644 --- a/powerline_shell/repos.py +++ b/powerline_shell/utils.py @@ -1,3 +1,13 @@ +import sys +import threading + +py3 = sys.version_info.major == 3 + +if py3: + def unicode(x): + return x + + class RepoStats(object): symbols = { 'detached': u'\u2693', @@ -43,14 +53,31 @@ def n_or_empty(self, _key): """ return unicode(self[_key]) if int(self[_key]) > 1 else u'' - def add_to_powerline(self, powerline, color): + 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('not_staged', color.GIT_NOTSTAGED_FG, color.GIT_NOTSTAGED_BG) add('untracked', 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 + + +class ThreadedSegment(threading.Thread): + def __init__(self, powerline): + super(ThreadedSegment, self).__init__() + self.powerline = powerline + self.start() diff --git a/test/repo_stats_test.py b/test/repo_stats_test.py index a3e2149c..393eac3e 100644 --- a/test/repo_stats_test.py +++ b/test/repo_stats_test.py @@ -1,6 +1,6 @@ import unittest import powerline_shell_base as p -from powerline_shell.repos import RepoStats +from powerline_shell.utils import RepoStats class RepoStatsTest(unittest.TestCase): From a374618ff472bbffb6836905943efd537061f4d5 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 26 Aug 2017 17:58:19 -0400 Subject: [PATCH 181/366] Convert the rest of the segments --- powerline_shell/segments/fossil.py | 40 ++++++++++++---------- powerline_shell/segments/hg.py | 39 ++++++++++++--------- powerline_shell/segments/node_version.py | 19 +++++----- powerline_shell/segments/npm_version.py | 19 +++++----- powerline_shell/segments/php_version.py | 25 ++++++++------ powerline_shell/segments/rbenv.py | 24 +++++++------ powerline_shell/segments/read_only.py | 13 ++++--- powerline_shell/segments/ruby_version.py | 27 ++++++++------- powerline_shell/segments/set_term_title.py | 31 ++++++++++------- powerline_shell/segments/ssh.py | 11 ++++-- powerline_shell/segments/svn.py | 31 +++++++++-------- powerline_shell/segments/time.py | 24 ++++++++----- powerline_shell/segments/uptime.py | 30 +++++++++------- powerline_shell/segments/username.py | 30 +++++++++------- 14 files changed, 210 insertions(+), 153 deletions(-) diff --git a/powerline_shell/segments/fossil.py b/powerline_shell/segments/fossil.py index 3183bb6c..1fa525f0 100644 --- a/powerline_shell/segments/fossil.py +++ b/powerline_shell/segments/fossil.py @@ -1,5 +1,7 @@ import os import subprocess +from ..utils import BasicSegment + def get_fossil_status(): has_modified_files = False @@ -9,15 +11,14 @@ def get_fossil_status(): 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 = powerline.theme.REPO_CLEAN_BG fg = powerline.theme.REPO_CLEAN_FG has_modified_files, has_untracked_files, has_missing_files = get_fossil_status() @@ -32,19 +33,22 @@ def _add_fossil_segment(powerline): 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 + +class Segment(BasicSegment): + def add_to_powerline(self): + """Wraps _add_fossil_segment in exception handling.""" + powerline = self.powerline + + # 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 diff --git a/powerline_shell/segments/hg.py b/powerline_shell/segments/hg.py index 7d7dc6a5..92371469 100644 --- a/powerline_shell/segments/hg.py +++ b/powerline_shell/segments/hg.py @@ -1,5 +1,7 @@ import os import subprocess +from ..utils import BasicSegment + def get_hg_status(): has_modified_files = False @@ -20,20 +22,23 @@ def get_hg_status(): 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 = powerline.theme.REPO_CLEAN_BG - fg = powerline.theme.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 = powerline.theme.REPO_DIRTY_BG - fg = powerline.theme.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) + +class Segment(BasicSegment): + def add_to_powerline(self): + powerline = self.powerline + branch = os.popen('hg branch 2> /dev/null').read().rstrip() + if len(branch) == 0: + return False + bg = powerline.theme.REPO_CLEAN_BG + fg = powerline.theme.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 = powerline.theme.REPO_DIRTY_BG + fg = powerline.theme.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) diff --git a/powerline_shell/segments/node_version.py b/powerline_shell/segments/node_version.py index 466a0864..e3a9f296 100644 --- a/powerline_shell/segments/node_version.py +++ b/powerline_shell/segments/node_version.py @@ -1,11 +1,14 @@ import subprocess +from ..utils import BasicSegment -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 +class Segment(BasicSegment): + def add_to_powerline(self): + powerline = self.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 diff --git a/powerline_shell/segments/npm_version.py b/powerline_shell/segments/npm_version.py index 0deb5f8d..164c1a04 100644 --- a/powerline_shell/segments/npm_version.py +++ b/powerline_shell/segments/npm_version.py @@ -1,11 +1,14 @@ import subprocess +from ..utils import BasicSegment -def add_npm_version_segment(powerline): - try: - p1 = subprocess.Popen(["npm", "--version"], stdout=subprocess.PIPE) - version = p1.communicate()[0].decode("utf-8").rstrip() - version = "npm " + version - powerline.append(version, 15, 18) - except OSError: - return +class Segment(BasicSegment): + def add_to_powerline(self): + powerline = self.powerline + try: + p1 = subprocess.Popen(["npm", "--version"], stdout=subprocess.PIPE) + version = p1.communicate()[0].decode("utf-8").rstrip() + version = "npm " + version + powerline.append(version, 15, 18) + except OSError: + return diff --git a/powerline_shell/segments/php_version.py b/powerline_shell/segments/php_version.py index 7b9b8aa3..f905a344 100644 --- a/powerline_shell/segments/php_version.py +++ b/powerline_shell/segments/php_version.py @@ -1,14 +1,17 @@ import subprocess +from ..utils import BasicSegment -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 +class Segment(BasicSegment): + def add_to_powerline(self): + powerline = self.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 diff --git a/powerline_shell/segments/rbenv.py b/powerline_shell/segments/rbenv.py index 1208f6c7..4b8c5d37 100644 --- a/powerline_shell/segments/rbenv.py +++ b/powerline_shell/segments/rbenv.py @@ -1,13 +1,17 @@ import subprocess +from ..utils import BasicSegment -def add_rbenv_segment(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 +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 diff --git a/powerline_shell/segments/read_only.py b/powerline_shell/segments/read_only.py index c2bf79e8..149b1136 100644 --- a/powerline_shell/segments/read_only.py +++ b/powerline_shell/segments/read_only.py @@ -1,7 +1,12 @@ import os +from ..utils import BasicSegment -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, powerline.theme.READONLY_FG, powerline.theme.READONLY_BG) +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) diff --git a/powerline_shell/segments/ruby_version.py b/powerline_shell/segments/ruby_version.py index 513d10f8..0e7bee1e 100644 --- a/powerline_shell/segments/ruby_version.py +++ b/powerline_shell/segments/ruby_version.py @@ -1,16 +1,19 @@ import os import subprocess +from ..utils import BasicSegment -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 +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 diff --git a/powerline_shell/segments/set_term_title.py b/powerline_shell/segments/set_term_title.py index 9846d6c4..97439591 100644 --- a/powerline_shell/segments/set_term_title.py +++ b/powerline_shell/segments/set_term_title.py @@ -1,17 +1,22 @@ import os import socket +from ..utils import BasicSegment -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: - 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, '') +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, '') diff --git a/powerline_shell/segments/ssh.py b/powerline_shell/segments/ssh.py index c4291628..5b8af8bf 100644 --- a/powerline_shell/segments/ssh.py +++ b/powerline_shell/segments/ssh.py @@ -1,6 +1,11 @@ import os +from ..utils import BasicSegment -def add_ssh_segment(powerline): - if os.getenv('SSH_CLIENT'): - powerline.append(' %s ' % powerline.network, powerline.theme.SSH_FG, powerline.theme.SSH_BG) +class Segment(BasicSegment): + def add_to_powerline(self): + powerline = self.powerline + if os.getenv('SSH_CLIENT'): + powerline.append(' %s ' % powerline.network, + powerline.theme.SSH_FG, + powerline.theme.SSH_BG) diff --git a/powerline_shell/segments/svn.py b/powerline_shell/segments/svn.py index 454b96f1..f2d98974 100644 --- a/powerline_shell/segments/svn.py +++ b/powerline_shell/segments/svn.py @@ -1,4 +1,5 @@ import subprocess +from ..utils import BasicSegment def _add_svn_segment(powerline): @@ -19,19 +20,21 @@ def _add_svn_segment(powerline): powerline.append(' %s ' % changes, powerline.theme.SVN_CHANGES_FG, powerline.theme.SVN_CHANGES_BG) -def add_svn_segment(powerline): - """Wraps _add_svn_segment in exception handling.""" +class Segment(BasicSegment): + def add_to_powerline(self): + """Wraps _add_svn_segment in exception handling.""" + powerline = self.powerline - # 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. + # 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 + try: + _add_svn_segment(powerline) + except OSError: + pass + except subprocess.CalledProcessError: + pass diff --git a/powerline_shell/segments/time.py b/powerline_shell/segments/time.py index dedad803..413abb67 100644 --- a/powerline_shell/segments/time.py +++ b/powerline_shell/segments/time.py @@ -1,10 +1,16 @@ -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') +from ..utils import BasicSegment +import time - powerline.append(time, powerline.theme.HOSTNAME_FG, powerline.theme.HOSTNAME_BG) + +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) diff --git a/powerline_shell/segments/uptime.py b/powerline_shell/segments/uptime.py index e53e2587..b2821008 100644 --- a/powerline_shell/segments/uptime.py +++ b/powerline_shell/segments/uptime.py @@ -1,16 +1,20 @@ import subprocess import re +from ..utils import BasicSegment -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, powerline.theme.CWD_FG, powerline.theme.PATH_BG) - except OSError: - return + +class Segment(BasicSegment): + def add_to_powerline(self): + powerline = self.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, powerline.theme.CWD_FG, powerline.theme.PATH_BG) + except OSError: + return diff --git a/powerline_shell/segments/username.py b/powerline_shell/segments/username.py index d8cc177d..be97c520 100644 --- a/powerline_shell/segments/username.py +++ b/powerline_shell/segments/username.py @@ -1,16 +1,20 @@ +from ..utils import BasicSegment -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 = powerline.theme.USERNAME_ROOT_BG - else: - bgcolor = powerline.theme.USERNAME_BG +class Segment(BasicSegment): + def add_to_powerline(self): + powerline = self.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') - powerline.append(user_prompt, powerline.theme.USERNAME_FG, bgcolor) + if os.getenv('USER') == 'root': + bgcolor = powerline.theme.USERNAME_ROOT_BG + else: + bgcolor = powerline.theme.USERNAME_BG + + powerline.append(user_prompt, powerline.theme.USERNAME_FG, bgcolor) From 0fcb9f82059ed7534966ff08cc73d77a1c93c76d Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 26 Aug 2017 18:36:36 -0400 Subject: [PATCH 182/366] convert fossil and npm segments to be threaded --- powerline_shell/segments/fossil.py | 73 ++++++++++++------------- powerline_shell/segments/npm_version.py | 19 ++++--- 2 files changed, 47 insertions(+), 45 deletions(-) diff --git a/powerline_shell/segments/fossil.py b/powerline_shell/segments/fossil.py index 1fa525f0..cb1a26b3 100644 --- a/powerline_shell/segments/fossil.py +++ b/powerline_shell/segments/fossil.py @@ -1,6 +1,18 @@ import os import subprocess -from ..utils import BasicSegment +from ..utils import ThreadedSegment + + +def get_fossil_branch(): + try: + subprocess.Popen(['fossil'], stdout=subprocess.PIPE).communicate() + except OSError: + return None + return ''.join([ + i.replace('*','').strip() + for i in os.popen("fossil branch 2> /dev/null").read().strip().split("\n") + if i.startswith('*') + ]) def get_fossil_status(): @@ -8,47 +20,34 @@ def get_fossil_status(): 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_untracked_files = bool( + os.popen("fossil extras 2>/dev/null").read().strip() + ) 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 = powerline.theme.REPO_CLEAN_BG - fg = powerline.theme.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 = powerline.theme.REPO_DIRTY_BG - fg = powerline.theme.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) - +class Segment(ThreadedSegment): + def run(self): + self.branch = get_fossil_branch() + self.status = get_fossil_status() if self.branch else None -class Segment(BasicSegment): def add_to_powerline(self): - """Wraps _add_fossil_segment in exception handling.""" + self.join() powerline = self.powerline - - # 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 + if not self.branch or not self.status: + return + has_modified, has_untracked, has_missing = self.status + bg = powerline.theme.REPO_CLEAN_BG + fg = powerline.theme.REPO_CLEAN_FG + if has_modified or has_untracked or has_missing: + bg = powerline.theme.REPO_DIRTY_BG + fg = powerline.theme.REPO_DIRTY_FG + extra = '' + if has_untracked: + extra += '+' + if has_missing: + extra += '!' + self.branch += (' ' + extra if extra != '' else '') + powerline.append(' %s ' % self.branch, fg, bg) diff --git a/powerline_shell/segments/npm_version.py b/powerline_shell/segments/npm_version.py index 164c1a04..4ef23bcd 100644 --- a/powerline_shell/segments/npm_version.py +++ b/powerline_shell/segments/npm_version.py @@ -1,14 +1,17 @@ import subprocess -from ..utils import BasicSegment +from ..utils import ThreadedSegment -class Segment(BasicSegment): - def add_to_powerline(self): - powerline = self.powerline +class Segment(ThreadedSegment): + def run(self): try: p1 = subprocess.Popen(["npm", "--version"], stdout=subprocess.PIPE) - version = p1.communicate()[0].decode("utf-8").rstrip() - version = "npm " + version - powerline.append(version, 15, 18) + self.version = p1.communicate()[0].decode("utf-8").rstrip() except OSError: - return + 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) From d5854473d319b04763d6976facbf5926c4560269 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 26 Aug 2017 18:50:37 -0400 Subject: [PATCH 183/366] fix setup script, move configuration into json --- .gitignore | 4 ++++ powerline_shell/__init__.py | 7 ++++--- setup.py | 7 +++++-- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index d84c36e5..42a5cc72 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,7 @@ powerline-shell.py *.py[co] config.py powerline_shell.egg-info/ +/build/ +/dist/ +tags +config.json diff --git a/powerline_shell/__init__.py b/powerline_shell/__init__.py index 4b233220..39906548 100644 --- a/powerline_shell/__init__.py +++ b/powerline_shell/__init__.py @@ -4,8 +4,8 @@ import argparse import os import sys -import config import importlib +import json from .themes.default import DefaultColor from .utils import warn, py3 @@ -142,10 +142,11 @@ def main(): arg_parser.add_argument('prev_error', nargs='?', type=int, default=0, help='Error code returned by the last command') args = arg_parser.parse_args() - + with open("config.json") as f: + config = json.loads(f.read()) powerline = Powerline(args, get_valid_cwd()) segments = [] - for seg_name in config.SEGMENTS: + for seg_name in config["segments"]: mod = importlib.import_module("powerline_shell.segments." + seg_name) segments.append(getattr(mod, "Segment")(powerline)) for segment in segments: diff --git a/setup.py b/setup.py index 69843b0a..6159f34c 100755 --- a/setup.py +++ b/setup.py @@ -7,7 +7,11 @@ author="Buck Ryan", url="httpss://github.com/banga/powerline-shell", classifiers=[], - py_modules=["powerline_shell"], + packages=[ + "powerline_shell", + "powerline_shell.segments", + "powerline_shell.themes", + ], install_requires=[ "argparse", ], @@ -15,5 +19,4 @@ [console_scripts] powerline-shell=powerline_shell:main """, - packages=["powerline_shell"], ) From 99ddecec21f95a8d936906eb6b3abe54f40fa99c Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 26 Aug 2017 20:16:57 -0400 Subject: [PATCH 184/366] more threaded segments --- powerline_shell/segments/hg.py | 31 +++++++++++++----------- powerline_shell/segments/node_version.py | 18 ++++++++------ powerline_shell/segments/php_version.py | 20 +++++++-------- 3 files changed, 38 insertions(+), 31 deletions(-) diff --git a/powerline_shell/segments/hg.py b/powerline_shell/segments/hg.py index 92371469..2acf3a1b 100644 --- a/powerline_shell/segments/hg.py +++ b/powerline_shell/segments/hg.py @@ -1,6 +1,6 @@ import os import subprocess -from ..utils import BasicSegment +from ..utils import ThreadedSegment def get_hg_status(): @@ -23,22 +23,25 @@ def get_hg_status(): return has_modified_files, has_untracked_files, has_missing_files -class Segment(BasicSegment): +class Segment(ThreadedSegment): + def run(self): + self.branch = os.popen('hg branch 2> /dev/null').read().rstrip() + self.status = get_hg_status() if self.branch else None + def add_to_powerline(self): - powerline = self.powerline - branch = os.popen('hg branch 2> /dev/null').read().rstrip() - if len(branch) == 0: - return False - bg = powerline.theme.REPO_CLEAN_BG - fg = powerline.theme.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 = powerline.theme.REPO_DIRTY_BG - fg = powerline.theme.REPO_DIRTY_FG + 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_files: + if has_untracked: extra += '+' - if has_missing_files: + if has_missing: extra += '!' branch += (' ' + extra if extra != '' else '') return powerline.append(' %s ' % branch, fg, bg) diff --git a/powerline_shell/segments/node_version.py b/powerline_shell/segments/node_version.py index e3a9f296..aa195928 100644 --- a/powerline_shell/segments/node_version.py +++ b/powerline_shell/segments/node_version.py @@ -1,14 +1,18 @@ import subprocess -from ..utils import BasicSegment +from ..utils import ThreadedSegment -class Segment(BasicSegment): - def add_to_powerline(self): - powerline = self.powerline +class Segment(ThreadedSegment): + def run(self): 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) + 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) diff --git a/powerline_shell/segments/php_version.py b/powerline_shell/segments/php_version.py index f905a344..dc9a955c 100644 --- a/powerline_shell/segments/php_version.py +++ b/powerline_shell/segments/php_version.py @@ -1,17 +1,17 @@ import subprocess -from ..utils import BasicSegment +from ..utils import ThreadedSegment -class Segment(BasicSegment): - def add_to_powerline(self): - powerline = self.powerline +class Segment(ThreadedSegment): + def run(self): 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) + self.version = output.split('-')[0] if '-' in output else output except OSError: - return + self.version = None + + def add_to_powerline(self): + self.join() + # FIXME no hard-coded colors + self.powerline.append(" " + version + " ", 15, 4) From 0bee43f2b3d0c470210450139eb8b338214ed187 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 26 Aug 2017 20:20:52 -0400 Subject: [PATCH 185/366] fix issues with php version --- powerline_shell/segments/php_version.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/powerline_shell/segments/php_version.py b/powerline_shell/segments/php_version.py index dc9a955c..52f18991 100644 --- a/powerline_shell/segments/php_version.py +++ b/powerline_shell/segments/php_version.py @@ -13,5 +13,7 @@ def run(self): def add_to_powerline(self): self.join() + if not self.version: + return # FIXME no hard-coded colors - self.powerline.append(" " + version + " ", 15, 4) + self.powerline.append(" " + self.version + " ", 15, 4) From 46f992d9f72df7f8a06ac6b68956e152978fafcb Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 26 Aug 2017 20:30:59 -0400 Subject: [PATCH 186/366] Fix tests --- powerline_shell/__init__.py | 4 +++- powerline_shell/segments/git.py | 4 ++-- powerline_shell/utils.py | 4 +++- test/cwd_test.py | 10 +++++----- test/repo_stats_test.py | 3 +-- test/segments_test/git_test.py | 28 ++++++++++++++++------------ test/segments_test/uptime_test.py | 7 ++++--- 7 files changed, 34 insertions(+), 26 deletions(-) diff --git a/powerline_shell/__init__.py b/powerline_shell/__init__.py index 39906548..9627271e 100644 --- a/powerline_shell/__init__.py +++ b/powerline_shell/__init__.py @@ -148,7 +148,9 @@ def main(): segments = [] for seg_name in config["segments"]: mod = importlib.import_module("powerline_shell.segments." + seg_name) - segments.append(getattr(mod, "Segment")(powerline)) + segment = getattr(mod, "Segment")(powerline) + segment.start() + segments.append(segment) for segment in segments: segment.add_to_powerline() sys.stdout.write(powerline.draw()) diff --git a/powerline_shell/segments/git.py b/powerline_shell/segments/git.py index 03dd09fc..95e2c2ae 100644 --- a/powerline_shell/segments/git.py +++ b/powerline_shell/segments/git.py @@ -66,11 +66,11 @@ def build_stats(): env=git_subprocess_env()) except OSError: # Popen will throw an OSError if git is not found - return None + return (None, None) pdata = p.communicate() if p.returncode != 0: - return None + return (None, None) status = pdata[0].decode("utf-8").splitlines() stats = parse_git_stats(status) diff --git a/powerline_shell/utils.py b/powerline_shell/utils.py index c8171905..27d7986f 100644 --- a/powerline_shell/utils.py +++ b/powerline_shell/utils.py @@ -75,9 +75,11 @@ 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 - self.start() diff --git a/test/cwd_test.py b/test/cwd_test.py index 111863e8..ed52dc36 100644 --- a/test/cwd_test.py +++ b/test/cwd_test.py @@ -3,7 +3,7 @@ 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 @@ def tearDown(self): 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 @@ def test_nonexistent_warns(self, warn, getenv): 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 @@ def test_falls_back_to_getcwd(self, warn, getenv): 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 diff --git a/test/repo_stats_test.py b/test/repo_stats_test.py index 393eac3e..fe4f10dd 100644 --- a/test/repo_stats_test.py +++ b/test/repo_stats_test.py @@ -1,12 +1,11 @@ import unittest -import powerline_shell_base as p from powerline_shell.utils import RepoStats class RepoStatsTest(unittest.TestCase): def setUp(self): - self.repo_stats = p.RepoStats() + self.repo_stats = RepoStats() self.repo_stats.not_staged = 1 self.repo_stats.conflicted = 4 diff --git a/test/segments_test/git_test.py b/test/segments_test/git_test.py index 7ca344ab..c2bcde59 100644 --- a/test/segments_test/git_test.py +++ b/test/segments_test/git_test.py @@ -3,11 +3,7 @@ import tempfile import shutil import sh -import powerline_shell_base as p -import segments.git as git - -git.Color = mock.MagicMock() -git.RepoStats = p.RepoStats +import powerline_shell.segments.git as git class GitTest(unittest.TestCase): @@ -19,6 +15,8 @@ def setUp(self): sh.cd(self.dirname) sh.git("init", ".") + self.segment = git.Segment(self.powerline) + def tearDown(self): shutil.rmtree(self.dirname) @@ -33,30 +31,35 @@ def _new_branch(self, 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.segment.start() + self.segment.add_to_powerline() self.assertEqual(self.powerline.append.call_args[0][0], ' bar ') def test_detached(self): @@ -64,7 +67,8 @@ def test_detached(self): 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. diff --git a/test/segments_test/uptime_test.py b/test/segments_test/uptime_test.py index d2dacd2c..3285a005 100644 --- a/test/segments_test/uptime_test.py +++ b/test/segments_test/uptime_test.py @@ -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) From 5d23890c81bc7fa60e585b8f20adaf99c848ab1a Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 26 Aug 2017 21:29:42 -0400 Subject: [PATCH 187/366] convert many arguments to config options --- .gitignore | 1 + powerline_shell/__init__.py | 106 ++++++++++++++------------- powerline_shell/color_compliment.py | 2 +- powerline_shell/segments/cwd.py | 17 +++-- powerline_shell/segments/hostname.py | 8 +- 5 files changed, 74 insertions(+), 60 deletions(-) diff --git a/.gitignore b/.gitignore index 42a5cc72..a18fc9f5 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ powerline_shell.egg-info/ /dist/ tags config.json +powerline-shell.json diff --git a/powerline_shell/__init__.py b/powerline_shell/__init__.py index 9627271e..7d70ebed 100644 --- a/powerline_shell/__init__.py +++ b/powerline_shell/__init__.py @@ -10,6 +10,36 @@ from .utils import warn, py3 +def get_valid_cwd(): + """ We check if the current working directory is valid or not. Typically + happens when you checkout a different branch on git that doesn't have + this directory. + We return the original cwd because the shell still considers that to be + the working directory, so returning our guess will confuse people + """ + # Prefer the PWD environment variable. Python's os.getcwd function follows + # symbolic links, which is undesirable. But if PWD is not set then fall + # back to this func + try: + cwd = os.getenv('PWD') or os.getcwd() + except: + warn("Your current directory is invalid. If you open a ticket at " + + "https://github.com/milkbikis/powerline-shell/issues/new " + + "we would love to help fix the issue.") + sys.stdout.write("> ") + sys.exit(1) + + parts = cwd.split(os.sep) + up = cwd + while parts and not os.path.exists(up): + parts.pop() + up = os.sep.join(parts) + if cwd != up: + warn("Your current directory is invalid. Lowest valid directory: " + + up) + return cwd + + class Powerline(object): symbols = { 'compatible': { @@ -38,11 +68,13 @@ class Powerline(object): 'bare': '%s', } - def __init__(self, args, cwd, theme=None): + def __init__(self, args, config, theme=None): self.args = args - self.cwd = cwd + self.config = config self.theme = theme or DefaultColor - mode, shell = args.mode, args.shell + self.cwd = get_valid_cwd() + mode = config.get("mode", "patched") + shell = config.get("shell", "bash") self.color_template = self.color_templates[shell] self.reset = self.color_template % '[0m' self.lock = Powerline.symbols[mode]['lock'] @@ -51,6 +83,9 @@ def __init__(self, args, cwd, theme=None): 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 '' @@ -91,60 +126,33 @@ def draw_segment(self, idx): segment[3])) -def get_valid_cwd(): - """ We check if the current working directory is valid or not. Typically - happens when you checkout a different branch on git that doesn't have - this directory. - We return the original cwd because the shell still considers that to be - the working directory, so returning our guess will confuse people - """ - # Prefer the PWD environment variable. Python's os.getcwd function follows - # symbolic links, which is undesirable. But if PWD is not set then fall - # back to this func - try: - cwd = os.getenv('PWD') or os.getcwd() - except: - warn("Your current directory is invalid. If you open a ticket at " + - "https://github.com/milkbikis/powerline-shell/issues/new " + - "we would love to help fix the issue.") - sys.stdout.write("> ") - sys.exit(1) - - parts = cwd.split(os.sep) - up = cwd - while parts and not os.path.exists(up): - parts.pop() - up = os.sep.join(parts) - if cwd != up: - warn("Your current directory is invalid. Lowest valid directory: " - + up) - return cwd +def find_config(): + for location in [ + "powerline-shell.json", + "~/.powerline-shell.json", + ]: + full = os.path.expanduser(location) + if os.path.exists(full): + return full 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('--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() - with open("config.json") as f: + + config_path = find_config() + if not config_path: + warn("No config found") + return 1 + with open(config_path) as f: config = json.loads(f.read()) - powerline = Powerline(args, get_valid_cwd()) + + powerline = Powerline(args, config) segments = [] for seg_name in config["segments"]: mod = importlib.import_module("powerline_shell.segments." + seg_name) diff --git a/powerline_shell/color_compliment.py b/powerline_shell/color_compliment.py index 08f8bea7..6a64dc45 100644 --- a/powerline_shell/color_compliment.py +++ b/powerline_shell/color_compliment.py @@ -6,7 +6,7 @@ from hashlib import md5 import sys from .colortrans import * -from ..utils import py3 +from .utils import py3 def getOppositeColor(r,g,b): diff --git a/powerline_shell/segments/cwd.py b/powerline_shell/segments/cwd.py index a1d7d295..22c439df 100644 --- a/powerline_shell/segments/cwd.py +++ b/powerline_shell/segments/cwd.py @@ -5,6 +5,10 @@ ELLIPSIS = u'\u2026' +def _mode(powerline): + return powerline.segment_conf("cwd", "mode", "fancy") + + def replace_home_dir(cwd): home = os.getenv('HOME') if cwd.startswith(home): @@ -34,8 +38,9 @@ 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 @@ -57,15 +62,15 @@ def add_cwd_segment(powerline): cwd = cwd.decode("utf-8") cwd = replace_home_dir(cwd) - if powerline.args.cwd_mode == 'plain': + if _mode(powerline) == '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 @@ -77,7 +82,7 @@ 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 _mode(powerline) == "dironly": # The user has indicated they only want the current directory to be # displayed, so chop everything else off names = names[-1:] diff --git a/powerline_shell/segments/hostname.py b/powerline_shell/segments/hostname.py index ddbaff6d..d3e62816 100644 --- a/powerline_shell/segments/hostname.py +++ b/powerline_shell/segments/hostname.py @@ -1,13 +1,13 @@ 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.args.colorize_hostname: - from lib.color_compliment import stringToHashToColorAndOpposite - from lib.colortrans import rgb2short - from socket import gethostname + if powerline.segment_conf("hostname", "colorize"): hostname = gethostname() FG, BG = stringToHashToColorAndOpposite(hostname) FG, BG = (rgb2short(*color) for color in [FG, BG]) From fc2f059ed478a16c70ca683fe475f1f06ff8eb50 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 26 Aug 2017 21:37:09 -0400 Subject: [PATCH 188/366] Fix theme support --- powerline_shell/themes/colortest.py => colortest.py | 0 powerline_shell/__init__.py | 11 +++++++---- powerline_shell/themes/basic.py | 4 +++- powerline_shell/themes/default.py | 2 +- .../themes/{solarized-dark.py => solarized_dark.py} | 3 +++ powerline_shell/themes/washed.py | 3 +++ 6 files changed, 17 insertions(+), 6 deletions(-) rename powerline_shell/themes/colortest.py => colortest.py (100%) rename powerline_shell/themes/{solarized-dark.py => solarized_dark.py} (94%) diff --git a/powerline_shell/themes/colortest.py b/colortest.py similarity index 100% rename from powerline_shell/themes/colortest.py rename to colortest.py diff --git a/powerline_shell/__init__.py b/powerline_shell/__init__.py index 7d70ebed..46511a05 100644 --- a/powerline_shell/__init__.py +++ b/powerline_shell/__init__.py @@ -6,7 +6,6 @@ import sys import importlib import json -from .themes.default import DefaultColor from .utils import warn, py3 @@ -68,10 +67,10 @@ class Powerline(object): 'bare': '%s', } - def __init__(self, args, config, theme=None): + def __init__(self, args, config, theme): self.args = args self.config = config - self.theme = theme or DefaultColor + self.theme = theme self.cwd = get_valid_cwd() mode = config.get("mode", "patched") shell = config.get("shell", "bash") @@ -152,7 +151,11 @@ def main(): with open(config_path) as f: config = json.loads(f.read()) - powerline = Powerline(args, 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) diff --git a/powerline_shell/themes/basic.py b/powerline_shell/themes/basic.py index 5d076915..efb87cde 100644 --- a/powerline_shell/themes/basic.py +++ b/powerline_shell/themes/basic.py @@ -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 diff --git a/powerline_shell/themes/default.py b/powerline_shell/themes/default.py index 6526158a..faa0473b 100644 --- a/powerline_shell/themes/default.py +++ b/powerline_shell/themes/default.py @@ -1,4 +1,4 @@ -class DefaultColor: +class DefaultColor(object): """ This class should have the default colors for every segment. Please test every new segment with this theme first. diff --git a/powerline_shell/themes/solarized-dark.py b/powerline_shell/themes/solarized_dark.py similarity index 94% rename from powerline_shell/themes/solarized-dark.py rename to powerline_shell/themes/solarized_dark.py index 4e158c8e..7e0f2d8a 100644 --- a/powerline_shell/themes/solarized-dark.py +++ b/powerline_shell/themes/solarized_dark.py @@ -1,3 +1,6 @@ +from .default import DefaultColor + + class Color(DefaultColor): USERNAME_FG = 15 USERNAME_BG = 4 diff --git a/powerline_shell/themes/washed.py b/powerline_shell/themes/washed.py index 3c455e3d..d1f2642c 100644 --- a/powerline_shell/themes/washed.py +++ b/powerline_shell/themes/washed.py @@ -1,3 +1,6 @@ +from .default import DefaultColor + + class Color(DefaultColor): USERNAME_FG = 8 USERNAME_BG = 251 From 658d440ac792a5d7c3a42bb8a7439ff022e83d73 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 26 Aug 2017 21:41:47 -0400 Subject: [PATCH 189/366] default config --- powerline_shell/__init__.py | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/powerline_shell/__init__.py b/powerline_shell/__init__.py index 46511a05..9f14bde3 100644 --- a/powerline_shell/__init__.py +++ b/powerline_shell/__init__.py @@ -134,6 +134,20 @@ def find_config(): 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() @@ -145,11 +159,11 @@ def main(): args = arg_parser.parse_args() config_path = find_config() - if not config_path: - warn("No config found") - return 1 - with open(config_path) as f: - config = json.loads(f.read()) + 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) From af0ecb1ce394607d21dd84f66ede4930c0f06ed5 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 26 Aug 2017 21:45:12 -0400 Subject: [PATCH 190/366] try to get circle working --- circle.yml | 4 +++- dev_requirements.txt => requirements-dev.txt | 0 2 files changed, 3 insertions(+), 1 deletion(-) rename dev_requirements.txt => requirements-dev.txt (100%) diff --git a/circle.yml b/circle.yml index 7638a893..3d60d330 100644 --- a/circle.yml +++ b/circle.yml @@ -1,5 +1,7 @@ dependencies: pre: - - sudo pip install -r dev_requirements.txt + - sudo pip install -r requirements-dev.txt - git config --global user.email "tester@example.com" - git config --global user.name "Tester McGee" +test: + nosetests diff --git a/dev_requirements.txt b/requirements-dev.txt similarity index 100% rename from dev_requirements.txt rename to requirements-dev.txt From dfeb3bc8c30c333bf4887bc06fb0110264dfd5f2 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 26 Aug 2017 22:11:23 -0400 Subject: [PATCH 191/366] travis --- .travis.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..d1ad0ae5 --- /dev/null +++ b/.travis.yml @@ -0,0 +1 @@ +language: python From a92a79047b57c1c4b755c1172bb636ce6a72d65a Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 26 Aug 2017 22:16:08 -0400 Subject: [PATCH 192/366] more travis --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index d1ad0ae5..a587362b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1 +1,5 @@ language: python +script: | + ./setup.py install + pip install -r requirements-dev.txt + nosetests From 73994c6a7b0fe2394ef7c42fb50d129ddcc309ba Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 26 Aug 2017 22:18:52 -0400 Subject: [PATCH 193/366] remove circle --- circle.yml | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 circle.yml diff --git a/circle.yml b/circle.yml deleted file mode 100644 index 3d60d330..00000000 --- a/circle.yml +++ /dev/null @@ -1,7 +0,0 @@ -dependencies: - pre: - - sudo pip install -r requirements-dev.txt - - git config --global user.email "tester@example.com" - - git config --global user.name "Tester McGee" -test: - nosetests From 807dc6dfc54f2319af7c5908ff2f8c20ea5a832e Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 26 Aug 2017 22:45:31 -0400 Subject: [PATCH 194/366] fix setup.py link --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 6159f34c..87e8bc7e 100755 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ version="0.1.0-alpha", description="A pretty prompt for your shell", author="Buck Ryan", - url="httpss://github.com/banga/powerline-shell", + url="https://github.com/banga/powerline-shell", classifiers=[], packages=[ "powerline_shell", From 401aef8fc24a78a5d0c4137cb9123d25683845d4 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sun, 27 Aug 2017 00:00:30 -0400 Subject: [PATCH 195/366] README updates --- README.md | 182 +++++++++++++++++++------------- powerline_shell/__init__.py | 11 +- powerline_shell/segments/cwd.py | 8 +- 3 files changed, 120 insertions(+), 81 deletions(-) diff --git a/README.md b/README.md index 2154a263..f0a64cbb 100644 --- a/README.md +++ b/README.md @@ -17,14 +17,16 @@ ZSH and Fish: - [Version Control](#version-control) - [Setup](#setup) - - [All Shells](#all-shells) - [Bash](#bash) - [ZSH](#zsh) - [Fish](#fish) - [Customization](#customization) + - [Config File](#config-file) - [Adding, Removing and Re-arranging segments](#adding-removing-and-re-arranging-segments) + - [Changing the Look](#changing-the-look) + - [Themes](#themes) + - [Segment Configuration](#segment-configuration) - [Contributing new types of segments](#contributing-new-types-of-segments) - - [Themes](#themes) - [Troubleshooting](#troubleshooting) @@ -68,53 +70,13 @@ setting your $TERM to `xterm-256color`, because that works for me. commit](https://github.com/milkbikis/powerline-shell/commit/2a84ecc) in your copy -- Clone this repository somewhere: +- Install using pip: ``` -git clone https://github.com/milkbikis/powerline-shell +pip install --index-url https://test.pypi.org/simple/ 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 ~/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`. - -``` - --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 -``` +- Setup your shell prompt using the instructions for your shell below. ### Bash @@ -122,7 +84,7 @@ 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 @@ -136,7 +98,7 @@ 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() { @@ -159,27 +121,115 @@ 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 +### 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 +``` + ### 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: + +- `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. + +### Changing the Look + +There are a few optional arguments which can be seen by running +`powerline-shell.py --help`. + +``` + --mode {patched,compatible,flat} + The characters used to make separators between + segments +``` + +#### 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 @@ -190,21 +240,7 @@ 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`. - -### Themes - -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. +after install the requirements in `requirements-dev.txt`. ## Troubleshooting diff --git a/powerline_shell/__init__.py b/powerline_shell/__init__.py index 9f14bde3..ac6fdc21 100644 --- a/powerline_shell/__init__.py +++ b/powerline_shell/__init__.py @@ -54,8 +54,8 @@ class Powerline(object): 'separator_thin': u'\uE0B1' }, 'flat': { - 'lock': '', - 'network': '', + 'lock': u'\uE0A2', + 'network': u'\uE0A2', 'separator': '', 'separator_thin': '' }, @@ -151,6 +151,8 @@ def find_config(): def main(): arg_parser = argparse.ArgumentParser() + 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']) @@ -158,6 +160,10 @@ def main(): help='Error code returned by the last command') args = arg_parser.parse_args() + 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: @@ -179,3 +185,4 @@ def main(): for segment in segments: segment.add_to_powerline() sys.stdout.write(powerline.draw()) + return 0 diff --git a/powerline_shell/segments/cwd.py b/powerline_shell/segments/cwd.py index 22c439df..f99eb13f 100644 --- a/powerline_shell/segments/cwd.py +++ b/powerline_shell/segments/cwd.py @@ -5,10 +5,6 @@ ELLIPSIS = u'\u2026' -def _mode(powerline): - return powerline.segment_conf("cwd", "mode", "fancy") - - def replace_home_dir(cwd): home = os.getenv('HOME') if cwd.startswith(home): @@ -62,7 +58,7 @@ def add_cwd_segment(powerline): cwd = cwd.decode("utf-8") cwd = replace_home_dir(cwd) - if _mode(powerline) == 'plain': + if powerline.segment_conf("cwd", "mode") == 'plain': powerline.append(' %s ' % (cwd,), powerline.theme.CWD_FG, powerline.theme.PATH_BG) return @@ -82,7 +78,7 @@ 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 _mode(powerline) == "dironly": + 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:] From c42bbf5133c101c53fa576de09897b2b03d9ae1f Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sun, 27 Aug 2017 00:09:41 -0400 Subject: [PATCH 196/366] fix notes about mode --- README.md | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index f0a64cbb..c82846d9 100644 --- a/README.md +++ b/README.md @@ -23,8 +23,8 @@ ZSH and Fish: - [Customization](#customization) - [Config File](#config-file) - [Adding, Removing and Re-arranging segments](#adding-removing-and-re-arranging-segments) - - [Changing the Look](#changing-the-look) - - [Themes](#themes) + - [Segment Separator](#segment-separator) + - [Themes](#themes) - [Segment Configuration](#segment-configuration) - [Contributing new types of segments](#contributing-new-types-of-segments) - [Troubleshooting](#troubleshooting) @@ -169,18 +169,19 @@ are: - `username` - Name of the logged-in user - `virtual_env` - Shows the name of the current virtual env or conda env. -### Changing the Look +### Segment Separator -There are a few optional arguments which can be seen by running -`powerline-shell.py --help`. +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: -``` - --mode {patched,compatible,flat} - The characters used to make separators between - segments -``` +- `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 +### 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 From 3edec346ef00f30eb2229067006dc3bd0823aa5b Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sun, 3 Sep 2017 16:47:32 -0400 Subject: [PATCH 197/366] create a setup.cfg --- setup.cfg | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 setup.cfg diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 00000000..1eee7db0 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,5 @@ +[bdist_wheel] +universal = 1 + +[metadata] +description-file = README.md From c3506d075e21171f2cf3abefb933f6bae44e2afa Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Tue, 5 Sep 2017 10:31:10 -0400 Subject: [PATCH 198/366] tests for hostname segment --- powerline_shell/segments/hostname.py | 15 ++++++--------- test/segments_test/hostname_test.py | 21 +++++++++++++++++++++ 2 files changed, 27 insertions(+), 9 deletions(-) create mode 100644 test/segments_test/hostname_test.py diff --git a/powerline_shell/segments/hostname.py b/powerline_shell/segments/hostname.py index d3e62816..894e139e 100644 --- a/powerline_shell/segments/hostname.py +++ b/powerline_shell/segments/hostname.py @@ -11,18 +11,15 @@ def add_to_powerline(self): hostname = gethostname() FG, BG = stringToHashToColorAndOpposite(hostname) FG, BG = (rgb2short(*color) for color in [FG, BG]) - host_prompt = ' %s ' % hostname.split('.')[0] - + 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 ' + if powerline.args.shell == "bash": + host_prompt = r" \h " + elif powerline.args.shell == "zsh": + host_prompt = " %m " else: - import socket - host_prompt = ' %s ' % socket.gethostname().split('.')[0] - + host_prompt = " %s " % gethostname().split(".")[0] powerline.append(host_prompt, powerline.theme.HOSTNAME_FG, powerline.theme.HOSTNAME_BG) diff --git a/test/segments_test/hostname_test.py b/test/segments_test/hostname_test.py new file mode 100644 index 00000000..68e941cf --- /dev/null +++ b/test/segments_test/hostname_test.py @@ -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) From b5f2d8a525c1d1c1b6dd76e6a22d81f5cde0e30d Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Tue, 5 Sep 2017 10:39:35 -0400 Subject: [PATCH 199/366] link to my config file for an example --- README.md | 3 +++ powerline_shell/segments/ssh.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c82846d9..a20cea26 100644 --- a/README.md +++ b/README.md @@ -137,6 +137,9 @@ 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 Once you have generated your config file, you can now start adding or removing diff --git a/powerline_shell/segments/ssh.py b/powerline_shell/segments/ssh.py index 5b8af8bf..f64c967d 100644 --- a/powerline_shell/segments/ssh.py +++ b/powerline_shell/segments/ssh.py @@ -4,8 +4,8 @@ class Segment(BasicSegment): def add_to_powerline(self): - powerline = self.powerline if os.getenv('SSH_CLIENT'): + powerline = self.powerline powerline.append(' %s ' % powerline.network, powerline.theme.SSH_FG, powerline.theme.SSH_BG) From b053eb4e51dc79ccc95d96ede7c8a4a6c723a146 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Tue, 5 Sep 2017 10:49:23 -0400 Subject: [PATCH 200/366] fix issues with hg segment --- powerline_shell/segments/hg.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/powerline_shell/segments/hg.py b/powerline_shell/segments/hg.py index 2acf3a1b..ca0e3390 100644 --- a/powerline_shell/segments/hg.py +++ b/powerline_shell/segments/hg.py @@ -43,5 +43,5 @@ def add_to_powerline(self): extra += '+' if has_missing: extra += '!' - branch += (' ' + extra if extra != '' else '') - return powerline.append(' %s ' % branch, fg, bg) + self.branch += (' ' + extra if extra != '' else '') + return self.powerline.append(' %s ' % self.branch, fg, bg) From 270af5bae534c0c4ca4a2084f41c90697c12cf79 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Tue, 5 Sep 2017 21:06:36 -0400 Subject: [PATCH 201/366] remove config.py.dist --- config.py.dist | 63 -------------------------------------------------- 1 file changed, 63 deletions(-) delete mode 100644 config.py.dist diff --git a/config.py.dist b/config.py.dist deleted file mode 100644 index 2affa3e5..00000000 --- a/config.py.dist +++ /dev/null @@ -1,63 +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 current ruby environment (see http://rbenv.org/) -# 'rbenv', - -# 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', - -# Adds a line break -# 'newline', - -# 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' From 0b02a4baad85f38c0e572096789a44ab59a3767e Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Tue, 5 Sep 2017 21:42:58 -0400 Subject: [PATCH 202/366] tests and fixes for hg segment --- powerline_shell/segments/hg.py | 56 ++++++++++++++++++++++++++-------- test/segments_test/git_test.py | 4 +-- test/segments_test/hg_test.py | 49 +++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 14 deletions(-) create mode 100644 test/segments_test/hg_test.py diff --git a/powerline_shell/segments/hg.py b/powerline_shell/segments/hg.py index ca0e3390..05cb2f71 100644 --- a/powerline_shell/segments/hg.py +++ b/powerline_shell/segments/hg.py @@ -1,6 +1,18 @@ 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(): @@ -8,25 +20,45 @@ def get_hg_status(): has_untracked_files = False has_missing_files = False - p = subprocess.Popen(['hg', 'status'], stdout=subprocess.PIPE) + 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 == '': + for line in output.split("\n"): + if line == "": continue - elif line[0] == '?': + elif line[0] == "?": has_untracked_files = True - elif line[0] == '!': + 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 = os.popen('hg branch 2> /dev/null').read().rstrip() - self.status = get_hg_status() if self.branch else None + self.branch, self.status = build_stats() def add_to_powerline(self): self.join() @@ -38,10 +70,10 @@ def add_to_powerline(self): if has_modified or has_untracked or has_missing: bg = self.powerline.theme.REPO_DIRTY_BG fg = self.powerline.theme.REPO_DIRTY_FG - extra = '' + extra = "" if has_untracked: - extra += '+' + extra += "+" if has_missing: - extra += '!' - self.branch += (' ' + extra if extra != '' else '') - return self.powerline.append(' %s ' % self.branch, fg, bg) + extra += "!" + self.branch += " " + extra + return self.powerline.append(" %s " % self.branch, fg, bg) diff --git a/test/segments_test/git_test.py b/test/segments_test/git_test.py index c2bcde59..ab8c9dd6 100644 --- a/test/segments_test/git_test.py +++ b/test/segments_test/git_test.py @@ -25,7 +25,7 @@ def _add_and_commit(self, filename): 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): @@ -57,7 +57,7 @@ def test_master_branch(self): def test_different_branch(self): self._add_and_commit("foo") - self._new_branch("bar") + self._checkout_new_branch("bar") self.segment.start() self.segment.add_to_powerline() self.assertEqual(self.powerline.append.call_args[0][0], ' bar ') diff --git a/test/segments_test/hg_test.py b/test/segments_test/hg_test.py new file mode 100644 index 00000000..7efb865d --- /dev/null +++ b/test/segments_test/hg_test.py @@ -0,0 +1,49 @@ +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 ") + From d23f3943502044e8088b68b30ef4a0602efc1d38 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Tue, 5 Sep 2017 21:47:03 -0400 Subject: [PATCH 203/366] file formatting for username segment --- powerline_shell/segments/username.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/powerline_shell/segments/username.py b/powerline_shell/segments/username.py index be97c520..b03dc093 100644 --- a/powerline_shell/segments/username.py +++ b/powerline_shell/segments/username.py @@ -1,18 +1,18 @@ from ..utils import BasicSegment +import os class Segment(BasicSegment): def add_to_powerline(self): powerline = self.powerline - import os - if powerline.args.shell == 'bash': - user_prompt = ' \\u ' - elif powerline.args.shell == 'zsh': - user_prompt = ' %n ' + if powerline.args.shell == "bash": + user_prompt = r" \u " + elif powerline.args.shell == "zsh": + user_prompt = " %n " else: - user_prompt = ' %s ' % os.getenv('USER') + user_prompt = " %s " % os.getenv("USER") - if os.getenv('USER') == 'root': + if os.getenv("USER") == "root": bgcolor = powerline.theme.USERNAME_ROOT_BG else: bgcolor = powerline.theme.USERNAME_BG From 3fb3764209d67d57b1d3fdaf911fd423646b9cdb Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Tue, 5 Sep 2017 21:47:51 -0400 Subject: [PATCH 204/366] change README to use normal pypi for installation --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a20cea26..628ffb09 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ setting your $TERM to `xterm-256color`, because that works for me. - Install using pip: ``` -pip install --index-url https://test.pypi.org/simple/ powerline-shell +pip install powerline-shell ``` - Setup your shell prompt using the instructions for your shell below. From 44a7f2c3e0d85e556a95c9444958e33d4701e9b0 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sun, 10 Sep 2017 19:46:07 -0400 Subject: [PATCH 205/366] svn file formatting --- powerline_shell/segments/svn.py | 48 +++++++++++---------------------- 1 file changed, 15 insertions(+), 33 deletions(-) diff --git a/powerline_shell/segments/svn.py b/powerline_shell/segments/svn.py index f2d98974..660ffe5a 100644 --- a/powerline_shell/segments/svn.py +++ b/powerline_shell/segments/svn.py @@ -2,39 +2,21 @@ from ..utils import BasicSegment -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, powerline.theme.SVN_CHANGES_FG, powerline.theme.SVN_CHANGES_BG) - - class Segment(BasicSegment): def add_to_powerline(self): - """Wraps _add_svn_segment in exception handling.""" powerline = self.powerline - - # 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 + 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 + p1 = subprocess.Popen(["svn", "status"], stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + p2 = subprocess.Popen(["grep", "-c", r"^[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, + powerline.theme.SVN_CHANGES_FG, + powerline.theme.SVN_CHANGES_BG) From 5ab153b9da13dd22ea23c9d2cb404f464569f090 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sun, 10 Sep 2017 19:50:27 -0400 Subject: [PATCH 206/366] Release version 0.1.0 --- CHANGELOG.md | 8 ++++++++ setup.py | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 69fdcf6f..1f3b347f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changes +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 diff --git a/setup.py b/setup.py index 87e8bc7e..23f0faa9 100755 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup(name="powerline-shell", - version="0.1.0-alpha", + version="0.1.0", description="A pretty prompt for your shell", author="Buck Ryan", url="https://github.com/banga/powerline-shell", From 73c08b07cf08608297cd000bbe96b3466a15d05f Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sun, 10 Sep 2017 20:31:59 -0400 Subject: [PATCH 207/366] Use sys.version_info[0] instead of .major Fixes https://github.com/banga/powerline-shell/issues/247 --- powerline_shell/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerline_shell/utils.py b/powerline_shell/utils.py index 27d7986f..7f97f6d5 100644 --- a/powerline_shell/utils.py +++ b/powerline_shell/utils.py @@ -1,7 +1,7 @@ import sys import threading -py3 = sys.version_info.major == 3 +py3 = sys.version_info[0] == 3 if py3: def unicode(x): From 7ad2bc28a6b1099ea164f68574cb097b357c274a Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sun, 10 Sep 2017 21:01:38 -0400 Subject: [PATCH 208/366] Redo svn segment to use RepoStats Closes https://github.com/banga/powerline-shell/pull/105 --- powerline_shell/segments/svn.py | 31 +++++++++++++++++++------------ test/segments_test/hg_test.py | 1 - 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/powerline_shell/segments/svn.py b/powerline_shell/segments/svn.py index 660ffe5a..27e21d66 100644 --- a/powerline_shell/segments/svn.py +++ b/powerline_shell/segments/svn.py @@ -1,22 +1,29 @@ import subprocess -from ..utils import BasicSegment +from ..utils import BasicSegment, RepoStats class Segment(BasicSegment): def add_to_powerline(self): - powerline = self.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 - p1 = subprocess.Popen(["svn", "status"], stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - p2 = subprocess.Popen(["grep", "-c", r"^[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, - powerline.theme.SVN_CHANGES_FG, - powerline.theme.SVN_CHANGES_BG) + + 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.untracked += 1 + elif line[0] == "C": + stats.conflicted += 1 + elif line[0] in ["A", "D", "I", "M", "R", "!", "~"]: + stats.not_staged += 1 + + stats.add_to_powerline(self.powerline) diff --git a/test/segments_test/hg_test.py b/test/segments_test/hg_test.py index 7efb865d..be8d147d 100644 --- a/test/segments_test/hg_test.py +++ b/test/segments_test/hg_test.py @@ -46,4 +46,3 @@ def test_standard(self): self.segment.start() self.segment.add_to_powerline() self.assertEqual(self.powerline.append.call_args[0][0], " default ") - From 4b328acf02de963f1f7ebf9f50a1149eae5ae7f6 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sun, 10 Sep 2017 21:04:26 -0400 Subject: [PATCH 209/366] unreleased changelog --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f3b347f..f9bcc7fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changes +Unreleased + +* 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 + 2017-09-10 * Complete overhaul of the project From 9e49b7db2408374d550e399c95689786fdba9d4b Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sun, 10 Sep 2017 21:17:36 -0400 Subject: [PATCH 210/366] Add solarized_light theme Closes #95 Closes #142 Closes #143 --- CHANGELOG.md | 2 ++ powerline_shell/themes/solarized_light.py | 38 +++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 powerline_shell/themes/solarized_light.py diff --git a/CHANGELOG.md b/CHANGELOG.md index f9bcc7fd..e977b6a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ Unreleased * 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 diff --git a/powerline_shell/themes/solarized_light.py b/powerline_shell/themes/solarized_light.py new file mode 100644 index 00000000..da14cdff --- /dev/null +++ b/powerline_shell/themes/solarized_light.py @@ -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 From c334d1231d3cb2485aa7a73d06b6fe58ff8671f8 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sun, 10 Sep 2017 21:45:17 -0400 Subject: [PATCH 211/366] Escape subshell commands --- powerline_shell/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/powerline_shell/__init__.py b/powerline_shell/__init__.py index ac6fdc21..2316a0fa 100644 --- a/powerline_shell/__init__.py +++ b/powerline_shell/__init__.py @@ -7,6 +7,7 @@ import importlib import json from .utils import warn, py3 +import re def get_valid_cwd(): @@ -100,7 +101,8 @@ 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, + sanitized = re.sub(r"([`$])", r"\\\1", content) + self.segments.append((sanitized, fg, bg, separator if separator is not None else self.separator, separator_fg if separator_fg is not None else bg)) From f12f94c6185b3a83158fa67799d0f2fc59f556c5 Mon Sep 17 00:00:00 2001 From: Emanuel Angelo Date: Tue, 12 Sep 2017 02:35:53 +0100 Subject: [PATCH 212/366] Add Bazaar segment --- powerline_shell/segments/bzr.py | 74 +++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 powerline_shell/segments/bzr.py diff --git a/powerline_shell/segments/bzr.py b/powerline_shell/segments/bzr.py new file mode 100644 index 00000000..0a2c47fd --- /dev/null +++ b/powerline_shell/segments/bzr.py @@ -0,0 +1,74 @@ +import os +import subprocess +from ..utils import 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 _subprocess_env(): + return {"PATH": get_PATH()} + + +def get_bzr_status(): + has_modified_files = False + has_untracked_files = False + has_missing_files = False + p = subprocess.Popen(['bzr', 'status'], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + env=_subprocess_env()) + output = p.communicate()[0].decode("utf-8") + if 'unknown:\n' in output: + has_untracked_files = True + elif 'removed:\n' in output: + has_missing_files = True + elif 'modified:\n' in output: + has_modified_files = True + return has_modified_files, has_untracked_files, has_missing_files + + +def build_stats(): + try: + p = subprocess.Popen(["bzr", "nick"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + env=_subprocess_env()) + except OSError: + # Will be thrown if bzr 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_bzr_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) + From 98e03022af568d68405d3c5f24a7751785c0c537 Mon Sep 17 00:00:00 2001 From: Emanuel Angelo Date: Tue, 12 Sep 2017 22:32:31 +0100 Subject: [PATCH 213/366] Reimplements bzr segment with RepoStats class --- powerline_shell/segments/bzr.py | 80 ++++++++++++++++----------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/powerline_shell/segments/bzr.py b/powerline_shell/segments/bzr.py index 0a2c47fd..456b6e34 100644 --- a/powerline_shell/segments/bzr.py +++ b/powerline_shell/segments/bzr.py @@ -1,6 +1,6 @@ import os import subprocess -from ..utils import ThreadedSegment +from ..utils import RepoStats, ThreadedSegment def get_PATH(): @@ -10,65 +10,65 @@ def get_PATH(): return os.getenv("PATH") -def _subprocess_env(): +def bzr_subprocess_env(): return {"PATH": get_PATH()} -def get_bzr_status(): - has_modified_files = False - has_untracked_files = False - has_missing_files = False - p = subprocess.Popen(['bzr', 'status'], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - env=_subprocess_env()) - output = p.communicate()[0].decode("utf-8") - if 'unknown:\n' in output: - has_untracked_files = True - elif 'removed:\n' in output: - has_missing_files = True - elif 'modified:\n' in output: - has_modified_files = True - return has_modified_files, has_untracked_files, has_missing_files +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 = "not_staged" + for statusline in status: + if statusline[:2] == " ": + setattr(stats, statustype, getattr(stats, statustype) + 1) + elif statusline == "added:": + statustype = "staged" + elif statusline in ("removed:", "missing:"): + statustype = "conflicted" + elif statusline == "unknown:": + statustype = "untracked" + else: # renamed, modified or kind changed + statustype = "not_staged" + return stats def build_stats(): try: - p = subprocess.Popen(["bzr", "nick"], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - env=_subprocess_env()) + p = subprocess.Popen(['bzr', 'status'], + stdout=subprocess.PIPE, stderr=subprocess.PIPE, + env=bzr_subprocess_env()) except OSError: - # Will be thrown if bzr cannot be found - return None, None - + # Popen will throw an OSError if bzr is not found + return (None, None) pdata = p.communicate() if p.returncode != 0: - return None, None - - branch = pdata[0].decode("utf-8").strip() - return branch, get_bzr_status() + 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.branch, self.status = build_stats() + self.stats, self.branch = build_stats() def add_to_powerline(self): self.join() - if not self.branch or not self.status: + if not self.stats: 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: + if self.stats.dirty: 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) + self.powerline.append(" " + self.branch + " ", fg, bg) + self.stats.add_to_powerline(self.powerline) From 2168f5eb890b33c2fb660eb03c4aa594aaa69144 Mon Sep 17 00:00:00 2001 From: Emanuel Angelo Date: Wed, 13 Sep 2017 13:16:48 +0100 Subject: [PATCH 214/366] Better association between bzr status and RepoStats qualifiers --- powerline_shell/segments/bzr.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/powerline_shell/segments/bzr.py b/powerline_shell/segments/bzr.py index 456b6e34..e5c14df0 100644 --- a/powerline_shell/segments/bzr.py +++ b/powerline_shell/segments/bzr.py @@ -30,11 +30,9 @@ def parse_bzr_stats(status): setattr(stats, statustype, getattr(stats, statustype) + 1) elif statusline == "added:": statustype = "staged" - elif statusline in ("removed:", "missing:"): - statustype = "conflicted" elif statusline == "unknown:": statustype = "untracked" - else: # renamed, modified or kind changed + else: # removed, missing, renamed, modified or kind changed statustype = "not_staged" return stats From bec4e1f649f96209454b64f1315c8a759b497396 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Wed, 13 Sep 2017 10:32:46 -0400 Subject: [PATCH 215/366] changelog for #283 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e977b6a6..a63c53da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ Unreleased +* Add Bazaar segment + ([@emansije](https://github.com/banga/powerline-shell/pull/283)) * Rewrite SVN segment to be consistent with git * Remove duplicate function in colortrans.py ([@jmtd](https://github.com/banga/powerline-shell/pull/273)) From 2c0a5909ce8497813e02523b1cda2d3b9c836706 Mon Sep 17 00:00:00 2001 From: Emanuel Angelo Date: Thu, 14 Sep 2017 00:25:24 +0100 Subject: [PATCH 216/366] Renames some RepoStats class qualifiers to more generic terms untracked -> new not_staged -> changed --- powerline_shell/segments/bzr.py | 6 +++--- powerline_shell/segments/git.py | 4 ++-- powerline_shell/segments/svn.py | 4 ++-- powerline_shell/utils.py | 24 ++++++++++++------------ 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/powerline_shell/segments/bzr.py b/powerline_shell/segments/bzr.py index e5c14df0..c90dfa8b 100644 --- a/powerline_shell/segments/bzr.py +++ b/powerline_shell/segments/bzr.py @@ -24,16 +24,16 @@ def _get_bzr_branch(): def parse_bzr_stats(status): stats = RepoStats() - statustype = "not_staged" + 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 = "untracked" + statustype = "new" else: # removed, missing, renamed, modified or kind changed - statustype = "not_staged" + statustype = "changed" return stats diff --git a/powerline_shell/segments/git.py b/powerline_shell/segments/git.py index 95e2c2ae..72ef7a18 100644 --- a/powerline_shell/segments/git.py +++ b/powerline_shell/segments/git.py @@ -47,12 +47,12 @@ def parse_git_stats(status): 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 else: if code[1] != ' ': - stats.not_staged += 1 + stats.changed += 1 if code[0] != ' ': stats.staged += 1 diff --git a/powerline_shell/segments/svn.py b/powerline_shell/segments/svn.py index 27e21d66..995d04dc 100644 --- a/powerline_shell/segments/svn.py +++ b/powerline_shell/segments/svn.py @@ -20,10 +20,10 @@ def add_to_powerline(self): stats = RepoStats() for line in stdout.splitlines(): if line[0] == "?": - stats.untracked += 1 + stats.new += 1 elif line[0] == "C": stats.conflicted += 1 elif line[0] in ["A", "D", "I", "M", "R", "!", "~"]: - stats.not_staged += 1 + stats.changed += 1 stats.add_to_powerline(self.powerline) diff --git a/powerline_shell/utils.py b/powerline_shell/utils.py index 7f97f6d5..135c8192 100644 --- a/powerline_shell/utils.py +++ b/powerline_shell/utils.py @@ -14,24 +14,24 @@ class RepoStats(object): 'ahead': u'\u2B06', 'behind': u'\u2B07', 'staged': u'\u2714', - 'not_staged': u'\u270E', - 'untracked': u'\u2753', + 'changed': u'\u270E', + 'new': u'\u2753', 'conflicted': u'\u273C' } def __init__(self): self.ahead = 0 self.behind = 0 - self.untracked = 0 - self.not_staged = 0 + self.new = 0 + self.changed = 0 self.staged = 0 self.conflicted = 0 @property def dirty(self): qualifiers = [ - self.untracked, - self.not_staged, + self.new, + self.changed, self.staged, self.conflicted, ] @@ -45,11 +45,11 @@ def n_or_empty(self, _key): 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 untracked files, but you - only want a number to appear next to the icon when there are more than - one untracked files, you can do: + 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("untracked") + icon_string + segment = repo_stats.n_or_empty("new") + icon_string """ return unicode(self[_key]) if int(self[_key]) > 1 else u'' @@ -62,8 +62,8 @@ def add(_key, fg, bg): 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('not_staged', color.GIT_NOTSTAGED_FG, color.GIT_NOTSTAGED_BG) - add('untracked', color.GIT_UNTRACKED_FG, color.GIT_UNTRACKED_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) From 30c5bdad4695a8fb02167355a9d4588b9208b81e Mon Sep 17 00:00:00 2001 From: Emanuel Angelo Date: Thu, 14 Sep 2017 01:13:27 +0100 Subject: [PATCH 217/366] Changes tests accordingly --- test/repo_stats_test.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/repo_stats_test.py b/test/repo_stats_test.py index fe4f10dd..123259ba 100644 --- a/test/repo_stats_test.py +++ b/test/repo_stats_test.py @@ -6,20 +6,20 @@ class RepoStatsTest(unittest.TestCase): def setUp(self): self.repo_stats = RepoStats() - self.repo_stats.not_staged = 1 + 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.untracked, 0) + self.assertEqual(self.repo_stats.new, 0) def test_n_or_empty__empty(self): - self.assertEqual(self.repo_stats.n_or_empty("not_staged"), u"") + 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["not_staged"], 1) + self.assertEqual(self.repo_stats["changed"], 1) From 66e64ba3083a6e1fb2b39e196d403bc6e55578b1 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Wed, 13 Sep 2017 20:19:12 -0400 Subject: [PATCH 218/366] changelog for #284 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a63c53da..a7f1051f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ Unreleased * 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)) From 2f5350e1eb395d8d80b9ba8d278a5d662c68c61a Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Wed, 13 Sep 2017 20:20:16 -0400 Subject: [PATCH 219/366] upgrade version to 0.2.0 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 23f0faa9..5da09d37 100755 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup(name="powerline-shell", - version="0.1.0", + version="0.2.0", description="A pretty prompt for your shell", author="Buck Ryan", url="https://github.com/banga/powerline-shell", From f9d3f1295217d65a6bb5a160c3fc302beb09d7a8 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Wed, 13 Sep 2017 20:21:07 -0400 Subject: [PATCH 220/366] get ready for 0.2.0 --- CHANGELOG.md | 2 +- README.md | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a7f1051f..0fa637fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changes -Unreleased +2017-09-13 (version 0.2.0) * Add Bazaar segment ([@emansije](https://github.com/banga/powerline-shell/pull/283)) diff --git a/README.md b/README.md index 628ffb09..c2c5b960 100644 --- a/README.md +++ b/README.md @@ -146,6 +146,7 @@ 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 From 166ae54ee2dc2e9fa84896a1fbbcb75468166f04 Mon Sep 17 00:00:00 2001 From: Emanuel Angelo Date: Thu, 14 Sep 2017 23:51:30 +0100 Subject: [PATCH 221/366] Redo fossil segment to use RepoStats This implementation does not work well in older versions of fossil, like 1.37, apparently due to a bug in that version of fossil that throws an error with `fossil changes --differ`. --- powerline_shell/segments/fossil.py | 90 ++++++++++++++++++------------ 1 file changed, 55 insertions(+), 35 deletions(-) diff --git a/powerline_shell/segments/fossil.py b/powerline_shell/segments/fossil.py index cb1a26b3..3bdb7245 100644 --- a/powerline_shell/segments/fossil.py +++ b/powerline_shell/segments/fossil.py @@ -1,53 +1,73 @@ import os import subprocess -from ..utils import ThreadedSegment +from ..utils import RepoStats, ThreadedSegment -def get_fossil_branch(): - try: - subprocess.Popen(['fossil'], stdout=subprocess.PIPE).communicate() - except OSError: - return None +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 os.popen("fossil branch 2> /dev/null").read().strip().split("\n") + for i in branches if i.startswith('*') ]) -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 = bool( - os.popen("fossil extras 2>/dev/null").read().strip() - ) - has_missing_files = 'MISSING' in output - has_modified_files = 'EDITED' in output - return has_modified_files, has_untracked_files, has_missing_files +def parse_fossil_stats(status): + stats = RepoStats() + for filestatus in [line.split()[0] for line in status.strip().split("\n")]: + if filestatus == "ADDED": + stats.staged += 1 + elif filestatus == "EXTRA": + stats.new += 1 + elif filestatus == "CONFLICT": + stats.conflicted += 1 + else: + stats.changed += 1 + return stats + + +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 = os.popen("fossil changes --differ 2>/dev/null").read().strip() + if status == "": + return (RepoStats(), branch) + stats = parse_fossil_stats(status) + return stats, branch class Segment(ThreadedSegment): def run(self): - self.branch = get_fossil_branch() - self.status = get_fossil_status() if self.branch else None + self.stats, self.branch = build_stats() def add_to_powerline(self): self.join() - powerline = self.powerline - if not self.branch or not self.status: + if not self.stats: return - has_modified, has_untracked, has_missing = self.status - bg = powerline.theme.REPO_CLEAN_BG - fg = powerline.theme.REPO_CLEAN_FG - if has_modified or has_untracked or has_missing: - bg = powerline.theme.REPO_DIRTY_BG - fg = powerline.theme.REPO_DIRTY_FG - extra = '' - if has_untracked: - extra += '+' - if has_missing: - extra += '!' - self.branch += (' ' + extra if extra != '' else '') - powerline.append(' %s ' % self.branch, fg, bg) + 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) From e09c53da58285761423e03321e5ddb82b2c2576c Mon Sep 17 00:00:00 2001 From: Emanuel Angelo Date: Fri, 15 Sep 2017 00:31:30 +0100 Subject: [PATCH 222/366] Hack around fossil bug For older versions of fossil that throw an error on `fossil changes --differ`, like version 1.37. --- powerline_shell/segments/fossil.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/powerline_shell/segments/fossil.py b/powerline_shell/segments/fossil.py index 3bdb7245..b2814e60 100644 --- a/powerline_shell/segments/fossil.py +++ b/powerline_shell/segments/fossil.py @@ -25,7 +25,7 @@ def _get_fossil_branch(): def parse_fossil_stats(status): stats = RepoStats() - for filestatus in [line.split()[0] for line in status.strip().split("\n")]: + for filestatus in [line.split()[0] for line in status]: if filestatus == "ADDED": stats.staged += 1 elif filestatus == "EXTRA": @@ -48,8 +48,10 @@ def build_stats(): branch = _get_fossil_branch() if branch == "": return (None, None) - status = os.popen("fossil changes --differ 2>/dev/null").read().strip() - if status == "": + status = os.popen("fossil changes 2>/dev/null").read().strip().split("\n") + extra = os.popen("fossil extras 2>/dev/null").read().strip().split("\n") + status += ["EXTRA " + filename for filename in extra if filename != ""] + if status == ['']: return (RepoStats(), branch) stats = parse_fossil_stats(status) return stats, branch From 9e6cb7d909e249abbb5b928857988b978ab21c70 Mon Sep 17 00:00:00 2001 From: Emanuel Angelo Date: Fri, 15 Sep 2017 19:27:02 +0100 Subject: [PATCH 223/366] Redo hg segment to use RepoStats --- powerline_shell/segments/hg.py | 67 +++++++++++++++------------------- 1 file changed, 29 insertions(+), 38 deletions(-) diff --git a/powerline_shell/segments/hg.py b/powerline_shell/segments/hg.py index 05cb2f71..c4f0fc48 100644 --- a/powerline_shell/segments/hg.py +++ b/powerline_shell/segments/hg.py @@ -1,7 +1,6 @@ import os import subprocess -from ..utils import ThreadedSegment -import subprocess +from ..utils import RepoStats, ThreadedSegment def get_PATH(): @@ -11,69 +10,61 @@ def get_PATH(): return os.getenv("PATH") -def _subprocess_env(): +def hg_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"], +def _get_hg_branch(): + p = subprocess.Popen(["hg", "branch"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, - env=_subprocess_env()) - output = p.communicate()[0].decode("utf-8") + env=hg_subprocess_env()) + branch = p.communicate()[0].decode("utf-8").rstrip('\n') + return branch + - 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 parse_hg_stats(status): + stats = RepoStats() + for statusline in status: + if statusline[0] == "A": + stats.staged += 1 + elif statusline[0] == "?": + stats.new += 1 + else: # [M]odified, [R]emoved, (!)missing + stats.changed += 1 + return stats def build_stats(): try: - p = subprocess.Popen(["hg", "branch"], + p = subprocess.Popen(["hg", "status"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, - env=_subprocess_env()) + env=hg_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() + status = pdata[0].decode("utf-8").splitlines() + stats = parse_hg_stats(status) + branch = _get_hg_branch() + return stats, branch class Segment(ThreadedSegment): def run(self): - self.branch, self.status = build_stats() + self.stats, self.branch = build_stats() def add_to_powerline(self): self.join() - if not self.branch or not self.status: + if not self.stats: 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: + if self.stats.dirty: 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) + self.powerline.append(" " + self.branch + " ", fg, bg) + self.stats.add_to_powerline(self.powerline) From 80f44541e60ce0e4d6574548edae803c0759a5bb Mon Sep 17 00:00:00 2001 From: Christian Mehlmauer Date: Fri, 15 Sep 2017 23:17:22 +0200 Subject: [PATCH 224/366] update readme --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c2c5b960..d075e12f 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,14 @@ setting your $TERM to `xterm-256color`, because that works for me. - Install using pip: ``` -pip install powerline-shell +pip install --user powerline-shell +``` + +PS: If you want to install powerline-shell for all users simply omit the `--user` flag + +- Install using the git version: +``` +python setup.py install --user ``` - Setup your shell prompt using the instructions for your shell below. From 063d3923df73d297c81f6351178ded140fa7f0ac Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 16 Sep 2017 10:02:11 -0400 Subject: [PATCH 225/366] fix two issues with fish shell --- powerline_shell/__init__.py | 3 +-- powerline_shell/segments/time.py | 9 +++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/powerline_shell/__init__.py b/powerline_shell/__init__.py index ac6fdc21..e5386cf6 100644 --- a/powerline_shell/__init__.py +++ b/powerline_shell/__init__.py @@ -73,8 +73,7 @@ def __init__(self, args, config, theme): self.theme = theme self.cwd = get_valid_cwd() mode = config.get("mode", "patched") - shell = config.get("shell", "bash") - self.color_template = self.color_templates[shell] + 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'] diff --git a/powerline_shell/segments/time.py b/powerline_shell/segments/time.py index 413abb67..ab4c9113 100644 --- a/powerline_shell/segments/time.py +++ b/powerline_shell/segments/time.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from ..utils import BasicSegment import time @@ -6,11 +7,11 @@ class Segment(BasicSegment): def add_to_powerline(self): powerline = self.powerline if powerline.args.shell == 'bash': - time = ' \\t ' + time_ = ' \\t ' elif powerline.args.shell == 'zsh': - time = ' %* ' + time_ = ' %* ' else: - time = ' %s ' % time.strftime('%H:%M:%S') - powerline.append(time, + time_ = ' %s ' % time.strftime('%H:%M:%S') + powerline.append(time_, powerline.theme.HOSTNAME_FG, powerline.theme.HOSTNAME_BG) From d2fd79690eec323d8a77f79fc69b728f4d331466 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 16 Sep 2017 10:03:11 -0400 Subject: [PATCH 226/366] prepare for 0.2.1 --- CHANGELOG.md | 4 ++++ setup.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fa637fa..87574bd3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changes +2017-09-16 (version 0.2.1) + +* Fix issues preventing fish shell from rendering. + 2017-09-13 (version 0.2.0) * Add Bazaar segment diff --git a/setup.py b/setup.py index 5da09d37..bbf527a2 100755 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup(name="powerline-shell", - version="0.2.0", + version="0.2.1", description="A pretty prompt for your shell", author="Buck Ryan", url="https://github.com/banga/powerline-shell", From 655a12a278bb5590b64d531ad3964e58666c903a Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Mon, 18 Sep 2017 09:13:10 -0400 Subject: [PATCH 227/366] Fix py3 issues in uptime and in unicode function --- powerline_shell/segments/uptime.py | 2 +- powerline_shell/utils.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/powerline_shell/segments/uptime.py b/powerline_shell/segments/uptime.py index b2821008..96e4c268 100644 --- a/powerline_shell/segments/uptime.py +++ b/powerline_shell/segments/uptime.py @@ -7,7 +7,7 @@ class Segment(BasicSegment): def add_to_powerline(self): powerline = self.powerline try: - output = subprocess.check_output(['uptime'], stderr=subprocess.STDOUT) + 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) diff --git a/powerline_shell/utils.py b/powerline_shell/utils.py index 135c8192..e3a9a2f0 100644 --- a/powerline_shell/utils.py +++ b/powerline_shell/utils.py @@ -5,7 +5,7 @@ if py3: def unicode(x): - return x + return str(x) class RepoStats(object): From 3e025e29470cec572cf0c9d2da4a7cda3280f564 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Mon, 18 Sep 2017 09:14:54 -0400 Subject: [PATCH 228/366] prepare 0.2.2 --- CHANGELOG.md | 5 +++++ setup.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87574bd3..b8f9816e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changes +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. diff --git a/setup.py b/setup.py index bbf527a2..ffa46e38 100755 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup(name="powerline-shell", - version="0.2.1", + version="0.2.2", description="A pretty prompt for your shell", author="Buck Ryan", url="https://github.com/banga/powerline-shell", From 7cd14c3267a20a380da861b5bc94464dd4d953c6 Mon Sep 17 00:00:00 2001 From: Emanuel Angelo Date: Tue, 19 Sep 2017 11:57:00 +0100 Subject: [PATCH 229/366] Fix bug when there are extra files and no tracked changes If the fossil repository had untracked files and no modifications in the tracked files, the parsing would fail because the status list would begin with an unexpected blank element. --- powerline_shell/segments/fossil.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/powerline_shell/segments/fossil.py b/powerline_shell/segments/fossil.py index b2814e60..52e52579 100644 --- a/powerline_shell/segments/fossil.py +++ b/powerline_shell/segments/fossil.py @@ -25,12 +25,12 @@ def _get_fossil_branch(): def parse_fossil_stats(status): stats = RepoStats() - for filestatus in [line.split()[0] for line in status]: - if filestatus == "ADDED": + for line in status: + if line.startswith("ADDED"): stats.staged += 1 - elif filestatus == "EXTRA": + elif line.startswith("EXTRA"): stats.new += 1 - elif filestatus == "CONFLICT": + elif line.startswith("CONFLICT"): stats.conflicted += 1 else: stats.changed += 1 @@ -48,11 +48,12 @@ def build_stats(): branch = _get_fossil_branch() if branch == "": return (None, None) - status = os.popen("fossil changes 2>/dev/null").read().strip().split("\n") + changes = os.popen("fossil changes 2>/dev/null").read().strip().split("\n") extra = os.popen("fossil extras 2>/dev/null").read().strip().split("\n") - status += ["EXTRA " + filename for filename in extra if filename != ""] - if status == ['']: + extra = ["EXTRA " + filename for filename in extra] + if changes == extra == ['']: return (RepoStats(), branch) + status = [line for line in changes + extra if line != ''] stats = parse_fossil_stats(status) return stats, branch From 40882fbacf56d1fa7a3dbd6c61ff5ffc51c140e6 Mon Sep 17 00:00:00 2001 From: Emanuel Angelo Date: Tue, 19 Sep 2017 12:15:27 +0100 Subject: [PATCH 230/366] Fixes bug that calculated an extra untracked file in the repository --- powerline_shell/segments/fossil.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerline_shell/segments/fossil.py b/powerline_shell/segments/fossil.py index 52e52579..8fbbb9dc 100644 --- a/powerline_shell/segments/fossil.py +++ b/powerline_shell/segments/fossil.py @@ -50,7 +50,7 @@ def build_stats(): return (None, None) 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] + extra = ["EXTRA " + filename for filename in extra if filename != ""] if changes == extra == ['']: return (RepoStats(), branch) status = [line for line in changes + extra if line != ''] From 0601b47b41b8b88513b1dc5a47b96aeebebe1466 Mon Sep 17 00:00:00 2001 From: Emanuel Angelo Date: Tue, 26 Sep 2017 02:33:02 +0100 Subject: [PATCH 231/366] Fixes bug in `test/repostats_test.py` --- test/repo_stats_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/repo_stats_test.py b/test/repo_stats_test.py index 123259ba..300d00b7 100644 --- a/test/repo_stats_test.py +++ b/test/repo_stats_test.py @@ -19,7 +19,7 @@ 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") + self.assertEqual(self.repo_stats.n_or_empty("conflicted"), 4) def test_index(self): self.assertEqual(self.repo_stats["changed"], 1) From b6c714253d3fc8767969503343f7d3c8b032eb2b Mon Sep 17 00:00:00 2001 From: Emanuel Angelo Date: Tue, 26 Sep 2017 02:42:00 +0100 Subject: [PATCH 232/366] Adds test for fossil segment It implies going from a threaded segment to a basic one, otherwise it throws a RuntimeError: threads can only be started once --- powerline_shell/segments/fossil.py | 23 +++++----- test/segments_test/fossil_test.py | 68 ++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 10 deletions(-) create mode 100644 test/segments_test/fossil_test.py diff --git a/powerline_shell/segments/fossil.py b/powerline_shell/segments/fossil.py index 8fbbb9dc..bfe38cd6 100644 --- a/powerline_shell/segments/fossil.py +++ b/powerline_shell/segments/fossil.py @@ -1,6 +1,6 @@ import os import subprocess -from ..utils import RepoStats, ThreadedSegment +from ..utils import RepoStats, BasicSegment def get_PATH(): @@ -37,6 +37,14 @@ def parse_fossil_stats(status): 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, @@ -48,22 +56,17 @@ def build_stats(): branch = _get_fossil_branch() if branch == "": return (None, None) - 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 != ""] - if changes == extra == ['']: + status = _get_fossil_status() + if status == []: return (RepoStats(), branch) - status = [line for line in changes + extra if line != ''] stats = parse_fossil_stats(status) return stats, branch -class Segment(ThreadedSegment): - def run(self): - self.stats, self.branch = build_stats() +class Segment(BasicSegment): def add_to_powerline(self): - self.join() + self.stats, self.branch = build_stats() if not self.stats: return bg = self.powerline.theme.REPO_CLEAN_BG diff --git a/test/segments_test/fossil_test.py b/test/segments_test/fossil_test.py new file mode 100644 index 00000000..34158739 --- /dev/null +++ b/test/segments_test/fossil_test.py @@ -0,0 +1,68 @@ +import unittest +import mock +import tempfile +import shutil +import sh +import powerline_shell.segments.fossil as fossil +from powerline_shell.utils import RepoStats + + +rs = RepoStats() +test_cases = { + "EXTRA new-file": rs.symbols["new"], + "EDITED modified-file": rs.symbols["changed"], + "CONFLICT conflicted-file": rs.symbols["conflicted"], + "ADDED added-file": rs.symbols["staged"], +} + + +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(): + check_output.return_value = [stdout] + self.segment.start() + self.segment.add_to_powerline() + self.assertEqual(self.powerline.append.call_args[0][0].split()[0], + result) From ebb7187f04f31f522d611830217a340dbfa9453b Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Tue, 26 Sep 2017 11:06:44 -0400 Subject: [PATCH 233/366] Update parsing tests --- powerline_shell/segments/fossil.py | 4 ++-- powerline_shell/utils.py | 24 +++++++++++++++++------- test/repo_stats_test.py | 2 +- test/segments_test/fossil_test.py | 17 ++++++----------- 4 files changed, 26 insertions(+), 21 deletions(-) diff --git a/powerline_shell/segments/fossil.py b/powerline_shell/segments/fossil.py index bfe38cd6..3c464f99 100644 --- a/powerline_shell/segments/fossil.py +++ b/powerline_shell/segments/fossil.py @@ -1,6 +1,6 @@ import os import subprocess -from ..utils import RepoStats, BasicSegment +from ..utils import RepoStats, ThreadedSegment def get_PATH(): @@ -63,7 +63,7 @@ def build_stats(): return stats, branch -class Segment(BasicSegment): +class Segment(ThreadedSegment): def add_to_powerline(self): self.stats, self.branch = build_stats() diff --git a/powerline_shell/utils.py b/powerline_shell/utils.py index e3a9a2f0..c99b08cc 100644 --- a/powerline_shell/utils.py +++ b/powerline_shell/utils.py @@ -19,13 +19,23 @@ class RepoStats(object): 'conflicted': u'\u273C' } - def __init__(self): - self.ahead = 0 - self.behind = 0 - self.new = 0 - self.changed = 0 - self.staged = 0 - self.conflicted = 0 + 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): diff --git a/test/repo_stats_test.py b/test/repo_stats_test.py index 300d00b7..123259ba 100644 --- a/test/repo_stats_test.py +++ b/test/repo_stats_test.py @@ -19,7 +19,7 @@ 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"), 4) + self.assertEqual(self.repo_stats.n_or_empty("conflicted"), u"4") def test_index(self): self.assertEqual(self.repo_stats["changed"], 1) diff --git a/test/segments_test/fossil_test.py b/test/segments_test/fossil_test.py index 34158739..9f9d01d4 100644 --- a/test/segments_test/fossil_test.py +++ b/test/segments_test/fossil_test.py @@ -6,13 +6,11 @@ import powerline_shell.segments.fossil as fossil from powerline_shell.utils import RepoStats - -rs = RepoStats() test_cases = { - "EXTRA new-file": rs.symbols["new"], - "EDITED modified-file": rs.symbols["changed"], - "CONFLICT conflicted-file": rs.symbols["conflicted"], - "ADDED added-file": rs.symbols["staged"], + "EXTRA new-file": RepoStats(new=1), + "EDITED modified-file": RepoStats(changed=1), + "CONFLICT conflicted-file": RepoStats(conflicted=1), + "ADDED added-file": RepoStats(staged=1), } @@ -61,8 +59,5 @@ def test_standard(self): @mock.patch('powerline_shell.segments.fossil._get_fossil_status') def test_all(self, check_output): for stdout, result in test_cases.items(): - check_output.return_value = [stdout] - self.segment.start() - self.segment.add_to_powerline() - self.assertEqual(self.powerline.append.call_args[0][0].split()[0], - result) + stats = fossil.parse_fossil_stats([stdout]) + self.assertEquals(result, stats) From f722ec75497f587514514de55677d7d3c9d995eb Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Fri, 29 Sep 2017 16:41:28 -0400 Subject: [PATCH 234/366] changelog for #286 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8f9816e..ec09e6a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changes +Unreleased + +* Redo Fossil segment to be consistent with git, svn, etc. + ([@emansije](https://github.com/banga/powerline-shell/pull/286)) + 2017-09-18 (version 0.2.2) * Fix python3 issue in uptime segment. Fixes From 219974601d0d4e2fb244450c48a803847a78aa24 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 30 Sep 2017 11:01:15 -0400 Subject: [PATCH 235/366] Make subshell escaping only happen for bash --- powerline_shell/__init__.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/powerline_shell/__init__.py b/powerline_shell/__init__.py index 78945870..2c87c642 100644 --- a/powerline_shell/__init__.py +++ b/powerline_shell/__init__.py @@ -100,8 +100,7 @@ def bgcolor(self, code): return self.color('48', code) def append(self, content, fg, bg, separator=None, separator_fg=None): - sanitized = re.sub(r"([`$])", r"\\\1", content) - self.segments.append((sanitized, fg, bg, + 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)) @@ -115,12 +114,16 @@ def draw(self): 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]), - segment[0], + sanitized, self.bgcolor(next_segment[2]) if next_segment else self.reset, self.fgcolor(segment[4]), segment[3])) From 01dd52f7db95f8646382a85356d666739bb04d34 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 30 Sep 2017 11:08:02 -0400 Subject: [PATCH 236/366] changelog for #282 --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ec09e6a0..28458bdb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ Unreleased * 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)) 2017-09-18 (version 0.2.2) From e336ae4478ff1c49c1d020296faa01920cb8462c Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 30 Sep 2017 11:09:16 -0400 Subject: [PATCH 237/366] Change symbol for SSH segment to be text "SSH" closes #287 --- powerline_shell/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/powerline_shell/__init__.py b/powerline_shell/__init__.py index 2c87c642..ec25c0df 100644 --- a/powerline_shell/__init__.py +++ b/powerline_shell/__init__.py @@ -50,13 +50,13 @@ class Powerline(object): }, 'patched': { 'lock': u'\uE0A2', - 'network': u'\uE0A2', + 'network': 'SSH', 'separator': u'\uE0B0', 'separator_thin': u'\uE0B1' }, 'flat': { 'lock': u'\uE0A2', - 'network': u'\uE0A2', + 'network': 'SSH', 'separator': '', 'separator_thin': '' }, From da56da3bb37e02775abbf021849686bc65b14bb7 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 30 Sep 2017 11:11:08 -0400 Subject: [PATCH 238/366] changelog for #287 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28458bdb..32f17efa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ Unreleased * 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) From a95090550cbef8a1f59fc36ae313fa50724c7b95 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 30 Sep 2017 11:11:51 -0400 Subject: [PATCH 239/366] version 0.3.0 --- CHANGELOG.md | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32f17efa..3f4d5112 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changes -Unreleased +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)) diff --git a/setup.py b/setup.py index ffa46e38..08fc42d1 100755 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup(name="powerline-shell", - version="0.2.2", + version="0.3.0", description="A pretty prompt for your shell", author="Buck Ryan", url="https://github.com/banga/powerline-shell", From 2dd4c6dbbf10909e0ab22b9821e3803dfbb17899 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 30 Sep 2017 17:08:46 -0400 Subject: [PATCH 240/366] re-implement #175 closes #175 --- powerline_shell/segments/username.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/powerline_shell/segments/username.py b/powerline_shell/segments/username.py index b03dc093..9e4d9d8d 100644 --- a/powerline_shell/segments/username.py +++ b/powerline_shell/segments/username.py @@ -1,5 +1,6 @@ from ..utils import BasicSegment import os +import pwd class Segment(BasicSegment): @@ -12,7 +13,7 @@ def add_to_powerline(self): else: user_prompt = " %s " % os.getenv("USER") - if os.getenv("USER") == "root": + if pwd.getpwuid(os.getuid())[0] == "root": bgcolor = powerline.theme.USERNAME_ROOT_BG else: bgcolor = powerline.theme.USERNAME_BG From 251277297fc89925f1c18ef861ad40a38882d567 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 30 Sep 2017 17:10:23 -0400 Subject: [PATCH 241/366] changelog for #175 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f4d5112..d1cb7b5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changes +Unreleased + +* Fix username segment's background color after "su" command + ([@Fak3](https://github.com/banga/powerline-shell/pull/175)) + 2017-09-30 (version 0.3.0) * Redo Fossil segment to be consistent with git, svn, etc. From 3c8172577d7e8352014621675de2c95c3378cc3c Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 30 Sep 2017 17:39:28 -0400 Subject: [PATCH 242/366] update battery segment to work with latest powerline shell plus refactor a bit and try to find the battery directory properly --- powerline_shell/segments/battery.py | 31 +++++++++++++++++++++++++++++ powerline_shell/themes/default.py | 2 +- segments/battery.py | 28 -------------------------- 3 files changed, 32 insertions(+), 29 deletions(-) create mode 100644 powerline_shell/segments/battery.py delete mode 100644 segments/battery.py diff --git a/powerline_shell/segments/battery.py b/powerline_shell/segments/battery.py new file mode 100644 index 00000000..d9acd417 --- /dev/null +++ b/powerline_shell/segments/battery.py @@ -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) diff --git a/powerline_shell/themes/default.py b/powerline_shell/themes/default.py index 31851284..3b8a2b7d 100644 --- a/powerline_shell/themes/default.py +++ b/powerline_shell/themes/default.py @@ -60,7 +60,7 @@ class DefaultColor(object): VIRTUAL_ENV_BG = 35 # a mid-tone green VIRTUAL_ENV_FG = 00 - + BATTERY_NORMAL_BG = 22 BATTERY_NORMAL_FG = 7 BATTERY_LOW_BG = 196 diff --git a/segments/battery.py b/segments/battery.py deleted file mode 100644 index 10efe1a4..00000000 --- a/segments/battery.py +++ /dev/null @@ -1,28 +0,0 @@ -def add_battery_segment(): - CAP_FILE = '/sys/class/power_supply/BAT0/capacity' - STATUS_FILE = '/sys/class/power_supply/BAT0/status' - LOW_BATTERY_THRESHOLD = 20 - - f = open(CAP_FILE) - cap = f.read().strip() - f.close() - - f = open(STATUS_FILE) - status = f.read().strip() - f.close() - - if status == 'Charging': - pwr = u' \u26A1 ' - else: - pwr = ' ' - - if int(cap) < LOW_BATTERY_THRESHOLD: - bg = Color.BATTERY_LOW_BG - fg = Color.BATTERY_LOW_FG - else: - bg = Color.BATTERY_NORMAL_BG - fg = Color.BATTERY_NORMAL_FG - - powerline.append(' ' + cap + '%' + pwr, fg, bg) - -add_battery_segment() From a103870c425f509cbbbd919508c3895273cedb74 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 30 Sep 2017 17:40:47 -0400 Subject: [PATCH 243/366] changelog for #204 --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1cb7b5a..ea61c5db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ 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) From 05f45e79f2b2794ead19bac0b5d6d914dca5db49 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 30 Sep 2017 17:49:46 -0400 Subject: [PATCH 244/366] update to latest powerline --- powerline_shell/segments/aws_profile.py | 12 ++++++++++++ segments/aws_profile.py | 11 ----------- 2 files changed, 12 insertions(+), 11 deletions(-) create mode 100644 powerline_shell/segments/aws_profile.py delete mode 100644 segments/aws_profile.py diff --git a/powerline_shell/segments/aws_profile.py b/powerline_shell/segments/aws_profile.py new file mode 100644 index 00000000..6e9433e6 --- /dev/null +++ b/powerline_shell/segments/aws_profile.py @@ -0,0 +1,12 @@ +from ..utils import BasicSegment +import os + + +class Segment(BasicSegment): + def add_to_powerline(self): + aws_profile = os.environ.get("AWS_PROFILE") or \ + os.environ.get("AWS_DEFAULT_PROFILE") + if aws_profile: + self.powerline.append(" aws:%s " % os.path.basename(aws_profile), + self.powerline.theme.AWS_PROFILE_FG, + self.powerline.theme.AWS_PROFILE_BG) diff --git a/segments/aws_profile.py b/segments/aws_profile.py deleted file mode 100644 index 5de2e100..00000000 --- a/segments/aws_profile.py +++ /dev/null @@ -1,11 +0,0 @@ - -def add_aws_profile_segment(powerline): - import os - - aws_profile = os.environ.get('AWS_PROFILE') or \ - os.environ.get('AWS_DEFAULT_PROFILE') - - if aws_profile: - powerline.append(' aws:%s ' % os.path.basename(aws_profile), - Color.AWS_PROFILE_FG, - Color.AWS_PROFILE_BG) From bea9a7efd3bc771308ddca7bdec497f19aec2299 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 30 Sep 2017 17:51:12 -0400 Subject: [PATCH 245/366] changelog for #223 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea61c5db..f4b749aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ Unreleased * 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)) +* New `aws_profile` segment which shows which AWS profile you are using. + ([@bryangrimes](https://github.com/banga/powerline-shell/pull/223)) 2017-09-30 (version 0.3.0) From 33e630c06d0736aedf4162b63324131b1c7cb289 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 30 Sep 2017 18:04:31 -0400 Subject: [PATCH 246/366] two releases in one day woot woot - version 0.3.1 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f4b749aa..d1c76100 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changes -Unreleased +2017-09-30 (version 0.3.1) * Fix username segment's background color after "su" command ([@Fak3](https://github.com/banga/powerline-shell/pull/175)) From 35dd28dcacaec16aaea81da9fef6174b3dee89ab Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 30 Sep 2017 18:05:11 -0400 Subject: [PATCH 247/366] woops actually change the version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 08fc42d1..aa93f9a6 100755 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup(name="powerline-shell", - version="0.3.0", + version="0.3.1", description="A pretty prompt for your shell", author="Buck Ryan", url="https://github.com/banga/powerline-shell", From 359c00acb9ab5cdd84153b9a9ec46f270bfe77e8 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 30 Sep 2017 18:08:30 -0400 Subject: [PATCH 248/366] add latest segments to readme --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index d075e12f..e3ae2280 100644 --- a/README.md +++ b/README.md @@ -153,6 +153,11 @@ 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: +- `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. From 8c9cd06ea313c0137d68120a3f29e9a04af3ba55 Mon Sep 17 00:00:00 2001 From: Emanuel Angelo Date: Sun, 1 Oct 2017 17:36:17 +0100 Subject: [PATCH 249/366] Adds tests for the hg segment using RepoStats --- powerline_shell/segments/hg.py | 8 +++++++- test/segments_test/hg_test.py | 16 ++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/powerline_shell/segments/hg.py b/powerline_shell/segments/hg.py index c4f0fc48..6c6ac9b1 100644 --- a/powerline_shell/segments/hg.py +++ b/powerline_shell/segments/hg.py @@ -35,6 +35,12 @@ def parse_hg_stats(status): return stats +def _get_hg_status(output): + """This function exists to enable mocking the `hg status` output in tests. + """ + return output[0].decode("utf-8").splitlines() + + def build_stats(): try: p = subprocess.Popen(["hg", "status"], @@ -47,7 +53,7 @@ def build_stats(): pdata = p.communicate() if p.returncode != 0: return None, None - status = pdata[0].decode("utf-8").splitlines() + status = _get_hg_status(pdata) stats = parse_hg_stats(status) branch = _get_hg_branch() return stats, branch diff --git a/test/segments_test/hg_test.py b/test/segments_test/hg_test.py index be8d147d..a6d89b73 100644 --- a/test/segments_test/hg_test.py +++ b/test/segments_test/hg_test.py @@ -4,6 +4,16 @@ import shutil import sh import powerline_shell.segments.hg as hg +from powerline_shell.utils import RepoStats + + +test_cases = { + "? new-file": RepoStats(new=1), + "M modified-file": RepoStats(changed=1), + "R removed-file": RepoStats(changed=1), + "! missing-file": RepoStats(changed=1), + "A added-file": RepoStats(staged=1), +} class HgTest(unittest.TestCase): @@ -46,3 +56,9 @@ def test_standard(self): self.segment.start() self.segment.add_to_powerline() self.assertEqual(self.powerline.append.call_args[0][0], " default ") + + @mock.patch('powerline_shell.segments.hg._get_hg_status') + def test_all(self, check_output): + for stdout, result in test_cases.items(): + stats = hg.parse_hg_stats([stdout]) + self.assertEquals(result, stats) From 1326d47c3984175faeb369ddd620d1186fb04b89 Mon Sep 17 00:00:00 2001 From: Emanuel Angelo Date: Sun, 1 Oct 2017 19:52:15 +0100 Subject: [PATCH 250/366] Adds tests for bzr segment --- powerline_shell/segments/bzr.py | 8 +++- test/segments_test/bzr_test.py | 78 +++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 test/segments_test/bzr_test.py diff --git a/powerline_shell/segments/bzr.py b/powerline_shell/segments/bzr.py index c90dfa8b..a6dc96cb 100644 --- a/powerline_shell/segments/bzr.py +++ b/powerline_shell/segments/bzr.py @@ -37,6 +37,12 @@ def parse_bzr_stats(status): return stats +def _get_bzr_status(output): + """This function exists to enable mocking the `bzr status` output in tests. + """ + return output[0].decode("utf-8").splitlines() + + def build_stats(): try: p = subprocess.Popen(['bzr', 'status'], @@ -48,7 +54,7 @@ def build_stats(): pdata = p.communicate() if p.returncode != 0: return (None, None) - status = pdata[0].decode("utf-8").splitlines() + status = _get_bzr_status(pdata) stats = parse_bzr_stats(status) branch = _get_bzr_branch() return stats, branch diff --git a/test/segments_test/bzr_test.py b/test/segments_test/bzr_test.py new file mode 100644 index 00000000..62fc6d16 --- /dev/null +++ b/test/segments_test/bzr_test.py @@ -0,0 +1,78 @@ +import unittest +import mock +import tempfile +import shutil +import sh +import powerline_shell.segments.bzr as bzr +from powerline_shell.utils import RepoStats + + +test_cases = ( + (["unknown:"," new-file"], RepoStats(new=1)), + (["added:"," added-file"], RepoStats(staged=1)), + (["modified:"," modified-file"], RepoStats(changed=1)), + (["removed:"," removed-file"], RepoStats(changed=1)), + (["missing:"," missing-file"], RepoStats(changed=1)), + (["renamed:"," renamed-file"], RepoStats(changed=1)), + (["kind changed:"," kind-changed-file"], RepoStats(changed=1)) +) + + +class BzrTest(unittest.TestCase): + + def setUp(self): + self.powerline = mock.MagicMock() + + self.dirname = tempfile.mkdtemp() + sh.cd(self.dirname) + sh.bzr("init-repo", ".") + sh.mkdir("trunk") + sh.cd("trunk") + sh.bzr("init") + + self.segment = bzr.Segment(self.powerline) + + def tearDown(self): + shutil.rmtree(self.dirname) + + def _add_and_commit(self, filename): + sh.touch(filename) + sh.bzr("add", filename) + sh.bzr("commit", "-m", "add file " + filename) + + def _checkout_new_branch(self, branch): + sh.cd("..") + sh.bzr("branch", "trunk", branch) + sh.cd(branch) + + @mock.patch("powerline_shell.segments.bzr.get_PATH") + def test_bzr_not_installed(self, get_PATH): + get_PATH.return_value = "" # so bzr can't be found + self.segment.start() + self.segment.add_to_powerline() + self.assertEqual(self.powerline.append.call_count, 0) + + def test_non_bzr_directory(self): + shutil.rmtree(".bzr") + self.segment.start() + self.segment.add_to_powerline() + self.assertEqual(self.powerline.append.call_count, 0) + + def test_trunk(self): + self._add_and_commit("foo") + self.segment.start() + self.segment.add_to_powerline() + self.assertEqual(self.powerline.append.call_args[0][0], " trunk ") + + def test_different_branch(self): + self._add_and_commit("foo") + self._checkout_new_branch("bar") + self.segment.start() + self.segment.add_to_powerline() + self.assertEqual(self.powerline.append.call_args[0][0], " bar ") + + @mock.patch('powerline_shell.segments.bzr._get_bzr_status') + def test_all(self, check_output): + for stdout, result in test_cases: + stats = bzr.parse_bzr_stats(stdout) + self.assertEquals(result, stats) From fbdb261d931cbf30117dc1a85eb99f96775f2e5a Mon Sep 17 00:00:00 2001 From: Emanuel Angelo Date: Sun, 1 Oct 2017 20:07:08 +0100 Subject: [PATCH 251/366] Completes the test for creating a new branch in mercurial for the hg segment --- test/segments_test/hg_test.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/segments_test/hg_test.py b/test/segments_test/hg_test.py index a6d89b73..34fddc15 100644 --- a/test/segments_test/hg_test.py +++ b/test/segments_test/hg_test.py @@ -57,6 +57,13 @@ def test_standard(self): self.segment.add_to_powerline() self.assertEqual(self.powerline.append.call_args[0][0], " default ") + def test_different_branch(self): + self._add_and_commit("foo") + self._checkout_new_branch("bar") + self.segment.start() + self.segment.add_to_powerline() + self.assertEqual(self.powerline.append.call_args[0][0], " bar ") + @mock.patch('powerline_shell.segments.hg._get_hg_status') def test_all(self, check_output): for stdout, result in test_cases.items(): From d3b859a0f510acca822937ecd37a5cc06d7c09b2 Mon Sep 17 00:00:00 2001 From: Emanuel Angelo Date: Sun, 1 Oct 2017 20:28:53 +0100 Subject: [PATCH 252/366] Completes the new branch creation test for the fossil segment --- test/segments_test/fossil_test.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/segments_test/fossil_test.py b/test/segments_test/fossil_test.py index 9f9d01d4..50a74267 100644 --- a/test/segments_test/fossil_test.py +++ b/test/segments_test/fossil_test.py @@ -36,6 +36,7 @@ def _add_and_commit(self, filename): def _checkout_new_branch(self, branch): sh.fossil("branch", "new", branch, "trunk") + sh.fossil("checkout", branch) @mock.patch("powerline_shell.segments.fossil.get_PATH") def test_fossil_not_installed(self, get_PATH): @@ -56,6 +57,13 @@ def test_standard(self): self.segment.add_to_powerline() self.assertEqual(self.powerline.append.call_args[0][0], " trunk ") + def test_different_branch(self): + self._add_and_commit("foo") + self._checkout_new_branch("bar") + self.segment.start() + self.segment.add_to_powerline() + self.assertEqual(self.powerline.append.call_args[0][0], " bar ") + @mock.patch('powerline_shell.segments.fossil._get_fossil_status') def test_all(self, check_output): for stdout, result in test_cases.items(): From 19a913c10898647865b1743d0b76a397e3b62f32 Mon Sep 17 00:00:00 2001 From: Arun Allamsetty Date: Tue, 3 Oct 2017 14:04:06 -0600 Subject: [PATCH 253/366] Dockerize tests for easy reproduction. --- .dockerignore | 9 +++++++++ Dockerfile | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..64fcd5f3 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,9 @@ +*.swp +.git/ +.gitignore +.travis.yml +CHANGELOG.md +Dockerfile +LICENSE +README.md +bash-powerline-screenshot.png diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..994a3853 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,39 @@ +FROM python:2.7-alpine + +MAINTAINER github.com/banga/powerline-shell + +ENV USER docker +ENV USERNAME "Docker User" + +# Create a 'docker' user because we might not want to run everything as 'root'. Use 9999 as the ID +# to keep it specific and away from the IDs in the host system. +RUN addgroup -g 9999 $USER && \ + adduser -u 9999 -G $USER -g "$USERNAME" -s /bin/bash -D $USER + +RUN apk add --no-cache --update \ + bzr \ + fossil \ + git \ + mercurial \ + php5 \ + subversion && \ + rm -rf /var/cache/apk/* + +RUN mkdir -p /usr/src/app +WORKDIR /usr/src/app + +# Cache the dev requirements. +COPY requirements-dev.txt . +RUN pip install -r requirements-dev.txt + +USER docker +RUN bzr whoami "$USERNAME <$USER@example.com>" && \ + git config --global user.email "$USER@example.com" && \ + git config --global user.name "$USERNAME" + +COPY . ./ +USER root +RUN chown -R docker:docker . + +USER docker +RUN nosetests From ef9c8f3e3301196c64ec74d219f47bafde01c17f Mon Sep 17 00:00:00 2001 From: Emanuel Angelo Date: Wed, 4 Oct 2017 22:33:55 +0100 Subject: [PATCH 254/366] 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. --- powerline_shell/segments/bzr.py | 7 +++++-- powerline_shell/segments/fossil.py | 7 +++++-- powerline_shell/segments/git.py | 7 +++++-- powerline_shell/segments/hg.py | 6 +++++- powerline_shell/utils.py | 7 ++++++- 5 files changed, 26 insertions(+), 8 deletions(-) diff --git a/powerline_shell/segments/bzr.py b/powerline_shell/segments/bzr.py index a6dc96cb..0a41f98c 100644 --- a/powerline_shell/segments/bzr.py +++ b/powerline_shell/segments/bzr.py @@ -73,6 +73,9 @@ def add_to_powerline(self): 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) diff --git a/powerline_shell/segments/fossil.py b/powerline_shell/segments/fossil.py index 3c464f99..bca0c881 100644 --- a/powerline_shell/segments/fossil.py +++ b/powerline_shell/segments/fossil.py @@ -74,6 +74,9 @@ def add_to_powerline(self): 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) diff --git a/powerline_shell/segments/git.py b/powerline_shell/segments/git.py index 72ef7a18..6ebc2288 100644 --- a/powerline_shell/segments/git.py +++ b/powerline_shell/segments/git.py @@ -98,6 +98,9 @@ def add_to_powerline(self): 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) diff --git a/powerline_shell/segments/hg.py b/powerline_shell/segments/hg.py index 6c6ac9b1..651eb4ce 100644 --- a/powerline_shell/segments/hg.py +++ b/powerline_shell/segments/hg.py @@ -72,5 +72,9 @@ def add_to_powerline(self): 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) diff --git a/powerline_shell/utils.py b/powerline_shell/utils.py index c99b08cc..4062ecf0 100644 --- a/powerline_shell/utils.py +++ b/powerline_shell/utils.py @@ -16,7 +16,12 @@ class RepoStats(object): 'staged': u'\u2714', 'changed': u'\u270E', 'new': u'\u2753', - 'conflicted': u'\u273C' + 'conflicted': u'\u273C', + 'git': u'\uE0A0', + 'hg': u'\u263F', + 'bzr': u'\u25C8', + 'fossil': u'\u24BB', # or 24D5, for lowercase 'f' + 'svn': u'\u2446' } def __init__(self, ahead=0, behind=0, new=0, changed=0, staged=0, conflicted=0): From 4942ad51e5564ba609eed32f9e52a65f2161fd9d Mon Sep 17 00:00:00 2001 From: Emanuel Angelo Date: Wed, 4 Oct 2017 22:36:11 +0100 Subject: [PATCH 255/366] Makes the svn segment a threaded one and makes it use the VCS symbol --- powerline_shell/segments/svn.py | 89 ++++++++++++++++++++++++--------- 1 file changed, 64 insertions(+), 25 deletions(-) diff --git a/powerline_shell/segments/svn.py b/powerline_shell/segments/svn.py index 995d04dc..49d99366 100644 --- a/powerline_shell/segments/svn.py +++ b/powerline_shell/segments/svn.py @@ -1,29 +1,68 @@ -import subprocess -from ..utils import BasicSegment, RepoStats +import subprocess, os +from ..utils import ThreadedSegment, 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 +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 svn_subprocess_env(): + return {"PATH": get_PATH()} + + +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 - 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) +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=svn_subprocess_env()) + except OSError: + # Popen will throw an OSError if svn is not found + return None + pdata = p.communicate() + if p.returncode != 0 or pdata[1][:22] == b'svn: warning: W155007:': + return None + status = _get_svn_status(pdata) + stats = parse_svn_stats(status) + return stats + + +class Segment(ThreadedSegment): + def run(self): + self.stats = 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 + if self.powerline.segment_conf("vcs", "show_symbol"): + symbol = RepoStats().symbols["svn"] + else: + symbol = "svn" + self.powerline.append(" " + symbol + " ", fg, bg) + self.stats.add_to_powerline(self.powerline) From dcfa23dedd23ebde88c3ae6d463893ff7a16430a Mon Sep 17 00:00:00 2001 From: Arun Allamsetty Date: Wed, 4 Oct 2017 16:07:44 -0600 Subject: [PATCH 256/366] Make travis use docker and update readme. --- .travis.yml | 9 ++++----- Dockerfile | 7 ++++--- README.md | 6 ++++-- test.sh | 4 ++++ 4 files changed, 16 insertions(+), 10 deletions(-) create mode 100755 test.sh diff --git a/.travis.yml b/.travis.yml index a587362b..db47f9ca 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,4 @@ -language: python -script: | - ./setup.py install - pip install -r requirements-dev.txt - nosetests +sudo: required +services: + - docker +script: ./test.sh diff --git a/Dockerfile b/Dockerfile index 994a3853..de5dc8e7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ MAINTAINER github.com/banga/powerline-shell ENV USER docker ENV USERNAME "Docker User" -# Create a 'docker' user because we might not want to run everything as 'root'. Use 9999 as the ID +# Create a 'docker' user because we do not want to run everything as 'root'. Use 9999 as the ID # to keep it specific and away from the IDs in the host system. RUN addgroup -g 9999 $USER && \ adduser -u 9999 -G $USER -g "$USERNAME" -s /bin/bash -D $USER @@ -33,7 +33,8 @@ RUN bzr whoami "$USERNAME <$USER@example.com>" && \ COPY . ./ USER root -RUN chown -R docker:docker . +RUN ./setup.py install && \ + chown -R docker:docker . USER docker -RUN nosetests +ENTRYPOINT ["/bin/sh"] diff --git a/README.md b/README.md index e3ae2280..479e220d 100644 --- a/README.md +++ b/README.md @@ -256,8 +256,10 @@ Make sure you introduce new default colors in `themes/default.py` for every new 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 `requirements-dev.txt`. +integration tests are both welcome. Run your tests by running the `test.sh` +script. It uses `docker` to manage dependencies and the environment. +Alternatively, you can run the `nosetests` command after installing the +requirements in `requirements-dev.txt`. ## Troubleshooting diff --git a/test.sh b/test.sh new file mode 100755 index 00000000..82151d36 --- /dev/null +++ b/test.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +docker build -t powerline-shell . +docker run --rm -it powerline-shell -c nosetests From b76f20d6bd31ba0d1450bf975d3c96aaa2e35ac1 Mon Sep 17 00:00:00 2001 From: Emanuel Angelo Date: Wed, 4 Oct 2017 23:22:38 +0100 Subject: [PATCH 257/366] Updates README.md with the latest VCS' segments modifications --- README.md | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index e3ae2280..9d86e4f1 100644 --- a/README.md +++ b/README.md @@ -42,19 +42,21 @@ 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 @@ -215,7 +217,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 `~/.powerline-shell.json` like: ``` { @@ -223,13 +225,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 @@ -240,6 +246,12 @@ The `hostname` segment provides one option: - `colorize`: If true, the hostname will be colorized based on a hash of itself. +The `vcs` variable has 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. + ### Contributing new types of segments The `powerline_shell/segments` directory contains python scripts which are From 51e5dd14c26d826e660b03090ddd73698f135152 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Thu, 5 Oct 2017 13:44:28 -0400 Subject: [PATCH 258/366] tcsh support Adds basic supported for tcsh in response to https://github.com/banga/powerline-shell/issues/299 --- README.md | 10 +++++++++- powerline_shell/__init__.py | 5 +++-- powerline_shell/segments/newline.py | 5 ++++- powerline_shell/segments/root.py | 1 + 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e3ae2280..f342e4ea 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # A Powerline style prompt for your shell A [Powerline](https://github.com/Lokaltog/vim-powerline) like prompt for Bash, -ZSH and Fish: +ZSH, Fish, and tcsh: ![MacVim+Solarized+Powerline+CtrlP](https://raw.github.com/banga/powerline-shell/master/bash-powerline-screenshot.png) @@ -132,6 +132,14 @@ function fish_prompt end ``` +### tcsh + +Add the following to your `.tcshrc`: + +``` +alias precmd 'set prompt="`powerline-shell --shell tcsh $?`"' +``` + ## Customization ### Config File diff --git a/powerline_shell/__init__.py b/powerline_shell/__init__.py index ec25c0df..53eed96a 100644 --- a/powerline_shell/__init__.py +++ b/powerline_shell/__init__.py @@ -63,7 +63,8 @@ class Powerline(object): } color_templates = { - 'bash': '\\[\\e%s\\]', + 'bash': r'\[\e%s\]', + 'tcsh': r'%%{\e%s%%}', 'zsh': '%%{%s%%}', 'bare': '%s', } @@ -159,7 +160,7 @@ def main(): 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']) + choices=['bash', 'tcsh', 'zsh', 'bare']) arg_parser.add_argument('prev_error', nargs='?', type=int, default=0, help='Error code returned by the last command') args = arg_parser.parse_args() diff --git a/powerline_shell/segments/newline.py b/powerline_shell/segments/newline.py index f25cb46b..d6c5e9f0 100644 --- a/powerline_shell/segments/newline.py +++ b/powerline_shell/segments/newline.py @@ -1,8 +1,11 @@ -from ..utils import BasicSegment +from ..utils import BasicSegment, warn class Segment(BasicSegment): def add_to_powerline(self): + if self.powerline.args.shell == "tcsh": + warn("newline segment not supported for tcsh (yet?)") + return self.powerline.append("\n", self.powerline.theme.RESET, self.powerline.theme.RESET, diff --git a/powerline_shell/segments/root.py b/powerline_shell/segments/root.py index 5b31c602..3590edc9 100644 --- a/powerline_shell/segments/root.py +++ b/powerline_shell/segments/root.py @@ -6,6 +6,7 @@ def add_to_powerline(self): powerline = self.powerline root_indicators = { 'bash': ' \\$ ', + 'tcsh': ' %# ', 'zsh': ' %# ', 'bare': ' $ ', } From 4d47ded4a98363c36780b86995ccd63c8f0e96de Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Fri, 6 Oct 2017 21:01:25 -0400 Subject: [PATCH 259/366] Changelog for tcsh --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1c76100..ce8234f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changes +Unreleased + +* tcsh support + 2017-09-30 (version 0.3.1) * Fix username segment's background color after "su" command From 538bd54fc7bfdc0478f368372794ab0523cf813f Mon Sep 17 00:00:00 2001 From: Emanuel Angelo Date: Sat, 7 Oct 2017 18:39:46 +0100 Subject: [PATCH 260/366] 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. --- powerline_shell/segments/svn.py | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/powerline_shell/segments/svn.py b/powerline_shell/segments/svn.py index 49d99366..e7053bfd 100644 --- a/powerline_shell/segments/svn.py +++ b/powerline_shell/segments/svn.py @@ -13,6 +13,16 @@ def svn_subprocess_env(): return {"PATH": get_PATH()} +def _get_svn_branch(): + p = subprocess.Popen(["svn", "info"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + env=svn_subprocess_env()) + working_dir_root_path = p.communicate()[0].decode("utf-8").splitlines()[1] + branch = os.path.basename(working_dir_root_path.split()[-1]) + return branch + + def parse_svn_stats(status): stats = RepoStats() for line in status: @@ -41,15 +51,16 @@ def build_stats(): return None pdata = p.communicate() if p.returncode != 0 or pdata[1][:22] == b'svn: warning: W155007:': - return None + return None, None status = _get_svn_status(pdata) stats = parse_svn_stats(status) - return stats + branch = _get_svn_branch() + return stats, branch class Segment(ThreadedSegment): def run(self): - self.stats = build_stats() + self.stats, self.branch = build_stats() def add_to_powerline(self): self.join() @@ -61,8 +72,8 @@ def add_to_powerline(self): bg = self.powerline.theme.REPO_DIRTY_BG fg = self.powerline.theme.REPO_DIRTY_FG if self.powerline.segment_conf("vcs", "show_symbol"): - symbol = RepoStats().symbols["svn"] + symbol = RepoStats().symbols["svn"] + " " else: - symbol = "svn" - self.powerline.append(" " + symbol + " ", fg, bg) + symbol = "" + self.powerline.append(" " + symbol + self.branch + " ", fg, bg) self.stats.add_to_powerline(self.powerline) From 2bc9944f171d8d7aaaa49c0b070db9f1fdeee969 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Tue, 10 Oct 2017 15:45:58 -0400 Subject: [PATCH 261/366] version 0.4.0 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index aa93f9a6..9389b583 100755 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup(name="powerline-shell", - version="0.3.1", + version="0.4.0", description="A pretty prompt for your shell", author="Buck Ryan", url="https://github.com/banga/powerline-shell", From 850a33368d24d1dce749b56745fd5c4574489798 Mon Sep 17 00:00:00 2001 From: Arun Allamsetty Date: Wed, 11 Oct 2017 13:51:14 -0600 Subject: [PATCH 262/366] Use aa8y/core in Dockerfile to make it shorter. --- Dockerfile | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/Dockerfile b/Dockerfile index de5dc8e7..80f4cf81 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,15 +1,8 @@ -FROM python:2.7-alpine +FROM aa8y/core:python2 MAINTAINER github.com/banga/powerline-shell -ENV USER docker -ENV USERNAME "Docker User" - -# Create a 'docker' user because we do not want to run everything as 'root'. Use 9999 as the ID -# to keep it specific and away from the IDs in the host system. -RUN addgroup -g 9999 $USER && \ - adduser -u 9999 -G $USER -g "$USERNAME" -s /bin/bash -D $USER - +USER root RUN apk add --no-cache --update \ bzr \ fossil \ @@ -19,14 +12,14 @@ RUN apk add --no-cache --update \ subversion && \ rm -rf /var/cache/apk/* -RUN mkdir -p /usr/src/app -WORKDIR /usr/src/app - -# Cache the dev requirements. +# Cache the dev requirements. Directory is set in the base image. +WORKDIR $APP_DIR COPY requirements-dev.txt . -RUN pip install -r requirements-dev.txt +RUN pip install -r requirements-dev.txt && \ + rm -rf requirements-dev.txt -USER docker +# '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" @@ -34,7 +27,7 @@ RUN bzr whoami "$USERNAME <$USER@example.com>" && \ COPY . ./ USER root RUN ./setup.py install && \ - chown -R docker:docker . + chown -R $USER:$USER . -USER docker -ENTRYPOINT ["/bin/sh"] +USER $USER +ENTRYPOINT ["/bin/bash"] From d90ea14e40191610ec1031aa1c348663f7357aa3 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Mon, 16 Oct 2017 14:36:16 -0400 Subject: [PATCH 263/366] remove --user as recommended install method --- README.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f342e4ea..00637db9 100644 --- a/README.md +++ b/README.md @@ -73,14 +73,20 @@ setting your $TERM to `xterm-256color`, because that works for me. - Install using pip: ``` -pip install --user powerline-shell +pip install powerline-shell ``` -PS: If you want to install powerline-shell for all users simply omit the `--user` flag +(*You can use the +[`--user`](https://pip.pypa.io/en/stable/user_guide/#user-installs) option to +install for just your user, if you'd like. But you may need to fiddle with your +`PATH` to get this working properly.*) + +- Or, install from the git repository: -- Install using the git version: ``` -python setup.py install --user +git clone https://github.com/banga/powerline-shell +cd powerline-shell +python setup.py install ``` - Setup your shell prompt using the instructions for your shell below. From f896fe1cc46a02088149b1c9188dca7b789f56f7 Mon Sep 17 00:00:00 2001 From: Theodore Dubois Date: Mon, 16 Oct 2017 11:46:10 -0700 Subject: [PATCH 264/366] Normalize $HOME --- powerline_shell/segments/cwd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerline_shell/segments/cwd.py b/powerline_shell/segments/cwd.py index f99eb13f..2fd639c9 100644 --- a/powerline_shell/segments/cwd.py +++ b/powerline_shell/segments/cwd.py @@ -6,7 +6,7 @@ def replace_home_dir(cwd): - home = os.getenv('HOME') + home = os.path.realpath(os.getenv('HOME')) if cwd.startswith(home): return '~' + cwd[len(home):] return cwd From 7d12565b258c45ec43fe7ec28f786a76e886ba48 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Mon, 16 Oct 2017 14:55:09 -0400 Subject: [PATCH 265/366] changelog for #309 --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce8234f4..af91fddc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # Changes -Unreleased +2017-10-16 (version 0.4.1) + +* Fix cwd bug when `$HOME` ends in a slash + ([@tbodt](https://github.com/banga/powerline-shell/pull/309)) + +2017-10-06 (version 0.4.0) * tcsh support From 3a73836863e19d8ca01d6eed2f2cd86bcfa6cc6a Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Mon, 16 Oct 2017 15:02:26 -0400 Subject: [PATCH 266/366] docker tests changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index af91fddc..b3c2c9d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ * Fix cwd bug when `$HOME` ends in a slash ([@tbodt](https://github.com/banga/powerline-shell/pull/309)) +* Use docker to run tests + ([@aa8y](https://github.com/banga/powerline-shell/pull/297)) 2017-10-06 (version 0.4.0) From d54dd499c5bf281d949605f0aad86fd6cd34ac2c Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Mon, 16 Oct 2017 15:02:56 -0400 Subject: [PATCH 267/366] version 0.4.1 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 9389b583..ea25fe7c 100755 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup(name="powerline-shell", - version="0.4.0", + version="0.4.1", description="A pretty prompt for your shell", author="Buck Ryan", url="https://github.com/banga/powerline-shell", From 3644bd16b21d254d5516deeb02507a5d22ea1489 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Mon, 16 Oct 2017 18:08:00 -0400 Subject: [PATCH 268/366] Remove unused code from battery segment --- powerline_shell/segments/battery.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/powerline_shell/segments/battery.py b/powerline_shell/segments/battery.py index d9acd417..5b1fc575 100644 --- a/powerline_shell/segments/battery.py +++ b/powerline_shell/segments/battery.py @@ -2,14 +2,12 @@ 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): + # See discussion in https://github.com/banga/powerline-shell/pull/204 + # regarding the directory where battery info is saved if os.path.exists("/sys/class/power_supply/BAT0"): dir_ = "/sys/class/power_supply/BAT0" elif os.path.exists("/sys/class/power_supply/BAT1"): From f9d95e65200151622b39dc954bbf13b5c1821a37 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Mon, 16 Oct 2017 18:09:21 -0400 Subject: [PATCH 269/366] Change repo new file symbol to ? Fixes #300 --- powerline_shell/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerline_shell/utils.py b/powerline_shell/utils.py index c99b08cc..34151453 100644 --- a/powerline_shell/utils.py +++ b/powerline_shell/utils.py @@ -15,7 +15,7 @@ class RepoStats(object): 'behind': u'\u2B07', 'staged': u'\u2714', 'changed': u'\u270E', - 'new': u'\u2753', + 'new': u'?', 'conflicted': u'\u273C' } From 2f584024640aa8e519291955977d4cfec7e4d841 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Mon, 16 Oct 2017 18:10:44 -0400 Subject: [PATCH 270/366] prepare 0.4.2 --- CHANGELOG.md | 4 ++++ setup.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3c2c9d0..c6c4afd8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changes +2017-10-16 (version 0.4.2) + +* VCS segments will use ASCII `?` instead of a unicode symbol for new files. + 2017-10-16 (version 0.4.1) * Fix cwd bug when `$HOME` ends in a slash diff --git a/setup.py b/setup.py index ea25fe7c..5250878e 100755 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup(name="powerline-shell", - version="0.4.1", + version="0.4.2", description="A pretty prompt for your shell", author="Buck Ryan", url="https://github.com/banga/powerline-shell", From 21cfded8aa2892812dda9a633afb261e4a01d9e3 Mon Sep 17 00:00:00 2001 From: Karthik Date: Tue, 17 Oct 2017 15:43:56 +0530 Subject: [PATCH 271/366] 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. --- powerline_shell/segments/virtual_env.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/powerline_shell/segments/virtual_env.py b/powerline_shell/segments/virtual_env.py index ffbefec6..b7821098 100644 --- a/powerline_shell/segments/virtual_env.py +++ b/powerline_shell/segments/virtual_env.py @@ -7,6 +7,9 @@ def add_to_powerline(self): 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) From 3bc516f64d05c0a8330b8ce66e860470859237e6 Mon Sep 17 00:00:00 2001 From: Thomas Cherry Date: Tue, 17 Oct 2017 22:23:19 -0400 Subject: [PATCH 272/366] new config to not shrink the current directory, only the path --- README.md | 1 + powerline_shell/segments/cwd.py | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9afd3551..f93aa0a4 100644 --- a/README.md +++ b/README.md @@ -248,6 +248,7 @@ The options for the `cwd` segment are: - `max_depth`: Maximum number of directories to show in path - `max_dir_size`: Maximum number of characters displayed for each directory in the path +- `last_max_dir_size`: Maximum number of characters displayed for the last path element. Defaults to `max_dir_size`. -1 means all characters. The `hostname` segment provides one option: diff --git a/powerline_shell/segments/cwd.py b/powerline_shell/segments/cwd.py index 2fd639c9..46f77ef6 100644 --- a/powerline_shell/segments/cwd.py +++ b/powerline_shell/segments/cwd.py @@ -64,6 +64,8 @@ def add_cwd_segment(powerline): names = split_path_into_names(cwd) + max_size = powerline.segment_conf("cwd", "max_dir_size") + last_max_size = powerline.segment_conf("cwd", "last_max_dir_size", max_size) max_depth = powerline.segment_conf("cwd", "max_depth", 5) if max_depth <= 0: warn("Ignoring cwd.max_depth option since it's not greater than 0") @@ -92,10 +94,18 @@ def add_cwd_segment(powerline): 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) - + + formated_name = "" + + # if last_max_size is below 0 then assume full name + if is_last_dir: + if last_max_size < 0: + formated_name = name + elif last_max_size >= 0: #yes, 0 is valid + formated_name = name[:last_max_size] + else: + formated_name = maybe_shorten_name(powerline, name) + powerline.append(' %s '%formated_name, fg, bg, separator, separator_fg) class Segment(BasicSegment): def add_to_powerline(self): From c599e7c34d8f54911dacbdbeb8a1cd445a167819 Mon Sep 17 00:00:00 2001 From: Thomas Cherry Date: Thu, 19 Oct 2017 06:42:22 -0400 Subject: [PATCH 273/366] making the config settings more human friendly --- powerline_shell/segments/cwd.py | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/powerline_shell/segments/cwd.py b/powerline_shell/segments/cwd.py index 46f77ef6..9ca0ba22 100644 --- a/powerline_shell/segments/cwd.py +++ b/powerline_shell/segments/cwd.py @@ -34,7 +34,9 @@ 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.""" + max_size = powerline.segment_conf("cwd", "max_dir_size") + if max_size: return name[:max_size] return name @@ -51,6 +53,31 @@ def get_fg_bg(powerline, name, is_last_dir): else: return (powerline.theme.PATH_FG, powerline.theme.PATH_BG,) +def conf_last_max_dir_size(powerline, default): + ''' + last_max_dir_size can be all, full, none, empty, one, or a positive number + all,full returns -1 ; none,empty returns 0 ; one returns 1 + default accepts a default value which is used if no valid value is configured + Returns -1 for full size or length of the last max dir size from the settings + ''' + last_max_size = default + raw = powerline.segment_conf("cwd", "last_max_dir_size", default) + if isinstance(raw, str): + raw = raw.lower() + if raw is None or raw=="": + pass + elif raw=="all" or raw=="full": + last_max_size = -1 + elif raw=="none" or raw=="empty": + last_max_size = 0 + elif raw=="one": + last_max_size = 1 + else: + try: + last_max_size = int(raw) + except ValueError: + warn("'%s' is not a valid number for cwd.last_max_dir_size, using %s." % (raw, last_max_size)) + return last_max_size def add_cwd_segment(powerline): cwd = powerline.cwd or os.getenv('PWD') @@ -65,7 +92,8 @@ def add_cwd_segment(powerline): names = split_path_into_names(cwd) max_size = powerline.segment_conf("cwd", "max_dir_size") - last_max_size = powerline.segment_conf("cwd", "last_max_dir_size", max_size) + #last_max_size = powerline.segment_conf("cwd", "last_max_dir_size", max_size) + last_max_size = conf_last_max_dir_size(powerline, max_size) max_depth = powerline.segment_conf("cwd", "max_depth", 5) if max_depth <= 0: warn("Ignoring cwd.max_depth option since it's not greater than 0") From 28ef36a35535e7c3477d47479ac7aef44fd3d0cd Mon Sep 17 00:00:00 2001 From: Patrick Fasano Date: Fri, 20 Oct 2017 14:23:57 -0400 Subject: [PATCH 274/366] battery: Add AC icon and low_battery_threshold config * When fully charged on AC, show plug character (U+1F50C). * Add config option to show percentage even if fully charged on AC. * Add config option to set low battery threshold. --- README.md | 5 +++++ powerline_shell/segments/battery.py | 18 ++++++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 9afd3551..34453a95 100644 --- a/README.md +++ b/README.md @@ -254,6 +254,11 @@ The `hostname` segment provides one option: - `colorize`: If true, the hostname will be colorized based on a hash of itself. +The options for the `battery` segment are: + +- `always_show_percentage`: If true, show percentage when fully charged on AC. +- `low_battery_threshold`: Threshold percentage for low-battery indicator color. + ### Contributing new types of segments The `powerline_shell/segments` directory contains python scripts which are diff --git a/powerline_shell/segments/battery.py b/powerline_shell/segments/battery.py index 5b1fc575..f6207045 100644 --- a/powerline_shell/segments/battery.py +++ b/powerline_shell/segments/battery.py @@ -1,8 +1,6 @@ from ..utils import BasicSegment, warn import os -LOW_BATTERY_THRESHOLD = 20 - class Segment(BasicSegment): def add_to_powerline(self): @@ -16,14 +14,22 @@ def add_to_powerline(self): warn("battery directory could not be found") return with open(os.path.join(dir_, "capacity")) as f: - cap = f.read().strip() + cap = int(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: + if status == "Full": + if self.powerline.segment_conf("battery", "always_show_percentage", False): + pwr_fmt = u" {cap:d}% \U0001F50C " + else: + pwr_fmt = u" \U0001F50C " + elif status == "Charging": + pwr_fmt = u" {cap:d}% \u26A1 " + else: + pwr_fmt = " {cap:d}% " + if cap < self.powerline.segment_conf("battery", "low_battery_threshold", 20): 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) + self.powerline.append(pwr_fmt.format(cap=cap), fg, bg) From dee6ef0dedf0e7f78a81583915372559ede5c852 Mon Sep 17 00:00:00 2001 From: Emanuel Angelo Date: Thu, 26 Oct 2017 01:53:03 +0100 Subject: [PATCH 275/366] Applied symbols `\u2B61\u20DF` and `\u2332` for bzr and fossil, respectively --- powerline_shell/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/powerline_shell/utils.py b/powerline_shell/utils.py index 2445f0de..aea7754e 100644 --- a/powerline_shell/utils.py +++ b/powerline_shell/utils.py @@ -19,8 +19,8 @@ class RepoStats(object): 'conflicted': u'\u273C', 'git': u'\uE0A0', 'hg': u'\u263F', - 'bzr': u'\u25C8', - 'fossil': u'\u24BB', # or 24D5, for lowercase 'f' + 'bzr': u'\u2B61\u20DF', + 'fossil': u'\u2332', 'svn': u'\u2446' } From 006be7777f0f8a340e5748b4fd78642368af0414 Mon Sep 17 00:00:00 2001 From: Thomas Cherry Date: Thu, 2 Nov 2017 22:46:56 -0400 Subject: [PATCH 276/366] got this to work with fish --- powerline_shell/segments/jobs.py | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/powerline_shell/segments/jobs.py b/powerline_shell/segments/jobs.py index e5d0551d..e15be835 100644 --- a/powerline_shell/segments/jobs.py +++ b/powerline_shell/segments/jobs.py @@ -6,6 +6,20 @@ class Segment(ThreadedSegment): + + def pidInfo(self, pid, tag): + ''' + run a ps and get some data from it + pid process to query + tag -o property in the ps command to query for + return the value from ps + ''' + ppid = str(pid) + proc = subprocess.Popen(['ps', '-p', ppid, '-o%s=' % tag], + stdout=subprocess.PIPE) + info = proc.communicate()[0].decode("utf-8").strip() + return info + def run(self): self.num_jobs = 0 if platform.system().startswith('CYGWIN'): @@ -15,14 +29,19 @@ def run(self): 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) + pcmd = self.pidInfo(os.getppid(), "command") + + pppid = self.pidInfo(os.getppid(), "ppid") + + #fish runs commands in a sub process, so you have to walk up the + # tree one time to get back to where you were with bash or other + # such shells + if pcmd=="fish": + pppid = self.pidInfo(pppid, "ppid") + + 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: From eb0f462717b739fd0f3b68c5b24238d150bf948d Mon Sep 17 00:00:00 2001 From: Thomas Cherry Date: Fri, 3 Nov 2017 22:07:05 -0400 Subject: [PATCH 277/366] adding a way to force fish mode for testing and to be more explicit --- powerline_shell/__init__.py | 3 ++- powerline_shell/segments/jobs.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/powerline_shell/__init__.py b/powerline_shell/__init__.py index 53eed96a..ec48f9c1 100644 --- a/powerline_shell/__init__.py +++ b/powerline_shell/__init__.py @@ -64,6 +64,7 @@ class Powerline(object): color_templates = { 'bash': r'\[\e%s\]', + 'fish': '%s', 'tcsh': r'%%{\e%s%%}', 'zsh': '%%{%s%%}', 'bare': '%s', @@ -160,7 +161,7 @@ def main(): 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', 'tcsh', 'zsh', 'bare']) + choices=['bash', "fish", 'tcsh', 'zsh', 'bare']) arg_parser.add_argument('prev_error', nargs='?', type=int, default=0, help='Error code returned by the last command') args = arg_parser.parse_args() diff --git a/powerline_shell/segments/jobs.py b/powerline_shell/segments/jobs.py index e15be835..1b378670 100644 --- a/powerline_shell/segments/jobs.py +++ b/powerline_shell/segments/jobs.py @@ -36,7 +36,7 @@ def run(self): #fish runs commands in a sub process, so you have to walk up the # tree one time to get back to where you were with bash or other # such shells - if pcmd=="fish": + if pcmd=="fish" or self.powerline.args.shell=="fish": pppid = self.pidInfo(pppid, "ppid") output_proc = subprocess.Popen(['ps', '-a', '-o', 'ppid'], stdout=subprocess.PIPE) From b601d52a3d793c4bf064c563d52867aab07c46bb Mon Sep 17 00:00:00 2001 From: Thomas Cherry Date: Mon, 6 Nov 2017 21:46:28 -0500 Subject: [PATCH 278/366] making things very simple --- powerline_shell/segments/cwd.py | 47 ++++----------------------------- 1 file changed, 5 insertions(+), 42 deletions(-) diff --git a/powerline_shell/segments/cwd.py b/powerline_shell/segments/cwd.py index 9ca0ba22..373fb6e7 100644 --- a/powerline_shell/segments/cwd.py +++ b/powerline_shell/segments/cwd.py @@ -34,9 +34,7 @@ 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.""" - max_size = powerline.segment_conf("cwd", "max_dir_size") - if max_size: return name[:max_size] return name @@ -53,31 +51,6 @@ def get_fg_bg(powerline, name, is_last_dir): else: return (powerline.theme.PATH_FG, powerline.theme.PATH_BG,) -def conf_last_max_dir_size(powerline, default): - ''' - last_max_dir_size can be all, full, none, empty, one, or a positive number - all,full returns -1 ; none,empty returns 0 ; one returns 1 - default accepts a default value which is used if no valid value is configured - Returns -1 for full size or length of the last max dir size from the settings - ''' - last_max_size = default - raw = powerline.segment_conf("cwd", "last_max_dir_size", default) - if isinstance(raw, str): - raw = raw.lower() - if raw is None or raw=="": - pass - elif raw=="all" or raw=="full": - last_max_size = -1 - elif raw=="none" or raw=="empty": - last_max_size = 0 - elif raw=="one": - last_max_size = 1 - else: - try: - last_max_size = int(raw) - except ValueError: - warn("'%s' is not a valid number for cwd.last_max_dir_size, using %s." % (raw, last_max_size)) - return last_max_size def add_cwd_segment(powerline): cwd = powerline.cwd or os.getenv('PWD') @@ -91,9 +64,7 @@ def add_cwd_segment(powerline): names = split_path_into_names(cwd) - max_size = powerline.segment_conf("cwd", "max_dir_size") - #last_max_size = powerline.segment_conf("cwd", "last_max_dir_size", max_size) - last_max_size = conf_last_max_dir_size(powerline, max_size) + full_cwd = powerline.segment_conf("cwd", "full_cwd", False) max_depth = powerline.segment_conf("cwd", "max_depth", 5) if max_depth <= 0: warn("Ignoring cwd.max_depth option since it's not greater than 0") @@ -122,18 +93,10 @@ def add_cwd_segment(powerline): if requires_special_home_display(powerline, name) or is_last_dir: separator = None separator_fg = None - - formated_name = "" - - # if last_max_size is below 0 then assume full name - if is_last_dir: - if last_max_size < 0: - formated_name = name - elif last_max_size >= 0: #yes, 0 is valid - formated_name = name[:last_max_size] - else: - formated_name = maybe_shorten_name(powerline, name) - powerline.append(' %s '%formated_name, fg, bg, separator, separator_fg) + + if not (is_last_dir and full_cwd): + name = maybe_shorten_name(powerline, name) + powerline.append(' %s ' % name, fg, bg, separator, separator_fg) class Segment(BasicSegment): def add_to_powerline(self): From 8d33e5542e998a4e95eb103381e2643254254bd5 Mon Sep 17 00:00:00 2001 From: mikewaters Date: Fri, 10 Nov 2017 12:03:10 -0500 Subject: [PATCH 279/366] Added a note about theme color codes. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9afd3551..137e46fe 100644 --- a/README.md +++ b/README.md @@ -223,7 +223,7 @@ 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. +settings. Theme colors are specified using [Xterm-256 color codes](https://jonasjacek.github.io/colors/). ### Segment Configuration From 5a9f199e07a4ab9b4f5efcbba6e333b9adc20565 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 25 Nov 2017 17:48:03 -0500 Subject: [PATCH 280/366] prepare 0.4.3 --- CHANGELOG.md | 6 ++++++ README.md | 3 ++- setup.py | 37 +++++++++++++++++++------------------ 3 files changed, 27 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6c4afd8..dd0f4e6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changes +2017-11-25 (version 0.4.3) + +* New option for `cwd` segment that allows the last directory to not be + shortened when `max_dir_size` is used + ([@jceaser](https://github.com/banga/powerline-shell/pull/321)). + 2017-10-16 (version 0.4.2) * VCS segments will use ASCII `?` instead of a unicode symbol for new files. diff --git a/README.md b/README.md index f93aa0a4..e7b426e3 100644 --- a/README.md +++ b/README.md @@ -248,7 +248,8 @@ The options for the `cwd` segment are: - `max_depth`: Maximum number of directories to show in path - `max_dir_size`: Maximum number of characters displayed for each directory in the path -- `last_max_dir_size`: Maximum number of characters displayed for the last path element. Defaults to `max_dir_size`. -1 means all characters. +- `full_cwd`: If true, the last directory will not be shortened when + `max_dir_size` is used. The `hostname` segment provides one option: diff --git a/setup.py b/setup.py index 5250878e..3b01dfd1 100755 --- a/setup.py +++ b/setup.py @@ -1,22 +1,23 @@ #!/usr/bin/env python from setuptools import setup, find_packages -setup(name="powerline-shell", - version="0.4.2", - 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 - """, +setup( + name="powerline-shell", + version="0.4.3", + 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 + """, ) From a4f0674bec4c07d57000361dfb91a7eb6b1c6658 Mon Sep 17 00:00:00 2001 From: Patrick Fasano Date: Sat, 25 Nov 2017 21:09:23 -0500 Subject: [PATCH 281/366] battery: Rename low_battery_threshold to low_threshold --- powerline_shell/segments/battery.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/powerline_shell/segments/battery.py b/powerline_shell/segments/battery.py index f6207045..24c5f1f5 100644 --- a/powerline_shell/segments/battery.py +++ b/powerline_shell/segments/battery.py @@ -13,6 +13,7 @@ def add_to_powerline(self): else: warn("battery directory could not be found") return + with open(os.path.join(dir_, "capacity")) as f: cap = int(f.read().strip()) with open(os.path.join(dir_, "status")) as f: @@ -26,7 +27,8 @@ def add_to_powerline(self): pwr_fmt = u" {cap:d}% \u26A1 " else: pwr_fmt = " {cap:d}% " - if cap < self.powerline.segment_conf("battery", "low_battery_threshold", 20): + + if cap < self.powerline.segment_conf("battery", "low_threshold", 20): bg = self.powerline.theme.BATTERY_LOW_BG fg = self.powerline.theme.BATTERY_LOW_FG else: From 6d99af1564bd3942e34a2f3a4c2434b74f549b9e Mon Sep 17 00:00:00 2001 From: Patrick Fasano Date: Sat, 25 Nov 2017 21:14:14 -0500 Subject: [PATCH 282/366] battery: Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0caa541a..44273a1d 100644 --- a/README.md +++ b/README.md @@ -259,7 +259,7 @@ The `hostname` segment provides one option: The options for the `battery` segment are: - `always_show_percentage`: If true, show percentage when fully charged on AC. -- `low_battery_threshold`: Threshold percentage for low-battery indicator color. +- `low_threshold`: Threshold percentage for low-battery indicator color. ### Contributing new types of segments From 7679889a797f9f2f6cb18b58e5d86dcbeee48c54 Mon Sep 17 00:00:00 2001 From: Patrick Fasano Date: Fri, 20 Oct 2017 19:00:33 -0400 Subject: [PATCH 283/366] svn: Update segment to ThreadedSegment --- powerline_shell/segments/svn.py | 56 +++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/powerline_shell/segments/svn.py b/powerline_shell/segments/svn.py index 995d04dc..4ffa7ee6 100644 --- a/powerline_shell/segments/svn.py +++ b/powerline_shell/segments/svn.py @@ -1,29 +1,51 @@ import subprocess -from ..utils import BasicSegment, RepoStats +from ..utils import ThreadedSegment, 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 +class Segment(ThreadedSegment): + def __init__(self, powerline): + super().__init__(powerline) + self.stats = None + self.revision = "" + def run(self): try: - p1 = subprocess.Popen(["svn", "status"], stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + 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 - stdout = p1.communicate()[0] - stats = RepoStats() - for line in stdout.splitlines(): + 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] == "?": - stats.new += 1 + self.stats.new += 1 elif line[0] == "C": - stats.conflicted += 1 + self.stats.conflicted += 1 elif line[0] in ["A", "D", "I", "M", "R", "!", "~"]: - stats.changed += 1 + self.stats.changed += 1 + + for line in svn_info.splitlines(): + line = line.decode("utf-8").strip() + if "Revision: " in line: + self.revision = line.split(" ", maxsplit=1)[1] + + 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 - stats.add_to_powerline(self.powerline) + self.powerline.append(" rev " + self.revision + " ", fg, bg) + self.stats.add_to_powerline(self.powerline) From e6c730c7baea42bb73148593d975282c4afacc0c Mon Sep 17 00:00:00 2001 From: Patrick Fasano Date: Sat, 25 Nov 2017 21:40:19 -0500 Subject: [PATCH 284/366] config: Support config in $XDG_CONFIG_HOME --- README.md | 3 ++- powerline_shell/__init__.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e7b426e3..c88b0ada 100644 --- a/README.md +++ b/README.md @@ -151,7 +151,8 @@ 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 +expected to be located at `~/.powerline-shell.json` or +`$XDG_CONFIG_HOME/powerline-shell/config.json`. You can generate the default config at this location using: ``` diff --git a/powerline_shell/__init__.py b/powerline_shell/__init__.py index 53eed96a..cf6a00ce 100644 --- a/powerline_shell/__init__.py +++ b/powerline_shell/__init__.py @@ -134,6 +134,7 @@ def find_config(): for location in [ "powerline-shell.json", "~/.powerline-shell.json", + os.path.join(os.environ.get("XDG_CONFIG_HOME", ""), "powerline-shell", "config.json"), ]: full = os.path.expanduser(location) if os.path.exists(full): From 2fba29ee22fed9d587c5a3e375bd8093f54942d0 Mon Sep 17 00:00:00 2001 From: Patrick Fasano Date: Mon, 27 Nov 2017 14:06:45 -0500 Subject: [PATCH 285/366] svn: Use Python 2-style super() call --- powerline_shell/segments/svn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerline_shell/segments/svn.py b/powerline_shell/segments/svn.py index 4ffa7ee6..67d568dc 100644 --- a/powerline_shell/segments/svn.py +++ b/powerline_shell/segments/svn.py @@ -4,7 +4,7 @@ class Segment(ThreadedSegment): def __init__(self, powerline): - super().__init__(powerline) + super(Segment, self).__init__(powerline) self.stats = None self.revision = "" From 88e3d6bcf8f30bcd14dbf36a3cebb2ce9fb92d63 Mon Sep 17 00:00:00 2001 From: Patrick Fasano Date: Tue, 28 Nov 2017 18:18:46 -0500 Subject: [PATCH 286/366] config: Use ~/.config as default for --- powerline_shell/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerline_shell/__init__.py b/powerline_shell/__init__.py index cf6a00ce..db9f7125 100644 --- a/powerline_shell/__init__.py +++ b/powerline_shell/__init__.py @@ -134,7 +134,7 @@ def find_config(): for location in [ "powerline-shell.json", "~/.powerline-shell.json", - os.path.join(os.environ.get("XDG_CONFIG_HOME", ""), "powerline-shell", "config.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): From c5a80667b95bdee5e1da76c30111e5030ed6c8ab Mon Sep 17 00:00:00 2001 From: Michael Stensby Date: Wed, 29 Nov 2017 15:42:49 -0700 Subject: [PATCH 287/366] Fix typos and inconsistent formatting in readme --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 44273a1d..240b3da1 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ quick look into the state of your repo: branch is dirty. - 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 + or pull is pending. In addition, git has a few extra symbols: @@ -68,7 +68,7 @@ setting your $TERM to `xterm-256color`, because that works for me. - 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 + your copy. - Install using pip: @@ -176,7 +176,7 @@ are: - `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. + 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. @@ -185,7 +185,7 @@ are: - `newline` - Inserts a newline into the prompt. - `node_version` - `node --version` - `npm_version` - `npm --version` -- `php_version` - Version of php on the machine +- `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. @@ -194,9 +194,9 @@ are: 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 +- `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 @@ -205,7 +205,7 @@ 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 +- `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 @@ -245,9 +245,9 @@ 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_depth`: Maximum number of directories to show in path. - `max_dir_size`: Maximum number of characters displayed for each directory in - the path + the path. - `full_cwd`: If true, the last directory will not be shortened when `max_dir_size` is used. From fba09ed096a6988df1e4e3faf4b2f123720d6144 Mon Sep 17 00:00:00 2001 From: ericLemanissier Date: Mon, 11 Dec 2017 12:44:47 +0100 Subject: [PATCH 288/366] fix package missing in cygwin resolves #323 --- powerline_shell/segments/username.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/powerline_shell/segments/username.py b/powerline_shell/segments/username.py index 9e4d9d8d..08f1ae7e 100644 --- a/powerline_shell/segments/username.py +++ b/powerline_shell/segments/username.py @@ -1,6 +1,10 @@ from ..utils import BasicSegment import os -import pwd +try: + import pwd +except ImportError: + pwd = None + import getpass class Segment(BasicSegment): @@ -13,7 +17,12 @@ def add_to_powerline(self): else: user_prompt = " %s " % os.getenv("USER") - if pwd.getpwuid(os.getuid())[0] == "root": + if pwd: + user_name = pwd.getpwuid(os.getuid())[0] + else: + user_name = getpass.getuser() + + if user_name == "root": bgcolor = powerline.theme.USERNAME_ROOT_BG else: bgcolor = powerline.theme.USERNAME_BG From 1809074a237bfc3aed2ea9d7379714694fb6e811 Mon Sep 17 00:00:00 2001 From: ericLemanissier Date: Tue, 19 Dec 2017 09:45:10 +0100 Subject: [PATCH 289/366] always using getpass package to get user --- powerline_shell/segments/username.py | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/powerline_shell/segments/username.py b/powerline_shell/segments/username.py index 08f1ae7e..b2803522 100644 --- a/powerline_shell/segments/username.py +++ b/powerline_shell/segments/username.py @@ -1,10 +1,6 @@ from ..utils import BasicSegment import os -try: - import pwd -except ImportError: - pwd = None - import getpass +import getpass class Segment(BasicSegment): @@ -16,13 +12,8 @@ def add_to_powerline(self): user_prompt = " %n " else: user_prompt = " %s " % os.getenv("USER") - - if pwd: - user_name = pwd.getpwuid(os.getuid())[0] - else: - user_name = getpass.getuser() - if user_name == "root": + if getpass.getuser() == "root": bgcolor = powerline.theme.USERNAME_ROOT_BG else: bgcolor = powerline.theme.USERNAME_BG From 40f54515c0bc7c330ca2e6d8b6484bb3c9659b9e Mon Sep 17 00:00:00 2001 From: ericLemanissier Date: Tue, 19 Dec 2017 09:45:57 +0100 Subject: [PATCH 290/366] space formatting --- powerline_shell/segments/username.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerline_shell/segments/username.py b/powerline_shell/segments/username.py index b2803522..f351afcc 100644 --- a/powerline_shell/segments/username.py +++ b/powerline_shell/segments/username.py @@ -12,7 +12,7 @@ def add_to_powerline(self): user_prompt = " %n " else: user_prompt = " %s " % os.getenv("USER") - + if getpass.getuser() == "root": bgcolor = powerline.theme.USERNAME_ROOT_BG else: From 6ddc482c1378896600369e8b070cc1a1259ebe71 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Tue, 19 Dec 2017 11:27:31 -0500 Subject: [PATCH 291/366] prepare 0.4.4 --- CHANGELOG.md | 9 +++++++++ setup.py | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd0f4e6f..dd44009b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changes +2017-12-19 (version 0.4.4) + +* New options and symbol for the `battery` segment + ([@kc9jud](https://github.com/b-ryan/powerline-shell/pull/332)) +* Update `svn` segment to use threads + ([@kc9jud](https://github.com/b-ryan/powerline-shell/pull/333)) +* Fix `username` segment in cygwin + ([@ericLemanissier](https://github.com/b-ryan/powerline-shell/commits/master)) + 2017-11-25 (version 0.4.3) * New option for `cwd` segment that allows the last directory to not be diff --git a/setup.py b/setup.py index 3b01dfd1..2e0b5f69 100755 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name="powerline-shell", - version="0.4.3", + version="0.4.4", description="A pretty prompt for your shell", author="Buck Ryan", url="https://github.com/banga/powerline-shell", From 62ffb74fd68722832ec3745e3dfe7054bbbca702 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Wed, 20 Dec 2017 12:14:54 -0500 Subject: [PATCH 292/366] Fix handling of CWD on Bash for Windows Fixes https://github.com/b-ryan/powerline-shell/issues/339 See comments for explanation --- powerline_shell/__init__.py | 36 +++++++++++++++++++++++---------- powerline_shell/segments/cwd.py | 2 +- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/powerline_shell/__init__.py b/powerline_shell/__init__.py index 53eed96a..84342852 100644 --- a/powerline_shell/__init__.py +++ b/powerline_shell/__init__.py @@ -10,18 +10,32 @@ import re +def _current_dir(): + """Returns the full current working directory as the user would have used + in their shell (ie. without following symbolic links). + + With the introduction of Bash for Windows, we can't use the PWD environment + variable very easily. `os.sep` for windows is `\` but the PWD variable will + use `/`. So just always use the `os` functions for dealing with paths. This + also is fine because the use of PWD below is done to avoid following + symlinks, which Windows doesn't have. + + For non-Windows systems, prefer the PWD environment variable. Python's + `os.getcwd` function follows symbolic links, which is undesirable.""" + if os.name == "nt": + return os.getcwd() + return os.getenv("PWD") or os.getcwd() + + def get_valid_cwd(): - """ We check if the current working directory is valid or not. Typically - happens when you checkout a different branch on git that doesn't have - this directory. - We return the original cwd because the shell still considers that to be - the working directory, so returning our guess will confuse people - """ - # Prefer the PWD environment variable. Python's os.getcwd function follows - # symbolic links, which is undesirable. But if PWD is not set then fall - # back to this func + """Determine and check the current working directory for validity. + + Typically, an directory arises when you checkout a different branch on git + that doesn't have this directory. When an invalid directory is found, a + warning is printed to the screen, but the directory is still returned + as-is, since this is what the shell considers to be the cwd.""" try: - cwd = os.getenv('PWD') or os.getcwd() + cwd = _current_dir() except: warn("Your current directory is invalid. If you open a ticket at " + "https://github.com/milkbikis/powerline-shell/issues/new " + @@ -36,7 +50,7 @@ def get_valid_cwd(): up = os.sep.join(parts) if cwd != up: warn("Your current directory is invalid. Lowest valid directory: " - + up) + + up) return cwd diff --git a/powerline_shell/segments/cwd.py b/powerline_shell/segments/cwd.py index 373fb6e7..c8717335 100644 --- a/powerline_shell/segments/cwd.py +++ b/powerline_shell/segments/cwd.py @@ -53,7 +53,7 @@ def get_fg_bg(powerline, name, is_last_dir): def add_cwd_segment(powerline): - cwd = powerline.cwd or os.getenv('PWD') + cwd = powerline.cwd if not py3: cwd = cwd.decode("utf-8") cwd = replace_home_dir(cwd) From d855683d1e54c7d37a76bb84be40d27aabba4644 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Wed, 20 Dec 2017 12:27:49 -0500 Subject: [PATCH 293/366] remove use of PWD in segments --- powerline_shell/segments/read_only.py | 3 +-- powerline_shell/segments/set_term_title.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/powerline_shell/segments/read_only.py b/powerline_shell/segments/read_only.py index 149b1136..c4fc60ea 100644 --- a/powerline_shell/segments/read_only.py +++ b/powerline_shell/segments/read_only.py @@ -5,8 +5,7 @@ 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): + if not os.access(powerline.cwd, os.W_OK): powerline.append(' %s ' % powerline.lock, powerline.theme.READONLY_FG, powerline.theme.READONLY_BG) diff --git a/powerline_shell/segments/set_term_title.py b/powerline_shell/segments/set_term_title.py index 97439591..fedc0773 100644 --- a/powerline_shell/segments/set_term_title.py +++ b/powerline_shell/segments/set_term_title.py @@ -17,6 +17,6 @@ def add_to_powerline(self): set_title = '\033]0;%s@%s: %s\007' % ( os.getenv('USER'), socket.gethostname().split('.')[0], - powerline.cwd or os.getenv('PWD'), + powerline.cwd, ) powerline.append(set_title, None, None, '') From 71cfe579fff1b1f1c3af255908ba18f8eaa4f50f Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Wed, 20 Dec 2017 12:47:27 -0500 Subject: [PATCH 294/366] prepare --- CHANGELOG.md | 5 +++++ setup.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd44009b..0abbea1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changes +2017-12-20 (version 0.4.5) + +* Fix `cwd` segment in Bash for Windows + ([@b-ryan](https://github.com/b-ryan/powerline-shell/pull/340)) + 2017-12-19 (version 0.4.4) * New options and symbol for the `battery` segment diff --git a/setup.py b/setup.py index 2e0b5f69..77666b59 100755 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name="powerline-shell", - version="0.4.4", + version="0.4.5", description="A pretty prompt for your shell", author="Buck Ryan", url="https://github.com/banga/powerline-shell", From 126f7006784f3619fd79ed0abf712f104c65fd5a Mon Sep 17 00:00:00 2001 From: Patrick Fasano Date: Thu, 11 Jan 2018 15:08:38 -0500 Subject: [PATCH 295/366] svn: Don't use kwarg for split() Fixes #344 --- powerline_shell/segments/svn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerline_shell/segments/svn.py b/powerline_shell/segments/svn.py index 67d568dc..c770e79a 100644 --- a/powerline_shell/segments/svn.py +++ b/powerline_shell/segments/svn.py @@ -35,7 +35,7 @@ def run(self): for line in svn_info.splitlines(): line = line.decode("utf-8").strip() if "Revision: " in line: - self.revision = line.split(" ", maxsplit=1)[1] + self.revision = line.split(" ", 1)[1] def add_to_powerline(self): self.join() From dfa784c810d842d090cd9c564ed5a8eb5314fc8f Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Thu, 11 Jan 2018 21:21:41 -0500 Subject: [PATCH 296/366] 0.4.6 --- CHANGELOG.md | 5 +++++ setup.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0abbea1b..ed529819 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changes +2018-01-11 (version 0.4.6) + +* Fix bug in SVN segment + ([@kc9jud](https://github.com/b-ryan/powerline-shell/pull/347)) + 2017-12-20 (version 0.4.5) * Fix `cwd` segment in Bash for Windows diff --git a/setup.py b/setup.py index 77666b59..fe96724a 100755 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name="powerline-shell", - version="0.4.5", + version="0.4.6", description="A pretty prompt for your shell", author="Buck Ryan", url="https://github.com/banga/powerline-shell", From f8649ee9850f701a845c50b181e5780473e5d645 Mon Sep 17 00:00:00 2001 From: Yuya Tanaka Date: Sat, 13 Jan 2018 19:27:15 +0900 Subject: [PATCH 297/366] Fix wrong filename in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 240b3da1..c278bcd8 100644 --- a/README.md +++ b/README.md @@ -229,7 +229,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 `~/.powerline-shell.json` like: ``` { From 4d4241fba069d045fd06f942caf787b944549b0a Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Mon, 15 Jan 2018 12:02:50 -0500 Subject: [PATCH 298/366] Add back SVN symbol --- powerline_shell/segments/svn.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/powerline_shell/segments/svn.py b/powerline_shell/segments/svn.py index c770e79a..32375a36 100644 --- a/powerline_shell/segments/svn.py +++ b/powerline_shell/segments/svn.py @@ -46,6 +46,9 @@ def add_to_powerline(self): 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(" rev " + symbol + self.revision + " ", fg, bg) self.stats.add_to_powerline(self.powerline) From ad27ed4ccc28f314d7985776b8e8663a33a67102 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Mon, 15 Jan 2018 12:10:11 -0500 Subject: [PATCH 299/366] 0.4.7 --- CHANGELOG.md | 6 ++++++ setup.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed529819..92f2019a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changes +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 diff --git a/setup.py b/setup.py index fe96724a..78f34b82 100755 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name="powerline-shell", - version="0.4.6", + version="0.4.7", description="A pretty prompt for your shell", author="Buck Ryan", url="https://github.com/banga/powerline-shell", From a1b536b85ba8b124a0e393491ac1dc1fc958a38d Mon Sep 17 00:00:00 2001 From: Emanuel Angelo Date: Thu, 18 Jan 2018 00:29:32 +0000 Subject: [PATCH 300/366] Fixes and enhances svn segment Uses the 'info' command with XML output to make it localization independent. Prepares the segment for testing. --- powerline_shell/segments/svn.py | 92 ++++++++++++++++++++++----------- 1 file changed, 62 insertions(+), 30 deletions(-) diff --git a/powerline_shell/segments/svn.py b/powerline_shell/segments/svn.py index 32375a36..0679fcbd 100644 --- a/powerline_shell/segments/svn.py +++ b/powerline_shell/segments/svn.py @@ -1,7 +1,65 @@ -import subprocess +import subprocess, os from ..utils import ThreadedSegment, RepoStats +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 svn_subprocess_env(): + return {"PATH": get_PATH()} + + +def _get_svn_revision(): + p = subprocess.Popen(["svn", "info", "--xml"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + env=svn_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=svn_subprocess_env()) + except OSError: + # Popen will throw an OSError if svn is not found + return 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) @@ -9,33 +67,7 @@ def __init__(self, powerline): 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() @@ -47,8 +79,8 @@ def add_to_powerline(self): bg = self.powerline.theme.REPO_DIRTY_BG fg = self.powerline.theme.REPO_DIRTY_FG if self.powerline.segment_conf("vcs", "show_symbol"): - symbol = RepoStats().symbols["svn"] + " " + symbol = " " + RepoStats().symbols["svn"] else: symbol = "" - self.powerline.append(" rev " + symbol + self.revision + " ", fg, bg) + self.powerline.append(symbol + " rev " + self.revision + " ", fg, bg) self.stats.add_to_powerline(self.powerline) From bcaa7e6e4dddf27acdb37757d02a5e360bdf455c Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sun, 28 Jan 2018 22:37:46 -0500 Subject: [PATCH 301/366] A possible solution for allowing custom themes --- powerline_shell/__init__.py | 23 +++++++++++++++++++---- powerline_shell/utils.py | 18 ++++++++++++++++++ 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/powerline_shell/__init__.py b/powerline_shell/__init__.py index 84342852..d572817e 100644 --- a/powerline_shell/__init__.py +++ b/powerline_shell/__init__.py @@ -6,7 +6,7 @@ import sys import importlib import json -from .utils import warn, py3 +from .utils import warn, py3, import_file import re @@ -168,6 +168,23 @@ def find_config(): } +class ThemeNotFoundException(Exception): + pass + + +def read_theme(config): + theme_name = config.get("theme", "default") + try: + mod = importlib.import_module("powerline_shell.themes." + theme_name) + except ImportError: + try: + mod = import_file("custom_theme", os.path.expanduser(theme_name)) + except ImportError: + raise ThemeNotFoundException( + "Theme " + theme_name + " cannot be found") + return getattr(mod, "Color") + + def main(): arg_parser = argparse.ArgumentParser() arg_parser.add_argument('--generate-config', action='store_true', @@ -190,9 +207,7 @@ def main(): else: config = DEFAULT_CONFIG - theme_name = config.get("theme", "default") - mod = importlib.import_module("powerline_shell.themes." + theme_name) - theme = getattr(mod, "Color") + theme = read_theme(config) powerline = Powerline(args, config, theme) segments = [] diff --git a/powerline_shell/utils.py b/powerline_shell/utils.py index aea7754e..e41a151a 100644 --- a/powerline_shell/utils.py +++ b/powerline_shell/utils.py @@ -98,3 +98,21 @@ class ThreadedSegment(threading.Thread): def __init__(self, powerline): super(ThreadedSegment, self).__init__() self.powerline = powerline + + +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) From f0293999c7a28fd6e8b7c81d1d4634268470214d Mon Sep 17 00:00:00 2001 From: Gaurav Nelson Date: Mon, 29 Jan 2018 14:00:34 +1000 Subject: [PATCH 302/366] added seperate variables for customizing colors for time segment --- powerline_shell/segments/time.py | 4 ++-- powerline_shell/themes/default.py | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/powerline_shell/segments/time.py b/powerline_shell/segments/time.py index ab4c9113..deafd49f 100644 --- a/powerline_shell/segments/time.py +++ b/powerline_shell/segments/time.py @@ -13,5 +13,5 @@ def add_to_powerline(self): 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) diff --git a/powerline_shell/themes/default.py b/powerline_shell/themes/default.py index a2178c1d..7bc98d8b 100644 --- a/powerline_shell/themes/default.py +++ b/powerline_shell/themes/default.py @@ -69,6 +69,9 @@ 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. From 4b26d19907ae87a57fe9172c33fba7ec12cfa272 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Mon, 29 Jan 2018 11:45:31 -0500 Subject: [PATCH 303/366] default time vars --- powerline_shell/themes/basic.py | 3 +++ powerline_shell/themes/solarized_dark.py | 3 +++ powerline_shell/themes/solarized_light.py | 3 +++ powerline_shell/themes/washed.py | 3 +++ 4 files changed, 12 insertions(+) diff --git a/powerline_shell/themes/basic.py b/powerline_shell/themes/basic.py index a6b745d9..aa0d9299 100644 --- a/powerline_shell/themes/basic.py +++ b/powerline_shell/themes/basic.py @@ -40,3 +40,6 @@ class Color(DefaultColor): AWS_PROFILE_FG = 14 AWS_PROFILE_BG = 8 + + TIME_FG = 8 + TIME_BG = 7 diff --git a/powerline_shell/themes/solarized_dark.py b/powerline_shell/themes/solarized_dark.py index a7562545..893a04bd 100644 --- a/powerline_shell/themes/solarized_dark.py +++ b/powerline_shell/themes/solarized_dark.py @@ -39,3 +39,6 @@ class Color(DefaultColor): AWS_PROFILE_FG = 7 AWS_PROFILE_BG = 2 + + TIME_FG = 15 + TIME_BG = 10 diff --git a/powerline_shell/themes/solarized_light.py b/powerline_shell/themes/solarized_light.py index da14cdff..ffb58b2f 100644 --- a/powerline_shell/themes/solarized_light.py +++ b/powerline_shell/themes/solarized_light.py @@ -36,3 +36,6 @@ class Color(DefaultColor): VIRTUAL_ENV_BG = 15 VIRTUAL_ENV_FG = 2 + + TIME_FG = 15 + TIME_BG = 10 diff --git a/powerline_shell/themes/washed.py b/powerline_shell/themes/washed.py index 37a149f4..fdccd588 100644 --- a/powerline_shell/themes/washed.py +++ b/powerline_shell/themes/washed.py @@ -39,3 +39,6 @@ class Color(DefaultColor): AWS_PROFILE_FG = 0 AWS_PROFILE_BG = 7 + + TIME_FG = 8 + TIME_BG = 7 From e7964d1682590b8a2f237e5fa82024e0b1ec2123 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Mon, 29 Jan 2018 12:01:32 -0500 Subject: [PATCH 304/366] prepare 0.4.8 --- CHANGELOG.md | 7 +++++++ README.md | 19 +++++++++++++++---- powerline_shell/themes/basic.py | 2 +- powerline_shell/themes/solarized_dark.py | 2 +- powerline_shell/themes/solarized_light.py | 2 +- powerline_shell/themes/washed.py | 2 +- setup.py | 2 +- 7 files changed, 27 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92f2019a..011051b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changes +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 diff --git a/README.md b/README.md index 212a9659..a1c12555 100644 --- a/README.md +++ b/README.md @@ -218,14 +218,25 @@ 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 `~/.powerline-shell.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 theme, please test your theme on multiple terminals, especially with default -settings. Theme colors are specified using [Xterm-256 color codes](https://jonasjacek.github.io/colors/). +settings. ### Segment Configuration diff --git a/powerline_shell/themes/basic.py b/powerline_shell/themes/basic.py index aa0d9299..bd4d2f9e 100644 --- a/powerline_shell/themes/basic.py +++ b/powerline_shell/themes/basic.py @@ -1,4 +1,4 @@ -from .default import DefaultColor +from powerline_shell.themes.default import DefaultColor class Color(DefaultColor): diff --git a/powerline_shell/themes/solarized_dark.py b/powerline_shell/themes/solarized_dark.py index 893a04bd..ec0f41bf 100644 --- a/powerline_shell/themes/solarized_dark.py +++ b/powerline_shell/themes/solarized_dark.py @@ -1,4 +1,4 @@ -from .default import DefaultColor +from powerline_shell.themes.default import DefaultColor class Color(DefaultColor): diff --git a/powerline_shell/themes/solarized_light.py b/powerline_shell/themes/solarized_light.py index ffb58b2f..d5a14d6f 100644 --- a/powerline_shell/themes/solarized_light.py +++ b/powerline_shell/themes/solarized_light.py @@ -1,4 +1,4 @@ -from .default import DefaultColor +from powerline_shell.themes.default import DefaultColor class Color(DefaultColor): diff --git a/powerline_shell/themes/washed.py b/powerline_shell/themes/washed.py index fdccd588..d2935095 100644 --- a/powerline_shell/themes/washed.py +++ b/powerline_shell/themes/washed.py @@ -1,4 +1,4 @@ -from .default import DefaultColor +from powerline_shell.themes.default import DefaultColor class Color(DefaultColor): diff --git a/setup.py b/setup.py index 78f34b82..fbffff85 100755 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name="powerline-shell", - version="0.4.7", + version="0.4.8", description="A pretty prompt for your shell", author="Buck Ryan", url="https://github.com/banga/powerline-shell", From 87b176037fd9df246d5cd083614543ecb362b0f6 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Mon, 29 Jan 2018 12:18:03 -0500 Subject: [PATCH 305/366] Change bash instructions for ps1 to not duplicate Fixes #331 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a1c12555..097a746d 100644 --- a/README.md +++ b/README.md @@ -99,10 +99,10 @@ Add the following to your `.bashrc` (or `.profile` on Mac): ``` 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 ``` From 15c4aee2775c37039b88c5548f1aea0cd1f45eff Mon Sep 17 00:00:00 2001 From: comagnaw Date: Thu, 1 Feb 2018 22:29:06 -0500 Subject: [PATCH 306/366] Add conversion to float before pass to rgb_to_hls --- powerline_shell/color_compliment.py | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/powerline_shell/color_compliment.py b/powerline_shell/color_compliment.py index 6a64dc45..39c7426d 100644 --- a/powerline_shell/color_compliment.py +++ b/powerline_shell/color_compliment.py @@ -10,20 +10,21 @@ def getOppositeColor(r,g,b): - hls = rgb_to_hls(r,g,b) - opp = list(hls[:]) - 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 - else: - opp[1] += 255/2 - if opp[2] > -0.5: # if saturation is low on first color increase second's - opp[2] -= 0.5 - opp = hls_to_rgb(*opp) - m = max(opp) - if m > 255: #colorsys module doesn't give caps to their conversions - opp = [ x*254/m for x in opp] - return tuple([ int(x) for x in opp]) + 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) + if opp[1] > 255/2: # for level you want to make sure they + opp[1] -= 255/2 # are quite different so easily readable + else: + opp[1] += 255/2 + if opp[2] > -0.5: # if saturation is low on first color increase second's + opp[2] -= 0.5 + opp = hls_to_rgb(*opp) + m = max(opp) + if m > 255: #colorsys module doesn't give caps to their conversions + opp = [ x*254/m for x in opp] + return tuple([ int(x) for x in opp]) def stringToHashToColorAndOpposite(string): if py3: From 0bca50bb18c7e74ae84f7f47b59f4068d2341d99 Mon Sep 17 00:00:00 2001 From: comagnaw Date: Sat, 3 Feb 2018 23:08:36 -0500 Subject: [PATCH 307/366] Adding getOppositeColor unittest. --- requirements-dev.txt | 1 + test/color_compliment_test.py | 49 +++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 test/color_compliment_test.py diff --git a/requirements-dev.txt b/requirements-dev.txt index 47a4588d..59d5eef7 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,3 +1,4 @@ nose>=1.3.7 mock>=1.3.0 sh>=1.11 +parameterized>=0.6.1 \ No newline at end of file diff --git a/test/color_compliment_test.py b/test/color_compliment_test.py new file mode 100644 index 00000000..47f72d07 --- /dev/null +++ b/test/color_compliment_test.py @@ -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))) From 81653f4c0ce05eae2479407d98a44bbc09698895 Mon Sep 17 00:00:00 2001 From: comagnaw Date: Sat, 3 Feb 2018 23:11:55 -0500 Subject: [PATCH 308/366] Fixing indent --- powerline_shell/color_compliment.py | 30 ++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/powerline_shell/color_compliment.py b/powerline_shell/color_compliment.py index 39c7426d..67906d5b 100644 --- a/powerline_shell/color_compliment.py +++ b/powerline_shell/color_compliment.py @@ -10,21 +10,21 @@ 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) - if opp[1] > 255/2: # for level you want to make sure they - opp[1] -= 255/2 # are quite different so easily readable - else: - opp[1] += 255/2 - if opp[2] > -0.5: # if saturation is low on first color increase second's - opp[2] -= 0.5 - opp = hls_to_rgb(*opp) - m = max(opp) - if m > 255: #colorsys module doesn't give caps to their conversions - opp = [ x*254/m for x in opp] - return tuple([ int(x) for x in opp]) + 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) + if opp[1] > 255/2: # for level you want to make sure they + opp[1] -= 255/2 # are quite different so easily readable + else: + opp[1] += 255/2 + if opp[2] > -0.5: # if saturation is low on first color increase second's + opp[2] -= 0.5 + opp = hls_to_rgb(*opp) + m = max(opp) + if m > 255: #colorsys module doesn't give caps to their conversions + opp = [ x*254/m for x in opp] + return tuple([ int(x) for x in opp]) def stringToHashToColorAndOpposite(string): if py3: From 235d3a8fda3c06f92c371dc65ba1a9d2800771e8 Mon Sep 17 00:00:00 2001 From: Igor Tarasov Date: Mon, 12 Feb 2018 00:16:04 +0400 Subject: [PATCH 309/366] 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. --- powerline_shell/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerline_shell/__init__.py b/powerline_shell/__init__.py index d572817e..c6d7c396 100644 --- a/powerline_shell/__init__.py +++ b/powerline_shell/__init__.py @@ -129,7 +129,7 @@ def draw(self): def draw_segment(self, idx): segment = self.segments[idx] - if self.args.shell == "bash": + if self.args.shell == "bash" and segment[0] != ' \\$ ': sanitized = re.sub(r"([`$])", r"\\\1", segment[0]) else: sanitized = segment[0] From c413236ee6cf87e859a273d41ee20e5d08ff52fa Mon Sep 17 00:00:00 2001 From: Igor Tarasov Date: Fri, 16 Feb 2018 00:43:42 +0400 Subject: [PATCH 310/366] Move escaping back to append and make it optional --- powerline_shell/__init__.py | 10 ++++------ powerline_shell/segments/root.py | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/powerline_shell/__init__.py b/powerline_shell/__init__.py index c6d7c396..68eb227e 100644 --- a/powerline_shell/__init__.py +++ b/powerline_shell/__init__.py @@ -114,7 +114,9 @@ def fgcolor(self, code): 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 @@ def draw(self): def draw_segment(self, idx): segment = self.segments[idx] - if self.args.shell == "bash" and segment[0] != ' \\$ ': - 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])) diff --git a/powerline_shell/segments/root.py b/powerline_shell/segments/root.py index 3590edc9..7779eacf 100644 --- a/powerline_shell/segments/root.py +++ b/powerline_shell/segments/root.py @@ -15,4 +15,4 @@ def add_to_powerline(self): 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) From a9050d0f6189e4bf515536d13c630414a413a784 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sun, 18 Feb 2018 21:09:22 -0500 Subject: [PATCH 311/366] respect max dir setting for plain cwd --- powerline_shell/segments/cwd.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/powerline_shell/segments/cwd.py b/powerline_shell/segments/cwd.py index c8717335..a7023178 100644 --- a/powerline_shell/segments/cwd.py +++ b/powerline_shell/segments/cwd.py @@ -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) From 9703379d5842b2939ad937c39d4cc3300a8ef964 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sun, 18 Feb 2018 21:42:02 -0500 Subject: [PATCH 312/366] create an stdout segment that just plops in outputs of commands --- powerline_shell/__init__.py | 9 ++++++--- powerline_shell/segments/stdout.py | 14 ++++++++++++++ powerline_shell/segments/svn.py | 5 ----- powerline_shell/utils.py | 6 ++++-- 4 files changed, 24 insertions(+), 10 deletions(-) create mode 100644 powerline_shell/segments/stdout.py diff --git a/powerline_shell/__init__.py b/powerline_shell/__init__.py index d572817e..bdaf6128 100644 --- a/powerline_shell/__init__.py +++ b/powerline_shell/__init__.py @@ -211,9 +211,12 @@ def main(): 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} + module_name = "powerline_shell.segments." + seg_conf["type"] + mod = importlib.import_module(module_name) + segment = getattr(mod, "Segment")(powerline, seg_conf) segment.start() segments.append(segment) for segment in segments: diff --git a/powerline_shell/segments/stdout.py b/powerline_shell/segments/stdout.py new file mode 100644 index 00000000..87a25591 --- /dev/null +++ b/powerline_shell/segments/stdout.py @@ -0,0 +1,14 @@ +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() + + def add_to_powerline(self): + self.join() + fg_color = self.segment_def.get("fg_color", self.powerline.theme.PATH_FG) + bg_color = self.segment_def.get("bg_color", self.powerline.theme.PATH_BG) + self.powerline.append(" %s " % self.output, fg_color, bg_color) diff --git a/powerline_shell/segments/svn.py b/powerline_shell/segments/svn.py index 0679fcbd..1bd24fc9 100644 --- a/powerline_shell/segments/svn.py +++ b/powerline_shell/segments/svn.py @@ -61,11 +61,6 @@ def build_stats(): class Segment(ThreadedSegment): - def __init__(self, powerline): - super(Segment, self).__init__(powerline) - self.stats = None - self.revision = "" - def run(self): self.stats, self.revision = build_stats() diff --git a/powerline_shell/utils.py b/powerline_shell/utils.py index e41a151a..608a3c1c 100644 --- a/powerline_shell/utils.py +++ b/powerline_shell/utils.py @@ -87,17 +87,19 @@ 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): From f0caebd26fce1244804ee0db755bfbbe01d56571 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sun, 18 Feb 2018 21:52:51 -0500 Subject: [PATCH 313/366] segment that gets an environment variable --- powerline_shell/segments/env.py | 10 ++++++++++ powerline_shell/segments/stdout.py | 9 ++++++--- powerline_shell/themes/default.py | 7 +++++++ 3 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 powerline_shell/segments/env.py diff --git a/powerline_shell/segments/env.py b/powerline_shell/segments/env.py new file mode 100644 index 00000000..67dc04ba --- /dev/null +++ b/powerline_shell/segments/env.py @@ -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.STDOUT_DEFAULT_FG), + self.segment_def.get("bg_color", self.powerline.theme.STDOUT_DEFAULT_BG)) diff --git a/powerline_shell/segments/stdout.py b/powerline_shell/segments/stdout.py index 87a25591..0a93b13d 100644 --- a/powerline_shell/segments/stdout.py +++ b/powerline_shell/segments/stdout.py @@ -6,9 +6,12 @@ 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() - fg_color = self.segment_def.get("fg_color", self.powerline.theme.PATH_FG) - bg_color = self.segment_def.get("bg_color", self.powerline.theme.PATH_BG) - self.powerline.append(" %s " % self.output, fg_color, bg_color) + self.powerline.append( + " %s " % self.output, + self.segment_def.get("fg_color", self.powerline.theme.ENV_DEFAULT_FG), + self.segment_def.get("bg_color", self.powerline.theme.ENV_DEFAULT_BG)) diff --git a/powerline_shell/themes/default.py b/powerline_shell/themes/default.py index 7bc98d8b..bad2da42 100644 --- a/powerline_shell/themes/default.py +++ b/powerline_shell/themes/default.py @@ -72,6 +72,13 @@ class DefaultColor(object): TIME_FG = 250 TIME_BG = 238 + STDOUT_DEFAULT_BG = 237 # dark grey + STDOUT_DEFAULT_FG = 250 # light grey + + ENV_DEFAULT_BG = 237 # dark grey + ENV_DEFAULT_FG = 250 # light grey + + class Color(DefaultColor): """ This subclass is required when the user chooses to use 'default' theme. From 84a6b215c14b97f5b268dcccbdd11c84e013cb39 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sun, 18 Feb 2018 22:02:44 -0500 Subject: [PATCH 314/366] docs for stdout and env --- README.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/README.md b/README.md index 097a746d..64a2bd15 100644 --- a/README.md +++ b/README.md @@ -20,9 +20,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) @@ -179,6 +181,7 @@ are: 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. +- `env` - See [Generic Segments](#generic-segments) - `fossil` - Details about the current Fossil repo. - `git` - Details about the current Git repo. - `hg` - Details about the current Mercurial repo. @@ -195,12 +198,39 @@ are: - `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. +- `stdout` - See [Generic Segments](#generic-segments) - `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. +### 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 By default, a unicode character (resembling the > symbol) is used to separate From 47ca2df524645dc9008598431c6d0ad7a2c43aec Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sun, 18 Feb 2018 22:04:43 -0500 Subject: [PATCH 315/366] nevermind on extra theme variables --- powerline_shell/segments/env.py | 4 ++-- powerline_shell/segments/stdout.py | 4 ++-- powerline_shell/themes/default.py | 6 ------ 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/powerline_shell/segments/env.py b/powerline_shell/segments/env.py index 67dc04ba..29ef048a 100644 --- a/powerline_shell/segments/env.py +++ b/powerline_shell/segments/env.py @@ -6,5 +6,5 @@ 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.STDOUT_DEFAULT_FG), - self.segment_def.get("bg_color", self.powerline.theme.STDOUT_DEFAULT_BG)) + self.segment_def.get("fg_color", self.powerline.theme.PATH_FG), + self.segment_def.get("bg_color", self.powerline.theme.PATH_BG)) diff --git a/powerline_shell/segments/stdout.py b/powerline_shell/segments/stdout.py index 0a93b13d..9286245e 100644 --- a/powerline_shell/segments/stdout.py +++ b/powerline_shell/segments/stdout.py @@ -13,5 +13,5 @@ def add_to_powerline(self): self.join() self.powerline.append( " %s " % self.output, - self.segment_def.get("fg_color", self.powerline.theme.ENV_DEFAULT_FG), - self.segment_def.get("bg_color", self.powerline.theme.ENV_DEFAULT_BG)) + self.segment_def.get("fg_color", self.powerline.theme.PATH_FG), + self.segment_def.get("bg_color", self.powerline.theme.PATH_BG)) diff --git a/powerline_shell/themes/default.py b/powerline_shell/themes/default.py index bad2da42..dff59048 100644 --- a/powerline_shell/themes/default.py +++ b/powerline_shell/themes/default.py @@ -72,12 +72,6 @@ class DefaultColor(object): TIME_FG = 250 TIME_BG = 238 - STDOUT_DEFAULT_BG = 237 # dark grey - STDOUT_DEFAULT_FG = 250 # light grey - - ENV_DEFAULT_BG = 237 # dark grey - ENV_DEFAULT_FG = 250 # light grey - class Color(DefaultColor): """ From 27574cc79b8e929492f3edcd96790f77c64c1db4 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Mon, 19 Feb 2018 10:45:02 -0500 Subject: [PATCH 316/366] Fix tests and some py2/py3 issues --- CHANGELOG.md | 7 +++++++ powerline_shell/segments/php_version.py | 8 +++++--- powerline_shell/segments/uptime.py | 4 ++-- powerline_shell/utils.py | 9 +++++++-- test/__init__.py | 0 test/segments_test/__init__.py | 0 test/segments_test/bzr_test.py | 4 ++++ test/segments_test/fossil_test.py | 4 ++++ test/segments_test/git_test.py | 4 ++++ test/segments_test/hg_test.py | 4 ++++ test/testing_utils.py | 4 ++++ 11 files changed, 41 insertions(+), 7 deletions(-) create mode 100644 test/__init__.py create mode 100644 test/segments_test/__init__.py create mode 100644 test/testing_utils.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 011051b4..5ee8149d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changes +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 diff --git a/powerline_shell/segments/php_version.py b/powerline_shell/segments/php_version.py index 52f18991..f482cf01 100644 --- a/powerline_shell/segments/php_version.py +++ b/powerline_shell/segments/php_version.py @@ -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 diff --git a/powerline_shell/segments/uptime.py b/powerline_shell/segments/uptime.py index 96e4c268..1c030611 100644 --- a/powerline_shell/segments/uptime.py +++ b/powerline_shell/segments/uptime.py @@ -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) diff --git a/powerline_shell/utils.py b/powerline_shell/utils.py index e41a151a..25d9ca59 100644 --- a/powerline_shell/utils.py +++ b/powerline_shell/utils.py @@ -4,8 +4,13 @@ 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): @@ -66,7 +71,7 @@ def n_or_empty(self, _key): 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): diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/test/segments_test/__init__.py b/test/segments_test/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/test/segments_test/bzr_test.py b/test/segments_test/bzr_test.py index 62fc6d16..b7357770 100644 --- a/test/segments_test/bzr_test.py +++ b/test/segments_test/bzr_test.py @@ -5,6 +5,7 @@ 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) diff --git a/test/segments_test/fossil_test.py b/test/segments_test/fossil_test.py index 50a74267..eba0b4b5 100644 --- a/test/segments_test/fossil_test.py +++ b/test/segments_test/fossil_test.py @@ -5,6 +5,7 @@ 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,6 +19,9 @@ 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) diff --git a/test/segments_test/git_test.py b/test/segments_test/git_test.py index ab8c9dd6..28b83f6b 100644 --- a/test/segments_test/git_test.py +++ b/test/segments_test/git_test.py @@ -4,12 +4,16 @@ 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) diff --git a/test/segments_test/hg_test.py b/test/segments_test/hg_test.py index 34fddc15..d5aa0337 100644 --- a/test/segments_test/hg_test.py +++ b/test/segments_test/hg_test.py @@ -5,6 +5,7 @@ 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,6 +21,9 @@ 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) diff --git a/test/testing_utils.py b/test/testing_utils.py new file mode 100644 index 00000000..e61e4c2b --- /dev/null +++ b/test/testing_utils.py @@ -0,0 +1,4 @@ +def dict_side_effect_fn(dict_): + def func(*args): + return dict_[args] + return func From a494cd4a456d9ac1ad60b37830d04454fd28ef0b Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Mon, 19 Feb 2018 10:45:27 -0500 Subject: [PATCH 317/366] prepare 0.4.9 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index fbffff85..96ee65a7 100755 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name="powerline-shell", - version="0.4.8", + version="0.4.9", description="A pretty prompt for your shell", author="Buck Ryan", url="https://github.com/banga/powerline-shell", From b07c8ef4cbd53bd2900d925c233b8d18557f6eb7 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Thu, 22 Feb 2018 10:23:23 -0500 Subject: [PATCH 318/366] Patch environment for VCS rather than creating new one Closes #240 --- CHANGELOG.md | 4 ++++ powerline_shell/segments/bzr.py | 4 +++- powerline_shell/segments/fossil.py | 4 +++- powerline_shell/segments/git.py | 9 ++++----- powerline_shell/segments/hg.py | 4 +++- powerline_shell/segments/svn.py | 4 +++- 6 files changed, 20 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ee8149d..82af0707 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changes +Unreleased + +* Patch environment for VCS subprocesses rather than generating a new one + 2018-02-19 (version 0.4.9) * Fix root user segment diff --git a/powerline_shell/segments/bzr.py b/powerline_shell/segments/bzr.py index 0a41f98c..c260c1ae 100644 --- a/powerline_shell/segments/bzr.py +++ b/powerline_shell/segments/bzr.py @@ -11,7 +11,9 @@ def get_PATH(): def bzr_subprocess_env(): - return {"PATH": get_PATH()} + env = dict(os.environ) + env.update({"PATH": get_PATH()}) + return env def _get_bzr_branch(): diff --git a/powerline_shell/segments/fossil.py b/powerline_shell/segments/fossil.py index bca0c881..78623cdc 100644 --- a/powerline_shell/segments/fossil.py +++ b/powerline_shell/segments/fossil.py @@ -11,7 +11,9 @@ def get_PATH(): def fossil_subprocess_env(): - return {"PATH": get_PATH()} + env = dict(os.environ) + env.update({"PATH": get_PATH()}) + return env def _get_fossil_branch(): diff --git a/powerline_shell/segments/git.py b/powerline_shell/segments/git.py index 6ebc2288..d2311622 100644 --- a/powerline_shell/segments/git.py +++ b/powerline_shell/segments/git.py @@ -12,17 +12,16 @@ def get_PATH(): def git_subprocess_env(): - return { + env = dict(os.environ) + env.update({ # 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(), - } + }) + return env def parse_git_branch_info(status): diff --git a/powerline_shell/segments/hg.py b/powerline_shell/segments/hg.py index 651eb4ce..33146c2e 100644 --- a/powerline_shell/segments/hg.py +++ b/powerline_shell/segments/hg.py @@ -11,7 +11,9 @@ def get_PATH(): def hg_subprocess_env(): - return {"PATH": get_PATH()} + env = dict(os.environ) + env.update({"PATH": get_PATH()}) + return env def _get_hg_branch(): diff --git a/powerline_shell/segments/svn.py b/powerline_shell/segments/svn.py index 0679fcbd..4618aacd 100644 --- a/powerline_shell/segments/svn.py +++ b/powerline_shell/segments/svn.py @@ -10,7 +10,9 @@ def get_PATH(): def svn_subprocess_env(): - return {"PATH": get_PATH()} + env = dict(os.environ) + env.update({"PATH": get_PATH()}) + return env def _get_svn_revision(): From 389080f5bf3951f52bba13825019940a5b4bbdcf Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Thu, 22 Feb 2018 10:30:49 -0500 Subject: [PATCH 319/366] prepare 0.4.10.rc1 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 96ee65a7..e79729e6 100755 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name="powerline-shell", - version="0.4.9", + version="0.4.10.rc1", description="A pretty prompt for your shell", author="Buck Ryan", url="https://github.com/banga/powerline-shell", From f6c7eaa10a3a92e3a6b0dda9e38daff258f5f472 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Thu, 22 Feb 2018 10:36:18 -0500 Subject: [PATCH 320/366] additional changelog for pending release --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 82af0707..4221c9fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ Unreleased * Patch environment for VCS subprocesses rather than generating a new one +* Fix `cwd` segment so it respects `max_depth` configuration 2018-02-19 (version 0.4.9) From 6ff4b503767b4b29d41cef32869aa207ae18d940 Mon Sep 17 00:00:00 2001 From: Blue-Dog-Archolite Date: Thu, 22 Feb 2018 12:34:51 -0700 Subject: [PATCH 321/366] 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 --- powerline_shell/segments/ruby_version.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/powerline_shell/segments/ruby_version.py b/powerline_shell/segments/ruby_version.py index 0e7bee1e..dc566fda 100644 --- a/powerline_shell/segments/ruby_version.py +++ b/powerline_shell/segments/ruby_version.py @@ -6,14 +6,17 @@ 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 From 599f14520883b6758b9fcfd9d8ef59572ed508f0 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Thu, 22 Feb 2018 20:16:02 -0500 Subject: [PATCH 322/366] changelog for #336 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4221c9fb..6578f90f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ Unreleased * 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)) 2018-02-19 (version 0.4.9) From 755ba297aa04f52ab9cd21c734ad9161a20063db Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Fri, 23 Feb 2018 23:14:40 -0500 Subject: [PATCH 323/366] take out ~/.config notes --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4e4570da..27a34684 100644 --- a/README.md +++ b/README.md @@ -153,15 +153,14 @@ 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` or -`$XDG_CONFIG_HOME/powerline-shell/config.json`. You can generate the +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 +(As an example, my config file is located here: [here](https://github.com/b-ryan/dotfiles/blob/master/home/powerline-shell.json)) ### Adding, Removing and Re-arranging segments From a209e6b12de245b5077b97d11ee140e14bf9af70 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Fri, 23 Feb 2018 23:17:43 -0500 Subject: [PATCH 324/366] 0.5.0 is upcoming --- CHANGELOG.md | 5 ++++- README.md | 4 ++-- setup.py | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6578f90f..9a6285d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,14 @@ # Changes -Unreleased +Unreleased (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)) 2018-02-19 (version 0.4.9) diff --git a/README.md b/README.md index 27a34684..046d7d50 100644 --- a/README.md +++ b/README.md @@ -153,8 +153,8 @@ 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 diff --git a/setup.py b/setup.py index e79729e6..880bea9d 100755 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name="powerline-shell", - version="0.4.10.rc1", + version="0.5.0.rc1", description="A pretty prompt for your shell", author="Buck Ryan", url="https://github.com/banga/powerline-shell", From d0dec6ce64e12d0ae736de95a60a9f0d1bba654c Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Fri, 23 Feb 2018 23:31:21 -0500 Subject: [PATCH 325/366] new repo path --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 27a34684..6d89adea 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ A [Powerline](https://github.com/Lokaltog/vim-powerline) like prompt 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 @@ -61,7 +61,7 @@ with an option `show_symbol` set to `true` (see 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) @@ -86,7 +86,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 ``` @@ -307,6 +307,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). From fc62b0f88835646b75682838dc88248214553892 Mon Sep 17 00:00:00 2001 From: Alex Pinkney Date: Tue, 20 Mar 2018 13:09:48 +0000 Subject: [PATCH 326/366] Move get_PATH and x_subprocess_env functions into utils.py --- powerline_shell/segments/bzr.py | 20 +++----------------- powerline_shell/segments/fossil.py | 17 ++--------------- powerline_shell/segments/git.py | 27 +++------------------------ powerline_shell/segments/hg.py | 20 +++----------------- powerline_shell/segments/svn.py | 21 ++++----------------- powerline_shell/utils.py | 26 ++++++++++++++++++++++++++ test/segments_test/bzr_test.py | 2 +- test/segments_test/fossil_test.py | 2 +- test/segments_test/git_test.py | 2 +- test/segments_test/hg_test.py | 2 +- 10 files changed, 45 insertions(+), 94 deletions(-) diff --git a/powerline_shell/segments/bzr.py b/powerline_shell/segments/bzr.py index c260c1ae..059c813c 100644 --- a/powerline_shell/segments/bzr.py +++ b/powerline_shell/segments/bzr.py @@ -1,25 +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(): - env = dict(os.environ) - env.update({"PATH": get_PATH()}) - return env +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 @@ -49,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) diff --git a/powerline_shell/segments/fossil.py b/powerline_shell/segments/fossil.py index 78623cdc..f745d846 100644 --- a/powerline_shell/segments/fossil.py +++ b/powerline_shell/segments/fossil.py @@ -1,19 +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(): - env = dict(os.environ) - env.update({"PATH": get_PATH()}) - return env +from ..utils import RepoStats, ThreadedSegment, get_subprocess_env def _get_fossil_branch(): @@ -51,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) diff --git a/powerline_shell/segments/git.py b/powerline_shell/segments/git.py index d2311622..de2b049e 100644 --- a/powerline_shell/segments/git.py +++ b/powerline_shell/segments/git.py @@ -1,27 +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(): - env = dict(os.environ) - env.update({ - # 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/153 - "PATH": get_PATH(), - }) - return env +from ..utils import RepoStats, ThreadedSegment, get_git_subprocess_env def parse_git_branch_info(status): @@ -32,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) @@ -62,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) diff --git a/powerline_shell/segments/hg.py b/powerline_shell/segments/hg.py index 33146c2e..be784355 100644 --- a/powerline_shell/segments/hg.py +++ b/powerline_shell/segments/hg.py @@ -1,26 +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(): - env = dict(os.environ) - env.update({"PATH": get_PATH()}) - return env +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 @@ -48,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 diff --git a/powerline_shell/segments/svn.py b/powerline_shell/segments/svn.py index 4618aacd..54aff61d 100644 --- a/powerline_shell/segments/svn.py +++ b/powerline_shell/segments/svn.py @@ -1,25 +1,12 @@ -import subprocess, os -from ..utils import ThreadedSegment, RepoStats - - -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 svn_subprocess_env(): - env = dict(os.environ) - env.update({"PATH": get_PATH()}) - return env +import subprocess +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=svn_subprocess_env()) + env=get_subprocess_env()) for line in p.communicate()[0].decode("utf-8").splitlines(): if "revision" in line: revision = line.split("=")[1].split('"')[1] @@ -49,7 +36,7 @@ def build_stats(): try: p = subprocess.Popen(['svn', 'status'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, - env=svn_subprocess_env()) + env=get_subprocess_env()) except OSError: # Popen will throw an OSError if svn is not found return None diff --git a/powerline_shell/utils.py b/powerline_shell/utils.py index 25d9ca59..4b6008fb 100644 --- a/powerline_shell/utils.py +++ b/powerline_shell/utils.py @@ -1,4 +1,5 @@ import sys +import os import threading py3 = sys.version_info[0] == 3 @@ -121,3 +122,28 @@ def import_file(module_name, path): 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") + diff --git a/test/segments_test/bzr_test.py b/test/segments_test/bzr_test.py index b7357770..bc19d386 100644 --- a/test/segments_test/bzr_test.py +++ b/test/segments_test/bzr_test.py @@ -49,7 +49,7 @@ def _checkout_new_branch(self, branch): 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() diff --git a/test/segments_test/fossil_test.py b/test/segments_test/fossil_test.py index eba0b4b5..a0144af4 100644 --- a/test/segments_test/fossil_test.py +++ b/test/segments_test/fossil_test.py @@ -42,7 +42,7 @@ def _checkout_new_branch(self, branch): 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() diff --git a/test/segments_test/git_test.py b/test/segments_test/git_test.py index 28b83f6b..adff77dc 100644 --- a/test/segments_test/git_test.py +++ b/test/segments_test/git_test.py @@ -35,7 +35,7 @@ def _checkout_new_branch(self, branch): 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() diff --git a/test/segments_test/hg_test.py b/test/segments_test/hg_test.py index d5aa0337..6fff96a1 100644 --- a/test/segments_test/hg_test.py +++ b/test/segments_test/hg_test.py @@ -42,7 +42,7 @@ def _add_and_commit(self, filename): 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() From 709c5ba215da0788acf1c1dcecb19f4f449c1b79 Mon Sep 17 00:00:00 2001 From: Alex Pinkney Date: Tue, 20 Mar 2018 13:16:28 +0000 Subject: [PATCH 327/366] Add git_stash segment --- README.md | 1 + powerline_shell/segments/git_stash.py | 36 +++++++++++++ powerline_shell/themes/default.py | 3 ++ test/segments_test/git_stash_test.py | 76 +++++++++++++++++++++++++++ 4 files changed, 116 insertions(+) create mode 100644 powerline_shell/segments/git_stash.py create mode 100644 test/segments_test/git_stash_test.py diff --git a/README.md b/README.md index 6d89adea..6b935014 100644 --- a/README.md +++ b/README.md @@ -181,6 +181,7 @@ are: value of the exit status in red. - `fossil` - Details about the current Fossil repo. - `git` - Details about the current Git repo. +- `git_stash` - Number of stashes in the current Git repo. - `hg` - Details about the current Mercurial repo. - `hostname` - Current machine's hostname. - `jobs` - Number of background jobs currently running. diff --git a/powerline_shell/segments/git_stash.py b/powerline_shell/segments/git_stash.py new file mode 100644 index 00000000..752d9a26 --- /dev/null +++ b/powerline_shell/segments/git_stash.py @@ -0,0 +1,36 @@ +import subprocess +from ..utils import ThreadedSegment, get_git_subprocess_env + +STASH_SYMBOL = u'\u2398' + + +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('\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, STASH_SYMBOL) + self.powerline.append(stash_str, fg, bg) diff --git a/powerline_shell/themes/default.py b/powerline_shell/themes/default.py index 7bc98d8b..3c937533 100644 --- a/powerline_shell/themes/default.py +++ b/powerline_shell/themes/default.py @@ -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 diff --git a/test/segments_test/git_stash_test.py b/test/segments_test/git_stash_test.py new file mode 100644 index 00000000..ba45217e --- /dev/null +++ b/test/segments_test/git_stash_test.py @@ -0,0 +1,76 @@ +import unittest +import mock +import tempfile +import shutil +import sh +import powerline_shell.segments.git_stash as git_stash + + +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(git_stash.STASH_SYMBOL) + 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(git_stash.STASH_SYMBOL) + self.assertEqual(self.powerline.append.call_args[0][0], expected) From 7f72c1b03137f58e216020af74be37c69d3c0928 Mon Sep 17 00:00:00 2001 From: Jakub Dundalek Date: Thu, 29 Mar 2018 15:59:43 +0200 Subject: [PATCH 328/366] Add format option for time segment --- README.md | 4 ++++ powerline_shell/segments/time.py | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6d89adea..3c289064 100644 --- a/README.md +++ b/README.md @@ -284,6 +284,10 @@ 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 diff --git a/powerline_shell/segments/time.py b/powerline_shell/segments/time.py index deafd49f..686b1dd8 100644 --- a/powerline_shell/segments/time.py +++ b/powerline_shell/segments/time.py @@ -6,7 +6,10 @@ 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_ = ' %* ' From 15a6172a2cd0362cde6d471dc434ad699e0ff64b Mon Sep 17 00:00:00 2001 From: Alex Pinkney Date: Tue, 10 Apr 2018 06:21:23 -0400 Subject: [PATCH 329/366] Move git stash symbol definition to utils.RepoStats.symbols --- powerline_shell/segments/git_stash.py | 6 ++---- powerline_shell/utils.py | 1 + 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/powerline_shell/segments/git_stash.py b/powerline_shell/segments/git_stash.py index 752d9a26..8fc41dfa 100644 --- a/powerline_shell/segments/git_stash.py +++ b/powerline_shell/segments/git_stash.py @@ -1,7 +1,5 @@ import subprocess -from ..utils import ThreadedSegment, get_git_subprocess_env - -STASH_SYMBOL = u'\u2398' +from ..utils import RepoStats, ThreadedSegment, get_git_subprocess_env def get_stash_count(): @@ -32,5 +30,5 @@ def add_to_powerline(self): fg = self.powerline.theme.GIT_STASH_FG sc = self.stash_count if self.stash_count > 1 else '' - stash_str = u' {}{} '.format(sc, STASH_SYMBOL) + stash_str = u' {}{} '.format(sc, RepoStats.symbols['stash']) self.powerline.append(stash_str, fg, bg) diff --git a/powerline_shell/utils.py b/powerline_shell/utils.py index 4b6008fb..56662f92 100644 --- a/powerline_shell/utils.py +++ b/powerline_shell/utils.py @@ -23,6 +23,7 @@ class RepoStats(object): 'changed': u'\u270E', 'new': u'?', 'conflicted': u'\u273C', + 'stash': u'\u2398', 'git': u'\uE0A0', 'hg': u'\u263F', 'bzr': u'\u2B61\u20DF', From e163b7aaebac36ef01ab7ed3a148df4ae571079c Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Tue, 10 Apr 2018 16:15:23 -0400 Subject: [PATCH 330/366] prepare 0.5.0 --- CHANGELOG.md | 2 ++ setup.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a6285d5..6e1b901a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ Unreleased (version 0.5.0) * 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) diff --git a/setup.py b/setup.py index 880bea9d..3d22ff54 100755 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name="powerline-shell", - version="0.5.0.rc1", + version="0.5.0", description="A pretty prompt for your shell", author="Buck Ryan", url="https://github.com/banga/powerline-shell", From 095dc37dd03727f1ca58f8af58a5d25e2199cf1d Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Tue, 10 Apr 2018 16:16:48 -0400 Subject: [PATCH 331/366] fix symbol for untracked --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 186d4a27..f1d2ad5a 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ following symbols: - `✎` -- 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 -- `❓` -- a file is untracked +- `?` -- a file is untracked Each of these will have a number next to it if more than one file matches. From e828f264bee152817a51b203628f5003f5da8d50 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Fri, 13 Apr 2018 10:13:25 -0400 Subject: [PATCH 332/366] python3 compat for git_stash fixes #384 tested py2 & py3 --- powerline_shell/segments/git_stash.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerline_shell/segments/git_stash.py b/powerline_shell/segments/git_stash.py index 8fc41dfa..594cf386 100644 --- a/powerline_shell/segments/git_stash.py +++ b/powerline_shell/segments/git_stash.py @@ -14,7 +14,7 @@ def get_stash_count(): if p.returncode != 0: return 0 - return pdata[0].count('\n') + return pdata[0].count(b'\n') class Segment(ThreadedSegment): From 8ff0806ac8ea78f66b10482d639ce7a93a302b29 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Fri, 13 Apr 2018 10:14:42 -0400 Subject: [PATCH 333/366] prepare 0.5.1 --- CHANGELOG.md | 6 +++++- setup.py | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e1b901a..c43cdf60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Changes -Unreleased (version 0.5.0) +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 diff --git a/setup.py b/setup.py index 3d22ff54..c81a1938 100755 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name="powerline-shell", - version="0.5.0", + version="0.5.1", description="A pretty prompt for your shell", author="Buck Ryan", url="https://github.com/banga/powerline-shell", From 8b9c0f2b80bbfa348b30b5830018b373c2c0c8dd Mon Sep 17 00:00:00 2001 From: James Simas Date: Thu, 19 Apr 2018 22:22:48 -0700 Subject: [PATCH 334/366] Fix filename for macOS --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f1d2ad5a..c74fb65f 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ python setup.py install ### Bash -Add the following to your `.bashrc` (or `.profile` on Mac): +Add the following to your `.bashrc` (or `.bash_profile` on macOS): ``` function _update_ps1() { From 31bd259e9d1033668666e2760b358bc6634447f2 Mon Sep 17 00:00:00 2001 From: Alvaro Bernal Date: Fri, 20 Apr 2018 14:13:58 +0100 Subject: [PATCH 335/366] Fix git_stash segment test failure --- test/segments_test/git_stash_test.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/segments_test/git_stash_test.py b/test/segments_test/git_stash_test.py index ba45217e..50f7ade4 100644 --- a/test/segments_test/git_stash_test.py +++ b/test/segments_test/git_stash_test.py @@ -4,6 +4,7 @@ import shutil import sh import powerline_shell.segments.git_stash as git_stash +from powerline_shell.utils import RepoStats class GitStashTest(unittest.TestCase): @@ -32,7 +33,7 @@ def _stash(self): @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 + 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) @@ -55,7 +56,7 @@ def test_one_stash(self): self._stash() self.segment.start() self.segment.add_to_powerline() - expected = u' {} '.format(git_stash.STASH_SYMBOL) + expected = u' {} '.format(RepoStats.symbols["stash"]) self.assertEqual(self.powerline.append.call_args[0][0], expected) def test_multiple_stashes(self): @@ -72,5 +73,5 @@ def test_multiple_stashes(self): self.segment.start() self.segment.add_to_powerline() - expected = u' 3{} '.format(git_stash.STASH_SYMBOL) + expected = u' 3{} '.format(RepoStats.symbols["stash"]) self.assertEqual(self.powerline.append.call_args[0][0], expected) From 4e74b9a12acc51e6dbac9b472d821f21274f0cc6 Mon Sep 17 00:00:00 2001 From: Monica Li Date: Sat, 21 Apr 2018 13:55:56 -0400 Subject: [PATCH 336/366] add gruvbox theme --- powerline_shell/themes/gruvbox.py | 111 ++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 powerline_shell/themes/gruvbox.py diff --git a/powerline_shell/themes/gruvbox.py b/powerline_shell/themes/gruvbox.py new file mode 100644 index 00000000..1326ea46 --- /dev/null +++ b/powerline_shell/themes/gruvbox.py @@ -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 From 668a96429142381eaf916f4f53b7db6ef293a71d Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 21 Apr 2018 15:59:39 -0400 Subject: [PATCH 337/366] update changes from #354 for py3 --- powerline_shell/color_compliment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerline_shell/color_compliment.py b/powerline_shell/color_compliment.py index 67906d5b..f0517115 100644 --- a/powerline_shell/color_compliment.py +++ b/powerline_shell/color_compliment.py @@ -10,7 +10,7 @@ def getOppositeColor(r,g,b): - r, g, b = [x/255.0 for x in r, g, b] # convert to float before getting hls value + 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) From 86fd04c7a860a58f358bbfd95c818b1593de2582 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 21 Apr 2018 16:15:12 -0400 Subject: [PATCH 338/366] implement fix for #249 closes #249 --- powerline_shell/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerline_shell/__init__.py b/powerline_shell/__init__.py index f3875b1a..a174ca36 100644 --- a/powerline_shell/__init__.py +++ b/powerline_shell/__init__.py @@ -90,7 +90,7 @@ def __init__(self, args, config, 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.reset = self.color_template % '[0m\]\[\e[0K' self.lock = Powerline.symbols[mode]['lock'] self.network = Powerline.symbols[mode]['network'] self.separator = Powerline.symbols[mode]['separator'] From ac3be5f7b3e83d81601d96eabe15ac69270196d1 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 21 Apr 2018 16:44:48 -0400 Subject: [PATCH 339/366] Better handling of invalid JSON config files Closes #371 --- powerline_shell/__init__.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/powerline_shell/__init__.py b/powerline_shell/__init__.py index a174ca36..455f418a 100644 --- a/powerline_shell/__init__.py +++ b/powerline_shell/__init__.py @@ -202,7 +202,12 @@ 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 From b2797c77cdae63313f70f8871b47aceab89e7d75 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 21 Apr 2018 17:00:41 -0400 Subject: [PATCH 340/366] README update including clarification of relation to powerline Closes #329 --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f1d2ad5a..ac0b516e 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ # 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/b-ryan/powerline-shell/master/bash-powerline-screenshot.png) @@ -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. + **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* From 5563655d82ef164c139e3a3cad8136bdda0c7178 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 21 Apr 2018 17:06:37 -0400 Subject: [PATCH 341/366] prepare 0.5.2 --- CHANGELOG.md | 9 +++++++++ setup.py | 4 +++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c43cdf60..76be97ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changes +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 diff --git a/setup.py b/setup.py index c81a1938..eb30f285 100755 --- a/setup.py +++ b/setup.py @@ -3,9 +3,11 @@ setup( name="powerline-shell", - version="0.5.1", + version="0.5.2", description="A pretty prompt for your shell", author="Buck Ryan", + author_email="buck@buckryan.com", + license="MIT", url="https://github.com/banga/powerline-shell", classifiers=[], packages=[ From 08c07fa1f13e63ffd140cf8c87f6d904227e75b5 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 21 Apr 2018 17:50:42 -0400 Subject: [PATCH 342/366] prepare 0.5.3 --- CHANGELOG.md | 5 +++++ setup.py | 11 +++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 76be97ab..a77c7ae5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changes +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 diff --git a/setup.py b/setup.py index eb30f285..f8dc9a81 100755 --- a/setup.py +++ b/setup.py @@ -3,13 +3,20 @@ setup( name="powerline-shell", - version="0.5.2", + version="0.5.3", description="A pretty prompt for your shell", author="Buck Ryan", author_email="buck@buckryan.com", license="MIT", url="https://github.com/banga/powerline-shell", - classifiers=[], + 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", From c64da3dde4f27dcec693df1ed8aba6e2448772a1 Mon Sep 17 00:00:00 2001 From: James Simas Date: Sat, 21 Apr 2018 19:33:56 -0700 Subject: [PATCH 343/366] Update macOS section --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c74fb65f..f7caf868 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ python setup.py install ### Bash -Add the following to your `.bashrc` (or `.bash_profile` on macOS): +Add the following to your `.bashrc` file: ``` function _update_ps1() { @@ -107,6 +107,8 @@ if [[ $TERM != linux && ! $PROMPT_COMMAND =~ _update_ps1 ]]; then 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`: From 73b01d659732637e72e4fe53fb430ccabc528d57 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sun, 22 Apr 2018 12:11:56 -0400 Subject: [PATCH 344/366] Revert "implement fix for #249" This reverts commit 86fd04c7a860a58f358bbfd95c818b1593de2582. Closes #389 --- CHANGELOG.md | 6 ++++++ powerline_shell/__init__.py | 2 +- setup.py | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a77c7ae5..e92da125 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changes +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) diff --git a/powerline_shell/__init__.py b/powerline_shell/__init__.py index 455f418a..92fd726d 100644 --- a/powerline_shell/__init__.py +++ b/powerline_shell/__init__.py @@ -90,7 +90,7 @@ def __init__(self, args, config, 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\]\[\e[0K' + self.reset = self.color_template % '[0m' self.lock = Powerline.symbols[mode]['lock'] self.network = Powerline.symbols[mode]['network'] self.separator = Powerline.symbols[mode]['separator'] diff --git a/setup.py b/setup.py index f8dc9a81..6b5a726b 100755 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name="powerline-shell", - version="0.5.3", + version="0.5.4", description="A pretty prompt for your shell", author="Buck Ryan", author_email="buck@buckryan.com", From 36486483eb433e87dc6a8581a5391ed7a7f753df Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Mon, 7 May 2018 10:53:02 -0400 Subject: [PATCH 345/366] changelog for #383 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e92da125..15e038b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changes +Unreleased (version 0.5.5) + +* 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 From 3b951784003a92183e31831f23f1afba4a82f15e Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Mon, 4 Jun 2018 14:45:30 -0400 Subject: [PATCH 346/366] fix issues with config file path fixes #409 --- README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index ac0b516e..46b05b9e 100644 --- a/README.md +++ b/README.md @@ -160,11 +160,12 @@ 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 ``` (As an example, my config file is located here: -[here](https://github.com/b-ryan/dotfiles/blob/master/home/powerline-shell.json)) +[here](https://github.com/b-ryan/dotfiles/blob/master/home/config/powerline-shell/config.json)) ### Adding, Removing and Re-arranging segments @@ -227,8 +228,8 @@ 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 `~/.powerline-shell.json`, setting the `"theme"` to the path of -the file. For example your configuration might have: +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" @@ -246,7 +247,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.json` like: +for the `cwd` segment are set in `~/.config/powerline-shell/config.json` like: ``` { From af919e1772693570d7739049d6f9ca91a02d9b13 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Wed, 20 Jun 2018 10:14:37 -0400 Subject: [PATCH 347/366] 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. --- powerline_shell/__init__.py | 39 ++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/powerline_shell/__init__.py b/powerline_shell/__init__.py index 92fd726d..1377dfb2 100644 --- a/powerline_shell/__init__.py +++ b/powerline_shell/__init__.py @@ -167,21 +167,26 @@ def find_config(): } -class ThemeNotFoundException(Exception): +class ModuleNotFoundException(Exception): pass -def read_theme(config): - theme_name = config.get("theme", "default") - try: - mod = importlib.import_module("powerline_shell.themes." + theme_name) - except ImportError: +class CustomImporter(object): + def __init__(self): + self.file_import_count = 0 + + def import_(self, module_prefix, module_or_file, description): try: - mod = import_file("custom_theme", os.path.expanduser(theme_name)) + mod = importlib.import_module(module_prefix + module_or_file) except ImportError: - raise ThemeNotFoundException( - "Theme " + theme_name + " cannot be found") - return getattr(mod, "Color") + 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(): @@ -211,13 +216,21 @@ def main(): else: config = DEFAULT_CONFIG - theme = read_theme(config) + 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) + seg_mod = custom_importer.import_( + "powerline_shell.segments.", + seg_name, + "Segment") + segment = getattr(seg_mod, "Segment")(powerline) segment.start() segments.append(segment) for segment in segments: From 3cf55e7b609f57bbcdf79c75f8df14089bf64aed Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Wed, 20 Jun 2018 10:18:58 -0400 Subject: [PATCH 348/366] get ready for 0.6.0 --- CHANGELOG.md | 3 ++- setup.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 15e038b2..4de27234 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ # Changes -Unreleased (version 0.5.5) +Unreleased (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)) diff --git a/setup.py b/setup.py index 6b5a726b..2ae8f58d 100755 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name="powerline-shell", - version="0.5.4", + version="0.6.0", description="A pretty prompt for your shell", author="Buck Ryan", author_email="buck@buckryan.com", From 7935d7ad113d39c83e4f4340151badfe47666463 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Wed, 20 Jun 2018 10:26:22 -0400 Subject: [PATCH 349/366] readme updates for custom segments --- README.md | 61 ++++++++++++++++++++++++------------------------------- 1 file changed, 27 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 4011dcc5..15cab78d 100644 --- a/README.md +++ b/README.md @@ -172,40 +172,33 @@ powerline-shell --generate-config > ~/.powerline-shell.json 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: - -- `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. -- `git_stash` - Number of stashes in 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. +can be seen +[here](https://github.com/b-ryan/powerline-shell/tree/master/powerline_shell/segments). + +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" +] +``` ### Segment Separator From 0ea47cc11583210bcbb231d45d26ce30218c89b5 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Wed, 20 Jun 2018 10:29:30 -0400 Subject: [PATCH 350/366] date the 0.6.0 release --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4de27234..a955a5d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changes -Unreleased (version 0.6.0) +2018-06-20 (version 0.6.0) * Support for custom themes * New option for the `time` segment to specify format of the displayed time From d095a2f3d5a0597c99420809acf0b0ad3b49cadd Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Thu, 21 Jun 2018 21:26:40 -0400 Subject: [PATCH 351/366] fix tests and new test dockerfile --- Dockerfile | 25 ++++++++++--------------- test.sh | 4 ++-- test/segments_test/bzr_test.py | 2 +- test/segments_test/fossil_test.py | 2 +- test/segments_test/git_stash_test.py | 2 +- test/segments_test/git_test.py | 2 +- test/segments_test/hg_test.py | 2 +- test/segments_test/hostname_test.py | 2 +- test/segments_test/uptime_test.py | 2 +- 9 files changed, 19 insertions(+), 24 deletions(-) diff --git a/Dockerfile b/Dockerfile index 80f4cf81..5409279b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -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 \ @@ -12,22 +12,17 @@ RUN apk add --no-cache --update \ 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 " && \ + 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 . +RUN ./setup.py install -USER $USER -ENTRYPOINT ["/bin/bash"] +ENV USER root diff --git a/test.sh b/test.sh index 82151d36..46a2ffba 100755 --- a/test.sh +++ b/test.sh @@ -1,4 +1,4 @@ #!/bin/sh - +set -eu docker build -t powerline-shell . -docker run --rm -it powerline-shell -c nosetests +docker run --rm -it powerline-shell nosetests "$@" diff --git a/test/segments_test/bzr_test.py b/test/segments_test/bzr_test.py index bc19d386..73dbebae 100644 --- a/test/segments_test/bzr_test.py +++ b/test/segments_test/bzr_test.py @@ -34,7 +34,7 @@ def setUp(self): 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) diff --git a/test/segments_test/fossil_test.py b/test/segments_test/fossil_test.py index a0144af4..34f914af 100644 --- a/test/segments_test/fossil_test.py +++ b/test/segments_test/fossil_test.py @@ -28,7 +28,7 @@ def setUp(self): 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) diff --git a/test/segments_test/git_stash_test.py b/test/segments_test/git_stash_test.py index 50f7ade4..1b228cd6 100644 --- a/test/segments_test/git_stash_test.py +++ b/test/segments_test/git_stash_test.py @@ -15,7 +15,7 @@ def setUp(self): sh.cd(self.dirname) sh.git("init", ".") - self.segment = git_stash.Segment(self.powerline) + self.segment = git_stash.Segment(self.powerline, {}) def tearDown(self): shutil.rmtree(self.dirname) diff --git a/test/segments_test/git_test.py b/test/segments_test/git_test.py index adff77dc..373fd68f 100644 --- a/test/segments_test/git_test.py +++ b/test/segments_test/git_test.py @@ -19,7 +19,7 @@ def setUp(self): 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) diff --git a/test/segments_test/hg_test.py b/test/segments_test/hg_test.py index 6fff96a1..004eac9c 100644 --- a/test/segments_test/hg_test.py +++ b/test/segments_test/hg_test.py @@ -29,7 +29,7 @@ def setUp(self): 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) diff --git a/test/segments_test/hostname_test.py b/test/segments_test/hostname_test.py index 68e941cf..05ae1f1b 100644 --- a/test/segments_test/hostname_test.py +++ b/test/segments_test/hostname_test.py @@ -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 diff --git a/test/segments_test/uptime_test.py b/test/segments_test/uptime_test.py index 3285a005..676b193e 100644 --- a/test/segments_test/uptime_test.py +++ b/test/segments_test/uptime_test.py @@ -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): From 067202f71a28e053687ff6c7bd9f0228cd4e6705 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Thu, 21 Jun 2018 21:29:37 -0400 Subject: [PATCH 352/366] prepare 0.7.0-rc1 --- CHANGELOG.md | 4 ++++ setup.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a955a5d4..cfd61b11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changes +2018-06-21 (version 0.7.0-rc1) + +* New generic `stdout` and `env` segments + 2018-06-20 (version 0.6.0) * Support for custom themes diff --git a/setup.py b/setup.py index 2ae8f58d..400f3fb1 100755 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name="powerline-shell", - version="0.6.0", + version="0.7.0-rc1", description="A pretty prompt for your shell", author="Buck Ryan", author_email="buck@buckryan.com", From feb9c8550e983b7a4cb8b65e217b35cce4677329 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sun, 1 Jul 2018 21:13:15 -0400 Subject: [PATCH 353/366] fix bug in svn segment --- Dockerfile | 9 ++++++--- powerline_shell/segments/svn.py | 2 +- test.sh | 4 +++- test/segments_test/svn_test.py | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 42 insertions(+), 5 deletions(-) create mode 100644 test/segments_test/svn_test.py diff --git a/Dockerfile b/Dockerfile index 5409279b..71481322 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,7 +9,8 @@ RUN apk add --no-cache --update \ git \ mercurial \ php5 \ - subversion && \ + subversion \ + && \ rm -rf /var/cache/apk/* RUN mkdir /code @@ -22,7 +23,9 @@ RUN bzr whoami "root " && \ git config --global user.email "root@example.com" && \ git config --global user.name "root" -COPY . ./ -RUN ./setup.py install +# COPY . ./ +# RUN ./setup.py install ENV USER root + +CMD ["nosetests"] diff --git a/powerline_shell/segments/svn.py b/powerline_shell/segments/svn.py index 93bc96ca..6869cf9c 100644 --- a/powerline_shell/segments/svn.py +++ b/powerline_shell/segments/svn.py @@ -39,7 +39,7 @@ def build_stats(): env=get_subprocess_env()) except OSError: # Popen will throw an OSError if svn is not found - return None + return None, None pdata = p.communicate() if p.returncode != 0 or pdata[1][:22] == b'svn: warning: W155007:': return None, None diff --git a/test.sh b/test.sh index 46a2ffba..7bfee70c 100755 --- a/test.sh +++ b/test.sh @@ -1,4 +1,6 @@ #!/bin/sh set -eu docker build -t powerline-shell . -docker run --rm -it powerline-shell nosetests "$@" +docker run --rm --interactive --tty \ + --volume $PWD:/code \ + powerline-shell "$@" diff --git a/test/segments_test/svn_test.py b/test/segments_test/svn_test.py new file mode 100644 index 00000000..d7d821f8 --- /dev/null +++ b/test/segments_test/svn_test.py @@ -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) From 09fd45d6fc16f06b99ffdeede8f25e7bfeaf74d7 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 15 Sep 2018 19:13:48 -0400 Subject: [PATCH 354/366] doc formatting --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6488dff4..e6295711 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,10 @@ if [[ $TERM != linux && ! $PROMPT_COMMAND =~ _update_ps1 ]]; then 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`. +**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 From 7332357af633980ce5e65616518bcdbd509febcc Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 15 Sep 2018 19:17:33 -0400 Subject: [PATCH 355/366] prepare 0.7.0 --- CHANGELOG.md | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cfd61b11..6d9bb97c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changes -2018-06-21 (version 0.7.0-rc1) +2018-09-15 (version 0.7.0) * New generic `stdout` and `env` segments diff --git a/setup.py b/setup.py index 400f3fb1..49c3f052 100755 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name="powerline-shell", - version="0.7.0-rc1", + version="0.7.0", description="A pretty prompt for your shell", author="Buck Ryan", author_email="buck@buckryan.com", From a9b8c9bb39dbfb7ec3c639e497b5a76fa6dcb8cc Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Sat, 15 Sep 2018 20:24:03 -0400 Subject: [PATCH 356/366] update metadata homepage --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 49c3f052..87482e21 100755 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ author="Buck Ryan", author_email="buck@buckryan.com", license="MIT", - url="https://github.com/banga/powerline-shell", + url="https://github.com/b-ryan/powerline-shell", classifiers=[ "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", From 256888344affcce3d9cfe6fdc932cc7d904c030a Mon Sep 17 00:00:00 2001 From: Thomas Cherry Date: Wed, 3 Jul 2019 23:03:52 -0400 Subject: [PATCH 357/366] fixing names as suggested --- powerline_shell/segments/jobs.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/powerline_shell/segments/jobs.py b/powerline_shell/segments/jobs.py index 1b378670..ee66ebcc 100644 --- a/powerline_shell/segments/jobs.py +++ b/powerline_shell/segments/jobs.py @@ -29,19 +29,19 @@ def run(self): output_proc.communicate()[0].decode("utf-8").splitlines()[1:]) self.num_jobs = output.count(os.getppid()) - 1 else: - pcmd = self.pidInfo(os.getppid(), "command") + pid_of_cmd = self.pidInfo(os.getppid(), "command") - pppid = self.pidInfo(os.getppid(), "ppid") + parent_process_id = self.pidInfo(os.getppid(), "ppid") #fish runs commands in a sub process, so you have to walk up the # tree one time to get back to where you were with bash or other # such shells - if pcmd=="fish" or self.powerline.args.shell=="fish": - pppid = self.pidInfo(pppid, "ppid") + if pid_of_cmd=="fish" or self.powerline.args.shell=="fish": + parent_process_id = self.pidInfo(parent_process_id, "ppid") 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(parent_process_id), output)) - 1 def add_to_powerline(self): self.join() if self.num_jobs > 0: From fd0b3a8ec41d521a793e7200fa35d2c06845de61 Mon Sep 17 00:00:00 2001 From: Thomas Cherry Date: Wed, 3 Jul 2019 23:21:33 -0400 Subject: [PATCH 358/366] removing need to explicity call out fish from the command line --- powerline_shell/__init__.py | 1 - powerline_shell/segments/jobs.py | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/powerline_shell/__init__.py b/powerline_shell/__init__.py index ec48f9c1..3d7d7b6d 100644 --- a/powerline_shell/__init__.py +++ b/powerline_shell/__init__.py @@ -64,7 +64,6 @@ class Powerline(object): color_templates = { 'bash': r'\[\e%s\]', - 'fish': '%s', 'tcsh': r'%%{\e%s%%}', 'zsh': '%%{%s%%}', 'bare': '%s', diff --git a/powerline_shell/segments/jobs.py b/powerline_shell/segments/jobs.py index ee66ebcc..3b1e6f65 100644 --- a/powerline_shell/segments/jobs.py +++ b/powerline_shell/segments/jobs.py @@ -29,14 +29,13 @@ def run(self): output_proc.communicate()[0].decode("utf-8").splitlines()[1:]) self.num_jobs = output.count(os.getppid()) - 1 else: - pid_of_cmd = self.pidInfo(os.getppid(), "command") - + parent_command = self.pidInfo(os.getppid(), "command") parent_process_id = self.pidInfo(os.getppid(), "ppid") #fish runs commands in a sub process, so you have to walk up the # tree one time to get back to where you were with bash or other # such shells - if pid_of_cmd=="fish" or self.powerline.args.shell=="fish": + if parent_command=="fish": parent_process_id = self.pidInfo(parent_process_id, "ppid") output_proc = subprocess.Popen(['ps', '-a', '-o', 'ppid'], stdout=subprocess.PIPE) From 33d1ae1ae9a147ecfbd4f33d3b346e4f4767a027 Mon Sep 17 00:00:00 2001 From: Thomas Cherry Date: Wed, 3 Jul 2019 23:23:08 -0400 Subject: [PATCH 359/366] removing need to explicity call out fish from the command line --- powerline_shell/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerline_shell/__init__.py b/powerline_shell/__init__.py index 3d7d7b6d..53eed96a 100644 --- a/powerline_shell/__init__.py +++ b/powerline_shell/__init__.py @@ -160,7 +160,7 @@ def main(): 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', "fish", 'tcsh', 'zsh', 'bare']) + choices=['bash', 'tcsh', 'zsh', 'bare']) arg_parser.add_argument('prev_error', nargs='?', type=int, default=0, help='Error code returned by the last command') args = arg_parser.parse_args() From 56f78ca0491fa734ce0585cf9fcef687f260f45c Mon Sep 17 00:00:00 2001 From: Paul Bauer Date: Sat, 15 May 2021 20:12:22 -0400 Subject: [PATCH 360/366] add nord theme --- powerline_shell/themes/nord.py | 89 ++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 powerline_shell/themes/nord.py diff --git a/powerline_shell/themes/nord.py b/powerline_shell/themes/nord.py new file mode 100644 index 00000000..2c006bcb --- /dev/null +++ b/powerline_shell/themes/nord.py @@ -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 From 3433b92e86b25ef747638bc5dc99bf291a838892 Mon Sep 17 00:00:00 2001 From: Binh Nguyen Date: Wed, 9 Mar 2022 14:50:46 +0700 Subject: [PATCH 361/366] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e6295711..257cb837 100644 --- a/README.md +++ b/README.md @@ -226,7 +226,7 @@ For example, your config could look like this: }, { "type": "env", - "var": "DOCKER_MACHINE_NAME", + "var": "DOCKER_MACHINE_NAME" }, ] } From 7adadf1e04a5a1e5a97f9e8dda01ed4f960b2c03 Mon Sep 17 00:00:00 2001 From: Jeeyong Um Date: Thu, 28 Jul 2022 20:17:28 +0900 Subject: [PATCH 362/366] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 257cb837..f7d274b8 100644 --- a/README.md +++ b/README.md @@ -135,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 ``` From db35d233d1fa37bc955d18f8c39c575bb153614f Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Thu, 22 Sep 2022 13:52:42 -0400 Subject: [PATCH 363/366] Fix jobs segment for bash 5, fish 3 --- powerline_shell/segments/jobs.py | 39 ++++++++++---------------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/powerline_shell/segments/jobs.py b/powerline_shell/segments/jobs.py index 3b1e6f65..9cb72254 100644 --- a/powerline_shell/segments/jobs.py +++ b/powerline_shell/segments/jobs.py @@ -7,43 +7,28 @@ class Segment(ThreadedSegment): - def pidInfo(self, pid, tag): - ''' - run a ps and get some data from it - pid process to query - tag -o property in the ps command to query for - return the value from ps - ''' - ppid = str(pid) - proc = subprocess.Popen(['ps', '-p', ppid, '-o%s=' % tag], - stdout=subprocess.PIPE) - info = proc.communicate()[0].decode("utf-8").strip() - return info - def run(self): self.num_jobs = 0 - if platform.system().startswith('CYGWIN'): + if platform.system().startswith("CYGWIN"): # cygwin ps is a special snowflake... - output_proc = subprocess.Popen(['ps', '-af'], stdout=subprocess.PIPE) + 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: - parent_command = self.pidInfo(os.getppid(), "command") - parent_process_id = self.pidInfo(os.getppid(), "ppid") - - #fish runs commands in a sub process, so you have to walk up the - # tree one time to get back to where you were with bash or other - # such shells - if parent_command=="fish": - parent_process_id = self.pidInfo(parent_process_id, "ppid") - - 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) + # 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(parent_process_id), 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) From 5763a35cc07c30f3fd68c3df1f8bdccd0d35eec0 Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Thu, 22 Sep 2022 13:55:46 -0400 Subject: [PATCH 364/366] add note about testing on zsh --- powerline_shell/segments/jobs.py | 1 + 1 file changed, 1 insertion(+) diff --git a/powerline_shell/segments/jobs.py b/powerline_shell/segments/jobs.py index 9cb72254..688ee71f 100644 --- a/powerline_shell/segments/jobs.py +++ b/powerline_shell/segments/jobs.py @@ -19,6 +19,7 @@ def run(self): # 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. From 0055f7c2b7320063ed67a5bd4f4a52dd44372a2b Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Thu, 22 Sep 2022 14:01:08 -0400 Subject: [PATCH 365/366] MINGW condition in job count Closes #330 --- powerline_shell/segments/jobs.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/powerline_shell/segments/jobs.py b/powerline_shell/segments/jobs.py index 688ee71f..dd0a3669 100644 --- a/powerline_shell/segments/jobs.py +++ b/powerline_shell/segments/jobs.py @@ -9,7 +9,8 @@ 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()), From f091bdc61c662ae23a1dde99bce29b4a88ab793a Mon Sep 17 00:00:00 2001 From: Buck Ryan Date: Thu, 22 Sep 2022 14:08:17 -0400 Subject: [PATCH 366/366] Switch CYGWIN job counting code from map to list comprehension Closes #516 --- powerline_shell/segments/jobs.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/powerline_shell/segments/jobs.py b/powerline_shell/segments/jobs.py index dd0a3669..22d00bee 100644 --- a/powerline_shell/segments/jobs.py +++ b/powerline_shell/segments/jobs.py @@ -13,8 +13,7 @@ def run(self): 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 = [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: # The following logic was tested on: