From fa23260be18a373d1a69ba8f9ab6a615249b478b Mon Sep 17 00:00:00 2001 From: km222uq Date: Mon, 20 Oct 2025 21:34:42 +0200 Subject: [PATCH] display tweaks and languages normalize --- pyproject.toml | 2 +- src/gitfetch/display.py | 37 +++++++++++++++++++++---------------- src/gitfetch/fetcher.py | 21 ++++++++++++++++++--- 3 files changed, 40 insertions(+), 20 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 75970ca..2959435 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "gitfetch" -version = "1.0.17" +version = "1.0.18" description = "A neofetch-style CLI tool for GitHub statistics" readme = "README.md" requires-python = ">=3.8" diff --git a/src/gitfetch/display.py b/src/gitfetch/display.py index 13c84eb..ca9809e 100644 --- a/src/gitfetch/display.py +++ b/src/gitfetch/display.py @@ -10,17 +10,18 @@ from datetime import datetime from .config import ConfigManager + class DisplayFormatter: """Formats and displays GitHub stats in a neofetch-style layout.""" - def __init__(self,config_manager: ConfigManager): + def __init__(self, config_manager: ConfigManager): """Initialize the display formatter.""" self.terminal_width = shutil.get_terminal_size().columns self.enable_color = sys.stdout.isatty() self.colors = config_manager.get_colors() def display(self, username: str, user_data: Dict[str, Any], - stats: Dict[str, Any],spaced=True) -> None: + stats: Dict[str, Any], spaced=True) -> None: """ Display GitHub statistics in neofetch style. @@ -35,13 +36,13 @@ def display(self, username: str, user_data: Dict[str, Any], if layout == 'minimal': # Only show contribution graph - self._display_minimal(username, stats,spaced) + self._display_minimal(username, stats, spaced) elif layout == 'compact': # Show graph and key info - self._display_compact(username, user_data, stats,spaced) + self._display_compact(username, user_data, stats, spaced) else: # Full layout with all sections - self._display_full(username, user_data, stats,spaced) + self._display_full(username, user_data, stats, spaced) print() # Empty line at the end @@ -68,11 +69,11 @@ def _display_minimal(self, username: str, stats: Dict[str, Any], spaced=True) -> print(line) def _display_compact(self, username: str, user_data: Dict[str, Any], - stats: Dict[str, Any], spaced= True) -> None: - """Display graph and minimal info side-by-side.""" + stats: Dict[str, Any], spaced=True) -> None: + """Display graph and minimal info side-by-side (no languages).""" contrib_graph = stats.get('contribution_graph', []) recent_weeks = self._get_recent_weeks(contrib_graph) - graph_width = max(40, (self.terminal_width - 10) // 2) + graph_width = max(40, (self.terminal_width - 40) // 2) graph_lines = self._get_contribution_graph_lines( contrib_graph, username, @@ -84,7 +85,6 @@ def _display_compact(self, username: str, user_data: Dict[str, Any], info_lines = self._format_user_info_compact(user_data, stats) achievements = self._build_achievements(recent_weeks) - # Combine sections right_side = list(info_lines) if achievements: right_side.append("") @@ -96,7 +96,6 @@ def _display_compact(self, username: str, user_data: Dict[str, Any], graph_part = (graph_lines[i] if i < len(graph_lines) else "") graph_len = self._display_width(graph_part) padding = " " * max(0, graph_width - graph_len) - info_part = (right_side[i] if i < len(right_side) else "") print(f"{graph_part}{padding} {info_part}") @@ -116,11 +115,17 @@ def _display_full(self, username: str, user_data: Dict[str, Any], pull_request_lines = self._format_pull_requests(stats) issue_lines = self._format_issues(stats) - section_columns = [ - pull_request_lines, - issue_lines, - ] - + # Only show PR/Issue columns if they fit side by side, otherwise show neither + section_columns = [] + if pull_request_lines and issue_lines: + pr_width = max((self._display_width(line) + for line in pull_request_lines), default=0) + issue_width = max((self._display_width(line) + for line in issue_lines), default=0) + total_width = pr_width + issue_width + len(" ") # gap + if total_width <= graph_width: + section_columns = [pull_request_lines, issue_lines] + # Do not show only one column; only show both if they fit combined_sections = self._combine_section_grid( section_columns, width_limit=graph_width ) @@ -132,7 +137,7 @@ def _display_full(self, username: str, user_data: Dict[str, Any], language_lines = self._format_languages(stats) right_side = list(info_lines) - if language_lines: + if language_lines and self.terminal_width >= 120: right_side.append("") right_side.extend(language_lines) diff --git a/src/gitfetch/fetcher.py b/src/gitfetch/fetcher.py index f8a9838..ab98f96 100644 --- a/src/gitfetch/fetcher.py +++ b/src/gitfetch/fetcher.py @@ -236,13 +236,28 @@ def _calculate_language_stats(self, repos: list) -> Dict[str, float]: Returns: Dictionary mapping language names to percentages """ - language_counts: Dict[str, int] = {} + from collections import defaultdict + + # First pass: collect all language occurrences with their casing + language_occurrences: Dict[str, Dict[str, int]] = defaultdict( + lambda: defaultdict(int)) for repo in repos: language = repo.get('language') if language: - language_counts[language] = language_counts.get( - language, 0) + 1 + # Group by lowercase name, but keep track of different casings + normalized = language.lower() + language_occurrences[normalized][language] += 1 + + # Second pass: choose canonical casing (most frequent) and sum counts + language_counts: Dict[str, int] = {} + + for normalized, casings in language_occurrences.items(): + # Find the most common casing + canonical_name = max(casings.items(), key=lambda x: x[1])[0] + # Sum all occurrences for this language + total_count = sum(casings.values()) + language_counts[canonical_name] = total_count # Calculate percentages total = sum(language_counts.values())