parent
8c3242b07e
commit
273aded7ff
195
main.go
195
main.go
|
@ -5,8 +5,11 @@ import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -46,18 +49,196 @@ func main() {
|
||||||
fmt.Printf("could not load data: %v", err)
|
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 clumpRe = regexp.MustCompile(`\W*`)
|
||||||
var p []string
|
|
||||||
if d.UsagePercY > 0 {
|
func search(query string, data Data) []string {
|
||||||
p = append(p, fmt.Sprintf("%s %s%%", resultmap["y"], color.GreenString("%f", d.UsagePercY)))
|
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, " ")
|
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) {
|
func loadData() (Data, error) {
|
||||||
|
|
32
struct.go
32
struct.go
|
@ -2,7 +2,13 @@ package main
|
||||||
|
|
||||||
type Data struct {
|
type Data struct {
|
||||||
Eras map[string]string `json:"eras"`
|
Eras map[string]string `json:"eras"`
|
||||||
Agents map[string]struct {
|
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 browser struct {
|
||||||
Browser string `json:"browser"`
|
Browser string `json:"browser"`
|
||||||
LongName string `json:"long_name"`
|
LongName string `json:"long_name"`
|
||||||
Abbr string `json:"abbr"`
|
Abbr string `json:"abbr"`
|
||||||
|
@ -10,23 +16,11 @@ type Data struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
UsageGlobal map[string]float64 `json:"usage_global"`
|
UsageGlobal map[string]float64 `json:"usage_global"`
|
||||||
Versions []string `json:"versions"`
|
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"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type stat string
|
type support string
|
||||||
|
|
||||||
func (s stat) Bool() bool {
|
func (s support) Bool() bool {
|
||||||
return s == "y"
|
return s == "y"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +34,7 @@ type data struct {
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
} `json:"links"`
|
} `json:"links"`
|
||||||
Categories []string `json:"categories"`
|
Categories []string `json:"categories"`
|
||||||
Stats map[string]map[string]stat `json:"stats"`
|
Stats map[string]map[string]support `json:"stats"`
|
||||||
Notes string `json:"notes"`
|
Notes string `json:"notes"`
|
||||||
NotesByNum map[string]string `json:"notes_by_num"`
|
NotesByNum map[string]string `json:"notes_by_num"`
|
||||||
UsagePercY float64 `json:"usage_perc_y"`
|
UsagePercY float64 `json:"usage_perc_y"`
|
||||||
|
@ -53,3 +47,9 @@ type data struct {
|
||||||
FirefoxID string `json:"firefox_id"`
|
FirefoxID string `json:"firefox_id"`
|
||||||
WebkitID string `json:"webkit_id"`
|
WebkitID string `json:"webkit_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type browserStat struct {
|
||||||
|
version string
|
||||||
|
support support
|
||||||
|
usage float64
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue