From 194564b9598769bbf68715d54eade320775c8526 Mon Sep 17 00:00:00 2001 From: XeonSquared Date: Sun, 12 Apr 2020 03:49:44 +1000 Subject: [PATCH] Added an actually workable editor for once. Skye's gonna be mad, it's like vim. --- lib/ed.lua | 266 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/shutil.lua | 4 + 2 files changed, 270 insertions(+) create mode 100644 lib/ed.lua diff --git a/lib/ed.lua b/lib/ed.lua new file mode 100644 index 0000000..5eb5115 --- /dev/null +++ b/lib/ed.lua @@ -0,0 +1,266 @@ +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) + 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() buffer[1] = "" end + 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 + print(string.format("\27[31m%4i \27[0m%s",i,(buffer[i] or "\27[36m~"):sub(cx,cx+mx-6))) + end + elseif mode == "i" then + print(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 diff --git a/lib/shutil.lua b/lib/shutil.lua index bb7e369..2b497f2 100644 --- a/lib/shutil.lua +++ b/lib/shutil.lua @@ -1,7 +1,11 @@ local component = require "component" local fs = require "fs" local shell = require "shell" +local ed = require "ed" local shutil = {} +shutil.ed = ed.interactive +shutil.vi = ed.visual +shutil.buffers = ed.ifunc.buffers local function wrapUnits(n) local scale = {"K","M","G","T","P"}