local utils = require("utils")
local core = {}
-------------------------------
-- conky interface functions --
-------------------------------
-- render `text` with the specified `font` if it is available on the system.
-- if `font ` unavailable, render `alt_text` instead with `alt_font`.
-- if `alt_font` is unavailable or not specified, render `alt_text` with the
-- current font.
-- if no `alt_text` is provided, it is assumed to be the same as `text`.
-- if no `text` is provided, it becomes a font-changing directive
function conky_font(font, text, alt_text, alt_font)
text = text and utils.unbrace(text) or ""
if alt_text == nil then
alt_text = text
else
alt_text = utils.unbrace(alt_text)
end
if font then
font = lcc.fonts[font]
end
if alt_font then
alt_font = lcc.fonts[alt_font]
end
if font then
return conky_parse(string.format("${font %s}%s", font, text))
elseif alt_font then
return conky_parse(string.format("${font %s}%s", alt_font, alt_text))
else
return conky_parse(alt_text)
end
end
-- padding
function conky_pad(text, max_len, align, char)
text = utils.unbrace(text)
return utils.padding(utils.trim(conky_parse(text)), max_len, align, char)
end
-- ratio as percentage
conky_ratio_perc = utils.ratio_perc
-- echo arguments
function conky_echo(...)
return ...
end
-- wrapper of string.format
function conky_format(...)
return string.format(...)
end
----------------
-- components --
----------------
-- section title
lcc.tpl.section = [[
${color1}${voffset $sr{-2}}${lua font icon {{%= icon %} ${voffset $sr{-1}}} {}}#
${lua font h1 {{%= title %}}} ${hr $sr{1}}${color}${voffset $sr{5}}]]
function core.section(title, icon)
return lcc.tpl.section { title = title, icon = icon }
end
-- print message
local _message_color = {
error = "${color #f33}",
warn = "${color #ff3}",
info = "${color #3f3}",
} -- TODO: to be added into named colors
function core.message(...)
local arg = { ... }
local level, text
if #arg < 1 then return "" end
if #arg < 2 then
text = ...
else
level, text = ...
end
if level and level:sub(-1, -1) == '+' then
level = level:sub(1, -2)
text = "${lua font h2}[" .. level:upper() .. "]${color}${font} " .. text
else
text = "${font}" .. text
end
return (_message_color[level] or "${color}") .. text
end
-- vertical spacing: `dy` is the height (in pixels) before scaling
lcc.tpl.dynamic_tform('vspace', "\n${voffset $sr{{%= dy %}}}")
function core.vspace(dy)
return lcc.tpl.vspace { dy = dy }
end
lcc.tpl.datetime = [[
${color0}${voffset $sr{2}}${lua font date ${time %b %-d}}${alignr}#
${lua font time ${time %H:%M}${voffset $sr{-35}} ${time %H:%M}${voffset $sr{-40}} time_alt}
${alignc}${lua font week ${time %^A}}
${alignc}${lua font year ${time %Y}}${color}
${voffset $sr{-8}}]]
function core.datetime()
return lcc.tpl.datetime()
end
lcc.tpl.system = [[
${font}${sysname} ${kernel} ${alignr}${machine}
Host:${alignr}${nodename}
Uptime:${alignr}${uptime}
Processes:${alignr}${running_processes} / ${processes}]]
function core.system(args)
return core.section("SYSTEM", "") .. "\n" .. lcc.tpl.system()
end
-- helper to generate conky text for top_x variables, with optional padding
local function _top_val_text(num, dev, type, padded_len, align)
if dev == "io" or dev == "mem" or dev == "time" then
dev = "_" .. dev
else
dev = ""
end
local s = string.format("${top%s %s %d}", dev, type, num)
if padded_len and align then
s = string.format("${lua pad {%s} %s %s %s}", s, padded_len, align, " ")
else
s = string.format("${lua pad {%s}}", s) -- just trim
end
return s
-- NOTE: the padding character here is FIGURE SPACE (U+2007)
-- see https://en.wikipedia.org/wiki/Whitespace_character
end
local function get_top_entries(max, dev, types, padded_len, align)
if max == nil or max <= 0 then return nil end
if max > 10 then max = 10 end
local function _p(param, idx)
if type(param) == "table" then return param[idx] end
return param
end
local top_entries = {}
for i = 1, max do
local v = {}
for j, t in ipairs(types) do
v[t] = _top_val_text(i, dev, t, _p(padded_len, j), _p(align, j))
end
table.insert(top_entries, v)
end
return top_entries
end
lcc.tpl.cpu = [[
${font}${execi 3600 grep model /proc/cpuinfo | cut -d : -f2 | tail -1 | sed 's/\s//'} ${alignr} ${cpu cpu0}%
${color3}${cpugraph cpu0}${color}
{% if top_cpu_entries then %}
${color2}${lua font h2 {PROCESS ${goto $sr{156}}PID ${goto $sr{194}}MEM% ${alignr}CPU%}}${font}${color}#
{% for _, v in ipairs(top_cpu_entries) do +%}
{%= v.name %} ${goto $sr{156}}{%= v.pid %}${alignr}${offset $sr{-44}}{%= v.mem %}
${voffset $sr{-13}}${alignr}{%= v.cpu %}{% end %}{% end %}]]
function core.cpu(args)
local top_n = utils.table.get(args, 'top_n', 5)
return core.section("CPU", "") .. "\n" .. lcc.tpl.cpu {
top_cpu_entries = get_top_entries(top_n, "cpu", { "name", "pid", "mem", "cpu" })
}
end
lcc.tpl.memory = [[
${color2}${lua font h2 RAM}${font}${color} ${alignc $sr{-16}}${mem} / ${memmax} ${alignr}${memperc}%
${color3}${membar}${color}
${color2}${lua font h2 SWAP}${font}${color} ${alignc $sr{-16}}${swap} / ${swapmax} ${alignr}${swapperc}%
${color3}${swapbar}${color}
{% if top_mem_entries then %}
${color2}${lua font h2 {PROCESS ${goto $sr{156}}PID ${goto $sr{198}}CPU%${alignr}MEM%}}${font}${color}#
{% for _, v in ipairs(top_mem_entries) do +%}
{%= v.name %} ${goto $sr{156}}{%= v.pid %}${alignr}${offset $sr{-44}}{%= v.cpu %}
${voffset $sr{-13}}${alignr}{%= v.mem %}{% end %}{% end %}]]
function core.memory(args)
local top_n = utils.table.get(args, 'top_n', 5)
return core.section("MEMORY", "") .. "\n" .. lcc.tpl.memory {
top_mem_entries = get_top_entries(top_n, "mem", { "name", "pid", "cpu", "mem" })
}
end
lcc.tpl.storage = [[
${lua disks 5}
${voffset $sr{4}}${lua font icon_s {} {Read:}} ${font}${diskio_read} ${alignr}${lua font icon_s {} {Write: }}${font}${diskio_write}${lua font icon_s { } {}}
${color3}${diskiograph_read {%= lcc.half_graph_size %}} ${alignr}${diskiograph_write {%= lcc.half_graph_size %}}${color}
{% if top_io_entries then %}
${color2}${lua font h2 {PROCESS ${goto $sr{156}}PID ${alignr}READ/WRITE}}${font}${color}#
{% for _, v in ipairs(top_io_entries) do +%}
{%= v.name %} ${goto $sr{156}}{%= v.pid %} ${alignr}{%= v.io_read %} / {%= v.io_write %}{% end %}{% end %}]]
function core.storage(args)
local top_n = utils.table.get(args, 'top_n', 5)
return core.section("STORAGE", "") .. "\n" .. lcc.tpl.storage {
top_io_entries = get_top_entries(top_n, "io", { "name", "pid", "io_read", "io_write" })
}
end
-- dynamically show mounted disks
lcc.tpl.disks = [[
{% if disks then %}
{% for _, v in ipairs(disks) do %}
${lua font h2 {{%= v.name %}}}${font} ${alignc $sr{-8}}{%= v.used_h %} / {%= v.size_h %} [{%= v.type %}] ${alignr}{%= v.used_perc %}%
${color3}${lua_bar ratio_perc {%= v.used %} {%= v.size %}}${color}
{% end %}
{% else %}
${font}(no mounted disk found)
{% end %}]]
function conky_disks(interv)
return core._interval_call(interv, function()
local disks = {}
for _, disk in ipairs(utils.enum_disks(
lcc.config.storage_include_fs,
lcc.config.storage_exclude_fs,
lcc.config.storage_exclude_paths)) do
-- get succinct name for the mount
local name = disk.mnt
local media = name:match("^/media/" .. utils.env.USER .. "/(.+)$")
if media then
name = media
elseif name == utils.env.HOME then
name = "${lua font icon_s ${voffset $sr{-4}}${font :bold:size=$sc{11}}⌂}"
end
table.insert(disks, {
name = name,
type = disk.type,
used = disk.used,
size = disk.size,
used_perc = utils.ratio_perc(disk.used, disk.size),
-- human friendly size strings
used_h = utils.filesize(disk.used),
size_h = utils.filesize(disk.size),
})
end
return utils.trim(lcc.tpl.disks { disks = disks })
end)
end
lcc.tpl.network = [[
${color2}${lua font icon_s { } {}}${lua font h2 {Local IPs}}${alignr}${lua font h2 {External IP}}${lua font icon_s { } {}}${font}${color}
${execi 60 ip a | grep inet | grep -vw lo | grep -v inet6 | cut -d \/ -f1 | sed 's/[^0-9\.]*//g'}#
${alignr}${texeci 3600 wget -q -O- https://ipecho.net/plain; echo}
${voffset $sr{5}}${lua ifaces 10}]]
function core.network()
return core.section("NETWORK", "") .. "\n" .. lcc.tpl.network()
end
-- dynamically show active ifaces
-- see https://matthiaslee.com/dynamically-changing-conky-network-interface/
lcc.tpl.ifaces = [[
{% if ifaces then %}{% for _, iface in ipairs(ifaces) do %}
${if_existing /sys/class/net/{%= iface %}/operstate up}#
${lua font icon_s ${voffset $sr{-1}}${font :size=$sc{7}}▼}${font} ${downspeed {%= iface %}} ${alignc $sr{-22}}${lua font h2 {{%= iface %}}}${font}#
${alignr}${upspeed {%= iface %}} ${lua font icon_s ${voffset $sr{-2}}${font :size=$sc{7}}▲}${font}
${color3}${downspeedgraph {%= iface %} {%= lcc.half_graph_size %}} ${alignr}${upspeedgraph {%= iface %} {%= lcc.half_graph_size %} }${color}#
${endif}
{% end %}
{% else %}
${font}(no active network interface found)
{% end %}]]
function conky_ifaces(interv)
return core._interval_call(interv, function()
return utils.trim(lcc.tpl.ifaces { ifaces = utils.enum_ifaces() })
end)
end
----------------------------
-- utils for internal use --
----------------------------
-- interval call
function core._interval_call(interv, ...)
local ret = utils.interval_call(tonumber(interv or 0), ...)
return ret and conky_parse(ret) or nil
end
return core