diff options
Diffstat (limited to 'plugins/git-prompt/gitstatus.py')
-rw-r--r-- | plugins/git-prompt/gitstatus.py | 132 |
1 files changed, 74 insertions, 58 deletions
diff --git a/plugins/git-prompt/gitstatus.py b/plugins/git-prompt/gitstatus.py index ee6fab9bd..a8eb8284b 100644 --- a/plugins/git-prompt/gitstatus.py +++ b/plugins/git-prompt/gitstatus.py @@ -1,68 +1,84 @@ #!/usr/bin/env python -# -*- coding: UTF-8 -*- - -# change those symbols to whatever you prefer -symbols = {'ahead of': '↑', 'behind': '↓', 'staged':'♦', 'changed':'‣', 'untracked':'…', 'clean':'⚡', 'unmerged':'≠', 'sha1':':'} - -from subprocess import Popen, PIPE - -output,error = Popen(['git','status'], stdout=PIPE, stderr=PIPE).communicate() - -if error: - import sys - sys.exit(0) -lines = output.splitlines() +from __future__ import print_function +import sys import re -behead_re = re.compile(r"^# Your branch is (ahead of|behind) '(.*)' by (\d+) commit") -diverge_re = re.compile(r"^# and have (\d+) and (\d+) different") +import shlex +from subprocess import Popen, PIPE, check_output -status = '' -staged = re.compile(r'^# Changes to be committed:$', re.MULTILINE) -changed = re.compile(r'^# Changed but not updated:$', re.MULTILINE) -untracked = re.compile(r'^# Untracked files:$', re.MULTILINE) -unmerged = re.compile(r'^# Unmerged paths:$', re.MULTILINE) -def execute(*command): - out, err = Popen(stdout=PIPE, stderr=PIPE, *command).communicate() - if not err: - nb = len(out.splitlines()) - else: - nb = '?' - return nb +def get_tagname_or_hash(): + """return tagname if exists else hash""" + cmd = 'git log -1 --format="%h%d"' + output = check_output(shlex.split(cmd)).decode('utf-8').strip() + hash_, tagname = None, None + # get hash + m = re.search('\(.*\)$', output) + if m: + hash_ = output[:m.start()-1] + # get tagname + m = re.search('tag: .*[,\)]', output) + if m: + tagname = 'tags/' + output[m.start()+len('tag: '): m.end()-1] -if staged.search(output): - nb = execute(['git','diff','--staged','--name-only','--diff-filter=ACDMRT']) - status += '%s%s' % (symbols['staged'], nb) -if unmerged.search(output): - nb = execute(['git','diff', '--staged','--name-only', '--diff-filter=U']) - status += '%s%s' % (symbols['unmerged'], nb) -if changed.search(output): - nb = execute(['git','diff','--name-only', '--diff-filter=ACDMRT']) - status += '%s%s' % (symbols['changed'], nb) -if untracked.search(output): -## nb = len(Popen(['git','ls-files','--others','--exclude-standard'],stdout=PIPE).communicate()[0].splitlines()) -## status += "%s" % (symbols['untracked']*(nb//3 + 1), ) - status += symbols['untracked'] -if status == '': - status = symbols['clean'] + if tagname: + return tagname + elif hash_: + return hash_ + return None -remote = '' -bline = lines[0] -if bline.find('Not currently on any branch') != -1: - branch = symbols['sha1']+ Popen(['git','rev-parse','--short','HEAD'], stdout=PIPE).communicate()[0][:-1] -else: - branch = bline.split(' ')[3] - bstatusline = lines[1] - match = behead_re.match(bstatusline) - if match: - remote = symbols[match.groups()[0]] - remote += match.groups()[2] - elif lines[2:]: - div_match = diverge_re.match(lines[2]) - if div_match: - remote = "{behind}{1}{ahead of}{0}".format(*div_match.groups(), **symbols) +# `git status --porcelain --branch` can collect all information +# branch, remote_branch, untracked, staged, changed, conflicts, ahead, behind +po = Popen(['git', 'status', '--porcelain', '--branch'], stdout=PIPE, stderr=PIPE) +stdout, sterr = po.communicate() +if po.returncode != 0: + sys.exit(0) # Not a git repository -print '\n'.join([branch,remote,status]) +# collect git status information +untracked, staged, changed, conflicts = [], [], [], [] +ahead, behind = 0, 0 +status = [(line[0], line[1], line[2:]) for line in stdout.decode('utf-8').splitlines()] +for st in status: + if st[0] == '#' and st[1] == '#': + if re.search('Initial commit on', st[2]): + branch = st[2].split(' ')[-1] + elif re.search('no branch', st[2]): # detached status + branch = get_tagname_or_hash() + elif len(st[2].strip().split('...')) == 1: + branch = st[2].strip() + else: + # current and remote branch info + branch, rest = st[2].strip().split('...') + if len(rest.split(' ')) == 1: + # remote_branch = rest.split(' ')[0] + pass + else: + # ahead or behind + divergence = ' '.join(rest.split(' ')[1:]) + divergence = divergence.lstrip('[').rstrip(']') + for div in divergence.split(', '): + if 'ahead' in div: + ahead = int(div[len('ahead '):].strip()) + elif 'behind' in div: + behind = int(div[len('behind '):].strip()) + elif st[0] == '?' and st[1] == '?': + untracked.append(st) + else: + if st[1] == 'M': + changed.append(st) + if st[0] == 'U': + conflicts.append(st) + elif st[0] != ' ': + staged.append(st) +out = ' '.join([ + branch, + str(ahead), + str(behind), + str(len(staged)), + str(len(conflicts)), + str(len(changed)), + str(len(untracked)), +]) +print(out, end='') |