v2.30.0-pre4 15d9fe3

parse.go RawHistoryFolder

1// Package bytesize provides human-friendly byte size parsing.
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// Parse parses a human-friendly byte size string.
21//
22// Supported units: B, KB, MB, GB, TB (case-insensitive).
23// The decimal prefix (1024-based) is used (KiB, MiB, etc.).
24//
25// Returns int64 to safely integrate with standard library functions like http.MaxBytesReader.
26// Maximum representable value is 9,223,372,036,854,775,807 bytes (~8 exabytes).
27//
28// Examples:
29//
30//	Parse("512MB")  // 536870912 bytes
31//	Parse("1GB")    // 1073741824 bytes
32//	Parse("100KB")  // 102400 bytes
33//	Parse("1.5GB")  // 1610612736 bytes
34func Parse(s string) (int64, error) {
35	s = strings.TrimSpace(s)
36
37	if s == "" {
38		return 0, fmt.Errorf("empty size string")
39	}
40
41	s = strings.ToUpper(s)
42
43	// Find the unit suffix - try longest first to avoid matching "B" before "KB"
44	units := []string{"TB", "GB", "MB", "KB", "B"}
45	var unit string
46	var valueStr string
47
48	for _, u := range units {
49		if strings.HasSuffix(s, u) {
50			unit = u
51			valueStr = strings.TrimSuffix(s, u)
52			break
53		}
54	}
55
56	if unit == "" {
57		return 0, fmt.Errorf("invalid size %q: missing unit (supported: B, KB, MB, GB, TB)", s)
58	}
59
60	valueStr = strings.TrimSpace(valueStr)
61	if valueStr == "" {
62		return 0, fmt.Errorf("invalid size %q: missing numeric value", s)
63	}
64
65	value, err := strconv.ParseFloat(valueStr, 64)
66	if err != nil {
67		return 0, fmt.Errorf("invalid size value %q in %q: %w", valueStr, s, err)
68	}
69
70	if value < 0 {
71		return 0, fmt.Errorf("invalid size %q: negative value not allowed", s)
72	}
73
74	multiplier := unitMultipliers[unit]
75	result := value * float64(multiplier)
76
77	// Check for overflow before converting to int64
78	if result > math.MaxInt64 {
79		return 0, fmt.Errorf("size %q exceeds maximum allowed value (9.2 EB)", s)
80	}
81
82	return int64(result), nil
83}

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