1
1
mirror of https://git.shadowkat.net/izaya/OC-PsychOS2.git synced 2024-11-25 12:42:10 -05:00
OC-PsychOS2/lib/ed.lua

270 lines
6.7 KiB
Lua

local ed = package.loaded.ed or {}
ed.bfunc = ed.bfunc or {}
ed.ifunc = ed.ifunc or setmetatable({},{__index=ed.bfunc})
ed.buffers = ed.buffers or {}
function ed.bfunc:load(fpath)
local f = io.open(fpath,"rb")
if not f then return false, "unable to open file" end
for line in f:lines() do
self[#self+1] = line
end
f:close()
self.path = fpath
return true, #self
end
function ed.bfunc:save(fpath)
local path = fpath or self.path
if not path then return false, "no path" end
self.path = path
local f = io.open(path,"wb")
if not f then return false, "unable to open file" end
for k,v in ipairs(self) do
f:write(v.."\n")
end
f:close()
self.dirty = false
return true
end
function ed.bfunc:close(discard)
if not discard and self.dirty then
local saved = self:save()
if not saved then return false, "unable to save buffer" end
end
for k,v in pairs(ed.buffers) do
if v == self then
table.remove(ed.buffers,k)
return true
end
end
return false, "unable to find buffer handle"
end
function ed.bfunc:range(start,finish)
start, finish = math.max(1,tonumber(start) or 1), math.min(#self,tonumber(finish) or #self)
local rt = {}
for i = start, finish do
rt[#rt+1] = self[i]
end
return rt
end
function ed.bfunc:checkCursor()
self.y = math.max(self.y,1)
self.y = math.min(self.y,#self)
self.x = math.max(self.x,1)
self.x = math.min(self.x,math.max(self[self.y]:len()+1,1))
end
function ed.ifunc.buffers()
for k,v in pairs(ed.buffers) do
print(string.format("\27[31m%4i\27[0m %s",k,v.path or "?"))
end
end
function ed.ifunc.help()
print("Available commands:")
for k,v in pairs(ed.bfunc) do
print(k)
end
for k,v in pairs(ed.ifunc) do
print(k)
end
end
function ed.ifunc:list(start,finish)
start, finish = math.max(1,tonumber(start) or 1), math.min(#self,tonumber(finish) or #self)
local lt = self:range(start,finish)
for k,v in pairs(lt) do
print(string.format("\27[31m%4d\27[0m %s",k+start-1,v))
end
end
function ed.ifunc:insert(p,o)
ed.ifunc.pointer(self,p)
while true do
io.write(string.format("\27[31m%4d\27[0m ",self.y + (o or 0)))
local line = io.read()
if line == "." then break end
table.insert(self,self.y + (o or 0),line)
self.dirty = true
self.y = self.y + 1
end
end
function ed.ifunc:append(p)
ed.ifunc.insert(self,p,1)
end
function ed.ifunc:pointer(n)
self.y = math.max(1,tonumber(n) or 1)
self.y = math.min(#self,self.y)
print(self.y)
end
function ed.newBuffer()
local nb = setmetatable({},{__index=ed.bfunc})
nb.x,nb.y = 1, 1
ed.buffers[#ed.buffers+1] = nb
return nb
end
function ed.open(buffer)
local bpath = buffer
if ed.buffers[buffer] then
buffer = ed.buffers[buffer]
end
if type(buffer) == "string" then
nb = ed.newBuffer()
nb:load(buffer)
buffer = nb
end
if type(buffer) ~= "table" then buffer = ed.newBuffer() end
buffer[1] = buffer[1] or ""
buffer.path = buffer.path or "/"..((bpath:sub(1,1) == "/" and table.concat(fs.segments(path),"/")) or table.concat(fs.segments(os.getenv("PWD").."/"..bpath),"/"))
return buffer
end
function ed.interactive(buffer)
buffer=ed.open(buffer)
while true do
io.write("\27[34mced:\27[0m ")
local line = io.read()
local words = {}
for word in line:gmatch("[^%s]+") do
words[#words+1] = word
end
local cmd = table.remove(words,1)
if ed.ifunc[cmd] then
print(ed.ifunc[cmd](buffer,table.unpack(words)))
elseif cmd == "quit" then
break
else
print("Unknown command.")
end
if cmd == "close" then
break
end
end
end
function ed.visual(buffer)
buffer=ed.open(buffer)
local mx, my = 40, 13
local cx,cy = math.max(1,buffer.x-mx//2), math.max(1,buffer.y-my//2)
local ox, oy
local mode = "c"
local mult, multstr = 1, ""
local resized = false
io.write("\27[999;999H\27[6n")
local function drawBuffer(force)
if cx ~= ox or cy ~= oy or force then
io.write("\27[2J\27[H")
for i = cy, cy+my do
io.write(string.format("\27[1;%iH\27[31m%4i \27[0m%s",(i-cy+1),i,(buffer[i] or "\27[36m~"):sub(cx,cx+mx-6)))
end
elseif mode == "i" then
io.write(string.format("\27[2K\27[999D\27[31m%4i \27[0m%s",buffer.y,(buffer[buffer.y] or "\27[36m~"):sub(cx,cx+mx-6)))
end
io.write(string.format("\27[1;%iH\27[0;36;%im\27[2K[%s] ced visual: %i,%i/%i, %iK free %i",my+2,(mode == "c" and 7) or 0, mode, buffer.x, buffer.y, #buffer, computer.freeMemory()//1024,mult))
io.write(string.format("\27[%i;%iH\27[0m",buffer.x+6-cx,buffer.y-cy+1))
end
os.setTimeout(0.0005)
while true do
drawBuffer()
ox, oy = cx, cy
io.write("\27[100;101m")
local c=io.read(1)
if c == "\27" then
local b = ""
repeat
c=io.read(1)
b=b..c
until c:match("%a")
dprint(b)
local nx, ny = b:match("%[(%d+);(%d+)")
if nx and ny then
mx, my = math.max(mx, tonumber(nx)), math.max(my, tonumber(ny)-2)
drawBuffer(true)
end
end
if mode == "c" then
if c == "q" then
io.write("\27[0m\27[2J\27[H")
break
elseif c == "h" then
buffer.x = buffer.x - mult
elseif c == "l" then
buffer.x = buffer.x + mult
elseif c == "j" then
buffer.y = buffer.y + mult
elseif c == "k" then
buffer.y = buffer.y - mult
elseif c == "d" then
for i = 1, mult do
table.remove(buffer,buffer.y)
end
drawBuffer(true)
elseif c == "i" or c == "\t" then
mode = "i"
elseif c == "a" then
buffer.x = buffer.x + 1
mode = "i"
elseif c == ":" then
io.write("\27[1;999H\27[2K")
ed.interactive(buffer)
drawBuffer(true)
elseif c == "w" then
buffer:save()
elseif c:match("%d") then
multstr = multstr .. c
mult = tonumber(multstr)
end
if c:match("%D") then
multstr = ""
mult = 1
end
else
if c == "\t" then
mode = "c"
elseif c == "\8" and buffer.x == 1 and buffer.y > 1 then
local lblen = buffer[buffer.y-1]:len()
buffer[buffer.y-1] = buffer[buffer.y-1] .. table.remove(buffer,buffer.y)
buffer.x, buffer.y = lblen+1, buffer.y - 1
drawBuffer(true)
elseif c == "\8" then
buffer[buffer.y] = buffer[buffer.y]:sub(1,buffer.x - 2)..buffer[buffer.y]:sub(buffer.x)
buffer.x = buffer.x - 1
else
buffer[buffer.y] = buffer[buffer.y]:sub(1,buffer.x-1)..c..buffer[buffer.y]:sub(buffer.x)
buffer.x = buffer.x + 1
local fh,sh = buffer[buffer.y]:match("(.*)\n(.*)")
if fh and sh then
buffer[buffer.y] = fh
table.insert(buffer,buffer.y+1,sh)
buffer.x, buffer.y = 1, buffer.y + 1
drawBuffer(true)
end
end
end
buffer:checkCursor()
local ax, amx = buffer.x + 5, mx - 5
if cy + my < buffer.y + 3 then
cy = math.min(#buffer-my,buffer.y + 6 - my)
end
if cy + 3 > buffer.y then
cy = math.max(1,buffer.y - 6)
end
if buffer.x + 5 > cx + mx - 4 then
cx = math.max(1,(buffer.x + 6) - (mx - 6))
end
if buffer.x < cx + 3 then
cx = math.max(1,buffer.x - 6)
end
end
end
return ed