Skip to content

Commit 0679075

Browse files
authored
Merge pull request #10 from Zeviraty/main
Added support for color configuration
2 parents a2ec212 + c2bb194 commit 0679075

File tree

3 files changed

+96
-39
lines changed

3 files changed

+96
-39
lines changed

src/gitfetch/cli.py

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,18 @@ def parse_args() -> argparse.Namespace:
4444
help="GitHub personal access token (optional, increases rate limits)"
4545
)
4646

47+
parser.add_argument(
48+
"--spaced",
49+
action="store_true",
50+
help="Enable spaced layout"
51+
)
52+
53+
parser.add_argument(
54+
"--not-spaced",
55+
action="store_true",
56+
help="Disable spaced layout"
57+
)
58+
4759
parser.add_argument(
4860
"--version",
4961
action="store_true",
@@ -94,7 +106,13 @@ def main() -> int:
94106
cache_expiry = config_manager.get_cache_expiry_hours()
95107
cache_manager = CacheManager(cache_expiry_hours=cache_expiry)
96108
fetcher = GitHubFetcher() # Uses gh CLI, no token needed
97-
formatter = DisplayFormatter()
109+
formatter = DisplayFormatter(config_manager)
110+
if args.spaced:
111+
spaced = True
112+
elif args.not_spaced:
113+
spaced = False
114+
else:
115+
spaced = True
98116

99117
# Handle cache clearing
100118
if args.clear_cache:
@@ -128,8 +146,12 @@ def main() -> int:
128146
username)
129147
stale_stats = cache_manager.get_stale_cached_stats(username)
130148
if stale_user_data is not None and stale_stats is not None:
131-
formatter.display(username, stale_user_data, stale_stats)
132-
print("\n🔄 Refreshing data in background...", file=sys.stderr)
149+
# Display stale cache immediately
150+
formatter.display(username, stale_user_data, stale_stats, spaced=spaced)
151+
print("\n🔄 Refreshing data in background...",
152+
file=sys.stderr)
153+
154+
# Refresh cache in background (don't wait for it)
133155
import threading
134156

135157
def refresh_cache():
@@ -150,7 +172,11 @@ def refresh_cache():
150172
user_data = fetcher.fetch_user_data(username)
151173
stats = fetcher.fetch_user_stats(username, user_data)
152174
cache_manager.cache_user_data(username, user_data, stats)
153-
formatter.display(username, user_data, stats)
175+
# else: fresh cache available, proceed to display
176+
177+
# Display the results
178+
formatter.display(username, user_data, stats, spaced=spaced)
179+
154180
return 0
155181
except Exception as e:
156182
print(f"Error: {e}", file=sys.stderr)

src/gitfetch/config.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,42 @@ def _ensure_config_dir(self) -> None:
2525

2626
def _load_config(self) -> None:
2727
"""Load configuration from file."""
28+
default_colors = {
29+
'reset': '\\033[0m',
30+
'bold': '\\033[1m',
31+
'dim': '\\033[2m',
32+
'red': '\\033[91m',
33+
'green': '\\033[92m',
34+
'yellow': '\\033[93m',
35+
'blue': '\\033[94m',
36+
'magenta': '\\033[95m',
37+
'cyan': '\\033[96m',
38+
'white': '\\033[97m',
39+
'orange': '\\033[38;2;255;165;0m',
40+
'accent': '\\033[1m',
41+
'header': '\\033[38;2;118;215;161m',
42+
'muted': '\\033[2m',
43+
'0': '\\033[48;5;238m',
44+
'1': '\\033[48;5;28m',
45+
'2': '\\033[48;5;34m',
46+
'3': '\\033[48;5;40m',
47+
'4': '\\033[48;5;82m'
48+
}
2849
if self.CONFIG_FILE.exists():
2950
self.config.read(self.CONFIG_FILE)
51+
if "COLORS" in self.config:
52+
self.config._sections['COLORS'] = {**default_colors, **self.config._sections['COLORS']}
53+
else:
54+
self.config._sections['COLORS'] = default_colors
3055
else:
3156
# Create default config
3257
self.config['DEFAULT'] = {
3358
'username': '',
3459
'cache_expiry_hours': '24'
3560
}
61+
self.config._sections['COLORS'] = default_colors
62+
for k,v in self.config._sections['COLORS'].items():
63+
self.config._sections['COLORS'][k] = v.encode('utf-8').decode('unicode_escape')
3664

3765
def get_default_username(self) -> Optional[str]:
3866
"""
@@ -44,6 +72,15 @@ def get_default_username(self) -> Optional[str]:
4472
username = self.config.get('DEFAULT', 'username', fallback='')
4573
return username if username else None
4674

75+
def get_colors(self) -> dict:
76+
"""
77+
Get colors
78+
79+
Returns:
80+
User defined colors or default colors if not set
81+
"""
82+
return self.config._sections["COLORS"]
83+
4784
def set_default_username(self, username: str) -> None:
4885
"""
4986
Set the default GitHub username in config.

src/gitfetch/display.py

Lines changed: 29 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -8,38 +8,40 @@
88
import re
99
import unicodedata
1010
from datetime import datetime
11-
11+
from .config import ConfigManager
1212

1313
class DisplayFormatter:
1414
"""Formats and displays GitHub stats in a neofetch-style layout."""
1515

16-
def __init__(self):
16+
def __init__(self,config_manager: ConfigManager):
1717
"""Initialize the display formatter."""
1818
self.terminal_width = shutil.get_terminal_size().columns
1919
self.enable_color = sys.stdout.isatty()
20+
self.colors = config_manager.get_colors()
2021

2122
def display(self, username: str, user_data: Dict[str, Any],
22-
stats: Dict[str, Any]) -> None:
23+
stats: Dict[str, Any],spaced=True) -> None:
2324
"""
2425
Display GitHub statistics in neofetch style.
2526
2627
Args:
2728
username: GitHub username
2829
user_data: User profile data
2930
stats: User statistics data
31+
spaced: Spaced layout
3032
"""
3133
# Determine layout based on terminal width
3234
layout = self._determine_layout()
3335

3436
if layout == 'minimal':
3537
# Only show contribution graph
36-
self._display_minimal(username, stats)
38+
self._display_minimal(username, stats,spaced)
3739
elif layout == 'compact':
3840
# Show graph and key info
39-
self._display_compact(username, user_data, stats)
41+
self._display_compact(username, user_data, stats,spaced)
4042
else:
4143
# Full layout with all sections
42-
self._display_full(username, user_data, stats)
44+
self._display_full(username, user_data, stats,spaced)
4345

4446
print() # Empty line at the end
4547

@@ -52,20 +54,21 @@ def _determine_layout(self) -> str:
5254
else:
5355
return 'full'
5456

55-
def _display_minimal(self, username: str, stats: Dict[str, Any]) -> None:
57+
def _display_minimal(self, username: str, stats: Dict[str, Any], spaced=True) -> None:
5658
"""Display only contribution graph for narrow terminals."""
5759
contrib_graph = stats.get('contribution_graph', [])
5860
graph_lines = self._get_contribution_graph_lines(
5961
contrib_graph,
6062
username,
6163
width_constraint=self.terminal_width - 4,
62-
include_sections=False
64+
include_sections=False,
65+
spaced=spaced,
6366
)
6467
for line in graph_lines:
6568
print(line)
6669

6770
def _display_compact(self, username: str, user_data: Dict[str, Any],
68-
stats: Dict[str, Any]) -> None:
71+
stats: Dict[str, Any], spaced= True) -> None:
6972
"""Display graph and minimal info side-by-side."""
7073
contrib_graph = stats.get('contribution_graph', [])
7174
recent_weeks = self._get_recent_weeks(contrib_graph)
@@ -74,7 +77,8 @@ def _display_compact(self, username: str, user_data: Dict[str, Any],
7477
contrib_graph,
7578
username,
7679
width_constraint=graph_width,
77-
include_sections=False
80+
include_sections=False,
81+
spaced=spaced,
7882
)
7983

8084
info_lines = self._format_user_info_compact(user_data, stats)
@@ -97,15 +101,16 @@ def _display_compact(self, username: str, user_data: Dict[str, Any],
97101
print(f"{graph_part}{padding} {info_part}")
98102

99103
def _display_full(self, username: str, user_data: Dict[str, Any],
100-
stats: Dict[str, Any]) -> None:
104+
stats: Dict[str, Any], spaced=True) -> None:
101105
"""Display full layout with graph and all info sections."""
102106
contrib_graph = stats.get('contribution_graph', [])
103107
graph_width = max(50, (self.terminal_width - 10) // 2)
104108
left_side = self._get_contribution_graph_lines(
105109
contrib_graph,
106110
username,
107111
width_constraint=graph_width,
108-
include_sections=False
112+
include_sections=False,
113+
spaced=spaced,
109114
)
110115

111116
pull_request_lines = self._format_pull_requests(stats)
@@ -152,7 +157,8 @@ def _display_full(self, username: str, user_data: Dict[str, Any],
152157
def _get_contribution_graph_lines(self, weeks_data: list,
153158
username: str,
154159
width_constraint: int = None,
155-
include_sections: bool = True) -> list:
160+
include_sections: bool = True,
161+
spaced: bool = True) -> list:
156162
"""
157163
Get contribution graph as lines for display.
158164
@@ -187,7 +193,10 @@ def _get_contribution_graph_lines(self, weeks_data: list,
187193
for idx in range(7):
188194
day = days[idx] if idx < len(days) else {}
189195
count = day.get('contributionCount', 0)
190-
block = self._get_contribution_block_spaced(count)
196+
if spaced:
197+
block = self._get_contribution_block_spaced(count)
198+
else:
199+
block = self._get_contribution_block(count)
191200
day_rows[idx].append(block)
192201

193202
lines = [*header_lines]
@@ -825,22 +834,7 @@ def _colorize(self, text: str, color: str) -> str:
825834
if not text:
826835
return text
827836

828-
colors = {
829-
'reset': '\033[0m',
830-
'bold': '\033[1m',
831-
'dim': '\033[2m',
832-
'red': '\033[91m',
833-
'green': '\033[92m',
834-
'yellow': '\033[93m',
835-
'blue': '\033[94m',
836-
'magenta': '\033[95m',
837-
'cyan': '\033[96m',
838-
'white': '\033[97m',
839-
'orange': '\033[38;2;255;165;0m',
840-
'accent': '\033[1m',
841-
'header': '\033[38;2;118;215;161m',
842-
'muted': '\033[2m'
843-
}
837+
colors = self.colors
844838

845839
color_code = colors.get(color.lower())
846840
reset = colors['reset']
@@ -882,15 +876,15 @@ def _get_contribution_block(self, count: int) -> str:
882876

883877
reset = '\033[0m'
884878
if count == 0:
885-
color = '\033[48;5;238m'
879+
color = self.colors['0']
886880
elif count < 3:
887-
color = '\033[48;5;28m'
881+
color = self.colors['1']
888882
elif count < 7:
889-
color = '\033[48;5;34m'
883+
color = self.colors['2']
890884
elif count < 13:
891-
color = '\033[48;5;40m'
885+
color = self.colors['3']
892886
else:
893-
color = '\033[48;5;82m'
887+
color = self.colors['4']
894888

895889
return f"{color} {reset}"
896890

0 commit comments

Comments
 (0)