aboutsummaryrefslogtreecommitdiffstats
path: root/widgets/slackware.lua
blob: 1971ca1bbc4788635f8dee79e6c1a984209c442c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
-- Slackware: the distribution version, package count, kernel, install age, and
-- how long since slackpkg's ChangeLog last changed.
--
-- Everything comes from a cache file written by bin/slackware-sample.sh:
-- conky's Lua cannot stat a file for an mtime, and counting the package
-- directory every two seconds would be a walk per draw.

local card = require 'lib.card'
local data = require 'lib.data'

local CACHE = (os.getenv('XDG_CACHE_HOME') or (os.getenv('HOME') .. '/.cache'))
  .. '/udt/slackware.txt'

-- Hours. A ChangeLog under a day old is current, under a week is ordinary, and
-- past that is worth noticing. This extends the shell prompt's binary green/red
-- into the board's three-state language rather than adding a fourth convention.
local WARN_H, CRIT_H = 24, 168

local SUBTITLE = 'last slackpkg update'

local M = {}

-- An age in seconds as a short string: hours below two days, then days. Short
-- because it is the card's big value and shares its line with the label.
local function age_str(seconds)
  if not seconds then return '--' end
  -- A future timestamp yields a negative age. Clock skew and a mirror's dated
  -- file both produce it, and '-8000h' on the dashboard reads as a bug.
  if seconds < 0 then seconds = 0 end
  local hours = seconds / 3600
  if hours < 48 then return string.format('%dh', math.floor(hours)) end
  return string.format('%dd', math.floor(hours / 24))
end

function M.draw(cr, rect, colors)
  local inner = card.card(cr, rect, colors)
  local function clamp(v, lo, hi) return math.max(lo, math.min(hi, v)) end
  local LABEL_F, BIG_F, ROW_F, SUB_F = 0.30, 1.0, 0.32, 0.26

  local kv = data.kv_parse(data.slurp(CACHE) or '')

  -- No cache at all: the sampler has not run. Name it, as the cache card does,
  -- rather than leaving a blank cell that is indistinguishable from a crash.
  if not kv.version then
    card.notice(cr, inner, colors, 'SLACKWARE', 'no slackware data',
      'bin/slackware-sample.sh')
    return
  end

  -- The ChangeLog age, the card's headline. A cache that exists without this
  -- key is a different failure from no cache: the sampler ran and the
  -- ChangeLog is what was missing, so the rows still draw and only this reads
  -- '--'.
  local changelog = tonumber(kv.changelog)
  local age_s = (changelog and changelog > 0) and (os.time() - changelog) or nil
  local age_txt = age_str(age_s)
  local age_colour = colors.label
  if age_s then
    age_colour = card.threshold(math.max(age_s, 0) / 3600, WARN_H, CRIT_H, colors)
  end

  -- 'Slackware 15.0+' -> '15.0+': the header already says which distribution.
  local version = (kv.version or ''):gsub('^Slackware%s+', '')

  local birth = tonumber(kv.birth)
  local install_age = (birth and birth > 0)
    and string.format('%dd', math.floor((os.time() - birth) / 86400)) or '--'

  local rows = {
    { 'VERSION',  version ~= '' and version or '--' },
    { 'PACKAGES', kv.packages or '--' },
    { 'KERNEL',   kv.kernel or '--' },
    { 'AGE',      install_age },
  }

  -- Fluid type: the height budget grows the content to fill the cell, the
  -- measured width fit pulls it back where a row would overrun.
  local groups = {
    { { card.title_str(card.ICON.slackware, 'SLACKWARE'), card.FONT_MONO, LABEL_F },
      { age_txt, card.FONT_HEAVY, BIG_F } },
    { { SUBTITLE, card.FONT_UI, SUB_F } },
  }
  for _, r in ipairs(rows) do
    groups[#groups + 1] = { { r[1], card.FONT_MONO, ROW_F },
                            { tostring(r[2]), card.FONT_MONO, ROW_F } }
  end
  local S = clamp(math.min(inner.h * 0.94 / (1.5 + #rows * 0.66),
    card.fit_unit(cr, inner.w * 0.96, groups, 100)), 10, 72)
  local label_size = S * LABEL_F
  local row_size   = S * ROW_F

  card.font(cr, card.FONT_HEAVY, S * BIG_F, false)
  card.rgba(cr, age_colour)
  card.text_right(cr, inner.x + inner.w, inner.y + S * BIG_F, age_txt)

  card.font(cr, card.FONT_MONO, label_size, false)
  card.title(cr, inner.x, inner.y + label_size, card.ICON.slackware,
    'SLACKWARE', colors)

  card.font(cr, card.FONT_UI, S * SUB_F, false)
  card.rgba(cr, colors.label, 0.65)
  card.text(cr, inner.x, inner.y + label_size + S * SUB_F * 1.5, SUBTITLE)

  local ey = inner.y + S * BIG_F + row_size * 1.6
  local step = row_size * 2.0
  card.font(cr, card.FONT_MONO, row_size, false)
  for _, r in ipairs(rows) do
    if ey + step > inner.y + inner.h then break end
    card.rgba(cr, colors.label)
    card.text(cr, inner.x, ey, r[1])
    card.rgba(cr, colors.value)
    card.text_right(cr, inner.x + inner.w, ey, tostring(r[2]))
    ey = ey + step
  end
end

return M