diff --git a/migration/.gitignore b/migration/.gitignore new file mode 100644 index 0000000..e6bd2f5 --- /dev/null +++ b/migration/.gitignore @@ -0,0 +1,4 @@ +*.svg +gitgraph +bin/cli/cli +bin/server/svg-server diff --git a/migration/bin/cli/cli.go b/migration/bin/cli/cli.go new file mode 100644 index 0000000..5334e94 --- /dev/null +++ b/migration/bin/cli/cli.go @@ -0,0 +1,30 @@ +package main + +import ( + "fmt" + "math/rand" + "time" + + "github.com/taigrr/gitgraph/term" +) + +func init() { + rand.Seed(time.Now().UnixMilli()) +} +func main() { + freq := []int{} + for i := 0; i < 7; i++ { + freq = append(freq, rand.Int()) + } + fmt.Println("week:") + term.GetWeekUnicode(freq) + fmt.Println() + fmt.Println() + fmt.Println() + freq = []int{} + for i := 0; i < 365; i++ { + freq = append(freq, rand.Int()) + } + fmt.Println("year:") + term.GetYearUnicode(freq) +} diff --git a/migration/bin/server/svg-server.go b/migration/bin/server/svg-server.go new file mode 100644 index 0000000..8144dfc --- /dev/null +++ b/migration/bin/server/svg-server.go @@ -0,0 +1,41 @@ +package main + +import ( + "math/rand" + "net/http" + "time" + + "github.com/gorilla/mux" + "github.com/taigrr/gitgraph/svg" +) + +type DayCount [366]int + +func init() { + rand.Seed(time.Now().UnixMilli()) +} +func main() { + r := mux.NewRouter() + r.HandleFunc("/weekly.svg", func(w http.ResponseWriter, r *http.Request) { + freq := []int{} + for i := 0; i < 7; i++ { + freq = append(freq, rand.Int()) + } + w.Header().Add("Content-Type", "text/html") + svg := svg.GetWeekSVG(freq) + svg.WriteTo(w) + + }) + r.HandleFunc("/yearly.svg", func(w http.ResponseWriter, r *http.Request) { + freq := []int{} + for i := 0; i < 365; i++ { + freq = append(freq, rand.Int()) + } + svg := svg.GetYearSVG(freq) + w.Header().Add("Content-Type", "text/html") + svg.WriteTo(w) + + }) + + http.ListenAndServe(":8080", r) +} diff --git a/migration/common/common.go b/migration/common/common.go new file mode 100644 index 0000000..621be6a --- /dev/null +++ b/migration/common/common.go @@ -0,0 +1,75 @@ +package common + +import ( + "bytes" + "image/color" + "math" + "sync" + + sc "github.com/taigrr/simplecolorpalettes/simplecolor" +) + +var ( + colorsLoaded sync.Once + colorScheme []sc.SimpleColor +) + +func CreateGraph() bytes.Buffer { + var x bytes.Buffer + return x +} + +func init() { + colors := []string{"#767960", "#a7297f", "#e8ca89", "#f5efd6", "#158266"} + // colors = []string{"#000000", "#0e4429", "#006d32", "#26a641", "#39d353"} + for _, c := range colors { + color := sc.FromHexString(c) + colorScheme = append(colorScheme, color) + } +} + +func SetColorScheme(c []color.Color) { + for _, c := range c { + colorScheme = append(colorScheme, sc.FromRGBA(c.RGBA())) + } +} + +func ColorForFrequency(freq, min, max int) sc.SimpleColor { + if freq == 0 { + return sc.SimpleColor(0) + } + spread := max - min + if spread < len(colorScheme)-1 { + return colorScheme[freq-min+1] + } + interval := float64(spread) / float64(len(colorScheme)) + colorIndex := 0 + for i := float64(min); i < float64(freq); i += float64(interval) { + colorIndex++ + } + if colorIndex > len(colorScheme)-1 { + colorIndex = len(colorScheme) - 1 + } + return colorScheme[colorIndex] +} + +func MinMax(f []int) (int, int) { + min, max := math.MaxInt, math.MinInt + for _, x := range f { + if x == 0 { + continue + } + if x < min { + min = x + } else if x > max { + max = x + } + } + if min == math.MaxInt { + min = 0 + } + if max == math.MinInt { + max = 0 + } + return min, max +} diff --git a/migration/go.mod b/migration/go.mod new file mode 100644 index 0000000..21ed1c3 --- /dev/null +++ b/migration/go.mod @@ -0,0 +1,25 @@ +module github.com/taigrr/gitgraph + +go 1.19 + +replace github.com/muesli/termenv => github.com/taigrr/termenv v0.11.2 + +require ( + github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b + github.com/gorilla/mux v1.8.0 + github.com/muesli/termenv v0.13.0 + github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c + github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef + github.com/taigrr/simplecolorpalettes v0.9.6 +) + +require ( + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mattn/go-runewidth v0.0.14 // indirect + github.com/rivo/uniseg v0.4.3 // indirect + golang.org/x/image v0.3.0 // indirect + golang.org/x/net v0.5.0 // indirect + golang.org/x/sys v0.4.0 // indirect + golang.org/x/text v0.6.0 // indirect +) diff --git a/migration/go.sum b/migration/go.sum new file mode 100644 index 0000000..069359d --- /dev/null +++ b/migration/go.sum @@ -0,0 +1,74 @@ +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= +github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= +github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b h1:slYM766cy2nI3BwyRiyQj/Ud48djTMtMebDqepE95rw= +github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= +github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw= +github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c h1:km8GpoQut05eY3GiYWEedbTT0qnSxrCjsVbb7yKY1KE= +github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c/go.mod h1:cNQ3dwVJtS5Hmnjxy6AgTPd0Inb3pW05ftPSX7NZO7Q= +github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef h1:Ch6Q+AZUxDBCVqdkI8FSpFyZDtCVBc2VmejdNrm5rRQ= +github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef/go.mod h1:nXTWP6+gD5+LUJ8krVhhoeHjvHTutPxMYl5SvkcnJNE= +github.com/taigrr/simplecolorpalettes v0.9.6 h1:eEFLPdI1o34t+YHs+QlgxcpN4zOg+5S3SlWt2EMS/6o= +github.com/taigrr/simplecolorpalettes v0.9.6/go.mod h1:MFLQqI3JOfSc+8GiO3amYfzBiozxITaQi+F1iEV8XpQ= +github.com/taigrr/termenv v0.11.2 h1:oqZR08HjGIzFWml4ROmoFvWi3KRG4UZYTPRrI9/lrPA= +github.com/taigrr/termenv v0.11.2/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/image v0.3.0 h1:HTDXbdK9bjfSWkPzDJIw89W8CAtfFGduujWs33NLLsg= +golang.org/x/image v0.3.0/go.mod h1:fXd9211C/0VTlYuAcOhW8dY/RtEJqODXOWBDpmYBf+A= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= diff --git a/migration/svg/svg.go b/migration/svg/svg.go new file mode 100644 index 0000000..a61c42b --- /dev/null +++ b/migration/svg/svg.go @@ -0,0 +1,104 @@ +package svg + +import ( + "bufio" + "bytes" + "fmt" + "image" + "image/png" + "os" + "sync" + + svg "github.com/ajstarks/svgo" + "github.com/srwiley/oksvg" + "github.com/srwiley/rasterx" + sc "github.com/taigrr/simplecolorpalettes/simplecolor" + + "github.com/taigrr/gitgraph/common" +) + +var ( + colorsLoaded sync.Once + colorScheme []sc.SimpleColor +) + +func GetWeekSVG(frequencies []int) bytes.Buffer { + squareColors := []sc.SimpleColor{} + min, max := common.MinMax(frequencies) + for _, f := range frequencies { + squareColors = append(squareColors, common.ColorForFrequency(f, min, max)) + } + return drawWeekImage(squareColors) +} + +func drawWeekImage(c []sc.SimpleColor) bytes.Buffer { + var sb bytes.Buffer + sbw := bufio.NewWriter(&sb) + squareLength := 10 + width := (len(c) + 1) * squareLength * 2 + height := squareLength * 2 + canvas := svg.New(sbw) + canvas.Start(width, height) + canvas.Rect(0, 0, width, height, "fill:black") + for i, s := range c { + canvas.Square(squareLength*2*(i+1), squareLength/2, squareLength, fmt.Sprintf("fill:%s", s.ToHex())) + } + canvas.End() + sbw.Flush() + return sb +} + +func GetYearSVG(frequencies []int) bytes.Buffer { + squareColors := []sc.SimpleColor{} + min, max := common.MinMax(frequencies) + for _, f := range frequencies { + squareColors = append(squareColors, common.ColorForFrequency(f, min, max)) + } + return drawYearImage(squareColors) +} + +func drawYearImage(c []sc.SimpleColor) bytes.Buffer { + // TODO here, draw suqares in appropriate colors, hopefully as an svg + var sb bytes.Buffer + sbw := bufio.NewWriter(&sb) + squareLength := 10 + width := (len(c)/7+1)*squareLength*2 + squareLength*5 + height := squareLength*9 + squareLength*3 + canvas := svg.New(sbw) + canvas.Start(width, height) + for i, s := range c { + canvas.Square(2*squareLength+width/(len(c)/7+1)*(i/7)+squareLength*2, squareLength/2+height/7*(i%7), squareLength, fmt.Sprintf("fill:%s", s.ToHex())) + } + canvas.Text(2*squareLength, squareLength*3, "Mon", fmt.Sprintf("text-anchor:middle;font-size:%dpx;fill:black", squareLength)) + canvas.Text(2*squareLength, int(float64(squareLength)*6.5), "Wed", fmt.Sprintf("text-anchor:middle;font-size:%dpx;fill:black", squareLength)) + canvas.Text(2*squareLength, int(float64(squareLength))*10, "Fri", fmt.Sprintf("text-anchor:middle;font-size:%dpx;fill:black", squareLength)) + canvas.End() + sbw.Flush() + return sb +} + +func svgToPng() { + w, h := 512, 512 + + in, err := os.Open("in.svg") + if err != nil { + panic(err) + } + defer in.Close() + + icon, _ := oksvg.ReadIconStream(in) + icon.SetTarget(0, 0, float64(w), float64(h)) + rgba := image.NewRGBA(image.Rect(0, 0, w, h)) + icon.Draw(rasterx.NewDasher(w, h, rasterx.NewScannerGV(w, h, rgba, rgba.Bounds())), 1) + + out, err := os.Create("out.png") + if err != nil { + panic(err) + } + defer out.Close() + + err = png.Encode(out, rgba) + if err != nil { + panic(err) + } +} diff --git a/migration/term/term.go b/migration/term/term.go new file mode 100644 index 0000000..0c492fa --- /dev/null +++ b/migration/term/term.go @@ -0,0 +1,77 @@ +package term + +import ( + "fmt" + "os" + "strings" + "sync" + + "github.com/muesli/termenv" + sc "github.com/taigrr/simplecolorpalettes/simplecolor" + + "github.com/taigrr/gitgraph/common" +) + +var ( + colorsLoaded sync.Once + colorScheme []sc.SimpleColor +) + +func GetWeekUnicode(frequencies []int) { + squareColors := []sc.SimpleColor{} + min, max := common.MinMax(frequencies) + for _, f := range frequencies { + squareColors = append(squareColors, common.ColorForFrequency(f, min, max)) + } + drawWeekUnicode(squareColors) +} + +func drawWeekUnicode(c []sc.SimpleColor) { + // o := termenv.NewOutput(os.Stdout) + o := termenv.NewOutputWithProfile(os.Stdout, termenv.TrueColor) + for w, color := range c { + style := o.String(block).Foreground(termenv.TrueColor.Color(color.ToHex())) + fmt.Print(style.String()) + // termenv.SetForegroundColor(termenv.ForegroundColor()) + if w == len(c)-1 { + fmt.Println() + } else { + fmt.Print(" ") + } + } +} + +func GetYearUnicode(frequencies []int) string { + squareColors := []sc.SimpleColor{} + min, max := common.MinMax(frequencies) + for _, f := range frequencies { + squareColors = append(squareColors, common.ColorForFrequency(f, min, max)) + } + return drawYearUnicode(squareColors) +} + +func drawYearUnicode(c []sc.SimpleColor) string { + // o := termenv.NewOutput(os.Stdout) + var s strings.Builder + o := termenv.NewOutputWithProfile(os.Stdout, termenv.TrueColor) + weeks := [7][]sc.SimpleColor{{}} + for i := 0; i < 7; i++ { + weeks[i] = []sc.SimpleColor{} + } + for i := range c { + weeks[i%7] = append(weeks[i%7], c[i]) + } + for _, row := range weeks { + for w, d := range row { + style := o.String(block).Foreground(termenv.TrueColor.Color(d.ToHex())) + s.WriteString(style.String()) + if w == len(row)-1 { + s.WriteString("\n") + } else { + s.WriteString(" ") + } + + } + } + return s.String() +} diff --git a/migration/term/unicode.go b/migration/term/unicode.go new file mode 100644 index 0000000..53439fb --- /dev/null +++ b/migration/term/unicode.go @@ -0,0 +1,3 @@ +package term + +const block = "▅"