9 Commits

Author SHA1 Message Date
mcplayer3 8aa08814a1 Apparently I left in some unused variables that were supposed to be removed by Tema 2026-06-20 15:40:58 +03:00
mcplayer3 eaae852961 Started to add custom colour palettes
I have literally no idea why it wont work but if anyone picks this up you'll know it works when the old Halyde colours show up
2026-06-20 15:40:51 +03:00
tema5002 93c632ed6e unsuccessfull attempt at renaming terminal to io... 2026-06-20 14:30:26 +03:00
tema5002 ab48b57e1b Implement profiler 2026-06-20 14:25:40 +03:00
WahPlus 45a09284c2 bedit: Fixed addition of weird DC3 character when saving 2026-06-20 11:27:04 +03:00
mcplayer3 8fc249433b Added saving functionality to bedit
(The text field for the save path needs improving though.)
2026-06-20 17:14:21 +10:00
WahPlus 69a033f9a2 Added Gitea migration warning 2026-06-20 10:12:47 +03:00
WahPlus 11dea2b9e8 Changed README shield to say DokuWiki 2026-06-20 10:12:42 +03:00
WahPlus 393802b34e Added DokuWiki docs to README 2026-06-20 10:11:50 +03:00
10 changed files with 483 additions and 122 deletions
+5 -3
View File
@@ -1,4 +1,6 @@
# Halyde
### If you are viewing on GitHub: Halyde has moved to [Gitea](https://git.sting.lt/Cerulean-Blue/Halyde). This repository is now a read-only mirror. Contributions, issues and pull requests will not be processed here. Please go to [the Gitea instance](https://git.sting.lt/Cerulean-Blue/Halyde) for that.
A universal, customizable and feature-packed operating system for OpenComputers.
<p align="center">
@@ -6,8 +8,8 @@ A universal, customizable and feature-packed operating system for OpenComputers.
<img src="https://img.shields.io/badge/Written_in-Lua-blue?style=plastic&logo=lua" /></a>
<a href="https://ocdoc.cil.li/">
<img src="https://img.shields.io/badge/Made_for-OpenComputers-yellow?style=plastic" /></a>
<a href="https://cerulean-blue.gitbook.io/halyde-docs">
<img src="https://img.shields.io/badge/Documented_on-GitBook-green?style=plastic&logo=gitbook" /></a>
<a href="https://wiki.sting.lt/">
<img src="https://img.shields.io/badge/Documented_on-DokuWiki-green?style=plastic" /></a>
</p>
## Installation
@@ -20,4 +22,4 @@ If for some reason that doesn't work, try:
`wget -f https://raw.githubusercontent.com/Team-Cerulean-Blue/Halyde/refs/heads/main/webinstall.lua /tmp/webinstall.lua && /tmp/webinstall.lua`
## Docs
Halyde is [documented on GitBook](https://cerulean-blue.gitbook.io/halyde-docs).
Halyde is [documented on DokuWiki](https://wiki.sting.lt/), however there is an alternative documentation on [GitBook](https://cerulean-blue.gitbook.io/halyde-docs/).
+156 -86
View File
@@ -69,6 +69,73 @@ local function removeLine(pos)
lines[length] = nil
end
local function save()
gpu.setForeground(0xFFFFFF)
gpu.setBackground(0x000000)
gpu.set(1, resY, "Enter a location to save:")
local savepath = file or ""
local saveCursorX = 27 + #savepath
local ready = false
local eventArgs = {}
gpu.fill(27, resY, resX - 27, 1, " ")
gpu.set(27, resY, savepath)
gpu.setForeground(0x000000)
gpu.setBackground(0xFFFFFF)
gpu.set(saveCursorX, resY, " ")
gpu.setForeground(0xFFFFFF)
gpu.setBackground(0x000000)
repeat
local shouldRender = false
coroutine.yield()
eventArgs = {event.pull("key_down", 0)}
if keyboard.keys[eventArgs[4]] == "enter" then
ready = true
end
if keyboard.keys[eventArgs[4]] == "back" then
savepath = string.sub(savepath, 1, #savepath - 1)
if saveCursorX > 27 then
saveCursorX = saveCursorX - 1
end
shouldRender = true
end
if not keyboard.keys.special[eventArgs[4]] and keyboard.keys[eventArgs[4]] then
savepath = savepath .. (string.char(eventArgs[3]) or "")
saveCursorX = saveCursorX + 1
shouldRender = true
end
if shouldRender then
gpu.fill(27, resY, resX - 27, 1, " ")
gpu.set(27, resY, savepath)
gpu.setForeground(0x000000)
gpu.setBackground(0xFFFFFF)
gpu.set(saveCursorX, resY, " ")
gpu.setForeground(0xFFFFFF)
gpu.setBackground(0x000000)
end
until ready
gpu.fill(1, resY, resX, 1, " ")
gpu.setForeground(0x000000)
gpu.setBackground(0xFFFFFF)
gpu.set(1, resY, "^X")
gpu.set(10, resY, "^S")
gpu.setForeground(0xFFFFFF)
gpu.setBackground(0x000000)
gpu.set(4, resY, "Exit")
gpu.set(13, resY, "Save")
local text = table.concat(lines, "\n")
local handle = fs.open(savepath, "w")
handle:write(text)
handle:close()
file = savepath
end
-- Initialize screen
renderText(0, 0)
gpu.setForeground(0x000000)
@@ -118,99 +185,102 @@ while true do
if keyboard.keys[eventArgs[4]] == "x" then
goto exit
end
end
if keyboard.keys[eventArgs[4]] == "up" and cursorY > 1 then
if cursorY - scrollY <= 1 then
renderBufferFlag = true
scrollY = scrollY - 1
else
if not previousCursorX and not previousCursorY then
previousCursorX = cursorX
previousCursorY = cursorY
if keyboard.keys[eventArgs[4]] == "s" then
save()
end
else
if keyboard.keys[eventArgs[4]] == "up" and cursorY > 1 then
if cursorY - scrollY <= 1 then
renderBufferFlag = true
scrollY = scrollY - 1
else
if not previousCursorX and not previousCursorY then
previousCursorX = cursorX
previousCursorY = cursorY
end
end
cursorY = cursorY - 1
-- The cursor absolute position still has to be moved, even if on-screen it won't move
if cursorX > string.len(lines[cursorY]) + 1 then -- cursor snapping, +1 to be 1 char in front of end of line
cursorX = string.len(lines[cursorY]) + 1
end
end
cursorY = cursorY - 1
-- The cursor absolute position still has to be moved, even if on-screen it won't move
if cursorX > string.len(lines[cursorY]) + 1 then -- cursor snapping, +1 to be 1 char in front of end of line
cursorX = string.len(lines[cursorY]) + 1
end
end
if keyboard.keys[eventArgs[4]] == "down" then
if cursorY - scrollY >= resY - 1 then
renderBufferFlag = true
scrollY = scrollY + 1
else
if not previousCursorX and not previousCursorY then
previousCursorX = cursorX
previousCursorY = cursorY
if keyboard.keys[eventArgs[4]] == "down" then
if cursorY - scrollY >= resY - 1 then
renderBufferFlag = true
scrollY = scrollY + 1
else
if not previousCursorX and not previousCursorY then
previousCursorX = cursorX
previousCursorY = cursorY
end
end
cursorY = cursorY + 1
if cursorX > string.len(lines[cursorY]) + 1 then
cursorX = string.len(lines[cursorY]) + 1
end
end
cursorY = cursorY + 1
if cursorX > string.len(lines[cursorY]) + 1 then
cursorX = string.len(lines[cursorY]) + 1
end
end
if keyboard.keys[eventArgs[4]] == "left" and cursorX > 1 then
if cursorX - scrollX <= 1 then
renderBufferFlag = true
scrollX = scrollX - 1
else
if not previousCursorX and not previousCursorY then
previousCursorX = cursorX
previousCursorY = cursorY
if keyboard.keys[eventArgs[4]] == "left" and cursorX > 1 then
if cursorX - scrollX <= 1 then
renderBufferFlag = true
scrollX = scrollX - 1
else
if not previousCursorX and not previousCursorY then
previousCursorX = cursorX
previousCursorY = cursorY
end
end
end
cursorX = cursorX - 1
end
if keyboard.keys[eventArgs[4]] == "right" and cursorX < string.len(lines[cursorY]) + 1 then
if cursorX - scrollX >= resX then
renderBufferFlag = true
scrollX = scrollX + 1
else
if not previousCursorX and not previousCursorY then
previousCursorX = cursorX
previousCursorY = cursorY
end
end
cursorX = cursorX + 1
end
if not keyboard.keys.special[eventArgs[4]] then
local line = lines[cursorY] or ""
line = string.sub(line, 1, cursorX - 1) .. string.char(eventArgs[3]) .. string.sub(line, cursorX, -1)
lines[cursorY] = line
cursorX = cursorX + 1
renderBufferFlag = true
end
if keyboard.keys[eventArgs[4]] == "back" then
local line = lines[cursorY]
local prevline = lines[cursorY - 1]
if cursorX > 1 then
line = string.sub(line, 1, cursorX - 2) .. string.sub(line, cursorX, -1) -- remove 1 char
elseif prevline then
prevline = prevline .. line -- copy line up to the next before removing it
ocelot.log(prevline)
line = nil
end
if line then
lines[cursorY] = line
else
removeLine(cursorY)
end
lines[cursorY - 1] = prevline
if not line then
cursorY = cursorY - 1 -- this can only trigger if the line is not the first
end
if cursorX > 1 then
cursorX = cursorX - 1
end
renderBufferFlag = true
end
if keyboard.keys[eventArgs[4]] == "enter" then
addLine(cursorY + 1)
cursorY = cursorY + 1
cursorX = 1
renderBufferFlag = true
if keyboard.keys[eventArgs[4]] == "right" and cursorX < string.len(lines[cursorY]) + 1 then
if cursorX - scrollX >= resX then
renderBufferFlag = true
scrollX = scrollX + 1
else
if not previousCursorX and not previousCursorY then
previousCursorX = cursorX
previousCursorY = cursorY
end
end
cursorX = cursorX + 1
end
if not keyboard.keys.special[eventArgs[4]] then
local line = lines[cursorY] or ""
line = string.sub(line, 1, cursorX - 1) .. string.char(eventArgs[3]) .. string.sub(line, cursorX, -1)
lines[cursorY] = line
cursorX = cursorX + 1
renderBufferFlag = true
end
if keyboard.keys[eventArgs[4]] == "back" then
local line = lines[cursorY]
local prevline = lines[cursorY - 1]
if cursorX > 1 then
line = string.sub(line, 1, cursorX - 2) .. string.sub(line, cursorX, -1) -- remove 1 char
elseif prevline then
prevline = prevline .. line -- copy line up to the next before removing it
ocelot.log(prevline)
line = nil
end
if line then
lines[cursorY] = line
else
removeLine(cursorY)
end
lines[cursorY - 1] = prevline
if not line then
cursorY = cursorY - 1 -- this can only trigger if the line is not the first
end
if cursorX > 1 then
cursorX = cursorX - 1
end
renderBufferFlag = true
end
if keyboard.keys[eventArgs[4]] == "enter" then
addLine(cursorY + 1)
cursorY = cursorY + 1
cursorX = 1
renderBufferFlag = true
end
end
end
until next(eventArgs) == nil
+3 -3
View File
@@ -1,9 +1,9 @@
COMMAND echo
USAGE [TEXT]...
DESCRIPTION Concatenates and prints text to the terminal.
DESCRIPTION Concatenates and prints text to the standard output.
ARG1 TEXT
ARG1DESCRIPTION Text to print.
EXAMPLE1 echo test
EXAMPLE2 echo Hello World!
EXAMPLE1DESCRIPTION Prints "test" to the terminal.
EXAMPLE2DESCRIPTION Prints "Hello World!" to the terminal.
EXAMPLE1DESCRIPTION Prints "test" to the standard output.
EXAMPLE2DESCRIPTION Prints "Hello World!" to the standard output.
+222
View File
@@ -0,0 +1,222 @@
-- TODO: make it somehow not depend on ESC s and ESC u
local profiler = require("profiler")
local PAL = {
{ fg = "\27[31m", bg = "\27[41m" },
{ fg = "\27[32m", bg = "\27[42m" },
{ fg = "\27[33m", bg = "\27[43m" },
{ fg = "\27[34m", bg = "\27[44m" },
{ fg = "\27[35m", bg = "\27[45m" },
{ fg = "\27[36m", bg = "\27[46m" },
{ fg = "\27[37m", bg = "\27[47m" }
}
local function pal(i) return PAL[((i - 1) % #PAL) + 1] end
local results = profiler.results()
if not results then
print("No profiling data")
return
end
local radius
local W = terminal.getResolution()
if (W == 160) then radius = 20
elseif (W == 80) then radius = 6
else radius = 0; PAL = {{fg = "", bg = ""}} end
local MIN_PC = math.min(3, 100 / (radius * 2))
local total = 0
for _, r in ipairs(results) do total = total + r.time end
local main = {}
local other = {}
local ot = 0
local on_ = 0
for _, r in ipairs(results) do
if r.time / total * 100 >= MIN_PC then
table.insert(main, r)
else
table.insert(other, r)
ot = ot + r.time;
on_ = on_ + 1
end
end
if on_ then
table.insert(main, { label = "other (" .. on_ .. ")", time = ot })
end
local START = -math.pi / 2
local slices = {}
local cur = START
for i, m in ipairs(main) do
local sw = m.time / total * 2 * math.pi
slices[i] = {
label = m.label,
time = m.time,
pc = ("%.1f%%"):format(m.time / total * 100),
color = pal(i),
sa = cur,
sw = sw
}
cur = cur + sw
end
if on_ then slices[#slices].color={fg = "\27[30m", bg = "\27[40m"} end
local ASP = 2
local cx = radius * ASP
local cy = radius
local function slice_at(sx, sy)
local dy = sy - cy
local dx = (sx - cx) / ASP
if dx * dx + dy * dy > radius * radius then return nil end
local a = math.atan2(dy, dx)
if a < START then a = a + 2 * math.pi end
for i, sl in ipairs(slices) do
if a >= sl.sa and a < sl.sa + sl.sw then return i end
end
return #slices
end
local SUB = {
{ dx = -0.25, dy = -0.375 },
{ dx = -0.25, dy = -0.125 },
{ dx = -0.25, dy = 0.125 },
{ dx = 0.25, dy = -0.375 },
{ dx = 0.25, dy = -0.125 },
{ dx = 0.25, dy = 0.125 },
{ dx = -0.25, dy = 0.375 },
{ dx = 0.25, dy = 0.375 },
}
for y = 0, radius * 2 do
local lx, rx = math.ceil(cx - radius * ASP), math.floor(cx + radius * ASP)
terminal.write(("\27[%dC"):format(lx))
for x = lx, rx do
local c = {}
local n = 0
for k = 1, 8 do
local s = slice_at(x + SUB[k].dx, y + SUB[k].dy)
c[k] = s
if s then n = n + 1 end
end
if n == 0 then
terminal.write("\27[0m ")
else
local counts = {}
local order = {}
for k = 1, 8 do
if c[k] then
local key = c[k]
if not counts[key] then
counts[key] = 0
table.insert(order, key)
end
counts[key] = counts[key] + 1
end
end
table.sort(order, function(a, b) return counts[a] > counts[b] end)
local dom = order[1]
local sub = order[2]
if n == 8 then
terminal.write(slices[dom].color.bg)
if sub == nil then
terminal.write(" ")
else
local mask = 0
for k = 1, 8 do
if c[k] == sub then mask = mask + (1 << (k - 1)) end
end
terminal.write(slices[sub].color.fg)
terminal.write(utf8.char(0x2800 + mask))
end
else
local mask = 0
for k = 1, 8 do
if c[k] == dom then mask = mask + (1 << (k - 1)) end
end
terminal.write("\27[0m")
terminal.write(slices[dom].color.fg)
terminal.write(utf8.char(0x2800 + mask))
end
end
end
terminal.write('\n')
end
terminal.write("\27[" .. radius * 2 + 1 .. "A\27[s")
local function draw_text(col, row, s)
terminal.write("\27[u\27[" .. col .. "C\27[" .. row - 1 .. "B" .. s)
end
terminal.write("\27[0m")
if radius == 0 then goto tier1gpu end
for _, sl in ipairs(slices) do
local y = math.floor(cy + radius * 0.62 * math.sin(sl.sa + sl.sw / 2) + 0.5)
local function in_slice(x, row)
local a = math.atan2(row - cy, (x - cx) / ASP)
if a < START then
a = a + 2 * math.pi
end
return a >= sl.sa and a < sl.sa + sl.sw
end
local function centered_draw(row, text)
local dy = row - cy
local half_w = math.sqrt(radius * radius - dy * dy) * ASP
local lx, rx = math.ceil(cx - half_w), math.floor(cx + half_w)
while lx <= rx and not in_slice(lx, row) do
lx = lx + 1
end
while rx >= lx and not in_slice(rx, row) do
rx = rx - 1
end
local avail = rx - lx + 1
if avail < 3 then
return
end
local t = #text > avail and text:sub(1, avail - 3) .. "..." or text
local start_x = lx + math.floor((avail - #t) / 2)
draw_text(start_x, row, sl.color.bg .. t)
end
centered_draw(y, sl.label)
centered_draw(y + 1, sl.pc)
end
::tier1gpu::
local max_w = 0
for _, sl in pairs(slices) do
max_w = math.max(#sl.label + 1, max_w)
end
for _, sl in pairs(other) do
max_w = math.max(#sl.label + 3, max_w)
end
local x = radius * 2 * ASP + 2
if radius == 0 then x = 0 end
local cw = W - x - 1
local suffix_w = 18
local max_lbl = math.max(4, cw - suffix_w)
terminal.write("\27[u\27[" .. x .. "C" .. ("\27[0m%" .. max_w .. "s %9s %6s"):format("label", "time", "share"))
terminal.write("\n")
for _, sl in ipairs(slices) do
local lbl = sl.label
if #lbl > max_lbl then
lbl = sl.label:sub(1, max_lbl - 1) .. ""
end
terminal.write("\n\27[" .. x .. "C" .. ("%s%" .. max_w .. "s\27[0m %9.4fs %6s"):format(sl.color.bg, lbl, sl.time, sl.pc))
end
for _, sl in ipairs(other) do
local lbl = sl.label
if #lbl > max_lbl - 2 then
lbl = sl.label:sub(1, max_lbl - 3) .. ""
end
terminal.write("\n\27[" .. x .. "C" .. ("%s%" .. max_w .. "s\27[0m %9.4fs %6s"):format(slices[#slices].color.bg, lbl, sl.time, ("%.1f%%"):format(sl.time / total * 100)))
end
if radius * 2 + 2 > #slices + #other then
terminal.write("\27[" .. radius * 2 + 2 .. "B")
end
terminal.write("\n")
+1
View File
@@ -0,0 +1 @@
{"palette":{"dark":{"0":"171421","1":"c01c28","2":"26a269","3":"a2734c","4":"12488b","5":"a347ba","6":"2aa1b3","7":"d0cfcc"},"bright":{"0":"5e5c64","1":"f66151","2":"33d17a","3":"e9ad0c","4":"2a7bde","5":"c061cb","6":"33c7de","7":"ffffff"}}}
+1
View File
@@ -0,0 +1 @@
{"palette":{"dark":{"0":"171421","1":"c01c28","2":"26a269","3":"a2734c","4":"12488b","5":"a347ba","6":"2aa1b3","7":"d0cfcc"},"bright":{"0":"5e5c64","1":"f66151","2":"33d17a","3":"e9ad0c","4":"2a7bde","5":"c061cb","6":"33c7de","7":"ffffff"}}}
+5 -4
View File
@@ -11,6 +11,7 @@ gpu.bind(screenAddress)
gpu.setResolution(gpu.maxResolution())
local log = assert(loadfile("/lib/log.lua")(loadfile))
_G.profiler = assert(loadfile("/lib/profiler.lua")())
log.kernel.info("Bound GPU to screen " .. tostring(screenAddress))
@@ -67,10 +68,10 @@ require("/halyde/kernel/datatools.lua") -- If this is not imported BEFORE modloa
log.kernel.info("Loading modules")
require("/halyde/kernel/modload.lua")
package.preload("component")
package.preload("computer")
package.preload("log")
package.preload("event")
local toPreload = { "component", "computer", "log", "event" }
for _, p in pairs(toPreload) do
profiler.profile("pre-loading " .. p, package.preload, p)
end
local computer = require("computer")
function wait(seconds)
+8
View File
@@ -19,8 +19,10 @@ local moduleTypes = {}
local modulesLoaded = {}
local function loadModule(modName)
local stop = profiler.start("loadModule(" .. tostring(modName) .. ")")
if table.find(modulesLoaded, modName) then
log.kernel.warn(string.format("[modload: %s] Module was already loaded - skipping", modName))
stop()
return true
end
@@ -28,6 +30,7 @@ local function loadModule(modName)
if not moduleData then
log.kernel.warn(string.format("[modload: %s] Could not find module data.", modName))
table.remove(moduleList, table.find(moduleList, modName))
stop()
return true
end
local ready = false
@@ -42,6 +45,7 @@ local function loadModule(modName)
end
if not ready then
log.kernel.info(string.format("[modload: %s] Module not ready - skipping", modName))
stop()
return false
end
if type(moduleData.dependencies) == "table" then
@@ -74,16 +78,19 @@ local function loadModule(modName)
tostring(err or "unknown error")
)
)
stop()
return false
else
table.insert(modulesLoaded, modName)
table.remove(moduleList, table.find(moduleList, modName))
end
end
stop()
return true
end
for _, modName in pairs(moduleList) do -- Get all the module types
local stop = profiler.start("getting module " .. modName .. ")")
log.kernel.info(string.format("[modload: %s] Getting data from module", modName))
local moduleData
local status, err = pcall(function()
@@ -123,6 +130,7 @@ for _, modName in pairs(moduleList) do -- Get all the module types
moduleTypes[modName] = moduleData.type -- Not the other way around because there can be multiple modules of the same type, but there can't be multiple entries with the same key
end
::continue::
stop()
end
local function loadAllModules() -- attempt at loading all modules, unless if they're not ready
+27 -6
View File
@@ -15,9 +15,10 @@ function module.init()
local serialize = require("serialize")
local unicode = require("unicode")
local event = require("event")
local fs = require("filesystem")
local json = require("json")
local component = require("component")
local computer = require("computer")
local gpu = component.gpu
_G._PUBLIC.terminal = {}
@@ -40,6 +41,19 @@ function module.init()
table.insert(readHistory[id],hist)
end
if not fs.exists("/halyde/config/terminal.json") then
fs.copy("/halyde/config/generate/terminal.json", "/halyde/config/terminal.json")
end
local config = ""
local tmpdata
local handle = fs.open("/halyde/config/terminal.json")
repeat
tmpdata = handle:read(math.huge)
config = config .. (tmpdata or "")
until not tmpdata
config = json.decode(config)
require("log").terminal.info("Loaded config file: " .. serialize(config, " "))
local function getColorPalette(depth)
if depth == 1 then
return {
@@ -92,7 +106,16 @@ function module.init()
}
end
if depth == 8 then
return {
local palette = {["dark"] = {}, ["bright"] = {}}
for i = 0, 7 do
palette["dark"][i] = tonumber(config.palette.dark[tostring(i)], 16)
end
for i = 0, 7 do
palette["bright"][i] = tonumber(config.palette.bright[tostring(i)], 16)
end
require("log").terminal.info("Set colour palette: " .. serialize(palette, " "))
return palette
--[[ return {
["dark"] = {
[0] = 0x0f0f0f, -- black
[1] = 0xcc2424, -- dark red
@@ -113,7 +136,7 @@ function module.init()
[6] = 0x33dbc0, -- cyan
[7] = 0xffffff -- white
}
}
} ]]
end
--[[ Original color palette:
{
@@ -145,15 +168,13 @@ function module.init()
local ANSIColorPalette = getColorPalette(gpu.maxDepth())
local expecting_unicode_bytes = 0
local unicode_bytes_left = 0
local unicode_codepoint = 0
local cursor = { x = 1, y = 1, X = nil, Y = nil } -- X and Y are managed by ESC s and ESC u
local printState = 0 -- 0:none 1:in ESC 2:in CSI
local color = {
FG = ANSIColorPalette["bright"][7], BG = ANSIColorPalette["dark"][0],
fg = nil, bg = nil, reverse = false
}
require("log").terminal.info("FG and BG: " .. color.FG .. " " .. color.BG)
color.fg = color.FG
color.bg = color.BG
local current_codepoint = 0
+35
View File
@@ -0,0 +1,35 @@
local thing = _G._PUBLIC or _G
thing.__PROFILER_INSTANCE = thing.__PROFILER_INSTANCE or { timers = {} }
local timers = thing.__PROFILER_INSTANCE.timers
local profiler = {}
function profiler.start(label, overwrite)
thing.__PROFILER_INSTANCE.lastadded = label
timers[label] = timers[label] or {}
if not timers[label].start or overwrite then
timers[label].start = os.clock()
end
return function() timers[label].time = timers[label].time or os.clock() - timers[label].start end
end
function profiler.results()
local _now = nil
local function now()
_now = _now or os.clock()
return _now
end
local out = {}
for label, t in pairs(timers) do
table.insert(out, { label = label, time = t.time or now() - t.start })
end
table.sort(out, function(a, b) return a.time > b.time end)
return out
end
function profiler.profile(label, func, ...)
local stop = profiler.start(label)
func(...)
stop()
end
return profiler