v2.31.0-dev17 bd898f0

parse.go RawHistoryFolder

1// Package bytesize provides human-friendly byte size parsing and formatting.
2package bytesize
3
4import (
5	"fmt"
6	"math"
7	"strconv"
8	"strings"
9)
10
11// unitMultipliers maps human-friendly unit suffixes to their byte values.
12var unitMultipliers = map[string]int64{
13	"B":  1,
14	"KB": 1 << 10, // 1024
15	"MB": 1 << 20, // 1048576
16	"GB": 1 << 30, // 1073741824
17	"TB": 1 << 40, // 1099511627776
18}
19
20// Format converts a byte count into a human-friendly string.
21//
22// Uses binary (1024-based) units: B, KB, MB, GB, TB.
23// Returns one decimal place for KB and above.
24//
25// Examples:
26//
27//	Format(512)        // "512 B"
28//	Format(1048576)    // "1.0 MB"
29//	Format(3609629152) // "3.4 GB"
30func Format(bytes int64) string {
31	if bytes <= 0 {
32		return "0 B"
33	}
34	units := []string{"B", "KB", "MB", "GB", "TB"}
35	size := float64(bytes)
36	unitIdx := 0
37	for size >= 1024 && unitIdx < len(units)-1 {
38		size /= 1024
39		unitIdx++
40	}
41	if unitIdx == 0 {
42		return fmt.Sprintf("%d B", bytes)
43	}
44	return fmt.Sprintf("%.1f %s", size, units[unitIdx])
45}
46
47// Parse parses a human-friendly byte size string.
48//
49// Supported units: B, KB, MB, GB, TB (case-insensitive).
50// The decimal prefix (1024-based) is used (KiB, MiB, etc.).
51//
52// Returns int64 to safely integrate with standard library functions like http.MaxBytesReader.
53// Maximum representable value is 9,223,372,036,854,775,807 bytes (~8 exabytes).
54//
55// Examples:
56//
57//	Parse("512MB")  // 536870912 bytes
58//	Parse("1GB")    // 1073741824 bytes
59//	Parse("100KB")  // 102400 bytes
60//	Parse("1.5GB")  // 1610612736 bytes
61func Parse(s string) (int64, error) {
62	s = strings.TrimSpace(s)
63
64	if s == "" {
65		return 0, fmt.Errorf("empty size string")
66	}
67
68	s = strings.ToUpper(s)
69
70	// Find the unit suffix - try longest first to avoid matching "B" before "KB"
71	units := []string{"TB", "GB", "MB", "KB", "B"}
72	var unit string
73	var valueStr string
74
75	for _, u := range units {
76		if strings.HasSuffix(s, u) {
77			unit = u
78			valueStr = strings.TrimSuffix(s, u)
79			break
80		}
81	}
82
83	if unit == "" {
84		return 0, fmt.Errorf("invalid size %q: missing unit (supported: B, KB, MB, GB, TB)", s)
85	}
86
87	valueStr = strings.TrimSpace(valueStr)
88	if valueStr == "" {
89		return 0, fmt.Errorf("invalid size %q: missing numeric value", s)
90	}
91
92	value, err := strconv.ParseFloat(valueStr, 64)
93	if err != nil {
94		return 0, fmt.Errorf("invalid size value %q in %q: %w", valueStr, s, err)
95	}
96
97	if value < 0 {
98		return 0, fmt.Errorf("invalid size %q: negative value not allowed", s)
99	}
100
101	multiplier := unitMultipliers[unit]
102	result := value * float64(multiplier)
103
104	// Check for overflow before converting to int64
105	if result > math.MaxInt64 {
106		return 0, fmt.Errorf("size %q exceeds maximum allowed value (9.2 EB)", s)
107	}
108
109	return int64(result), nil
110}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close