more work, intitial impl

Signed-off-by: jolheiser <john.olheiser@gmail.com>
main
jolheiser 2022-10-06 23:44:11 -05:00
parent 8c3242b07e
commit 273aded7ff
Signed by: jolheiser
GPG Key ID: B853ADA5DA7BBF7A
2 changed files with 224 additions and 43 deletions

195
main.go
View File

@ -5,8 +5,11 @@ import (
"flag"
"fmt"
"io/fs"
"math"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"time"
@ -46,18 +49,196 @@ func main() {
fmt.Printf("could not load data: %v", err)
}
fmt.Println(data)
query := fs.Arg(0)
// Find a single feature
if feat, ok := data.Data[query]; ok {
fmt.Println(formatFeat(feat, data, false))
return
}
// Find multiple features
features := search(query, data)
switch len(features) {
case 0:
fmt.Printf("%q not found", query)
case 1:
fmt.Println(formatFeat(data.Data[features[0]], data, false))
default:
for _, feat := range features {
fmt.Println(formatFeat(data.Data[feat], data, true))
}
}
}
func showFeat(d data) {
var p []string
if d.UsagePercY > 0 {
p = append(p, fmt.Sprintf("%s %s%%", resultmap["y"], color.GreenString("%f", d.UsagePercY)))
var clumpRe = regexp.MustCompile(`\W*`)
func search(query string, data Data) []string {
var results []string
query = strings.ToLower(query)
for key, dat := range data.Data {
matcher := clumpRe.ReplaceAllString(strings.ToLower(key+dat.Title+dat.Description+dat.Keywords+strings.Join(dat.Categories, "")), "")
if strings.Contains(matcher, query) {
results = append(results, key)
}
}
if d.UsagePercA > 0 {
p = append(p, fmt.Sprintf("%s %s%%", resultmap["a"], color.YellowString("%f", d.UsagePercA)))
return results
}
var replaceNoteRe = regexp.MustCompile(`[\r\n]+`)
func formatFeat(feat data, d Data, short bool) string {
bold := color.New(color.Bold)
var out strings.Builder
out.WriteString(bold.Sprint(feat.Title))
var p []string
if feat.UsagePercY > 0 {
p = append(p, fmt.Sprintf("%s %s%%", resultmap["y"], color.GreenString("%f", feat.UsagePercY)))
}
if feat.UsagePercA > 0 {
p = append(p, fmt.Sprintf("%s %s%%", resultmap["a"], color.YellowString("%f", feat.UsagePercA)))
}
percentages := strings.Join(p, " ")
out.WriteString(" " + percentages)
status := fmt.Sprintf(" [%s]\n", d.Statuses[feat.Status])
out.WriteString(status)
if !short {
out.WriteString("\t" + strings.TrimSpace(feat.Description) + "\n\n")
}
if short {
out.WriteString("\t")
}
needNote := make(map[int]struct{})
for browser, stats := range feat.Stats {
if d.Agents[browser].Type != "desktop" {
continue
}
if !short {
out.WriteString("\t")
}
out.WriteString(d.Agents[browser].Browser + " ")
results := makeResults(d.Agents[browser], stats)
if len(results) == 1 {
results[0].version = ""
}
for _, result := range results {
out.WriteString(makeResult(result, needNote))
}
if !short {
out.WriteString("\n")
}
}
if !short {
out.WriteString("\n")
}
if !short {
for num, note := range feat.NotesByNum {
n, _ := strconv.Atoi(num)
if _, ok := needNote[n]; !ok {
continue
}
out.WriteString(fmt.Sprintf("\t\t%s%s", color.YellowString(string(supernums[n])), note))
}
if feat.Notes != "" {
out.WriteString(fmt.Sprintf("\t %s %s", resultmap["i"], replaceNoteRe.ReplaceAllString(feat.Notes, " ")))
}
}
return out.String()
}
var supportRe = regexp.MustCompile(`#(\d+)`)
func makeResult(stat browserStat, nums map[int]struct{}) string {
support := string(stat.support[0])
var out strings.Builder
bace := "\u2800"
if s, ok := resultmap[support]; ok {
out.WriteString(s)
} else {
out.WriteString(support)
}
out.WriteString(bace)
if stat.version != "" {
out.WriteString(stat.version)
}
if strings.Contains(string(stat.support), "x") {
out.WriteString("ᵖ")
}
match := supportRe.FindStringSubmatch(string(stat.support))
if match != nil {
num, _ := strconv.Atoi(match[1])
nums[num] = struct{}{}
out.WriteString(string(supernums[num]))
}
if stat.usage > 0 {
str := out.String()
if string(str[len(str)-1]) != bace {
out.WriteString(" ")
}
out.WriteString(fmt.Sprintf("(%f) ", math.Round(stat.usage*1)/1))
}
out.WriteString(" ")
str := out.String()
switch support {
case "y":
return color.GreenString(str)
case "n":
return color.RedString(str)
case "a":
return color.YellowString(str)
default:
return str
}
}
func makeResults(browser browser, stats map[string]support) []browserStat {
var results []browserStat
var current browserStat
for idx, version := range browser.Versions {
if version == "" {
continue
}
support := stats[version]
var usage float64
if u, ok := browser.UsageGlobal[version]; ok {
usage = u
}
ver := version
if len(browser.Versions) > idx {
ver += "+"
}
if support[0] == 'p' {
support = "n" + support[1:]
}
if current.version == "" || current.support != support {
current = browserStat{
version: ver,
support: support,
usage: 0,
}
results = append(results, current)
}
current.usage += usage
}
return results
}
func loadData() (Data, error) {

View File

@ -1,32 +1,26 @@
package main
type Data struct {
Eras map[string]string `json:"eras"`
Agents map[string]struct {
Browser string `json:"browser"`
LongName string `json:"long_name"`
Abbr string `json:"abbr"`
Prefix string `json:"prefix"`
Type string `json:"type"`
UsageGlobal map[string]float64 `json:"usage_global"`
Versions []string `json:"versions"`
} `json:"agents"`
Statuses struct {
Rec string `json:"rec"`
Pr string `json:"pr"`
Cr string `json:"cr"`
Wd string `json:"wd"`
Ls string `json:"ls"`
Other string `json:"other"`
Unoff string `json:"unoff"`
} `json:"statuses"`
Cats map[string][]string `json:"cats"`
Data map[string]data `json:"data"`
Eras map[string]string `json:"eras"`
Agents map[string]browser `json:"agents"`
Statuses map[string]string `json:"statuses"`
Cats map[string][]string `json:"cats"`
Data map[string]data `json:"data"`
}
type stat string
type browser struct {
Browser string `json:"browser"`
LongName string `json:"long_name"`
Abbr string `json:"abbr"`
Prefix string `json:"prefix"`
Type string `json:"type"`
UsageGlobal map[string]float64 `json:"usage_global"`
Versions []string `json:"versions"`
}
func (s stat) Bool() bool {
type support string
func (s support) Bool() bool {
return s == "y"
}
@ -39,17 +33,23 @@ type data struct {
URL string `json:"url"`
Title string `json:"title"`
} `json:"links"`
Categories []string `json:"categories"`
Stats map[string]map[string]stat `json:"stats"`
Notes string `json:"notes"`
NotesByNum map[string]string `json:"notes_by_num"`
UsagePercY float64 `json:"usage_perc_y"`
UsagePercA float64 `json:"usage_perc_a"`
UCPrefix bool `json:"ucprefix"`
Parent string `json:"parent"`
Keywords string `json:"keywords"`
IEID string `json:"ie_id"`
ChromeID string `json:"chrome_id"`
FirefoxID string `json:"firefox_id"`
WebkitID string `json:"webkit_id"`
Categories []string `json:"categories"`
Stats map[string]map[string]support `json:"stats"`
Notes string `json:"notes"`
NotesByNum map[string]string `json:"notes_by_num"`
UsagePercY float64 `json:"usage_perc_y"`
UsagePercA float64 `json:"usage_perc_a"`
UCPrefix bool `json:"ucprefix"`
Parent string `json:"parent"`
Keywords string `json:"keywords"`
IEID string `json:"ie_id"`
ChromeID string `json:"chrome_id"`
FirefoxID string `json:"firefox_id"`
WebkitID string `json:"webkit_id"`
}
type browserStat struct {
version string
support support
usage float64
}