on main help sign in
chore(ui): add new letterforms: h, y, p, e, with alts
15f20e6Christian Rocha
go.mod+1−1
@@ -31,7 +31,7 @@ require (
31 github.com/charmbracelet/x/exp/charmtone v0.0.0-20260109001716-2fbdffcb221f
31 github.com/charmbracelet/x/exp/charmtone v0.0.0-20260109001716-2fbdffcb221f
32 github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f
32 github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f
33 github.com/charmbracelet/x/exp/ordered v0.1.0
33 github.com/charmbracelet/x/exp/ordered v0.1.0
34− github.com/charmbracelet/x/exp/slice v0.0.0-20260209194814-eeb2896ac759
34+ github.com/charmbracelet/x/exp/slice v0.0.0-20260422141420-a6cbdff8a7e2
35 github.com/charmbracelet/x/exp/strings v0.1.0
35 github.com/charmbracelet/x/exp/strings v0.1.0
36 github.com/charmbracelet/x/powernap v0.1.4
36 github.com/charmbracelet/x/powernap v0.1.4
37 github.com/charmbracelet/x/term v0.2.2
37 github.com/charmbracelet/x/term v0.2.2
go.sum+2−2
@@ -122,8 +122,8 @@ github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f h1:pk6g
122github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f/go.mod h1:IfZAMTHB6XkZSeXUqriemErjAWCCzT0LwjKFYCZyw0I=
122github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f/go.mod h1:IfZAMTHB6XkZSeXUqriemErjAWCCzT0LwjKFYCZyw0I=
123github.com/charmbracelet/x/exp/ordered v0.1.0 h1:55/qLwjIh0gL0Vni+QAWk7T/qRVP6sBf+2agPBgnOFE=
123github.com/charmbracelet/x/exp/ordered v0.1.0 h1:55/qLwjIh0gL0Vni+QAWk7T/qRVP6sBf+2agPBgnOFE=
124github.com/charmbracelet/x/exp/ordered v0.1.0/go.mod h1:5UHwmG+is5THxMyCJHNPCn2/ecI07aKNrW+LcResjJ8=
124github.com/charmbracelet/x/exp/ordered v0.1.0/go.mod h1:5UHwmG+is5THxMyCJHNPCn2/ecI07aKNrW+LcResjJ8=
125−github.com/charmbracelet/x/exp/slice v0.0.0-20260209194814-eeb2896ac759 h1:96wFGlst+IDv3dIf5q29nw470wJYB3YAgemiciLZcG0=
125+github.com/charmbracelet/x/exp/slice v0.0.0-20260422141420-a6cbdff8a7e2 h1:EXQ7j9kQUGILoSIbxrr1osK9Ca3xqc6EJ7710FIiI3U=
126−github.com/charmbracelet/x/exp/slice v0.0.0-20260209194814-eeb2896ac759/go.mod h1:vqEfX6xzqW1pKKZUUiFOKg0OQ7bCh54Q2vR/tserrRA=
126+github.com/charmbracelet/x/exp/slice v0.0.0-20260422141420-a6cbdff8a7e2/go.mod h1:vqEfX6xzqW1pKKZUUiFOKg0OQ7bCh54Q2vR/tserrRA=
127github.com/charmbracelet/x/exp/strings v0.1.0 h1:i69S2XI7uG1u4NLGeJPSYU++Nmjvpo9nwd6aoEm7gkA=
127github.com/charmbracelet/x/exp/strings v0.1.0 h1:i69S2XI7uG1u4NLGeJPSYU++Nmjvpo9nwd6aoEm7gkA=
128github.com/charmbracelet/x/exp/strings v0.1.0/go.mod h1:/ehtMPNh9K4odGFkqYJKpIYyePhdp1hLBRvyY4bWkH8=
128github.com/charmbracelet/x/exp/strings v0.1.0/go.mod h1:/ehtMPNh9K4odGFkqYJKpIYyePhdp1hLBRvyY4bWkH8=
129github.com/charmbracelet/x/json v0.2.0 h1:DqB+ZGx2h+Z+1s98HOuOyli+i97wsFQIxP2ZQANTPrQ=
129github.com/charmbracelet/x/json v0.2.0 h1:DqB+ZGx2h+Z+1s98HOuOyli+i97wsFQIxP2ZQANTPrQ=
internal/ui/logo/example/main.gonew file+49
@@ -0,0 +1,49 @@
1+package main
2+
3+import (
4+ "fmt"
5+ "math/rand/v2"
6+
7+ "charm.land/lipgloss/v2"
8+ "github.com/charmbracelet/crush/internal/ui/logo"
9+ "github.com/charmbracelet/x/exp/slice"
10+)
11+
12+func renderLetterforms(stretch bool) string {
13+ letterFuncs := []func(bool) string{
14+ logo.LetterH,
15+ logo.LetterY,
16+ logo.LetterYAlt,
17+ logo.LetterP,
18+ logo.LetterE,
19+ logo.LetterEAlt,
20+ logo.LetterR,
21+ logo.LetterC,
22+ logo.LetterR,
23+ logo.LetterU,
24+ logo.LetterSAlt,
25+ logo.LetterH,
26+ }
27+
28+ // Which letter to stretch, if we're stretching.
29+ stretchIndex := -1
30+ if stretch {
31+ stretchIndex = rand.IntN(len(letterFuncs))
32+ }
33+
34+ // Build letterforms.
35+ letterforms := make([]string, len(letterFuncs))
36+ for i, f := range letterFuncs {
37+ letterforms[i] = f(stretch && i == stretchIndex)
38+ }
39+ letterforms = slice.Intersperse(letterforms, " ")
40+
41+ return lipgloss.JoinHorizontal(lipgloss.Top, letterforms...)
42+}
43+
44+func main() {
45+ fmt.Println(renderLetterforms(false))
46+ for range 10 {
47+ fmt.Println(renderLetterforms(true))
48+ }
49+}
internal/ui/logo/letterforms.gonew file+419
@@ -0,0 +1,419 @@
1+package logo
2+
3+import (
4+ "strings"
5+
6+ "charm.land/lipgloss/v2"
7+ "github.com/MakeNowJust/heredoc"
8+ "github.com/charmbracelet/x/exp/slice"
9+)
10+
11+// renderWord renders letterforms to fork a word. stretchIndex is the index of
12+// the letter to stretch, or -1 if no letter should be stretched.
13+func renderWord(spacing int, stretchIndex int, letterforms ...letterform) string {
14+ if spacing < 0 {
15+ spacing = 0
16+ }
17+
18+ renderedLetterforms := make([]string, len(letterforms))
19+
20+ // pick one letter randomly to stretch
21+ for i, letter := range letterforms {
22+ renderedLetterforms[i] = letter(i == stretchIndex)
23+ }
24+
25+ if spacing > 0 {
26+ // Add spaces between the letters and render.
27+ renderedLetterforms = slice.Intersperse(renderedLetterforms, strings.Repeat(" ", spacing))
28+ }
29+ return strings.TrimSpace(
30+ lipgloss.JoinHorizontal(lipgloss.Top, renderedLetterforms...),
31+ )
32+}
33+
34+// LetterC renders the letter C in a stylized way. It takes an integer that
35+// determines how many cells to stretch the letter. If the stretch is less than
36+// 1, it defaults to no stretching.
37+func LetterC(stretch bool) string {
38+ // Here's what we're making:
39+ //
40+ // ▄▀▀▀▀
41+ // █
42+ // ▀▀▀▀
43+
44+ left := heredoc.Doc(`
45+ ▄
46+ █
47+ `)
48+ right := heredoc.Doc(`
49+ ▀
50+
51+ ▀
52+ `)
53+ return joinLetterform(
54+ left,
55+ stretchLetterformPart(right, letterformProps{
56+ stretch: stretch,
57+ width: 4,
58+ minStretch: 7,
59+ maxStretch: 12,
60+ }),
61+ )
62+}
63+
64+// LetterE renders the letter E in a stylized way. It takes an integer that
65+// determines how many cells to stretch the letter. If the stretch is less than
66+// 1, it defaults to no stretching.
67+//
68+// This is an alternate letterform. DO NOT REMOVE.
69+func LetterE(stretch bool) string {
70+ // Here's what we're making:
71+ //
72+ // █▀▀▀▀
73+ // █▀▀▀▀
74+ // ▀▀▀▀▀
75+
76+ left := heredoc.Doc(`
77+ █
78+ █
79+ ▀
80+ `)
81+ middle := heredoc.Doc(`
82+ ▀
83+ ▀
84+ ▀
85+ `)
86+ return joinLetterform(
87+ left,
88+ stretchLetterformPart(middle, letterformProps{
89+ stretch: stretch,
90+ width: 4,
91+ minStretch: 7,
92+ maxStretch: 12,
93+ }),
94+ )
95+}
96+
97+// LetterEAlt renders the letter E in a stylized way. It takes an integer that
98+// determines how many cells to stretch the letter. If the stretch is less than
99+// 1, it defaults to no stretching.
100+//
101+// This is an alternate letterform. DO NOT REMOVE.
102+func LetterEAlt(stretch bool) string {
103+ // Here's what we're making:
104+ //
105+ // █▀▀▀▀
106+ // █ ▀▀▀
107+ // ▀▀▀▀▀
108+
109+ left := heredoc.Doc(`
110+ █▀
111+ █
112+ ▀▀
113+ `)
114+ middle := heredoc.Doc(`
115+ ▀
116+ ▀
117+ ▀
118+ `)
119+ return joinLetterform(
120+ left,
121+ stretchLetterformPart(middle, letterformProps{
122+ stretch: stretch,
123+ width: 3,
124+ minStretch: 6,
125+ maxStretch: 11,
126+ }),
127+ )
128+}
129+
130+// LetterH renders the letter H in a stylized way. It takes an integer that
131+// determines how many cells to stretch the letter. If the stretch is less than
132+// 1, it defaults to no stretching.
133+func LetterH(stretch bool) string {
134+ // Here's what we're making:
135+ //
136+ // █ █
137+ // █▀▀▀█
138+ // ▀ ▀
139+
140+ side := heredoc.Doc(`
141+ █
142+ █
143+ ▀`)
144+ middle := heredoc.Doc(`
145+
146+ ▀
147+ `)
148+ return joinLetterform(
149+ side,
150+ stretchLetterformPart(middle, letterformProps{
151+ stretch: stretch,
152+ width: 3,
153+ minStretch: 8,
154+ maxStretch: 12,
155+ }),
156+ side,
157+ )
158+}
159+
160+// LetterP renders the letter P in a stylized way. It takes an integer that
161+// determines how many cells to stretch the letter. If the stretch is less than
162+// 1, it defaults to no stretching.
163+func LetterP(stretch bool) string {
164+ // Here's what we're making:
165+ //
166+ // █▀▀▀▄
167+ // █▀▀▀
168+ // ▀
169+
170+ left := heredoc.Doc(`
171+ █
172+ █
173+ ▀
174+ `)
175+ center := heredoc.Doc(`
176+ ▀
177+ ▀
178+ `)
179+ right := heredoc.Doc(`
180+ ▄
181+
182+
183+ `)
184+ return joinLetterform(
185+ left,
186+ stretchLetterformPart(center, letterformProps{
187+ stretch: stretch,
188+ width: 3,
189+ minStretch: 7,
190+ maxStretch: 12,
191+ }),
192+ right,
193+ )
194+}
195+
196+// LetterR renders the letter R in a stylized way. It takes an integer that
197+// determines how many cells to stretch the letter. If the stretch is less than
198+// 1, it defaults to no stretching.
199+func LetterR(stretch bool) string {
200+ // Here's what we're making:
201+ //
202+ // █▀▀▀▄
203+ // █▀▀▀▄
204+ // ▀ ▀
205+
206+ left := heredoc.Doc(`
207+ █
208+ █
209+ ▀
210+ `)
211+ center := heredoc.Doc(`
212+ ▀
213+ ▀
214+ `)
215+ right := heredoc.Doc(`
216+ ▄
217+ ▄
218+ ▀
219+ `)
220+ return joinLetterform(
221+ left,
222+ stretchLetterformPart(center, letterformProps{
223+ stretch: stretch,
224+ width: 3,
225+ minStretch: 7,
226+ maxStretch: 12,
227+ }),
228+ right,
229+ )
230+}
231+
232+// LetterSAlt renders the letter S in a stylized way, more so than
233+// [letterS]. It takes an integer that determines how many cells to stretch the
234+// letter. If the stretch is less than 1, it defaults to no stretching.
235+//
236+// This is an alternate letterform. DO NOT REMOVE.
237+func LetterSAlt(stretch bool) string {
238+ // Here's what we're making:
239+ //
240+ // ▄▀▀▀▀▀
241+ // ▀▀▀▀▀█
242+ // ▀▀▀▀▀
243+
244+ left := heredoc.Doc(`
245+ ▄
246+ ▀
247+ ▀
248+ `)
249+ center := heredoc.Doc(`
250+ ▀
251+ ▀
252+ ▀
253+ `)
254+ right := heredoc.Doc(`
255+ ▀
256+ █
257+ `)
258+ return joinLetterform(
259+ left,
260+ stretchLetterformPart(center, letterformProps{
261+ stretch: stretch,
262+ width: 3,
263+ minStretch: 7,
264+ maxStretch: 12,
265+ }),
266+ right,
267+ )
268+}
269+
270+// LetterU renders the letter U in a stylized way. It takes an integer that
271+// determines how many cells to stretch the letter. If the stretch is less than
272+// 1, it defaults to no stretching.
273+func LetterU(stretch bool) string {
274+ // Here's what we're making:
275+ //
276+ // █ █
277+ // █ █
278+ // ▀▀▀
279+
280+ side := heredoc.Doc(`
281+ █
282+ █
283+ `)
284+ middle := heredoc.Doc(`
285+
286+
287+ ▀
288+ `)
289+ return joinLetterform(
290+ side,
291+ stretchLetterformPart(middle, letterformProps{
292+ stretch: stretch,
293+ width: 3,
294+ minStretch: 7,
295+ maxStretch: 12,
296+ }),
297+ side,
298+ )
299+}
300+
301+// LetterY renders the letter Y in a stylized way. It takes an integer that
302+// determines how many cells to stretch the letter. If the stretch is less than
303+// 1, it defaults to no stretching.
304+//
305+// This is an alternate letterform. DO NOT REMOVE.
306+func LetterY(stretch bool) string {
307+ // Here's what we're making:
308+ //
309+ // █ █
310+ // ▀▄▀
311+ // ▀
312+
313+ side := heredoc.Doc(`
314+ █
315+
316+ `)
317+ inside := heredoc.Doc(`
318+
319+ ▀
320+
321+ `)
322+ middle := heredoc.Doc(`
323+
324+ ▄
325+ ▀
326+ `)
327+ if stretch {
328+ middle = heredoc.Doc(`
329+
330+ █
331+ ▀
332+ `)
333+ }
334+
335+ stretchedInside := stretchLetterformPart(inside, letterformProps{
336+ stretch: stretch,
337+ width: 1,
338+ minStretch: 4,
339+ maxStretch: 10,
340+ })
341+
342+ return joinLetterform(
343+ side,
344+ stretchedInside,
345+ middle,
346+ stretchedInside,
347+ side,
348+ )
349+}
350+
351+// LetterYAlt renders the letter Y in a stylized way. It takes an integer that
352+// determines how many cells to stretch the letter. If the stretch is less than
353+// 1, it defaults to no stretching.
354+//
355+// This is an alternate letterform. DO NOT REMOVE.
356+func LetterYAlt(stretch bool) string {
357+ // Here's what we're making:
358+ //
359+ // █ █
360+ // ▀▀▀▀█
361+ // ▀▀▀▀
362+
363+ left := heredoc.Doc(`
364+ █
365+ ▀
366+ ▀
367+ `)
368+ middle := heredoc.Doc(`
369+
370+ ▀
371+ ▀
372+ `)
373+ right := heredoc.Doc(`
374+ █
375+ █
376+
377+ `)
378+
379+ return joinLetterform(
380+ left,
381+ stretchLetterformPart(middle, letterformProps{
382+ stretch: stretch,
383+ width: 3,
384+ minStretch: 6,
385+ maxStretch: 10,
386+ }),
387+ right,
388+ )
389+}
390+
391+func joinLetterform(letters ...string) string {
392+ return lipgloss.JoinHorizontal(lipgloss.Top, letters...)
393+}
394+
395+// letterformProps defines letterform stretching properties.
396+// for readability.
397+type letterformProps struct {
398+ width int
399+ minStretch int
400+ maxStretch int
401+ stretch bool
402+}
403+
404+// stretchLetterformPart is a helper function for letter stretching. If randomize
405+// is false the minimum number will be used.
406+func stretchLetterformPart(s string, p letterformProps) string {
407+ if p.maxStretch < p.minStretch {
408+ p.minStretch, p.maxStretch = p.maxStretch, p.minStretch
409+ }
410+ n := p.width
411+ if p.stretch {
412+ n = cachedRandN(p.maxStretch-p.minStretch) + p.minStretch //nolint:gosec
413+ }
414+ parts := make([]string, n)
415+ for i := range parts {
416+ parts[i] = s
417+ }
418+ return lipgloss.JoinHorizontal(lipgloss.Top, parts...)
419+}
internal/ui/logo/logo.go+5−223
@@ -7,10 +7,8 @@ import (
7 "strings"
7 "strings"
8
8
9 "charm.land/lipgloss/v2"
9 "charm.land/lipgloss/v2"
10− "github.com/MakeNowJust/heredoc"
11 "github.com/charmbracelet/crush/internal/ui/styles"
10 "github.com/charmbracelet/crush/internal/ui/styles"
12 "github.com/charmbracelet/x/ansi"
11 "github.com/charmbracelet/x/ansi"
13− "github.com/charmbracelet/x/exp/slice"
14)
12)
15
13
16// letterform represents a letterform. It can be stretched horizontally by
14// letterform represents a letterform. It can be stretched horizontally by
@@ -44,11 +42,11 @@ func Render(s *styles.Styles, version string, compact bool, o Opts) string {
44 // Title.
42 // Title.
45 const spacing = 1
43 const spacing = 1
46 letterforms := []letterform{
44 letterforms := []letterform{
47− letterC,
45+ LetterC,
48− letterR,
46+ LetterR,
49− letterU,
47+ LetterU,
50− letterSStylized,
48+ LetterSAlt,
51− letterH,
49+ LetterH,
52 }
50 }
53 stretchIndex := -1 // -1 means no stretching.
51 stretchIndex := -1 // -1 means no stretching.
54 if !compact {
52 if !compact {
@@ -127,219 +125,3 @@ func SmallRender(t *styles.Styles, width int) string {
127 }
125 }
128 return title
126 return title
129}
127}
130−
131−// renderWord renders letterforms to fork a word. stretchIndex is the index of
132−// the letter to stretch, or -1 if no letter should be stretched.
133−func renderWord(spacing int, stretchIndex int, letterforms ...letterform) string {
134− if spacing < 0 {
135− spacing = 0
136− }
137−
138− renderedLetterforms := make([]string, len(letterforms))
139−
140− // pick one letter randomly to stretch
141− for i, letter := range letterforms {
142− renderedLetterforms[i] = letter(i == stretchIndex)
143− }
144−
145− if spacing > 0 {
146− // Add spaces between the letters and render.
147− renderedLetterforms = slice.Intersperse(renderedLetterforms, strings.Repeat(" ", spacing))
148− }
149− return strings.TrimSpace(
150− lipgloss.JoinHorizontal(lipgloss.Top, renderedLetterforms...),
151− )
152−}
153−
154−// letterC renders the letter C in a stylized way. It takes an integer that
155−// determines how many cells to stretch the letter. If the stretch is less than
156−// 1, it defaults to no stretching.
157−func letterC(stretch bool) string {
158− // Here's what we're making:
159− //
160− // ▄▀▀▀▀
161− // █
162− // ▀▀▀▀
163−
164− left := heredoc.Doc(`
165− ▄
166− █
167− `)
168− right := heredoc.Doc(`
169− ▀
170−
171− ▀
172− `)
173− return joinLetterform(
174− left,
175− stretchLetterformPart(right, letterformProps{
176− stretch: stretch,
177− width: 4,
178− minStretch: 7,
179− maxStretch: 12,
180− }),
181− )
182−}
183−
184−// letterH renders the letter H in a stylized way. It takes an integer that
185−// determines how many cells to stretch the letter. If the stretch is less than
186−// 1, it defaults to no stretching.
187−func letterH(stretch bool) string {
188− // Here's what we're making:
189− //
190− // █ █
191− // █▀▀▀█
192− // ▀ ▀
193−
194− side := heredoc.Doc(`
195− █
196− █
197− ▀`)
198− middle := heredoc.Doc(`
199−
200− ▀
201− `)
202− return joinLetterform(
203− side,
204− stretchLetterformPart(middle, letterformProps{
205− stretch: stretch,
206− width: 3,
207− minStretch: 8,
208− maxStretch: 12,
209− }),
210− side,
211− )
212−}
213−
214−// letterR renders the letter R in a stylized way. It takes an integer that
215−// determines how many cells to stretch the letter. If the stretch is less than
216−// 1, it defaults to no stretching.
217−func letterR(stretch bool) string {
218− // Here's what we're making:
219− //
220− // █▀▀▀▄
221− // █▀▀▀▄
222− // ▀ ▀
223−
224− left := heredoc.Doc(`
225− █
226− █
227− ▀
228− `)
229− center := heredoc.Doc(`
230− ▀
231− ▀
232− `)
233− right := heredoc.Doc(`
234− ▄
235− ▄
236− ▀
237− `)
238− return joinLetterform(
239− left,
240− stretchLetterformPart(center, letterformProps{
241− stretch: stretch,
242− width: 3,
243− minStretch: 7,
244− maxStretch: 12,
245− }),
246− right,
247− )
248−}
249−
250−// letterSStylized renders the letter S in a stylized way, more so than
251−// [letterS]. It takes an integer that determines how many cells to stretch the
252−// letter. If the stretch is less than 1, it defaults to no stretching.
253−func letterSStylized(stretch bool) string {
254− // Here's what we're making:
255− //
256− // ▄▀▀▀▀▀
257− // ▀▀▀▀▀█
258− // ▀▀▀▀▀
259−
260− left := heredoc.Doc(`
261− ▄
262− ▀
263− ▀
264− `)
265− center := heredoc.Doc(`
266− ▀
267− ▀
268− ▀
269− `)
270− right := heredoc.Doc(`
271− ▀
272− █
273− `)
274− return joinLetterform(
275− left,
276− stretchLetterformPart(center, letterformProps{
277− stretch: stretch,
278− width: 3,
279− minStretch: 7,
280− maxStretch: 12,
281− }),
282− right,
283− )
284−}
285−
286−// letterU renders the letter U in a stylized way. It takes an integer that
287−// determines how many cells to stretch the letter. If the stretch is less than
288−// 1, it defaults to no stretching.
289−func letterU(stretch bool) string {
290− // Here's what we're making:
291− //
292− // █ █
293− // █ █
294− // ▀▀▀
295−
296− side := heredoc.Doc(`
297− █
298− █
299− `)
300− middle := heredoc.Doc(`
301−
302−
303− ▀
304− `)
305− return joinLetterform(
306− side,
307− stretchLetterformPart(middle, letterformProps{
308− stretch: stretch,
309− width: 3,
310− minStretch: 7,
311− maxStretch: 12,
312− }),
313− side,
314− )
315−}
316−
317−func joinLetterform(letters ...string) string {
318− return lipgloss.JoinHorizontal(lipgloss.Top, letters...)
319−}
320−
321−// letterformProps defines letterform stretching properties.
322−// for readability.
323−type letterformProps struct {
324− width int
325− minStretch int
326− maxStretch int
327− stretch bool
328−}
329−
330−// stretchLetterformPart is a helper function for letter stretching. If randomize
331−// is false the minimum number will be used.
332−func stretchLetterformPart(s string, p letterformProps) string {
333− if p.maxStretch < p.minStretch {
334− p.minStretch, p.maxStretch = p.maxStretch, p.minStretch
335− }
336− n := p.width
337− if p.stretch {
338− n = cachedRandN(p.maxStretch-p.minStretch) + p.minStretch //nolint:gosec
339− }
340− parts := make([]string, n)
341− for i := range parts {
342− parts[i] = s
343− }
344− return lipgloss.JoinHorizontal(lipgloss.Top, parts...)
345−}
internal/ui/logo/rand.go+2−2
@@ -14,8 +14,8 @@ func cachedRandN(n int) int {
14 randCachesMu.Lock()
14 randCachesMu.Lock()
15 defer randCachesMu.Unlock()
15 defer randCachesMu.Unlock()
16
16
17− if n, ok := randCaches[n]; ok {
17+ if nPrime, ok := randCaches[n]; ok {
18− return n
18+ return nPrime
19 }
19 }
20
20
21 r := rand.IntN(n)
21 r := rand.IntN(n)