From 8b816170aa05ec43e8af2c2d183a28491935762c Mon Sep 17 00:00:00 2001 From: Jasur Sadikov Date: Mon, 7 Jul 2025 13:42:25 +0200 Subject: [PATCH 1/2] Resolves #100. Adds `git stash` view. --- src/mud/runner.py | 63 ++++++++++++++++++++++++++++------------------- src/mud/styles.py | 1 + 2 files changed, 39 insertions(+), 25 deletions(-) diff --git a/src/mud/runner.py b/src/mud/runner.py index 85eed20..227cf7e 100644 --- a/src/mud/runner.py +++ b/src/mud/runner.py @@ -104,6 +104,7 @@ def status(self, repos: Dict[str, List[str]]) -> None: f'{YELLOW}{glyphs('git-repo')}{glyphs('space')}{RESET}Directory', f'{GREEN}{glyphs('branch')}{glyphs('space')}{RESET}Branch', f'{CYAN}{glyphs('origin-sync')}{glyphs('space')}{RESET}Origin Sync', + f'{RED}{glyphs('stash')}{glyphs('space')}{RESET}Stash', f'{BRIGHT_YELLOW}{glyphs('info')}{glyphs('space')}{RESET}Status', f'{BRIGHT_GREEN}{glyphs('git-modified')}{glyphs('space')}{RESET}Modified Files']) @@ -113,9 +114,10 @@ def status(self, repos: Dict[str, List[str]]) -> None: status = repo.status() modified = status.items() formatted_path = link(self._get_formatted_path(path), os.path.abspath(path)) + head_info = self._get_head_info(repo) origin_sync = self._get_origin_sync(repo) + stash_count = self._stash_count(repo) mini_status = self._get_status_string(modified) - head_info = self._get_head_info(repo) colored_output = [] for file, flag in modified: @@ -130,7 +132,7 @@ def status(self, repos: Dict[str, List[str]]) -> None: else: color = CYAN colored_output.append(link(self._get_formatted_path(file, False, color), os.path.join(repo_path, file))) - table.add_row([formatted_path, head_info, origin_sync, mini_status, ', '.join(colored_output)]) + table.add_row([formatted_path, head_info, origin_sync, stash_count, mini_status, ', '.join(colored_output)]) utils.print_table(table) @@ -354,29 +356,40 @@ def _get_status_string(files: Dict[str, int]) -> str: @staticmethod def _get_head_info(repo: Repository) -> str: - if not repo.head_is_unborn: - if repo.head_is_detached: - for ref_name in repo.references: - if not ref_name.startswith('refs/tags/'): - continue - ref = repo.references.get(ref_name) - obj = repo[ref.target] - commit_oid = obj.target if isinstance(obj, pygit2.Tag) else ref.target - if commit_oid == ref.target: - branch = ref_name.replace('refs/tags/', '') - return f'{BRIGHT_MAGENTA}{glyphs('tag')}{RESET}{glyphs('space')}{branch}{RESET}' - commit_id = str(repo.revparse_single('HEAD').id) - return f'{CYAN}{glyphs('commit')}{RESET}{glyphs('space')}{commit_id[-8:]}' - else: - branch = repo.head.shorthand - if '/' in branch: - branch_path = branch.split('/') - icon = Runner._get_branch_icon(branch_path[0]) - return f'{icon}{RESET}{glyphs('space')}{branch_path[0]}{RESET}/{BOLD}{('/'.join(branch_path[1:]))}{RESET}' - return f'{Runner._get_branch_icon(branch)}{RESET}{glyphs('space')}{branch}' - else: + if repo.head_is_unborn: return '' + if repo.head_is_detached: + head_target = repo.head.target + for ref_name in repo.references: + if ref_name.startswith('refs/tags/'): + ref = repo.references[ref_name] + tag_obj = repo[ref.target] + tag_commit = tag_obj.target if isinstance(tag_obj, pygit2.Tag) else ref.target + if tag_commit == head_target: + tag_name = ref_name.replace('refs/tags/', '') + return f'{BRIGHT_MAGENTA}{glyphs("tag")}{RESET}{glyphs("space")}{tag_name}{RESET}' + + # fallback: show short commit hash + return f'{CYAN}{glyphs("commit")}{RESET}{glyphs("space")}{str(head_target)[-8:]}' + + # normal branch + branch = repo.head.shorthand + if '/' in branch: + parts = branch.split('/') + icon = Runner._get_branch_icon(parts[0]) + return f'{icon}{RESET}{glyphs("space")}{parts[0]}{RESET}/{BOLD}{"/".join(parts[1:])}{RESET}' + return f'{Runner._get_branch_icon(branch)}{RESET}{glyphs("space")}{branch}' + + @staticmethod + def _stash_count(repo: Repository) -> str: + count: int = len(repo.listall_stashes()) + + if count == 0: + return '' + else: + return f'{BRIGHT_RED}{glyphs("stash")}{RESET}{glyphs('space')}x{str(count)}' + @staticmethod def _get_origin_sync(repo: Repository) -> str: sync_str = '' @@ -418,9 +431,9 @@ def apply_styles(text: str) -> str: return color + quote + text + quote + END_FRG if file_system and abs_path: - return apply_styles(os.path.abspath(path)) + parts = os.path.abspath(path).split('/') + return apply_styles((DIM + '/'.join(parts[:-1]) + '/' + END_DIM + parts[-1])) - # TODO: Has some issues with coloring here if os.path.isabs(path): home = os.path.expanduser('~') if path.startswith(home): diff --git a/src/mud/styles.py b/src/mud/styles.py index 06a5b5c..53a7e78 100644 --- a/src/mud/styles.py +++ b/src/mud/styles.py @@ -89,6 +89,7 @@ 'tag': ['\uf02b', '>'], 'tags': ['\uf02c', ''], 'terminal': ['\ue795', ''], + 'stash': ['\uf1c0', ''], 'directory': ['\uf4d4', ''], '(': ['\uE0B2', ''], ')': ['\uE0B0', ''], From 9331a049680227c32b2160bebc1bdb2f8f5de605 Mon Sep 17 00:00:00 2001 From: Jasur Sadikov Date: Mon, 7 Jul 2025 13:43:47 +0200 Subject: [PATCH 2/2] Code simplifed --- src/mud/runner.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/mud/runner.py b/src/mud/runner.py index 227cf7e..518331b 100644 --- a/src/mud/runner.py +++ b/src/mud/runner.py @@ -384,11 +384,8 @@ def _get_head_info(repo: Repository) -> str: @staticmethod def _stash_count(repo: Repository) -> str: count: int = len(repo.listall_stashes()) + return '' if count == 0 else f'{BRIGHT_RED}{glyphs("stash")}{RESET}{glyphs('space')}x{str(count)}' - if count == 0: - return '' - else: - return f'{BRIGHT_RED}{glyphs("stash")}{RESET}{glyphs('space')}x{str(count)}' @staticmethod def _get_origin_sync(repo: Repository) -> str: