From ef9c8f3e3301196c64ec74d219f47bafde01c17f Mon Sep 17 00:00:00 2001 From: Emanuel Angelo Date: Wed, 4 Oct 2017 22:33:55 +0100 Subject: [PATCH 1/5] 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 2/5] 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 b76f20d6bd31ba0d1450bf975d3c96aaa2e35ac1 Mon Sep 17 00:00:00 2001 From: Emanuel Angelo Date: Wed, 4 Oct 2017 23:22:38 +0100 Subject: [PATCH 3/5] 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 538bd54fc7bfdc0478f368372794ab0523cf813f Mon Sep 17 00:00:00 2001 From: Emanuel Angelo Date: Sat, 7 Oct 2017 18:39:46 +0100 Subject: [PATCH 4/5] 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 dee6ef0dedf0e7f78a81583915372559ede5c852 Mon Sep 17 00:00:00 2001 From: Emanuel Angelo Date: Thu, 26 Oct 2017 01:53:03 +0100 Subject: [PATCH 5/5] 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' }