lots and LOTS of stuff

i lost track sorry
This commit is contained in:
Ponali
2025-09-14 13:37:41 +02:00
parent ef0ffa1886
commit d3d5f21ab1
14 changed files with 272 additions and 124 deletions
+1
View File
@@ -1 +1,2 @@
.stfolder
home/*
+5 -3
View File
@@ -1,3 +1,4 @@
local shell = require("shell")
local fs = require("filesystem")
local args = {...}
local command = args[1]
@@ -11,8 +12,9 @@ if not command then
print(data)
return
end
if shell.aliases[command] then
command = shell.aliases[command]
local aliases = shell.getAliases()
if aliases[command] then
command = aliases[command]
end
if fs.exists("/halyde/apps/helpdb/" .. command .. ".txt") then
local handle, data, tmpdata = fs.open("/halyde/apps/helpdb/" .. command .. ".txt", "r"), "", nil
@@ -21,7 +23,7 @@ if fs.exists("/halyde/apps/helpdb/" .. command .. ".txt") then
data = data .. (tmpdata or "")
until not tmpdata
print(data)
local aliases = table.copy(shell.aliases)
-- local aliases = table.copy(shell.aliases)
if table.find(aliases, command) then
local aliasIndex = table.find(aliases, command)
local aliasString = "Aliases:\n " .. aliasIndex
+3
View File
@@ -1,5 +1,6 @@
All default Halyde shell commands:
argentum Uses the Argentum package manager.
boot Boots to another OS.
cat Concatenates and prints a file.
cd Changes directory.
clear Clears the screen.
@@ -9,12 +10,14 @@ All default Halyde shell commands:
edit Opens the text editor.
fetch Displays system information.
help Shows this.
label Labels storage devices and EEPROMS.
ls Lists files.
lscor Lists coroutines.
lua Starts the Lua shell.
mkdir Makes a directory.
mv Moves/renames a file.
reboot Reboots the computer.
resolution Sets the resolution.
rm Deletes a file.
shutdown Shuts down the computer.
+2 -2
View File
@@ -1,6 +1,6 @@
print("\27[44m".._VERSION.."\27[0m shell")
print('Type "exit" to exit.')
terminal.readHistory["lua"] = {""}
-- terminal.readHistory["lua"] = {""}
local fs = require("filesystem")
local loadedLibraries = ""
@@ -15,7 +15,7 @@ while true do
local command = terminal.read("lua", "\27[44mlua>\27[0m ")
if command == "exit" then
return
else
elseif command~="" then
local function runCommand()
local func = load(loadedLibraries.."return "..command,"=stdin") or load(loadedLibraries..command,"=stdin")
local res = {assert(func)()}
+6 -1
View File
@@ -3,6 +3,7 @@ local filesystem = assert(loadfile("/lib/filesystem.lua")(loadfile))
_G._OSVERSION = "HALYDE VERSION" -- TODO: Put this in a separate config file
_G._OSLOGO = ""
_G._PUBLIC = {}
_G._PUBLIC.unicode = assert(loadfile("/lib/unicode.lua")(loadfile))
local handle, tmpdata = filesystem.open("/halyde/config/oslogo.ans", "r"), nil
repeat
@@ -14,7 +15,8 @@ _G.package = {["preloaded"] = {}}
loadfile("/halyde/kernel/modules/datatools.lua")()
function _G.require(module, ...)
function _G.reqgen(load)
return function(module, ...)
local args = table.pack(...)
if package.preloaded[module] then
return package.preloaded[module]
@@ -36,6 +38,9 @@ function _G.require(module, ...)
handle:close()
return(assert(load(data, "="..modulepath))(table.unpack(args)))
end
end
_G.require = reqgen(_G.load)
function _G.package.preload(module)
local handle, data, tmpdata = assert(filesystem.open("/lib/" .. module .. ".lua", "r")), "", nil
+1
View File
@@ -13,6 +13,7 @@ local conversionTables = {
}
function table.find(tab, item)
checkArg(1,tab,"table")
for k, v in pairs(tab) do
if v == item then
return k
+20 -10
View File
@@ -4,9 +4,19 @@ local maxEventQueueLength = 10 -- increase if events start getting dropped
local computer = require("computer")
_G._PUBLIC.keyboard.ctrlDown = false
_G._PUBLIC.keyboard.altDown = false
_G._PUBLIC.keyboard.shiftDown = false
local ctrlDown = false
local altDown = false
local shiftDown = false
function _G._PUBLIC.keyboard.getCtrlDown()
return ctrlDown
end
function _G._PUBLIC.keyboard.getAltDown()
return altDown
end
function _G._PUBLIC.keyboard.getShiftDown()
return shiftDown
end
--local ocelot = component.proxy(component.list("ocelot")())
@@ -21,12 +31,12 @@ while true do
local keycode = args[5]
local key = _PUBLIC.keyboard.keys[keycode]
if key == "lcontrol" then
_PUBLIC.keyboard.ctrlDown = true
ctrlDown = true
elseif key == "lmenu" then
_PUBLIC.keyboard.altDown = true
altDown = true
elseif key == "lshift" then
_PUBLIC.keyboard.shiftDown = true
elseif key == "c" and _PUBLIC.keyboard.ctrlDown and _PUBLIC.keyboard.altDown then
shiftDown = true
elseif key == "c" and ctrlDown and altDown then
if print then
print("\n\27[91mCoroutine "..tostring(#tsched.tasks).." killed.")
end
@@ -36,11 +46,11 @@ while true do
local keycode = args[5]
local key = _PUBLIC.keyboard.keys[keycode]
if key == "lcontrol" then
_PUBLIC.keyboard.ctrlDown = false
ctrlDown = false
elseif key == "lmenu" then
_PUBLIC.keyboard.altDown = false
altDown = false
elseif key == "lshift" then
_PUBLIC.keyboard.shiftDown = true
shiftDown = true
end
end
end
+19 -10
View File
@@ -1,21 +1,24 @@
local log = require("log")
local fs = require("filesystem")
local modulePath = "/halyde/kernel/modules"
local modules = assert(fs.list(modulePath))
local moduleList = assert(fs.list(modulePath))
local modules = {}
local moduleTypes = {}
local function loadModule(modName)
local moduleData = assert(require(fs.concat(modulePath, modName)), "Module did not return anything!") -- TODO: Make this not actually throw an error, rather put something in the log and move on
table.remove(modules, table.find(modules, modName))
local moduleData = modules[modName]
table.remove(moduleList, table.find(moduleList, modName))
if not moduleData then return end
if not moduleData.check() then
return
end
if moduleData.dependencies then
for _, dependency in pairs(moduleData.dependencies) do
if table.find(modules, dependency) then
if table.find(moduleList, dependency) then
loadModule(dependency)
elseif table.find(modules, dependency .. ".lua") then
elseif table.find(moduleList, dependency .. ".lua") then
loadModule(dependency .. ".lua")
else
for typeLookupDrvName, typeLookupDrvType in pairs(moduleTypes) do
@@ -33,16 +36,22 @@ local function loadModule(modName)
end
end
for _, modName in pairs(modules) do -- Get all the module types
local moduleData = assert(require(fs.concat(modulePath, modName)), "Module did not return anything!") -- TODO: Make this not actually throw an error, rather put something in the log and move on
for _, modName in pairs(moduleList) do -- Get all the module types
local moduleData = require(fs.concat(modulePath, modName)) -- TODO: Make this not actually throw an error, rather put something in the log and move on
if type(moduleData)~="table" then
log.add(string.format("[modload: %s] Module returned invalid type (%s) - skipping",modName,type(moduleData)),"error")
goto continue
end
modules[modName]=moduleData
if moduleData.type then
--print(moduleData.type)
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::
end
while modules[1] do
if modules[1]:sub(-1, -1) ~= "/" then -- Check if it's not a directory. If it is, it might be module config
loadModule(modules[1])
while moduleList[1] do
if moduleList[1]:sub(-1, -1) ~= "/" then -- Check if it's not a directory. If it is, it might be module config
loadModule(moduleList[1])
end
end
-1
View File
@@ -9,7 +9,6 @@ end
function module.init()
local publicTable = {
"print",
"require",
"_VERSION",
"_OSVERSION",
"assert",
+59
View File
@@ -48,6 +48,24 @@ function module.init()
return nil
end
return globalTable.vars[key]
end,["__pairs"]=function()
if not _G.ipc.shared[currentPID] then
return pairs({})
end
local globalTable
for _, tab in pairs(_G.ipc.shared[currentPID]) do
if tab.sharedWith == pid then
globalTable = tab
end
end
if not globalTable then
return pairs({})
end
if not globalTable.vars then
return pairs({})
end
return pairs(table.copy(globalTable.vars))
end})
return shareTable
end
@@ -75,6 +93,8 @@ function module.init()
end
globalTable.vars[key] = value
end, ["__index"] = function(_, key)
print(_G.ipc.shared)
local currentPID = _PUBLIC.tsched.getCurrentTask().id
if not _G.ipc.shared[currentPID] then
return nil
@@ -92,7 +112,40 @@ function module.init()
return nil
end
return globalTable.vars[key]
end,["__pairs"]=function()
if not _G.ipc.shared[currentPID] then
return pairs({})
end
local globalTable
for _, tab in pairs(_G.ipc.shared[currentPID]) do
if tab.sharedWith == pid then
globalTable = tab
end
end
if not globalTable then
return pairs({})
end
if not globalTable.vars then
return pairs({})
end
return pairs(table.copy(globalTable.vars))
end})
-- check if the reverse is also available
--[[ if not _G.ipc.shared[pid] then
_G.ipc.shared[pid]={}
end
for _, tab in pairs(_G.ipc.shared[pid]) do
if tab.sharedWith == currentPID then
return -- it's already added
end
end
local reverseTable = {}
reverseTable.vars = globalTable.vars
reverseTable.sharedWith = currentPID
table.insert(_G.ipc.shared[pid],reverseTable) ]]
return shareTable
end
@@ -114,6 +167,12 @@ function module.init()
end
end
return returnTable
end,["__pairs"]=function()
local ftbl = {}
for i in pairs(_G.ipc.shared) do
ftbl[i]=_PUBLIC.ipc.shared[i]
end
return pairs(ftbl)
end})
end
+65 -43
View File
@@ -14,11 +14,36 @@ function module.init()
local computer = require("computer")
local gpu = component.gpu
_G._PUBLIC.terminal = {}
_PUBLIC.terminal.cursorPosX = 1
_PUBLIC.terminal.cursorPosY = 1
_PUBLIC.terminal.readHistory = {}
local cursorPosX = 1
local cursorPosY = 1
local width, height = gpu.getResolution()
function _PUBLIC.terminal.getCursorPos()
return cursorPosX,cursorPosY
end
function _PUBLIC.terminal.setCursorPos(x,y)
checkArg(1,x,"number","nil")
checkArg(2,y,"number","nil")
if type(x)~=nil then cursorPosX=math.min(math.max(x,1),width) end
if type(y)~=nil then cursorPosY=math.min(math.max(y,1),height) end
end
local readHistory = {}
function _PUBLIC.terminal.getHistory(id)
checkArg(1,id,"string")
return table.copy(readHistory[id])
end
function _PUBLIC.terminal.setHistory(id,hist)
checkArg(1,id,"string")
checkArg(2,hist,"table")
for i=1,#hist do
hist[i]=tostring(hist[i])
end
readHistory[id]=hist
end
function _PUBLIC.terminal.addToHistory(id,hist)
checkArg(1,id,"string")
checkArg(2,hist,"string")
table.insert(readHistory[id],hist)
end
local ANSIColorPalette = {
["dark"] = {
@@ -50,7 +75,6 @@ function module.init()
gpu.setBackground(defaultBackgroundColor)
local function scrollDown()
local width, height = gpu.getResolution()
if gpu.copy(1,1,width,height,0,-1) then
local prevForeground = gpu.getForeground()
local prevBackground = gpu.getBackground()
@@ -59,14 +83,14 @@ function module.init()
gpu.fill(1, height, width, 1, " ")
gpu.setForeground(prevForeground)
gpu.setBackground(prevBackground)
_PUBLIC.terminal.cursorPosY=height
cursorPosY=height
end
end
local function newLine()
_PUBLIC.terminal.cursorPosX=1
_PUBLIC.terminal.cursorPosY = _PUBLIC.terminal.cursorPosY + 1
if _PUBLIC.terminal.cursorPosY>height then
cursorPosX=1
cursorPosY = cursorPosY + 1
if cursorPosY>height then
scrollDown()
end
end
@@ -103,8 +127,6 @@ function module.init()
end
function _PUBLIC.terminal.write(text, textWrap)
local width, height = gpu.getResolution()
-- you don't know how tiring this was just for ANSI escape code support
if textWrap == nil then
@@ -129,12 +151,12 @@ function module.init()
return
end
while true do
gpu.set(_PUBLIC.terminal.cursorPosX,_PUBLIC.terminal.cursorPosY,section)
if unicode.wlen(section) > width - _PUBLIC.terminal.cursorPosX + 1 and textWrap then
section = section:sub(width - _PUBLIC.terminal.cursorPosX + 2)
gpu.set(cursorPosX,cursorPosY,section)
if unicode.wlen(section) > width - cursorPosX + 1 and textWrap then
section = section:sub(width - cursorPosX + 2)
newLine()
else
_PUBLIC.terminal.cursorPosX = _PUBLIC.terminal.cursorPosX+unicode.wlen(section)
cursorPosX = cursorPosX+unicode.wlen(section)
break
end
end
@@ -152,7 +174,7 @@ function module.init()
newLine()
elseif string.byte(text,i)==13 then
printSection()
_PUBLIC.terminal.cursorPosX=1
cursorPosX=1
elseif string.byte(text,i)==0x1b and i<=#text-2 then
printSection()
--ocelot.log("0x1b char detected")
@@ -204,7 +226,7 @@ function module.init()
end
end
else
--gpu.set(_PUBLIC.terminal.cursorPosX,_PUBLIC.terminal.cursorPosY,string.sub(text,i,i))
--gpu.set(cursorPosX,cursorPosY,string.sub(text,i,i))
section = section..string.sub(text,i,i)
end
::continue::
@@ -226,11 +248,10 @@ function module.init()
end
function _G._PUBLIC.terminal.clear()
width, height = gpu.getResolution()
gpu.setForeground(defaultForegroundColor)
gpu.setBackground(defaultBackgroundColor)
gpu.fill(1,1,width,height," ")
_PUBLIC.terminal.cursorPosX, _PUBLIC.terminal.cursorPosY = 1, 1
cursorPosX, cursorPosY = 1, 1
end
function _G._PUBLIC.terminal.read(readHistoryType, prefix, defaultText, maxChars)
@@ -244,22 +265,22 @@ function module.init()
local historyIdx
if readHistoryType then
if not _PUBLIC.terminal.readHistory[readHistoryType] then
_PUBLIC.terminal.readHistory[readHistoryType] = {text}
elseif _PUBLIC.terminal.readHistory[readHistoryType][#_PUBLIC.terminal.readHistory[readHistoryType] ] ~= "" then
table.insert(_PUBLIC.terminal.readHistory[readHistoryType], text)
if not readHistory[readHistoryType] then
readHistory[readHistoryType] = {text}
elseif readHistory[readHistoryType][#readHistory[readHistoryType] ] ~= text then
table.insert(readHistory[readHistoryType], text)
end
historyIdx = #_PUBLIC.terminal.readHistory[readHistoryType]
historyIdx = #readHistory[readHistoryType]
end
local function updateHistory()
if not readHistoryType then return end
_PUBLIC.terminal.readHistory[readHistoryType][historyIdx]=text
readHistory[readHistoryType][historyIdx]=text
end
local cur = unicode.len(text)+1
if prefix then _PUBLIC.terminal.write(prefix) end
local startX, startY = _PUBLIC.terminal.cursorPosX, _PUBLIC.terminal.cursorPosY
local startX, startY = cursorPosX, cursorPosY
local fg, bg = gpu.getForeground(), gpu.getBackground()
local cursorBlink = true
local function get(idx)
@@ -378,17 +399,18 @@ function module.init()
while true do
local args = {event.pull("key_down", "clipboard", 0.5)}
local ctrlDown = _PUBLIC.keyboard.getCtrlDown()
if args and args[1] == "key_down" and args[4] then
local key = _PUBLIC.keyboard.keys[args[4]]
if key=="up" and readHistoryType then
historyIdx=math.max(historyIdx-1,1)
reprint(_PUBLIC.terminal.readHistory[readHistoryType][historyIdx])
reprint(readHistory[readHistoryType][historyIdx])
elseif key=="down" and readHistoryType then
historyIdx=math.min(historyIdx+1,#_PUBLIC.terminal.readHistory[readHistoryType])
reprint(_PUBLIC.terminal.readHistory[readHistoryType][historyIdx])
elseif key=="left" and _PUBLIC.keyboard.ctrlDown then
historyIdx=math.min(historyIdx+1,#readHistory[readHistoryType])
reprint(readHistory[readHistoryType][historyIdx])
elseif key=="left" and ctrlDown then
moveWord(-1)
elseif key=="right" and _PUBLIC.keyboard.ctrlDown then
elseif key=="right" and ctrlDown then
moveWord(1)
elseif key=="left" then
moveCur(-1)
@@ -398,9 +420,9 @@ function module.init()
moveCur(-math.huge)
elseif key=="end" then
moveCur(math.huge)
elseif key=="back" and _PUBLIC.keyboard.ctrlDown then
elseif key=="back" and ctrlDown then
deleteWord(-1)
elseif key=="delete" and _PUBLIC.keyboard.ctrlDown then
elseif key=="delete" and ctrlDown then
deleteWord(1)
elseif key=="back" and cur>1 then
text=unicode.sub(text,1,cur-2)..unicode.sub(text,cur)
@@ -439,21 +461,21 @@ function module.init()
end
if readHistoryType then
if _PUBLIC.terminal.readHistory[readHistoryType][#_PUBLIC.terminal.readHistory[readHistoryType]]=="" then
table.remove(_PUBLIC.terminal.readHistory[readHistoryType],#_PUBLIC.terminal.readHistory[readHistoryType])
if readHistory[readHistoryType][#readHistory[readHistoryType]]=="" then
table.remove(readHistory[readHistoryType],#readHistory[readHistoryType])
end
if historyIdx<#_PUBLIC.terminal.readHistory[readHistoryType] then
table.remove(_PUBLIC.terminal.readHistory[readHistoryType],historyIdx)
table.insert(_PUBLIC.terminal.readHistory[readHistoryType],text)
if historyIdx<#readHistory[readHistoryType] then
table.remove(readHistory[readHistoryType],historyIdx)
table.insert(readHistory[readHistoryType],text)
end
while #_PUBLIC.terminal.readHistory[readHistoryType] > 50 do
table.remove(_PUBLIC.terminal.readHistory[readHistoryType], 1)
while #readHistory[readHistoryType] > 50 do
table.remove(readHistory[readHistoryType], 1)
end
end
_PUBLIC.terminal.cursorPosX=1
_PUBLIC.terminal.cursorPosY=_PUBLIC.terminal.cursorPosY+math.ceil((unicode.wlen(text)+startX-1)/width)
if _PUBLIC.terminal.cursorPosY>height then scrollDown() end
cursorPosX=1
cursorPosY=cursorPosY+math.ceil((unicode.wlen(text)+startX-1)/width)
if cursorPosY>height then scrollDown() end
return text
end
+15 -4
View File
@@ -29,11 +29,16 @@ function _G._PUBLIC.tsched.runAsTask(path,...)
-- Userland environment definition
local userland = table.copy(_PUBLIC)
userland._G = userland
userland.load=function(chunk,chunkname,mode,env)
if not env or env==_G then env=userland end -- if they SOMEHOW get the kernel environment they're not running jack shit
return load(chunk,chunkname,mode,env)
end
userland.require = reqgen(userland.load)
assert(load(data, "="..path, "t", userland))(table.unpack(args))
end, function(errorMessage)
return errorMessage .. "\n \n" .. debug.traceback()
end, path, table.unpack(args))
end, --[[ path,]] table.unpack(args))
if not result then
if print then
gpu.freeAllBuffers()
@@ -44,14 +49,20 @@ function _G._PUBLIC.tsched.runAsTask(path,...)
end
--require(path, table.unpack(args))
end
_PUBLIC.tsched.addTask(taskFunction, string.match(tostring(path), "([^/]+)%.lua$"))
local _,taskInfo = _PUBLIC.tsched.addTask(taskFunction, string.match(tostring(path), "([^/]+)%.lua$"))
taskInfo.path = path
taskInfo.args = table.copy(args)
end
function _G._PUBLIC.tsched.addTask(func, name)
local task = coroutine.create(func)
table.insert(tsched.tasks, {["task"] = task, ["name"] = name, ["id"] = idCounter})
local taskInfo = {["task"] = task, ["name"] = name, ["id"] = idCounter}
if currentTask and type(currentTask.id)=="number" then
taskInfo.parent = currentTask.id
end
table.insert(tsched.tasks, taskInfo)
idCounter = idCounter + 1
return task
return task, taskInfo
end
function _G._PUBLIC.tsched.removeTask(id)
+31 -7
View File
@@ -10,9 +10,30 @@ local shellcfg = json.decode(data)
local component = require("component")
local gpu = component.gpu
local workingDirectory = shellcfg["defaultWorkingDirectory"]
local aliases = shellcfg["aliases"]
_G.shell = {}
_G.shell.workingDirectory = shellcfg["defaultWorkingDirectory"]
_G.shell.aliases = shellcfg["aliases"]
function _G.shell.getWorkingDirectory()
return workingDirectory
end
function _G.shell.setWorkingDirectory(dir)
checkArg(1, dir, "string")
workingDirectory = dir
end
function _G.shell.getAliases()
return table.copy(aliases)
end
function _G.shell.addAlias(executable, aliasName)
checkArg(1, executable, "string")
checkArg(2, aliasName, "string")
aliases[aliasName]=executable
end
function _G.shell.removeAlias(aliasName)
checkArg(1, aliasName, "string")
aliases[aliasName]=nil
end
local function runAsTask(path, ...)
--ocelot.log("running " .. path .. " as coroutine")
@@ -36,9 +57,9 @@ end
function _G.shell.run(command)
checkArg(1, command, "string")
if shell.aliases[command:match("[^ ]+")] then
if aliases[command:match("[^ ]+")] then
local _, cmdend = command:find("[^ ]+")
command = shell.aliases[command:match("[^ ]+")] .. command:sub(cmdend + 1)
command = aliases[command:match("[^ ]+")] .. command:sub(cmdend + 1)
end
local gm, result, args, trimmedCommand = command:gmatch("[^ ]+"), nil, {}, command
while true do
@@ -98,6 +119,9 @@ function _G.shell.run(command)
print("No such file or command: "..args[1])
end
local shareTable = ipc.shareWithAll()
shareTable.shell = _G.shell
print(shellcfg["startupMessage"]:format(_OSVERSION, shellcfg.splashMessages[math.random(1, #shellcfg.splashMessages)]))
while true do
coroutine.yield()
@@ -105,10 +129,10 @@ while true do
--print(shellcfg["prompt"]:format(shell.workingDirectory),false)
-- termlib.cursorPosX = #(shell.workingDirectory .. " > ")
-- termlib.cursorPosY = termlib.cursorPosY - 1
if shell.workingDirectory:sub(-1, -1) ~= "/" then
shell.workingDirectory = shell.workingDirectory .. "/"
if workingDirectory:sub(-1, -1) ~= "/" then
workingDirectory = workingDirectory .. "/"
end
local shellCommand = terminal.read("shell", shellcfg.prompt:format(shell.workingDirectory))
local shellCommand = terminal.read("shell", shellcfg.prompt:format(workingDirectory))
shell.run(shellCommand)
gpu.freeAllBuffers()
end
+8 -6
View File
@@ -83,6 +83,7 @@ function serialize.table(tbl,colors,stack)
local metatbl = getmetatable(tbl)
local metakeys = {}
local metastring = ""
if type(metatbl)=="table" then
for i,v in pairs(metatbl) do
keyNumber=false
@@ -91,16 +92,17 @@ function serialize.table(tbl,colors,stack)
end
if #metakeys>0 then
out=out.."\n "
if colors then out=out.."\x1b[92m" end
if colors then metastring=metastring.."\x1b[92m" end
if table.find(metakeys,"__tostring") then
out=out.."tostring: "..serialize.string(tostring(tbl)).."\n "
metastring=metastring.."tostring: "..serialize.string(tostring(tbl)).."\n "
table.remove(metakeys,table.find(metakeys,"__tostring"))
end
out=out..table.concat(metakeys,", ")
if colors then out=out.."\x1b[39m" end
metastring=metastring..table.concat(metakeys,", ")
if colors then metastring=metastring.."\x1b[39m" end
out=out..metastring
end
if keyAmount==0 then return "{}" end
if keyAmount==0 then return "{"..metastring.."}" end
if keyNumber then
-- fix strings not being serialised
local vals = {}
@@ -117,7 +119,7 @@ function serialize.table(tbl,colors,stack)
table.insert(vals,tostring(v))
end
end
return "{"..table.concat(vals,", ").."}"
return "{"..table.concat(vals,", ")..(#metakeys>0 and "\n "..metastring or "").."}"
end
return "{\n"..out.."\n}"
end