aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-10-18 10:40:18 +0200
committerDanilo M. <danix@danix.xyz>2026-10-18 10:40:18 +0200
commite54d9405dd818cd3ee7c203b8ec1d21713470904 (patch)
tree5b7afeff3bcec5c79c9aee4c9a1d09bc610fe3eb
parent7f14e983c2ed73f69dbdd7bb155203a0762b814a (diff)
downloadconky-theme-udt-e54d9405dd818cd3ee7c203b8ec1d21713470904.tar.gz
conky-theme-udt-e54d9405dd818cd3ee7c203b8ec1d21713470904.zip
feat: the cache and slackware cards move to quickshell
Both cards are now drawn by quickshell, so the conky copies go: the two widgets, their samplers and texeci lines, their fixtures and icons, and du_parse with human_bytes, which only the cache card used. kv_parse stays for breaktimer; its test now runs on an inline string. README gains a Samplers section listing what conky still schedules, and DESIGN.md's examples point at the cards that remain. Their slots in the layout are left open. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
-rw-r--r--DESIGN.md12
-rw-r--r--README.md49
-rwxr-xr-xbin/cache-sample.sh33
-rwxr-xr-xbin/slackware-sample.sh52
-rw-r--r--conky.conf.in4
-rw-r--r--dashboard.lua2
-rw-r--r--lib/card.lua4
-rw-r--r--lib/data.lua48
-rw-r--r--test/fixtures/du_output5
-rw-r--r--test/fixtures/slackware_cache5
-rw-r--r--test/test_data.lua38
-rw-r--r--widgets/breaktimer.lua2
-rw-r--r--widgets/cache.lua83
-rw-r--r--widgets/slackware.lua117
14 files changed, 33 insertions, 421 deletions
diff --git a/DESIGN.md b/DESIGN.md
index cd7a8a5..604e7cb 100644
--- a/DESIGN.md
+++ b/DESIGN.md
@@ -20,7 +20,7 @@ bottom:
- **Variable band.** One element may absorb the height left over, chosen per
card: the daylight arc in `weather`. Or the type itself fills the cell.
-Failure states keep the chrome and draw a notice in it ("no cache data", `--`
+Failure states keep the chrome and draw a notice in it ("no calendar data", `--`
for a missing sensor). An empty cell is indistinguishable from a crashed
widget, so a card never draws nothing. A missing sensor is `--`, never `0`:
zero is a legitimate reading.
@@ -38,7 +38,7 @@ Everything else exists to keep those two readable at any cell size.
of a width fit and a height budget. `card.fit_unit` measures candidate rows
and returns the largest base size that fits the width, and a row that would
collide pulls the size down. Bigger cell, bigger type instead of empty space.
- The `cache` card does this; a card that cannot afford the
+ The `breaktimer` card does this; a card that cannot afford the
measuring pass may key off width with a clamped factor.
- **Roles.** `FONT_MONO` for labels and row text, `FONT_HEAVY` for the big
number, `FONT_UI` for prose (a condition description, a notice). Sizes within
@@ -52,11 +52,11 @@ One language for every measured quantity, so state is read rather than decoded:
| State | Role | Example |
|---|---|---|
-| fine | `ok` | a fresh cache, a current changelog |
-| busy | `warning` | a cache past 25% |
-| hot / full | `critical` | a cache past 75%, a stale changelog |
+| fine | `ok` | breaktimer working |
+| busy | `warning` | breaktimer paused |
+| hot / full | `critical` | a quantity past its upper threshold |
-- Proportions (cache usage) use **25% / 75%**.
+- Proportions use **25% / 75%**.
- `warning` is the palette's middle role. The board should show all three
states in normal use, or the language is not earning its place.
- The big value's colour follows what it is: `body` for a plain number, the
diff --git a/README.md b/README.md
index 400d4e6..c5b261b 100644
--- a/README.md
+++ b/README.md
@@ -63,55 +63,39 @@ in the source, so no real location appears in committed files.
## System widgets
-Three cards cover the machine itself:
-
-- **Cache**: `~/.cache` total and its four largest subdirectories.
-- **Slackware**: distribution version, package count, kernel, install age, and
- time since the last `slackpkg` ChangeLog update. See below.
-
CPU, RAM, temperatures, the GPU, disks, network and the public address used to
be cards here. They moved to the performance panel of the quickshell island
(`desktop/island/` in the quickshell repo), which also warns from the status
-pill. The island keeps writing `~/.cache/udt/pubip.txt`.
+pill. The island keeps writing `~/.cache/udt/pubip.txt`. The cache and
+Slackware cards followed them to quickshell.
The updates card, a copy of nvtable's table, moved to the updates page of the
quickshell drawer (`desktop/modules/updates/`), which sorts each pending update
into the action it needs and covers Slackware itself.
-The cache card reads a cache file that a sampler writes; it never calls `du`
-itself. Sampling is scheduled by conky itself: `conky.text` carries
-a threaded `${texeci}` per sampler, even though that block renders nothing under Cairo.
+## Samplers
+
+Cards read cache files that samplers write; none shells out from a draw.
+Sampling is scheduled by conky itself: `conky.text` carries a threaded
+`${texeci}` per sampler, even though that block renders nothing under Cairo.
${texeci 900 ~/.config/conky/bin/weather-fetch.sh}
- ${texeci 900 ~/.config/conky/bin/cache-sample.sh}
- ${texeci 900 ~/.config/conky/bin/slackware-sample.sh}
${texeci 300 ~/.config/conky/bin/calendar-sample.sh}
+ ${texeci 5 ~/.config/conky/bin/breaktimer-sample.sh}
${texeci 1800 ~/.config/conky/bin/immich-fetch.sh}
-The cache and Slackware samplers run every 15 minutes, because `du -sh
-~/.cache` walks the tree and takes about 100ms warm, which is fine on a slow
-cycle and unthinkable on the 2-second draw. The calendar
-sampler runs every five minutes: khal costs about 200ms of Python startup,
-which rules out calling it from a draw, and the cache has to notice both a
-vdirsyncer run and the day rolling over. Tying them to
-conky means nothing samples while the dashboard is down.
+The calendar sampler runs every five minutes: khal costs about 200ms of Python
+startup, which rules out calling it from a draw, and the cache has to notice
+both a vdirsyncer run and the day rolling over. Tying them to conky means
+nothing samples while the dashboard is down.
To run a sampler by hand:
- ./bin/cache-sample.sh; echo "exit: $?"
- ./bin/slackware-sample.sh; echo "exit: $?"
./bin/calendar-sample.sh; echo "exit: $?"
All print nothing and exit 0 on success, and all write a temp file and rename
it over the target, so the widget never reads a half-written file.
-### Slackware
-
-The big top-right value is the time since `/var/lib/slackpkg/ChangeLog.txt`
-last changed, coloured `ok` under 24 hours, `warning` to a week, `critical`
-beyond, the same three-role language the cache card uses. Below it: distribution version, package count, kernel, and install age
-(the root filesystem's birth time, where the filesystem records one).
-
### Calendar
The month grid with the week's appointments under it. A day carrying an event
@@ -186,9 +170,8 @@ Anything with a comfortable range and an uncomfortable one is coloured by the
same three roles, so a card reads without learning a new scheme: `ok` below the
first threshold, `warning` between them, `critical` above the second.
-Cache usage uses 25% and 75%. The Slackware card's ChangeLog age uses the same
-three roles on an hour scale (24 / 168) instead of a percentage. These are
-starting values, and sit in one table per widget so they are easy to retune.
+Thresholds are starting values, and sit in one table per widget so they are
+easy to retune.
## Changing the layout
@@ -252,8 +235,8 @@ cell is left sparse; size it off the height alone and a short cell shrinks the
text to a whisper. The robust way is a measured fit: `card.fit_unit()` returns
the largest base size at which every row still fits the width, and the widget
takes the smaller of that and its height budget. Larger cell, larger type; a row
-that would collide pulls the size back down. The cache card does
-this. A card that cannot afford the measuring pass can still key off width with
+that would collide pulls the size back down. The breaktimer and
+immich cards do this. A card that cannot afford the measuring pass can still key off width with
a clamp, `math.max(lo, math.min(hi, inner.w * k))`; the clock and weather
cards do.
diff --git a/bin/cache-sample.sh b/bin/cache-sample.sh
deleted file mode 100755
index 202bc63..0000000
--- a/bin/cache-sample.sh
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/bin/bash
-# Sample ~/.cache sizes into a cache file, for widgets/cache.lua.
-#
-# du walks the tree and costs about 100ms warm, which is fine every 15 minutes
-# and unthinkable on a 2-second draw. The old conky config used the same
-# interval for the same reason.
-
-set -u
-
-CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/udt"
-CACHE="$CACHE_DIR/cachesize.txt"
-TARGET="${XDG_CACHE_HOME:-$HOME/.cache}"
-
-umask 077
-mkdir -p "$CACHE_DIR"
-
-TMP="$CACHE.tmp.$$"
-trap 'rm -f "$TMP"' EXIT
-
-# Total first, then the four largest children. `sort -h` compares human sizes
-# numerically; the Lua side converts them again because it needs the ratio to
-# the total, not just the order.
-{
- du -sh "$TARGET" 2>/dev/null
- du -sh "$TARGET"/* 2>/dev/null | sort -hr | head -4
-} > "$TMP"
-
-if [ ! -s "$TMP" ]; then
- echo "cache-sample: du produced nothing" >&2
- exit 1
-fi
-
-mv -f "$TMP" "$CACHE"
diff --git a/bin/slackware-sample.sh b/bin/slackware-sample.sh
deleted file mode 100755
index 066c520..0000000
--- a/bin/slackware-sample.sh
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/bin/bash
-# Sample Slackware facts into a cache file, for widgets/slackware.lua.
-#
-# Conky's Lua has no lfs, so it cannot stat a file for an mtime, and counting
-# 2800 package files every two seconds would be a directory walk per draw.
-# Both belong here.
-
-set -u
-
-CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/udt"
-CACHE="$CACHE_DIR/slackware.txt"
-
-umask 077
-mkdir -p "$CACHE_DIR"
-
-TMP="$CACHE.tmp.$$"
-trap 'rm -f "$TMP"' EXIT
-
-VERSION=$(cat /etc/slackware-version 2>/dev/null || echo unknown)
-
-# /var/log/packages is a symlink to /var/lib/pkgtools/packages. GNU ls follows
-# it either way, so the trailing slash is belt and braces rather than the load
-# bearing part; what would break this is adding -d, which lists the link itself
-# and reports one package.
-#
-# The real trap is `ls` being aliased: the user's shell aliases it to `ls -lh`,
-# and a long-format listing counts a "total" header line as a package. This
-# script is not interactive so aliases do not apply, but do not move this
-# counting into anything that is.
-PACKAGES=$(ls -1 /var/log/packages/ 2>/dev/null | wc -l)
-
-# Epochs, never formatted dates. The shell function this replaces rebuilds a
-# date string from `ls -l` output with the year hardcoded, which breaks every
-# January and on any file older than six months, when ls prints a year instead
-# of a time and the field offsets shift.
-CHANGELOG=$(stat -c %Y /var/lib/slackpkg/ChangeLog.txt 2>/dev/null || echo 0)
-
-# Filesystem birth time: the install date. Not every filesystem records it,
-# and those that do not report 0, which the widget shows as '--'.
-BIRTH=$(stat -c %W / 2>/dev/null || echo 0)
-
-KERNEL=$(uname -r)
-
-{
- echo "version $VERSION"
- echo "packages $PACKAGES"
- echo "changelog $CHANGELOG"
- echo "birth $BIRTH"
- echo "kernel $KERNEL"
-} > "$TMP"
-
-mv -f "$TMP" "$CACHE"
diff --git a/conky.conf.in b/conky.conf.in
index 1bec680..3e31272 100644
--- a/conky.conf.in
+++ b/conky.conf.in
@@ -52,7 +52,7 @@ conky.config = {
-- Cairo output covers conky.text, so nothing here is visible. The execi still
-- fires on schedule: verified with a probe config whose only text was an execi
--- producing no output. This is what runs the weather, disks and cache
+-- producing no output. This is what runs the weather, calendar and other
-- samplers, and tying it to conky means nothing fetches while the dashboard is
-- down. breaktimer runs at 5s, its daemon's own tick, so the countdown advances
-- in the steps the daemon counts in.
@@ -60,4 +60,4 @@ conky.config = {
-- texeci, not execi: execi runs in conky's main loop and blocks the draw until
-- the script exits. At 0.1s while visible, a slow sampler or an Immich
-- download stalls the scroll; texeci runs each in its own thread.
-conky.text = [[${texeci 900 ~/.config/conky/bin/weather-fetch.sh}${texeci 900 ~/.config/conky/bin/cache-sample.sh}${texeci 900 ~/.config/conky/bin/slackware-sample.sh}${texeci 300 ~/.config/conky/bin/calendar-sample.sh}${texeci 5 ~/.config/conky/bin/breaktimer-sample.sh}${texeci 1800 ~/.config/conky/bin/immich-fetch.sh}]]
+conky.text = [[${texeci 900 ~/.config/conky/bin/weather-fetch.sh}${texeci 300 ~/.config/conky/bin/calendar-sample.sh}${texeci 5 ~/.config/conky/bin/breaktimer-sample.sh}${texeci 1800 ~/.config/conky/bin/immich-fetch.sh}]]
diff --git a/dashboard.lua b/dashboard.lua
index fd3e2e5..53b0ab8 100644
--- a/dashboard.lua
+++ b/dashboard.lua
@@ -26,8 +26,6 @@ local layout = {
{ widget = 'calendar', col = 2.5, row = 1, w = 3, h = 6 },
-- Clustered near weather and clock
{ widget = 'breaktimer', col = 4, row = 7, w = 2, h = 3 },
- { widget = 'cache', col = 12, row = 7, w = 2, h = 3 },
- { widget = 'slackware', col = 12, row = 10, w = 2, h = 3 },
-- Centred on the board. Twice as many rows as columns because cells are
-- about twice as wide as tall, so this span comes out square.
{ widget = 'immich', col = 5.5, row = 1, w = 4, h = 6 },
diff --git a/lib/card.lua b/lib/card.lua
index 0a93c88..0869ce9 100644
--- a/lib/card.lua
+++ b/lib/card.lua
@@ -215,8 +215,6 @@ end
-- fontconfig alone: a missing glyph draws as an invisible blank and a wrong
-- codepoint as a plausible neighbour, so neither fails visibly.
M.ICON = {
- cache = '\u{F0ABA}', -- folder-clock
- slackware = '\u{F318}', -- linux-slackware
breaktimer = '\u{F13AB}', -- timer
calendar = '\u{F0E17}', -- calendar-month
immich = '\u{F02F9}', -- image-multiple
@@ -315,7 +313,7 @@ end
--
-- This counts codepoints, not rendered width, so it does not account for a
-- double-width CJK glyph. That is the right trade here: the strings it cuts
--- are cache directory names and hardware model strings. Measure with
+-- are calendar titles and place names. Measure with
-- M.measure when true rendered width matters.
function M.truncate(s, limit)
s = tostring(s or '')
diff --git a/lib/data.lua b/lib/data.lua
index 6b32f07..1b4c64f 100644
--- a/lib/data.lua
+++ b/lib/data.lua
@@ -16,55 +16,13 @@ function M.slurp(path)
return s
end
--- Human-readable size to bytes: '1.1G' -> 1181116006.
---
--- Needed because du -sh is what the sampler runs (its output is also what the
--- card displays), and 'biggest' has to be decided numerically: sorted as
--- strings, '245M' beats '1.1G'.
-local SUFFIX = { K = 1024, M = 1024^2, G = 1024^3, T = 1024^4, P = 1024^5 }
-
-function M.human_bytes(s)
- if type(s) ~= 'string' then return nil end
- local n, suf = s:match('^%s*([%d%.]+)%s*([KMGTP]?)')
- n = tonumber(n)
- if not n then return nil end
- return n * (SUFFIX[suf] or 1)
-end
-
--- Parse `du -sh` output: the first line is the total, the rest are children
--- already sorted largest-first by the sampler. Returns nil when there is
--- nothing usable, so the widget can draw its "no data" state.
-function M.du_parse(text)
- if type(text) ~= 'string' or text == '' then return nil end
- local lines = {}
- for line in text:gmatch('[^\n]+') do lines[#lines + 1] = line end
- if #lines == 0 then return nil end
-
- local function entry(line)
- local label, path = line:match('^(%S+)%s+(.+)$')
- if not label then return nil end
- return { label = label, bytes = M.human_bytes(label) or 0,
- name = path:match('([^/]+)/?$') or path, path = path }
- end
-
- local total = entry(lines[1])
- if not total then return nil end
- local items = {}
- for i = 2, #lines do
- local e = entry(lines[i])
- if e then items[#items + 1] = e end
- end
- return { total = total, items = items }
-end
-
-- Parse 'key value' lines into a table of strings.
--
--- Values stay strings and are converted by the caller. The sampler writes
--- epochs as integers and the widget decides whether an age reads as hours or
--- days; a parser that guessed would have to know that.
+-- Values stay strings and are converted by the caller; a parser that guessed
+-- types would have to know what each key means.
--
-- Only the first space separates, so a value keeps its own spaces:
--- 'version Slackware 15.0+' yields 'Slackware 15.0+', not 'Slackware'.
+-- 'title Long break' yields 'Long break', not 'Long'.
function M.kv_parse(text)
local out = {}
if type(text) ~= 'string' then return out end
diff --git a/test/fixtures/du_output b/test/fixtures/du_output
deleted file mode 100644
index a45b787..0000000
--- a/test/fixtures/du_output
+++ /dev/null
@@ -1,5 +0,0 @@
-1.6G /home/you/.cache
-1.1G /home/you/.cache/mozilla
-245M /home/you/.cache/pip
-131M /home/you/.cache/go-build
-85M /home/you/.cache/opencode
diff --git a/test/fixtures/slackware_cache b/test/fixtures/slackware_cache
deleted file mode 100644
index 3f2b2ac..0000000
--- a/test/fixtures/slackware_cache
+++ /dev/null
@@ -1,5 +0,0 @@
-version Slackware 15.0+
-packages 1234
-changelog 1758000000
-birth 1700000000
-kernel 6.12.1
diff --git a/test/test_data.lua b/test/test_data.lua
index df6775b..9066241 100644
--- a/test/test_data.lua
+++ b/test/test_data.lua
@@ -20,30 +20,6 @@ local function read(path)
return s
end
--- === Cache files ==========================================================
--- du -sh: total first, then children largest-first. The suffixes must be
--- converted, not string-sorted: '1.1G' outranks '245M' numerically and loses
--- to it alphabetically.
-local cache = data.du_parse(read('test/fixtures/du_output'))
-assert(cache.total, 'a total is parsed')
-assert(cache.total.label == '1.6G', 'total label, got ' .. tostring(cache.total.label))
-assert(#cache.items == 4, 'four children, got ' .. tostring(#cache.items))
-assert(cache.items[1].name == 'mozilla', 'largest child, got ' .. tostring(cache.items[1].name))
-assert(cache.items[1].label == '1.1G', 'its label, got ' .. tostring(cache.items[1].label))
-assert(cache.items[2].name == 'pip', 'second child, got ' .. tostring(cache.items[2].name))
-
--- Sizes are compared as bytes, which is what makes 'biggest' meaningful.
-assert(cache.items[1].bytes > cache.items[2].bytes, '1.1G must outrank 245M')
-assert(cache.items[1].bytes > 1e9, 'a G suffix is about a billion bytes')
-assert(cache.items[4].bytes < 1e8, 'an M suffix is far smaller')
-
--- Share of the total drives the highlight colour.
-assert(cache.items[1].bytes / cache.total.bytes > 0.5,
- 'mozilla dominates this fixture, which is what the highlight keys on')
-
-assert(data.du_parse('') == nil, 'empty input gives nil')
-assert(data.du_parse(nil) == nil, 'nil gives nil')
-
-- === card.truncate ========================================================
-- Truncation is by CHARACTER, not byte: slicing a UTF-8 string mid-sequence
-- emits an invalid byte that Cairo draws as a replacement box, and the name
@@ -66,16 +42,10 @@ assert(card.truncate(nil, 10) == '', 'nil truncates to empty')
assert(card.truncate('abc', 0) == '', 'a zero limit gives empty')
-- === kv_parse =============================================================
--- The slackware sampler writes 'key value' lines. The format is deliberately
--- dumber than the data: epochs stay integers rather than becoming formatted
--- dates, so the widget decides how to render an age and the shell never
--- reconstructs a date string.
-local kv = data.kv_parse(read('test/fixtures/slackware_cache'))
-assert(kv.version == 'Slackware 15.0+', 'version, got ' .. tostring(kv.version))
--- The value keeps its internal spaces: only the FIRST space is the separator.
-assert(kv.packages == '1234', 'packages, got ' .. tostring(kv.packages))
-assert(kv.changelog == '1758000000', 'changelog, got ' .. tostring(kv.changelog))
-assert(kv.kernel == '6.12.1', 'kernel, got ' .. tostring(kv.kernel))
+-- Samplers write 'key value' lines; only the FIRST space is the separator.
+local kv = data.kv_parse('title Long break\nremain 125\n')
+assert(kv.title == 'Long break', 'value keeps its spaces, got ' .. tostring(kv.title))
+assert(kv.remain == '125', 'remain, got ' .. tostring(kv.remain))
-- A key the sampler did not write reads nil, which is how the widget tells
-- "the sampler ran but this fact was unavailable" from "no sampler".
diff --git a/widgets/breaktimer.lua b/widgets/breaktimer.lua
index 6fed30e..fa8649b 100644
--- a/widgets/breaktimer.lua
+++ b/widgets/breaktimer.lua
@@ -25,7 +25,7 @@ function M.draw(cr, rect, colors)
local bt = data.breaktimer_parse(data.slurp(CACHE) or '')
- -- No cache at all: the sampler has not run. Name it, as the slackware card
+ -- No cache at all: the sampler has not run. Name it, as every cached card
-- does, rather than leaving a blank cell that is indistinguishable from a
-- crash. A stopped daemon is NOT this case: the sampler still writes a cache,
-- with running no, which the card draws as 'fermo'.
diff --git a/widgets/cache.lua b/widgets/cache.lua
deleted file mode 100644
index c6391ca..0000000
--- a/widgets/cache.lua
+++ /dev/null
@@ -1,83 +0,0 @@
--- Cache: ~/.cache total and its four largest subdirectories.
---
--- Reads a cache file written by bin/cache-sample.sh. du walks the tree and
--- costs about 100ms, which cannot happen on a 2-second draw.
-
-local card = require 'lib.card'
-local data = require 'lib.data'
-
-local CACHE = (os.getenv('XDG_CACHE_HOME') or (os.getenv('HOME') .. '/.cache'))
- .. '/udt/cachesize.txt'
-
-local M = {}
-
-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
- -- Fluid type. One base size S drives every element. The height budget makes
- -- the content fill the cell; the measured width fit pulls S down only where
- -- the header or a row would overrun the card. A tall cell gets larger type
- -- instead of empty space, and nothing collides.
- local LABEL_F, ROW_F = 0.30, 0.32
-
- local c = data.du_parse(data.slurp(CACHE) or '')
- if not c then
- card.notice(cr, inner, colors, 'CACHE', 'no cache data', 'bin/cache-sample.sh')
- return
- end
-
- local items = c.items or {}
- local names = {}
- for i, e in ipairs(items) do
- -- By character, not byte: a cache directory can carry an accented name and
- -- a byte slice cuts one in half, which Cairo draws as a replacement box.
- names[i] = card.truncate(e.name, 18)
- end
-
- local row_n = #items
- local S_h = inner.h * 0.94 / (1.78 + row_n * 0.64)
- local groups = {
- { { card.title_str(card.ICON.cache, 'CACHE'), card.FONT_MONO, LABEL_F },
- { c.total.label, card.FONT_HEAVY, 1.0 } },
- }
- for i = 1, row_n do
- groups[#groups + 1] = { { names[i], card.FONT_MONO, ROW_F },
- { items[i].label, card.FONT_MONO, ROW_F } }
- end
- local S = clamp(math.min(S_h, 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_MONO, label_size, false)
- card.title(cr, inner.x, inner.y + label_size, card.ICON.cache, 'CACHE', colors)
-
- -- The total shares the header line with the label, set on the same baseline
- -- and right-aligned: the width carries the number instead of an otherwise
- -- empty row beneath it.
- card.font(cr, card.FONT_HEAVY, S, false)
- card.rgba(cr, colors.body)
- card.text_right(cr, inner.x + inner.w, inner.y + S, c.total.label)
-
- local ey = inner.y + S + label_size * 2.6
- local step = row_size * 2.0
-
- card.font(cr, card.FONT_MONO, row_size, false)
- for i, e in ipairs(items) do
- if ey + step > inner.y + inner.h then break end
- -- The biggest offender is the point of the card, so it carries colour:
- -- critical when it is over half the total, warning otherwise. The rest
- -- stay in the ordinary value colour so the eye lands on the one to delete.
- local colour = colors.value
- if i == 1 then
- local share = c.total.bytes > 0 and (e.bytes / c.total.bytes) or 0
- colour = share > 0.5 and colors.critical or colors.warning
- end
- card.rgba(cr, colors.label)
- card.text(cr, inner.x, ey, names[i])
- card.rgba(cr, colour)
- card.text_right(cr, inner.x + inner.w, ey, e.label)
- ey = ey + step
- end
-end
-
-return M
diff --git a/widgets/slackware.lua b/widgets/slackware.lua
deleted file mode 100644
index 1971ca1..0000000
--- a/widgets/slackware.lua
+++ /dev/null
@@ -1,117 +0,0 @@
--- 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