OC-KittenOS/tfilemgr.lua

234 lines
6.7 KiB
Lua

-- The File Manager (manager of files).
-- Args:
local filetype, openmode, gpu = ...
local fileManager = nil
function fileManager(filetype, openmode)
-- Like policykit, this is a trusted gateway.
-- Note that The File Manager just returns a path {fs, path}.
-- The File Wrapper is given that path, and the open mode.
local title = nil
-- Valid open modes are:
-- nil: The File Wrapper should not be invoked -
-- likely a "file manager launcher" application.
if openmode == nil then title = "File Manager" end
-- "r": Open the file for reading. Binary mode is assumed.
if openmode == "r" then
title = "Read " .. filetype
end
if openmode == "w" then
title = "Write " .. filetype
end
-- "w": Open the file for truncate-writing, again binary assumed.
if not title then error("Bad openmode") end
local scrW, scrH = gpu.getResolution()
gpu.setBackground(0)
gpu.setForeground(0xFFFFFF)
local function cls()
gpu.fill(1, 1, scrW, scrH, " ")
end
local function menuKey(cursor, el, text, ka, kc, allowEntry)
if ka == 13 then
-- entry denied, so we hit here.
return cursor, text
end
if kc == 200 then
cursor = cursor - 1
if cursor < 1 then cursor = el end
return cursor, text, false, true
end
if kc == 208 then
cursor = cursor + 1
if cursor > el then cursor = 1 end
return cursor, text, false, true
end
if allowEntry then
if ka == 8 then
return cursor, unicode.sub(text, 1, unicode.len(text) - 1), true
end
if (ka ~= 0) and (ka ~= ("/"):byte()) and (ka ~= ("\\"):byte()) then
text = text .. unicode.char(ka)
return cursor, text, true
end
end
return cursor, text
end
local function menu(title, entries, allowEntry)
cls()
gpu.fill(1, 1, scrW, 1, "-")
gpu.set(1, 1, title)
local cursor = 1
local escrH = scrH
local entryText = ""
local cursorBlinky = false
if allowEntry then escrH = scrH - 1 end
while true do
for y = 2, escrH do
local o = cursor + (y - 8)
local s = tostring(entries[o])
if not entries[o] then s = "" end
if o == cursor then s = ">" .. s else s = " " .. s end
gpu.fill(1, y, scrW, 1, " ")
gpu.set(1, y, s)
end
cursorBlinky = not cursorBlinky
if allowEntry then
gpu.fill(1, scrH, scrW, 1, " ")
if cursorBlinky then
gpu.set(1, scrH, ":" .. entryText)
else
gpu.set(1, scrH, ":" .. entryText .. "_")
end
end
local t, p1, p2, p3, p4 = computer.pullSignal(1)
if t == "key_down" then
if p2 == 13 then
if allowEntry then
if entryText ~= "" then
return entryText
end
else
return entries[cursor]
end
end
cursor, entryText, search, lookup = menuKey(cursor, #entries, entryText, p2, p3, allowEntry)
if search then
for k, v in ipairs(entries) do
if v:sub(1, v:len()) == entryText then cursor = k end
end
end
if lookup then
entryText = entries[cursor]
end
end
end
end
local currentDir = nil
local currentDrive = nil
local function listDir(dv, dr)
if dv == nil then
local l = {}
local t = {}
for c in component.list("filesystem") do
l[c] = {c, "/"}
table.insert(t, c)
end
return l, t, "Filesystems"
end
local names = component.invoke(dv, "list", dr)
local l = {}
for k, v in ipairs(names) do
if component.invoke(dv, "isDirectory", dr .. v) then
l[v] = {dv, dr .. v}
end
end
return l, names, dv .. ":" .. dr
end
local function isDir(dv, dr)
if dv == nil then return true end
return component.invoke(dv, "isDirectory", dr)
end
local tagMkdir = "// Create Directory //"
local tagCancel = "// Cancel //"
local tagOpen = "// Open //"
local tagDelete = "// Delete //"
local tagRename = "// Rename //"
local tagCopy = "// Copy //"
local tagBack = ".."
local function textEntry(title)
local txt = menu(title, {tagCancel}, true)
if txt ~= tagCancel then return txt end
return nil
end
local function report(title)
menu(title, {"OK"}, false)
end
local history = {}
local function navigate(ndr, ndd)
table.insert(history, {currentDrive, currentDir})
currentDrive, currentDir = ndr, ndd
end
while true do
local map, sl, name = listDir(currentDrive, currentDir)
if #history ~= 0 then
table.insert(sl, tagBack)
end
table.insert(sl, tagCancel)
if currentDrive then
table.insert(sl, tagMkdir)
end
local str = menu(title .. " " .. name, sl, (openmode == "w") and currentDrive)
if str == tagBack then
local r = table.remove(history, #history)
currentDrive, currentDir = table.unpack(r)
else
if str == tagCancel then return nil end
if str == tagMkdir then
local nam = textEntry("Create Directory...")
if nam then
component.invoke(currentDrive, "makeDirectory", currentDir .. nam)
end
else
if map[str] then
if map[str][1] and currentDrive then
local act = menu(name .. ":" .. str, {tagOpen, tagRename, tagDelete, tagCancel})
if act == tagOpen then
navigate(table.unpack(map[str]))
end
if act == tagRename then
local s = textEntry("Rename " .. str)
if s then
component.invoke(map[str][1], "rename", map[str][2], currentDir .. s)
end
end
if act == tagDelete then
component.invoke(map[str][1], "remove", map[str][2])
end
else
navigate(table.unpack(map[str]))
end
else
if openmode == "w" then return {currentDrive, currentDir .. str} end
local r = currentDir .. str
local subTag = "Size: " .. math.ceil(component.invoke(currentDrive, "size", r) / 1024) .. "KiB"
if openmode == "r" then subTag = tagOpen end
local act = menu(name .. ":" .. str, {subTag, tagRename, tagCopy, tagDelete, tagCancel})
if act == tagOpen then return {currentDrive, currentDir .. str} end
if act == tagRename then
local s = textEntry("Rename " .. str)
component.invoke(currentDrive, "rename", currentDir .. str, currentDir .. s)
end
if act == tagCopy then
local f2 = fileManager("Copy " .. str, "w")
if f2 then
local h = component.invoke(currentDrive, "open", currentDir .. str, "rb")
if not h then
report("Couldn't open file!")
else
local h2 = component.invoke(f2[1], "open", f2[2], "wb")
if not h2 then
report("Couldn't open dest. file!")
else
local chk = component.invoke(currentDrive, "read", h, 128)
while chk do
component.invoke(f2[1], "write", h2, chk)
chk = component.invoke(currentDrive, "read", h, 128)
end
end
component.invoke(currentDrive, "close", h)
end
end
end
if act == tagDelete then
component.invoke(currentDrive, "remove", currentDir .. str)
end
end
end
end
end
end
return fileManager(filetype, openmode)