local Y=require("yaru.core") local gfx=require("yaru.gfx") local ui=require("yaru.ui") local computer=require("computer") local component=require("component") local fs=require("filesystem") local unicode=require("unicode") local M={} local TABS={{"proc","Processes"},{"res","Resources"},{"fs","File Systems"},{"comp","Devices"}} local BARS={" ","▁","▂","▃","▄","▅","▆","▇","█"} local function graph(x,y,w,h,hist,maxv,fg,bg) gfx.fill(x,y,w,h,bg) local n=#hist for i=1,math.min(w,n)do local v=hist[n-i+1]/maxv local cells=v*h local col=x+w-i for r=0,h-1 do local fillAmt=cells-r if fillAmt>=1 then gfx.cell(col,y+h-1-r,"█",fg,bg) elseif fillAmt>0 then gfx.cell(col,y+h-1-r,BARS[1+math.floor(fillAmt*8)],fg,bg)end end end end local function processes() local process=require("process") local r={} for co,p in pairs(process.list)do local tid=tostring(co):gsub("^thread: 0x","") local isThread=false for _,q in pairs(process.list)do for _,h in ipairs(q.data.handles or{})do local mt=getmetatable(h) if mt and mt.process==p then isThread=true end end end local data=p.data local term=rawget(data,"yaruTerm") r[#r+1]={id=tid:sub(-6),cmd=p.command or tostring(p.path),thread=isThread,term=term, status=coroutine.status(co),handles=#(data.handles or{})} end table.sort(r,function(a,b)return a.cmd120 then table.remove(st.mem,1);table.remove(st.energy,1)end end sample() win.tickInterval=2 function win.tick(w)sample();Y.redraw(w)end function win.header(w,hw) local x=3 for _,tb in ipairs(TABS)do local sel=st.tab==tb[1] x=x+ui.button(w,x,1,tb[2],function()st.tab=tb[1];st.top=0 end,sel and nil or"flat")+1 end end function win.draw(w,cw,ch) local t=Y.theme gfx.fill(1,1,cw,ch,t.view) if st.tab=="res"then local tot,free=computer.totalMemory(),computer.freeMemory() local used=tot-free gfx.text(2,1,"Memory",t.fg,t.view) local ms=string.format("%s used of %s (%d%%)",ui.size(used),ui.size(tot),used*100//tot) gfx.text(cw-1-unicode.len(ms),1,ms,t.dim,t.view) local gh=math.max(3,(ch-8)//2) ui.graph(2,2,cw-3,gh,st.mem,tot,t.accent) local y=3+gh local me=computer.maxEnergy() gfx.text(2,y,"Energy",t.fg,t.view) local es=me>0 and string.format("%.0f of %.0f (%d%%)",computer.energy(),me,computer.energy()*100//me)or"n/a" gfx.text(cw-1-unicode.len(es),y,es,t.dim,t.view) ui.graph(2,y+1,cw-3,gh,st.energy,math.max(1,me),t.success) y=y+gh+2 local gs=gfx.stats gfx.text(2,y,string.format("Desktop: last frame %.1f ms, %d GPU runs • total GPU set %d fill %d copy %d, colour changes %d", Y.stats.lastFrameMs or 0,Y.stats.lastRuns or 0,gs.set,gs.fill,gs.copy,gs.fg+gs.bg),t.dim,t.view) gfx.text(2,y+1,string.format("Uptime %d:%02d:%02d • windows %d • loaded app modules: %s",math.floor(computer.uptime()//3600), math.floor(computer.uptime()//60%60),math.floor(computer.uptime()%60),#Y.windows,(function() local l={}for k in pairs(Y.modules)do l[#l+1]=k end return table.concat(l,", ")end)()),t.dim,t.view) elseif st.tab=="proc"then local list=processes() gfx.fill(1,1,cw,1,t.sidebar) gfx.text(2,1,"ID",t.dim,t.sidebar);gfx.text(10,1,"Command",t.dim,t.sidebar) gfx.text(cw-28,1,"Type",t.dim,t.sidebar);gfx.text(cw-16,1,"State",t.dim,t.sidebar) for i=1,ch-1 do local p=list[st.top+i] if not p then break end local y=i+1 gfx.text(2,y,p.id,t.dim,t.view) gfx.text(10,y,ui.trunc(p.cmd,cw-40),t.fg,t.view) gfx.text(cw-28,y,p.term and("terminal "..p.term)or(p.thread and"thread"or"process"),t.dim,t.view) gfx.text(cw-16,y,p.status,p.status=="running"and t.success or t.dim,t.view) end ui.scrollbar(cw,2,ch-1,st.top,ch-1,#list) elseif st.tab=="fs"then local y=1 local seen={} for proxy,path in fs.mounts()do if not seen[proxy.address]and y+2<=ch then seen[proxy.address]=true local total,used=proxy.spaceTotal(),proxy.spaceUsed() local label=proxy.getLabel()or proxy.address:sub(1,8) gfx.text(2,y,ui.trunc(path.." "..label..(proxy.isReadOnly()and" (read-only)"or""),cw-30),t.fg,t.view) local s=total==math.huge and ui.size(used).." used"or string.format("%s of %s",ui.size(used),ui.size(total)) gfx.text(cw-1-unicode.len(s),y,s,t.dim,t.view) gfx.fill(2,y+1,cw-3,1,t.sep) if total>0 and total~=math.huge then gfx.fill(2,y+1,math.max(1,math.floor((cw-3)*used/total)),1,t.accent)end y=y+3 end end else local list={} for addr,typ in component.list()do list[#list+1]={typ,addr}end table.sort(list,function(a,b)return a[1]