Skip to content

Commit d719264

Browse files
committed
custom width
1 parent d973d80 commit d719264

File tree

3 files changed

+174
-49
lines changed

3 files changed

+174
-49
lines changed

README.md

Lines changed: 103 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# gitfetch
22

3-
A neofetch-style CLI tool for GitHub, GitLab, Gitea, Forgejo, Codeberg, and Sourcehut statistics. Display your profile and stats from various git hosting platforms in a beautiful, colorful terminal interface.
3+
A neofetch-style CLI tool for GitHub, GitLab, Gitea, Forgejo, Codeberg, and Sourcehut statistics. Display your profile and stats from various git hosting platforms in a beautiful, colorful terminal interface with extensive customization options and intelligent layout adaptation.
44

55
<img width="3024" height="1964" alt="image" src="https://github.com/user-attachments/assets/bbb18d5d-4787-4998-a352-e8f4e59642c0" />
66

@@ -11,9 +11,10 @@ A neofetch-style CLI tool for GitHub, GitLab, Gitea, Forgejo, Codeberg, and Sour
1111
- Neofetch-style display with ASCII art
1212
- Comprehensive statistics from multiple git hosting platforms
1313
- Smart SQLite-based caching system for faster subsequent runs
14-
- Persistent configuration with default username support
1514
- Cross-platform support (macOS and Linux)
1615
- First-run initialization with interactive provider selection
16+
- Customize contribution characters, hide/show sections, control display elements
17+
- Flags for advanced configuration (e.g., `--no-date`, `--graph-only`, `--custom-box`, `--width`, `--height`) see full list below with `gitfetch --help`
1718

1819
## Supported Platforms
1920

@@ -118,6 +119,8 @@ Fetch stats for specific user:
118119
gitfetch username
119120
```
120121

122+
### Cache Options
123+
121124
Bypass cache and fetch fresh data:
122125

123126
```bash
@@ -130,6 +133,95 @@ Clear cache:
130133
gitfetch --clear-cache
131134
```
132135

136+
### Visual Customization
137+
138+
Customize contribution block characters:
139+
140+
```bash
141+
gitfetch --custom-box "██"
142+
gitfetch --custom-box ""
143+
gitfetch --custom-box ""
144+
```
145+
146+
Set custom graph dimensions:
147+
148+
```bash
149+
gitfetch --width 50 --height 5 # 50 chars wide, 5 days high
150+
gitfetch --width 100 # Custom width, default height
151+
gitfetch --height 3 # Default width, 3 days high
152+
```
153+
154+
Hide month/date labels:
155+
156+
```bash
157+
gitfetch --no-date
158+
```
159+
160+
Show only contribution graph:
161+
162+
```bash
163+
gitfetch --graph-only
164+
```
165+
166+
Hide specific sections:
167+
168+
```bash
169+
gitfetch --no-achievements # Hide achievements
170+
gitfetch --no-languages # Hide languages
171+
gitfetch --no-issues # Hide issues section
172+
gitfetch --no-pr # Hide pull requests
173+
gitfetch --no-account # Hide account info
174+
gitfetch --no-grid # Hide contribution grid
175+
```
176+
177+
Combine multiple options:
178+
179+
```bash
180+
gitfetch --no-date --no-achievements --custom-box "" --width 60
181+
```
182+
183+
### Layout Control
184+
185+
gitfetch automatically adapts to your terminal size, but you can control spacing:
186+
187+
```bash
188+
gitfetch --spaced # Enable spaced layout
189+
gitfetch --not-spaced # Disable spaced layout
190+
```
191+
192+
### Custom Dimensions and Coloring Accuracy
193+
194+
The coloring system uses GitHub's standard contribution levels, which are absolute thresholds that remain consistent regardless of the time period or dimensions displayed:
195+
196+
- **0 contributions**: Lightest gray
197+
- **1-2 contributions**: Light green (Level 1)
198+
- **3-6 contributions**: Medium green (Level 2)
199+
- **7-12 contributions**: Dark green (Level 3)
200+
- **13+ contributions**: Darkest green (Level 4)
201+
202+
**What Custom Dimensions Affect:**
203+
204+
- `--width` and `--height` control how many weeks/days are visible
205+
- The coloring thresholds remain the same (GitHub standard)
206+
- You see the same accurate representation, just for a different time period
207+
208+
**When It Might Seem "Inaccurate":**
209+
If you're viewing only recent weeks with generally lower activity, everything might appear in lighter colors. This is actually correct - those weeks truly have fewer contributions compared to your overall history standards.
210+
211+
**Recommendation:** The current coloring is accurate. Custom dimensions don't reduce accuracy - they just show different portions of your accurately-colored contribution history.
212+
213+
## Intelligent Layout System
214+
215+
gitfetch automatically selects the best layout based on your terminal dimensions:
216+
217+
- **Full Layout**: Shows all sections (graph, account info, languages, achievements) when there's sufficient space (width ≥ 120 columns)
218+
- **Compact Layout**: Shows graph and key info side-by-side for medium terminals
219+
- **Minimal Layout**: Shows only the contribution graph for narrow terminals
220+
221+
The system considers both terminal width AND height to ensure optimal display. For very short terminals, it may choose more compact layouts even with sufficient width.
222+
223+
You can override automatic layout selection using the `--width` and `--height` flags to set custom graph dimensions, which will force gitfetch to adapt the layout accordingly.
224+
133225
## Troubleshooting
134226

135227
### Error: GitHub CLI is not authenticated
@@ -167,12 +259,17 @@ username = yourusername
167259
cache_expiry_hours = 24
168260
provider = github
169261
provider_url = https://api.github.com
262+
custom_box = ■
170263
```
171264

172265
- `username`: Your default username (automatically detected)
173266
- `cache_expiry_hours`: How long to keep cached data (default: 24 hours)
174267
- `provider`: Git hosting provider (github, gitlab, gitea, sourcehut)
175268
- `provider_url`: API URL for the provider
269+
- `custom_box`: Character used for contribution blocks (default: ■)
270+
271+
**Note**: Custom graph dimensions (`--width`, `--height`) and section visibility flags (`--no-*`) are command-line only and not saved in the configuration file.
272+
Howerver if there is a need for it to be added to the config file please open an issue.
176273

177274
### [COLORS] Section
178275

@@ -207,10 +304,12 @@ If you have an older version of gitfetch that stored cache in `~/.config/gitfetc
207304
```bash
208305
rm ~/.config/gitfetch/cache.db
209306
```
307+
210308
## Acknowledgements
211309

212-
- Inspired by the beautiful contribution graph design from [Kusa](https://github.com/Ryu0118/Kusa) by Ryu0118.
213-
- Inspired by the very cool and extremely fun tool [songfetch](https://github.com/fwtwoo/songfetch) by fwtwoo.
310+
- Inspired by the beautiful contribution graph design from [Kusa](https://github.com/Ryu0118/Kusa) by Ryu0118
311+
- Inspired by the very cool and extremely fun tool [songfetch](https://github.com/fwtwoo/songfetch) by fwtwoo
312+
- Built with modern Python practices and extensive customization options for the ultimate git statistics display
214313

215314
## License
216315

src/gitfetch/cli.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,18 @@ def parse_args() -> argparse.Namespace:
120120
help="Hide contribution grid/graph"
121121
)
122122

123+
visual_group.add_argument(
124+
"--width",
125+
type=int,
126+
help="Set custom width for contribution graph"
127+
)
128+
129+
visual_group.add_argument(
130+
"--height",
131+
type=int,
132+
help="Set custom height for contribution graph"
133+
)
134+
123135
return parser.parse_args()
124136

125137

@@ -176,7 +188,7 @@ def main() -> int:
176188
args.graph_only, not args.no_achievements,
177189
not args.no_languages, not args.no_issues,
178190
not args.no_pr, not args.no_account,
179-
not args.no_grid)
191+
not args.no_grid, args.width, args.height)
180192
if args.spaced:
181193
spaced = True
182194
elif args.not_spaced:

src/gitfetch/display.py

Lines changed: 58 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,16 @@ class DisplayFormatter:
1616

1717
def __init__(self, config_manager: ConfigManager,
1818
custom_box: Optional[str] = None,
19-
show_date: bool = True,
19+
show_date: Optional[bool] = None,
2020
graph_only: bool = False,
2121
show_achievements: bool = True,
2222
show_languages: bool = True,
2323
show_issues: bool = True,
2424
show_pr: bool = True,
2525
show_account: bool = True,
26-
show_grid: bool = True):
26+
show_grid: bool = True,
27+
custom_width: Optional[int] = None,
28+
custom_height: Optional[int] = None):
2729
"""Initialize the display formatter."""
2830
terminal_size = shutil.get_terminal_size()
2931
self.terminal_width = terminal_size.columns
@@ -33,14 +35,17 @@ def __init__(self, config_manager: ConfigManager,
3335
self.enable_color = sys.stdout.isatty()
3436
self.colors = config_manager.get_colors()
3537
self.custom_box = custom_box or config_manager.get_custom_box() or "■"
36-
self.show_date = show_date
38+
self.show_date = (show_date if show_date is not None
39+
else config_manager.get_show_date())
3740
self.graph_only = graph_only
3841
self.show_achievements = show_achievements
3942
self.show_languages = show_languages
4043
self.show_issues = show_issues
4144
self.show_pr = show_pr
4245
self.show_account = show_account
4346
self.show_grid = show_grid
47+
self.custom_width = custom_width
48+
self.custom_height = custom_height
4449

4550
def display(self, username: str, user_data: Dict[str, Any],
4651
stats: Dict[str, Any], spaced=True) -> None:
@@ -96,14 +101,11 @@ def _calculate_minimal_dimensions(self, username: str,
96101
height = len(header_lines)
97102
return (width, height)
98103

99-
contrib_graph = stats.get('contribution_graph', [])
100-
graph_lines = self._get_contribution_graph_lines(
101-
contrib_graph, username, width_constraint=self.terminal_width - 4,
102-
include_sections=False, spaced=True
103-
)
104-
width = max((self._display_width(line) for line in graph_lines),
105-
default=0)
106-
height = len(graph_lines)
104+
# Use custom dimensions if provided
105+
width = (self.custom_width if self.custom_width is not None
106+
else self.terminal_width - 4)
107+
height = (self.custom_height if self.custom_height is not None
108+
else 7)
107109
return (width, height)
108110

109111
def _calculate_compact_dimensions(self, username: str,
@@ -112,17 +114,20 @@ def _calculate_compact_dimensions(self, username: str,
112114
"""Calculate dimensions for compact layout."""
113115
contrib_graph = stats.get('contribution_graph', [])
114116
recent_weeks = self._get_recent_weeks(contrib_graph)
115-
graph_width = max(40, (self.terminal_width - 40) // 2)
117+
graph_width = (self.custom_width if self.custom_width is not None
118+
else max(40, (self.terminal_width - 40) // 2))
116119

117120
if self.show_grid:
118-
graph_lines = self._get_contribution_graph_lines(
119-
contrib_graph, username, width_constraint=graph_width,
120-
include_sections=False, spaced=True
121-
)
121+
# Use custom height for graph height
122+
graph_height = (self.custom_height if self.custom_height is not None
123+
else 7)
122124
else:
123125
# Just header for dimensions
124126
total_contribs = self._calculate_total_contributions(recent_weeks)
125127
graph_lines = self._graph_header(username, total_contribs)
128+
graph_width = max((self._display_width(line) for line in graph_lines),
129+
default=0)
130+
graph_height = len(graph_lines)
126131

127132
right_side = []
128133
if self.show_account:
@@ -135,7 +140,7 @@ def _calculate_compact_dimensions(self, username: str,
135140
right_side.append("")
136141
right_side.extend(achievements)
137142

138-
max_lines = max(len(graph_lines), len(right_side))
143+
max_lines = max(graph_height, len(right_side))
139144
right_width = max((self._display_width(line) for line in right_side),
140145
default=0)
141146
total_width = graph_width + 2 + right_width
@@ -291,30 +296,32 @@ def _display_full(self, username: str, user_data: Dict[str, Any],
291296
)
292297

293298
# Add PR/issues sections to left side if enabled
294-
if self.show_pr or self.show_issues:
295-
pull_request_lines = (self._format_pull_requests(stats)
296-
if self.show_pr else [])
297-
issue_lines = (self._format_issues(stats)
298-
if self.show_issues else [])
299-
300-
# Only show PR/Issue columns if they fit side by side
301-
section_columns = []
302-
if pull_request_lines and issue_lines:
303-
pr_width = max((self._display_width(line)
304-
for line in pull_request_lines), default=0)
305-
issue_width = max((self._display_width(line)
306-
for line in issue_lines), default=0)
307-
total_width = pr_width + issue_width + len(" ") # gap
308-
if total_width <= graph_width:
309-
section_columns = [pull_request_lines, issue_lines]
310-
# Do not show only one column; only show both if they fit
311-
combined_sections = self._combine_section_grid(
312-
section_columns, width_limit=graph_width
313-
)
314-
if combined_sections:
315-
if left_side:
316-
left_side.append("")
317-
left_side.extend(combined_sections)
299+
if self.show_pr or self.show_issues:
300+
pull_request_lines = self._format_pull_requests(
301+
stats) if self.show_pr else []
302+
issue_lines = self._format_issues(
303+
stats) if self.show_issues else []
304+
305+
section_columns = []
306+
if pull_request_lines and issue_lines:
307+
pr_width = max((self._display_width(line)
308+
for line in pull_request_lines), default=0)
309+
issue_width = max((self._display_width(line)
310+
for line in issue_lines), default=0)
311+
total_width = pr_width + issue_width + len(" ") # gap
312+
if total_width <= graph_width:
313+
section_columns = [pull_request_lines, issue_lines]
314+
elif pull_request_lines:
315+
section_columns = [pull_request_lines]
316+
elif issue_lines:
317+
section_columns = [issue_lines]
318+
319+
combined_sections = self._combine_section_grid(
320+
section_columns, width_limit=graph_width)
321+
if combined_sections:
322+
if left_side:
323+
left_side.append("")
324+
left_side.extend(combined_sections)
318325
elif not self.show_grid:
319326
# If no grid and no PR/issues, show just header
320327
total_contribs = self._calculate_total_contributions(
@@ -386,18 +393,25 @@ def _get_contribution_graph_lines(self, weeks_data: list,
386393
return [*header_lines, *self._empty_graph_placeholder()]
387394

388395
# Calculate how many weeks we can fit
389-
if width_constraint is None:
396+
if self.custom_width is not None:
397+
width_constraint = self.custom_width
398+
elif width_constraint is None:
390399
width_constraint = self.terminal_width - 8
391400

392401
max_weeks = self._calculate_max_weeks(width_constraint)
393402
display_weeks = recent_weeks[-max_weeks:] if len(
394403
recent_weeks) > max_weeks else recent_weeks
395404

405+
# Determine how many days to show
406+
days_to_show = 7
407+
if self.custom_height is not None:
408+
days_to_show = min(7, max(1, self.custom_height))
409+
396410
# Prepare rows for each day of the week (Sun-Sat)
397-
day_rows = [[] for _ in range(7)]
411+
day_rows = [[] for _ in range(days_to_show)]
398412
for week in display_weeks:
399413
days = week.get('contributionDays', [])
400-
for idx in range(7):
414+
for idx in range(days_to_show):
401415
day = days[idx] if idx < len(days) else {}
402416
count = day.get('contributionCount', 0)
403417
if spaced:

0 commit comments

Comments
 (0)