label.go

 1package bug
 2
 3import (
 4	"crypto/sha1"
 5	"fmt"
 6	"io"
 7	"strings"
 8
 9	"github.com/MichaelMure/git-bug/util/text"
10)
11
12// RGBColor is a color type in the form red, green, blue
13type RGBColor struct {
14	red   uint8
15	green uint8
16	blue  uint8
17}
18
19type Label string
20
21func (l Label) String() string {
22	return string(l)
23}
24
25// RGBColor from a Label computed in a deterministic way
26func (l Label) RGBColor() RGBColor {
27	id := 0
28	hash := sha1.Sum([]byte(l))
29
30	// colors from: https://material-ui.com/style/color/
31	colors := []RGBColor{
32		RGBColor{red: 244, green: 67, blue: 54},   // red
33		RGBColor{red: 233, green: 30, blue: 99},   // pink
34		RGBColor{red: 156, green: 39, blue: 176},  // purple
35		RGBColor{red: 103, green: 58, blue: 183},  // deepPurple
36		RGBColor{red: 63, green: 81, blue: 181},   // indigo
37		RGBColor{red: 33, green: 150, blue: 243},  // blue
38		RGBColor{red: 3, green: 169, blue: 244},   // lightBlue
39		RGBColor{red: 0, green: 188, blue: 212},   // cyan
40		RGBColor{red: 0, green: 150, blue: 136},   // teal
41		RGBColor{red: 76, green: 175, blue: 80},   // green
42		RGBColor{red: 139, green: 195, blue: 74},  // lightGreen
43		RGBColor{red: 205, green: 220, blue: 57},  // lime
44		RGBColor{red: 255, green: 235, blue: 59},  // yellow
45		RGBColor{red: 255, green: 193, blue: 7},   // amber
46		RGBColor{red: 255, green: 152, blue: 0},   // orange
47		RGBColor{red: 255, green: 87, blue: 34},   // deepOrange
48		RGBColor{red: 121, green: 85, blue: 72},   // brown
49		RGBColor{red: 158, green: 158, blue: 158}, // grey
50		RGBColor{red: 96, green: 125, blue: 139},  // blueGrey
51	}
52
53	for _, char := range hash {
54		id = (id + int(char)) % len(colors)
55	}
56
57	return colors[id]
58}
59
60// UnmarshalGQL implements the graphql.Unmarshaler interface
61func (l *Label) UnmarshalGQL(v interface{}) error {
62	_, ok := v.(string)
63	if !ok {
64		return fmt.Errorf("labels must be strings")
65	}
66
67	*l = v.(Label)
68
69	return nil
70}
71
72// MarshalGQL implements the graphql.Marshaler interface
73func (l Label) MarshalGQL(w io.Writer) {
74	_, _ = w.Write([]byte(`"` + l.String() + `"`))
75}
76
77func (l Label) Validate() error {
78	str := string(l)
79
80	if text.Empty(str) {
81		return fmt.Errorf("empty")
82	}
83
84	if strings.Contains(str, "\n") {
85		return fmt.Errorf("should be a single line")
86	}
87
88	if !text.Safe(str) {
89		return fmt.Errorf("not fully printable")
90	}
91
92	return nil
93}