aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-09-17 19:08:13 +0200
committerDanilo M. <danix@danix.xyz>2026-09-17 19:08:13 +0200
commit9b18e17eee451a9a900f792add2c4c2eeb2af533 (patch)
tree7466a0953c5a4c9d7b3200723baf4d21a9bf225d /lib
parentf1be1bef9c3563fd78f811f54e5a64b1d993e4da (diff)
downloadconky-theme-udt-9b18e17eee451a9a900f792add2c4c2eeb2af533.tar.gz
conky-theme-udt-9b18e17eee451a9a900f792add2c4c2eeb2af533.zip
feat: parse the CPU and motherboard model strings
Stripping by rule rather than by a table of known parts: a leading vendor word, trademark noise, a trailing core count or clock. The Intel fixture exists to keep it a rule. DMI placeholders read as no board at all. 'To Be Filled By O.E.M.' on the dashboard is worse than a blank row. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/data.lua65
1 files changed, 65 insertions, 0 deletions
diff --git a/lib/data.lua b/lib/data.lua
index 13e5ebd..1afc9c9 100644
--- a/lib/data.lua
+++ b/lib/data.lua
@@ -297,4 +297,69 @@ function M.kv_parse(text)
return out
end
+-- The CPU's marketing name, stripped to what identifies it.
+--
+-- '/proc/cpuinfo' repeats the model name once per thread; the first is enough.
+-- The stripping is rules, not a table of known CPUs: a leading vendor word,
+-- the registered-trademark noise, and a trailing core count or clock, all of
+-- which are constant boilerplate that costs a third of the row on a card
+-- measured in pixels.
+--
+-- AMD Ryzen 7 9700X 8-Core Processor -> Ryzen 7 9700X
+-- Intel(R) Core(TM) i7-8700K CPU @ 3.7GHz -> Core i7-8700K
+function M.cpu_model(cpuinfo)
+ if type(cpuinfo) ~= 'string' then return nil end
+ local s = cpuinfo:match('model name%s*:%s*([^\n]+)')
+ if not s then return nil end
+ s = s:gsub('%(R%)', ''):gsub('%(TM%)', ''):gsub('%(tm%)', '')
+ s = s:gsub('^%s*AMD%s+', ''):gsub('^%s*Intel%s+', '')
+ s = s:gsub('%s+%d+%-Core Processor.*$', '')
+ s = s:gsub('%s+CPU%s*@.*$', '')
+ s = s:gsub('%s+Processor%s*$', '')
+ s = s:gsub('%s+', ' '):gsub('^%s+', ''):gsub('%s+$', '')
+ if s == '' then return nil end
+ return s
+end
+
+-- The motherboard, from the two world-readable DMI files.
+--
+-- board_vendor and board_name are readable without privilege, unlike the
+-- serial fields in the same directory. The vendor's corporate suffix is
+-- dropped because every vendor has one and none of it identifies the board.
+--
+-- A board reporting the DMI placeholder is treated as no board at all:
+-- 'To Be Filled By O.E.M.' on the dashboard is worse than a blank row.
+local DMI_PLACEHOLDER = {
+ ['to be filled by o.e.m.'] = true,
+ ['system manufacturer'] = true,
+ ['default string'] = true,
+ ['unknown'] = true,
+ ['n/a'] = true,
+}
+
+local function dmi_clean(s)
+ if type(s) ~= 'string' then return nil end
+ s = s:gsub('%s+', ' '):gsub('^%s+', ''):gsub('%s+$', '')
+ if s == '' or DMI_PLACEHOLDER[s:lower()] then return nil end
+ return s
+end
+
+function M.board_name(vendor, name)
+ vendor = dmi_clean(vendor)
+ name = dmi_clean(name)
+ if vendor then
+ -- Corporate boilerplate, longest first so 'Co., Ltd.' does not leave 'Co.'
+ vendor = vendor:gsub('%s+Technology Co%.,? Ltd%.?$', '')
+ vendor = vendor:gsub('%s+COMPUTER INC%.?$', '')
+ vendor = vendor:gsub('%s+Corporation$', ''):gsub('%s+Corp%.?$', '')
+ vendor = vendor:gsub('%s+Inc%.?$', ''):gsub('%s+INC%.?$', '')
+ vendor = vendor:gsub('%s+Co%.,?%s*Ltd%.?$', ''):gsub('%s+CO%.,?%s*LTD%.?$', '')
+ vendor = vendor:gsub('%s+GmbH$', ''):gsub('%s+LLC$', '')
+ vendor = vendor:gsub('%s+$', '')
+ if vendor == '' then vendor = nil end
+ end
+ if vendor and name then return vendor .. ' ' .. name end
+ return name or vendor
+end
+
return M