You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
wttr.in/share/we-lang/format.go

387 lines
8.9 KiB

package main
import (
"fmt"
"strings"
"unicode/utf8"
"github.com/mattn/go-runewidth"
)
var (
windDir = map[string]string{
"N": "\033[1m↓\033[0m",
"NNE": "\033[1m↓\033[0m",
"NE": "\033[1m↙\033[0m",
"ENE": "\033[1m↙\033[0m",
"E": "\033[1m←\033[0m",
"ESE": "\033[1m←\033[0m",
"SE": "\033[1m↖\033[0m",
"SSE": "\033[1m↖\033[0m",
"S": "\033[1m↑\033[0m",
"SSW": "\033[1m↑\033[0m",
"SW": "\033[1m↗\033[0m",
"WSW": "\033[1m↗\033[0m",
"W": "\033[1m→\033[0m",
"WNW": "\033[1m→\033[0m",
"NW": "\033[1m↘\033[0m",
"NNW": "\033[1m↘\033[0m",
}
)
func formatTemp(c cond) string {
color := func(temp int, explicitPlus bool) string {
var col = 0
if !config.Inverse {
// Extemely cold temperature must be shown with violet
// because dark blue is too dark
col = 165
switch temp {
case -15, -14, -13:
col = 171
case -12, -11, -10:
col = 33
case -9, -8, -7:
col = 39
case -6, -5, -4:
col = 45
case -3, -2, -1:
col = 51
case 0, 1:
col = 50
case 2, 3:
col = 49
case 4, 5:
col = 48
case 6, 7:
col = 47
case 8, 9:
col = 46
case 10, 11, 12:
col = 82
case 13, 14, 15:
col = 118
case 16, 17, 18:
col = 154
case 19, 20, 21:
col = 190
case 22, 23, 24:
col = 226
case 25, 26, 27:
col = 220
case 28, 29, 30:
col = 214
case 31, 32, 33:
col = 208
case 34, 35, 36:
col = 202
default:
if temp > 0 {
col = 196
}
}
} else {
col = 16
switch temp {
case -15, -14, -13:
col = 17
case -12, -11, -10:
col = 18
case -9, -8, -7:
col = 19
case -6, -5, -4:
col = 20
case -3, -2, -1:
col = 21
case 0, 1:
col = 30
case 2, 3:
col = 28
case 4, 5:
col = 29
case 6, 7:
col = 30
case 8, 9:
col = 34
case 10, 11, 12:
col = 35
case 13, 14, 15:
col = 36
case 16, 17, 18:
col = 40
case 19, 20, 21:
col = 59
case 22, 23, 24:
col = 100
case 25, 26, 27:
col = 101
case 28, 29, 30:
col = 94
case 31, 32, 33:
col = 166
case 34, 35, 36:
col = 52
default:
if temp > 0 {
col = 196
}
}
}
if config.Imperial {
temp = (temp*18 + 320) / 10
}
if explicitPlus {
return fmt.Sprintf("\033[38;5;%03dm+%d\033[0m", col, temp)
}
return fmt.Sprintf("\033[38;5;%03dm%d\033[0m", col, temp)
}
t := c.TempC
if t == 0 {
t = c.TempC2
}
// hyphen := " - "
// if (config.Lang == "sl") {
// hyphen = "-"
// }
// hyphen = ".."
explicitPlus1 := false
explicitPlus2 := false
if c.FeelsLikeC != t {
if t > 0 {
explicitPlus1 = true
}
if c.FeelsLikeC > 0 {
explicitPlus2 = true
}
if explicitPlus1 {
explicitPlus2 = false
}
return pad(
fmt.Sprintf("%s(%s) °%s",
color(t, explicitPlus1),
color(c.FeelsLikeC, explicitPlus2),
unitTemp[config.Imperial]),
15)
}
// if c.FeelsLikeC < t {
// if c.FeelsLikeC < 0 && t > 0 {
// explicitPlus = true
// }
// return pad(fmt.Sprintf("%s%s%s °%s", color(c.FeelsLikeC, false), hyphen, color(t, explicitPlus), unitTemp[config.Imperial]), 15)
// } else if c.FeelsLikeC > t {
// if t < 0 && c.FeelsLikeC > 0 {
// explicitPlus = true
// }
// return pad(fmt.Sprintf("%s%s%s °%s", color(t, false), hyphen, color(c.FeelsLikeC, explicitPlus), unitTemp[config.Imperial]), 15)
// }
return pad(fmt.Sprintf("%s °%s", color(c.FeelsLikeC, false), unitTemp[config.Imperial]), 15)
}
func formatWind(c cond) string {
windInRightUnits := func(spd int) int {
if config.WindMS {
spd = (spd * 1000) / 3600
} else {
if config.Imperial {
spd = (spd * 1000) / 1609
}
}
return spd
}
color := func(spd int) string {
var col = 46
switch spd {
case 1, 2, 3:
col = 82
case 4, 5, 6:
col = 118
case 7, 8, 9:
col = 154
case 10, 11, 12:
col = 190
case 13, 14, 15:
col = 226
case 16, 17, 18, 19:
col = 220
case 20, 21, 22, 23:
col = 214
case 24, 25, 26, 27:
col = 208
case 28, 29, 30, 31:
col = 202
default:
if spd > 0 {
col = 196
}
}
spd = windInRightUnits(spd)
return fmt.Sprintf("\033[38;5;%03dm%d\033[0m", col, spd)
}
unitWindString := unitWind(0, config.Lang)
if config.WindMS {
unitWindString = unitWind(2, config.Lang)
} else {
if config.Imperial {
unitWindString = unitWind(1, config.Lang)
}
}
hyphen := " - "
// if (config.Lang == "sl") {
// hyphen = "-"
// }
hyphen = "-"
cWindGustKmph := color(c.WindGustKmph)
cWindspeedKmph := color(c.WindspeedKmph)
if windInRightUnits(c.WindGustKmph) > windInRightUnits(c.WindspeedKmph) {
return pad(fmt.Sprintf("%s %s%s%s %s", windDir[c.Winddir16Point], cWindspeedKmph, hyphen, cWindGustKmph, unitWindString), 15)
}
return pad(fmt.Sprintf("%s %s %s", windDir[c.Winddir16Point], cWindspeedKmph, unitWindString), 15)
}
func formatVisibility(c cond) string {
if config.Imperial {
c.VisibleDistKM = (c.VisibleDistKM * 621) / 1000
}
return pad(fmt.Sprintf("%d %s", c.VisibleDistKM, unitVis(config.Imperial, config.Lang)), 15)
}
func formatRain(c cond) string {
rainUnit := float32(c.PrecipMM)
if config.Imperial {
rainUnit = float32(c.PrecipMM) * 0.039
}
if c.ChanceOfRain != "" {
return pad(fmt.Sprintf(
"%.1f %s | %s%%",
rainUnit,
unitRain(config.Imperial, config.Lang),
c.ChanceOfRain), 15)
}
return pad(fmt.Sprintf("%.1f %s", rainUnit, unitRain(config.Imperial, config.Lang)), 15)
}
func formatCond(cur []string, c cond, current bool) (ret []string) {
var icon []string
if i, ok := codes[c.WeatherCode]; !ok {
icon = iconUnknown
} else {
icon = i
}
if config.Inverse {
// inverting colors
for i := range icon {
icon[i] = strings.Replace(icon[i], "38;5;226", "38;5;94", -1)
icon[i] = strings.Replace(icon[i], "38;5;250", "38;5;243", -1)
icon[i] = strings.Replace(icon[i], "38;5;21", "38;5;18", -1)
icon[i] = strings.Replace(icon[i], "38;5;255", "38;5;245", -1)
icon[i] = strings.Replace(icon[i], "38;5;111", "38;5;63", -1)
icon[i] = strings.Replace(icon[i], "38;5;251", "38;5;238", -1)
}
}
//desc := fmt.Sprintf("%-15.15v", c.WeatherDesc[0].Value)
desc := c.WeatherDesc[0].Value
if config.RightToLeft {
for runewidth.StringWidth(desc) < 15 {
desc = " " + desc
}
for runewidth.StringWidth(desc) > 15 {
_, size := utf8.DecodeLastRuneInString(desc)
desc = desc[size:]
}
} else {
for runewidth.StringWidth(desc) < 15 {
desc += " "
}
for runewidth.StringWidth(desc) > 15 {
_, size := utf8.DecodeLastRuneInString(desc)
desc = desc[:len(desc)-size]
}
}
if current {
if config.RightToLeft {
desc = c.WeatherDesc[0].Value
if runewidth.StringWidth(desc) < 15 {
desc = strings.Repeat(" ", 15-runewidth.StringWidth(desc)) + desc
}
} else {
desc = c.WeatherDesc[0].Value
}
} else {
if config.RightToLeft {
if frstRune, size := utf8.DecodeRuneInString(desc); frstRune != ' ' {
desc = "…" + desc[size:]
for runewidth.StringWidth(desc) < 15 {
desc = " " + desc
}
}
} else {
if lastRune, size := utf8.DecodeLastRuneInString(desc); lastRune != ' ' {
desc = desc[:len(desc)-size] + "…"
//for numberOfSpaces < runewidth.StringWidth(fmt.Sprintf("%c", lastRune)) - 1 {
for runewidth.StringWidth(desc) < 15 {
desc = desc + " "
}
}
}
}
if config.RightToLeft {
ret = append(ret, fmt.Sprintf("%v %v %v", cur[0], desc, icon[0]), fmt.Sprintf("%v %v %v", cur[1], formatTemp(c), icon[1]), fmt.Sprintf("%v %v %v", cur[2], formatWind(c), icon[2]), fmt.Sprintf("%v %v %v", cur[3], formatVisibility(c), icon[3]), fmt.Sprintf("%v %v %v", cur[4], formatRain(c), icon[4]))
} else {
ret = append(ret, fmt.Sprintf("%v %v %v", cur[0], icon[0], desc), fmt.Sprintf("%v %v %v", cur[1], icon[1], formatTemp(c)), fmt.Sprintf("%v %v %v", cur[2], icon[2], formatWind(c)), fmt.Sprintf("%v %v %v", cur[3], icon[3], formatVisibility(c)), fmt.Sprintf("%v %v %v", cur[4], icon[4], formatRain(c)))
}
return
}
func justifyCenter(s string, width int) string {
appendSide := 0
for runewidth.StringWidth(s) <= width {
if appendSide == 1 {
s = s + " "
appendSide = 0
} else {
s = " " + s
appendSide = 1
}
}
return s
}
func reverse(s string) string {
r := []rune(s)
for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
r[i], r[j] = r[j], r[i]
}
return string(r)
}
func pad(s string, mustLen int) (ret string) {
ret = s
realLen := utf8.RuneCountInString(ansiEsc.ReplaceAllLiteralString(s, ""))
delta := mustLen - realLen
if delta > 0 {
if config.RightToLeft {
ret = strings.Repeat(" ", delta) + ret + "\033[0m"
} else {
ret += "\033[0m" + strings.Repeat(" ", delta)
}
} else if delta < 0 {
toks := ansiEsc.Split(s, 2)
tokLen := utf8.RuneCountInString(toks[0])
esc := ansiEsc.FindString(s)
if tokLen > mustLen {
ret = fmt.Sprintf("%.*s\033[0m", mustLen, toks[0])
} else {
ret = fmt.Sprintf("%s%s%s", toks[0], esc, pad(toks[1], mustLen-tokLen))
}
}
return
}