diff --git a/powerline/config_files/colorschemes/default.json b/powerline/config_files/colorschemes/default.json index 61b8cc36..89f17c3c 100644 --- a/powerline/config_files/colorschemes/default.json +++ b/powerline/config_files/colorschemes/default.json @@ -43,6 +43,8 @@ "branch_dirty": { "fg": "brightyellow", "bg": "gray2", "attrs": [] }, "branch_clean": { "fg": "gray9", "bg": "gray2", "attrs": [] }, "branch:divider": { "fg": "gray7", "bg": "gray2", "attrs": [] }, + "stash": "branch_dirty", + "stash:divider": "branch:divider", "cwd": "information:additional", "cwd:current_folder": "information:regular", "cwd:divider": { "fg": "gray7", "bg": "gray4", "attrs": [] }, diff --git a/powerline/config_files/colorschemes/solarized.json b/powerline/config_files/colorschemes/solarized.json index e858e68c..4f11fa47 100644 --- a/powerline/config_files/colorschemes/solarized.json +++ b/powerline/config_files/colorschemes/solarized.json @@ -15,6 +15,7 @@ "branch": { "fg": "solarized:base1", "bg": "solarized:base02", "attrs": [] }, "branch_dirty": { "fg": "solarized:yellow", "bg": "solarized:base02", "attrs": [] }, "branch_clean": { "fg": "solarized:base1", "bg": "solarized:base02", "attrs": [] }, + "stash": "branch_dirty", "email_alert_gradient": { "fg": "solarized:base3", "bg": "yellow_orange_red", "attrs": [] }, "email_alert": "warning:regular", "cwd": "information:additional", diff --git a/powerline/config_files/colorschemes/vim/solarized.json b/powerline/config_files/colorschemes/vim/solarized.json index bf603851..054edb08 100644 --- a/powerline/config_files/colorschemes/vim/solarized.json +++ b/powerline/config_files/colorschemes/vim/solarized.json @@ -12,6 +12,7 @@ "readonly_indicator": { "fg": "solarized:red", "bg": "solarized:base01", "attrs": [] }, "branch_dirty": { "fg": "solarized:yellow", "bg": "solarized:base01", "attrs": [] }, "branch:divider": { "fg": "solarized:base1", "bg": "solarized:base01", "attrs": [] }, + "stash:divider": "branch:divider", "file_name": { "fg": "solarized:base3", "bg": "solarized:base01", "attrs": ["bold"] }, "window_title": { "fg": "solarized:base3", "bg": "solarized:base01", "attrs": [] }, "file_name_no_file": { "fg": "solarized:base3", "bg": "solarized:base01", "attrs": ["bold"] }, diff --git a/powerline/config_files/colorschemes/vim/solarizedlight.json b/powerline/config_files/colorschemes/vim/solarizedlight.json index 2dcbb23d..928b8a50 100644 --- a/powerline/config_files/colorschemes/vim/solarizedlight.json +++ b/powerline/config_files/colorschemes/vim/solarizedlight.json @@ -12,6 +12,8 @@ "readonly_indicator": { "fg": "solarized:red", "bg": "solarized:base2", "attrs": [] }, "branch_dirty": { "fg": "solarized:yellow", "bg": "solarized:base2", "attrs": [] }, "branch:divider": { "fg": "solarized:base1", "bg": "solarized:base2", "attrs": [] }, + "stash": "branch_dirty", + "stash:divider": "branch:divider", "file_name": { "fg": "solarized:base03", "bg": "solarized:base2", "attrs": ["bold"] }, "window_title": { "fg": "solarized:base03", "bg": "solarized:base2", "attrs": [] }, "file_size": { "fg": "solarized:base03", "bg": "solarized:base2", "attrs": [] }, diff --git a/powerline/config_files/themes/ascii.json b/powerline/config_files/themes/ascii.json index 7b12d446..c6760613 100644 --- a/powerline/config_files/themes/ascii.json +++ b/powerline/config_files/themes/ascii.json @@ -15,6 +15,9 @@ "branch": { "before": "BR " }, + "stash": { + "before": "ST " + }, "cwd": { "args": { "ellipsis": "..." diff --git a/powerline/config_files/themes/powerline.json b/powerline/config_files/themes/powerline.json index 4ca9f0ee..db8246b7 100644 --- a/powerline/config_files/themes/powerline.json +++ b/powerline/config_files/themes/powerline.json @@ -14,6 +14,9 @@ "branch": { "before": " " }, + "stash": { + "before": "⌆ " + }, "cwd": { "args": { "ellipsis": "⋯" diff --git a/powerline/config_files/themes/powerline_unicode7.json b/powerline/config_files/themes/powerline_unicode7.json index d470d3a9..0d3c5d13 100644 --- a/powerline/config_files/themes/powerline_unicode7.json +++ b/powerline/config_files/themes/powerline_unicode7.json @@ -14,6 +14,9 @@ "branch": { "before": "🔀 " }, + "stash": { + "before": "📝" + }, "cwd": { "args": { "ellipsis": "⋯" diff --git a/powerline/config_files/themes/shell/default.json b/powerline/config_files/themes/shell/default.json index 480da5c9..38039d80 100644 --- a/powerline/config_files/themes/shell/default.json +++ b/powerline/config_files/themes/shell/default.json @@ -30,6 +30,10 @@ "function": "powerline.segments.shell.last_pipe_status", "priority": 10 }, + { + "function": "powerline.segments.common.vcs.stash", + "priority": 50 + }, { "function": "powerline.segments.common.vcs.branch", "priority": 40 diff --git a/powerline/config_files/themes/unicode.json b/powerline/config_files/themes/unicode.json index 4b52fd3b..049dcf08 100644 --- a/powerline/config_files/themes/unicode.json +++ b/powerline/config_files/themes/unicode.json @@ -14,6 +14,9 @@ "branch": { "before": "⎇ " }, + "stash": { + "before": "⌆" + }, "cwd": { "args": { "ellipsis": "⋯" diff --git a/powerline/config_files/themes/unicode_terminus.json b/powerline/config_files/themes/unicode_terminus.json index b7b005e4..47320529 100644 --- a/powerline/config_files/themes/unicode_terminus.json +++ b/powerline/config_files/themes/unicode_terminus.json @@ -14,6 +14,9 @@ "branch": { "before": "BR " }, + "stash": { + "before": "ST " + }, "cwd": { "args": { "ellipsis": "…" diff --git a/powerline/config_files/themes/unicode_terminus_condensed.json b/powerline/config_files/themes/unicode_terminus_condensed.json index fc9e90aa..bac59be2 100644 --- a/powerline/config_files/themes/unicode_terminus_condensed.json +++ b/powerline/config_files/themes/unicode_terminus_condensed.json @@ -14,6 +14,9 @@ "branch": { "before": "B " }, + "stash": { + "before": "S " + }, "cwd": { "args": { "use_path_separator": true, diff --git a/powerline/lib/vcs/git.py b/powerline/lib/vcs/git.py index c1d77a61..9bdf56e4 100644 --- a/powerline/lib/vcs/git.py +++ b/powerline/lib/vcs/git.py @@ -102,6 +102,13 @@ try: def ignore_event(path, name): return False + def stash(self): + try: + stashref = git.Repository(git_directory(self.directory)).lookup_reference('refs/stash') + except KeyError: + return 0 + return sum(1 for _ in stashref.log()) + def do_status(self, directory, path): if path: try: @@ -171,6 +178,9 @@ except ImportError: def _gitcmd(self, directory, *args): return readlines(('git',) + args, directory) + def stash(self): + return sum(1 for _ in self._gitcmd(self.directory, 'stash', 'list')) + def do_status(self, directory, path): if path: try: diff --git a/powerline/segments/common/vcs.py b/powerline/segments/common/vcs.py index 90e4e772..1aa5d110 100644 --- a/powerline/segments/common/vcs.py +++ b/powerline/segments/common/vcs.py @@ -56,3 +56,34 @@ branch = with_docstring(BranchSegment(), Highlight groups used: ``branch_clean``, ``branch_dirty``, ``branch``. ''') + + +@requires_filesystem_watcher +@requires_segment_info +class StashSegment(Segment): + divider_highlight_group = None + + @staticmethod + def get_directory(segment_info): + return segment_info['getcwd']() + + def __call__(self, pl, segment_info, create_watcher): + name = self.get_directory(segment_info) + if name: + repo = guess(path=name, create_watcher=create_watcher) + if repo is not None: + stash = getattr(repo, 'stash', None) + if stash: + stashes = stash() + if stashes: + return [{ + 'contents': str(stashes), + 'highlight_groups': ['stash'], + 'divider_highlight_group': self.divider_highlight_group + }] + +stash = with_docstring(StashSegment(), +'''Return the number of current VCS stash entries, if any. + +Highlight groups used: ``stash``. +''') diff --git a/powerline/segments/vim/__init__.py b/powerline/segments/vim/__init__.py index 8c740c95..28bcef67 100644 --- a/powerline/segments/vim/__init__.py +++ b/powerline/segments/vim/__init__.py @@ -22,7 +22,7 @@ from powerline.lib import add_divider_highlight_group from powerline.lib.vcs import guess from powerline.lib.humanize_bytes import humanize_bytes from powerline.lib import wraps_saveargs as wraps -from powerline.segments.common.vcs import BranchSegment +from powerline.segments.common.vcs import BranchSegment, StashSegment from powerline.segments import with_docstring from powerline.lib.unicode import string, unicode @@ -510,6 +510,25 @@ Divider highlight group used: ``branch:divider``. ''') +@requires_filesystem_watcher +@requires_segment_info +class VimStashSegment(StashSegment): + divider_highlight_group = 'stash:divider' + + @staticmethod + def get_directory(segment_info): + if vim_getbufoption(segment_info, 'buftype'): + return None + return buffer_name(segment_info) + + +stash = with_docstring(VimStashSegment(), +'''Return the number of stashes in the current working branch. + +Highlight groups used: ``stash``. +''') + + @requires_filesystem_watcher @requires_segment_info def file_vcs_status(pl, segment_info, create_watcher): diff --git a/tests/test_lib.py b/tests/test_lib.py index 6c7aac25..799fc272 100644 --- a/tests/test_lib.py +++ b/tests/test_lib.py @@ -566,6 +566,32 @@ class TestVCS(TestCase): self.do_branch_rename_test(repo, lambda b: re.match(r'^[a-f0-9]+$', b)) finally: call(['git', 'checkout', '-q', 'master'], cwd=GIT_REPO) + # Test stashing + self.assertEqual(repo.stash(), 0) + + def stash_save(): + with open(os.path.join(GIT_REPO, 'file'), 'w') as f: + f.write('abc') + return call(['git', 'stash', '-u'], cwd=GIT_REPO, stdout=PIPE) + + def stash_drop(): + return call(['git', 'stash', 'drop'], cwd=GIT_REPO, stdout=PIPE) + + def stash_list(): + return call(['git', 'stash', 'list'], cwd=GIT_REPO, stdout=PIPE) + + try: + stash_save() + self.assertEqual(repo.stash(), 1) + stash_save() + self.assertEqual(repo.stash(), 2) + stash_drop() + self.assertEqual(repo.stash(), 1) + stash_drop() + self.assertEqual(repo.stash(), 0) + finally: + while stash_list(): + stash_drop() def test_git_sym(self): create_watcher = get_fallback_create_watcher() diff --git a/tests/test_segments.py b/tests/test_segments.py index 0a7adcbf..f15fffde 100644 --- a/tests/test_segments.py +++ b/tests/test_segments.py @@ -738,6 +738,29 @@ class TestVcs(TestCommon): 'divider_highlight_group': None }]) + def test_stash(self): + pl = Pl() + create_watcher = get_fallback_create_watcher() + stash = partial(self.module.stash, pl=pl, create_watcher=create_watcher, segment_info={'getcwd': os.getcwd}) + + def forge_stash(n): + return replace_attr(self.module, 'guess', get_dummy_guess(stash=lambda: n, directory='/tmp/tests')) + + with forge_stash(0): + self.assertEqual(stash(), None) + with forge_stash(1): + self.assertEqual(stash(), [{ + 'highlight_groups': ['stash'], + 'contents': '1', + 'divider_highlight_group': None + }]) + with forge_stash(2): + self.assertEqual(stash(), [{ + 'highlight_groups': ['stash'], + 'contents': '2', + 'divider_highlight_group': None + }]) + class TestTime(TestCommon): module_name = 'time' @@ -1390,6 +1413,30 @@ class TestVim(TestCase): {'divider_highlight_group': 'branch:divider', 'highlight_groups': ['branch_clean', 'branch'], 'contents': 'foo'} ]) + def test_stash(self): + pl = Pl() + create_watcher = get_fallback_create_watcher() + with vim_module._with('buffer', '/foo') as segment_info: + stash = partial(self.vim.stash, pl=pl, create_watcher=create_watcher, segment_info=segment_info) + + def forge_stash(n): + return replace_attr(self.vcs, 'guess', get_dummy_guess(stash=lambda: n)) + + with forge_stash(0): + self.assertEqual(stash(), None) + with forge_stash(1): + self.assertEqual(stash(), [{ + 'divider_highlight_group': 'stash:divider', + 'highlight_groups': ['stash'], + 'contents': '1' + }]) + with forge_stash(2): + self.assertEqual(stash(), [{ + 'divider_highlight_group': 'stash:divider', + 'highlight_groups': ['stash'], + 'contents': '2' + }]) + def test_file_vcs_status(self): pl = Pl() create_watcher = get_fallback_create_watcher()