Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --Porting vim.lua from a CC script I found on pastebin
- --Todo:
- --port rest of the functions to OC
- --add rest of the binds
- --add line numbering (use bind to toggle it)
- --Adding imports first
- local allthecomps = require("component")
- local event = require("event")
- local fs = require("filesystem")
- local gpu = allthecomps.gpu --will I need it? I do not know
- local keyboard = require("keyboard")
- local term = require("term")
- local state = 0
- local tArgs = { ... }
- local x,y = 1,1
- local w,h = gpu.getResolution() --rather than term.getsize. apparently I do need the gpu.
- local tLines = {} --the central table the entire file is stored in.
- --maybe this will be the site of optimization
- local scrollX, scrollY = 0,0
- local clipboard = {}
- local sStatus,sSearch = "",""
- local bSearchBack = false
- if #tArgs == 0 then
- error("Usage: vim <path>")
- end
- local sPath = fs.canonical(tArgs[1])
- local sFileName = string.match(sPath, "[^/]+$")
- local bReadOnly = false --fs.isReadOnly(sPath) --I don't think isReadOnly exists in OC
- local bReadOnlyW = false
- if fs.exists(sPath) and fs.isDirectory(sPath) then
- error("Cannot edit a directory") --should add support for viewing dirs, or maybe not to save memory
- end
- local bNewFile = false
- local bChanged = false
- local redrawS
- print(1)
- -- Helper functions
- local function getFilesize()
- local filesize = 0
- for k,v in pairs(tLines) do
- filesize = filesize + string.len(v)+1
- end
- return filesize
- end
- local function redrawStatus(bsec)
- local _x,_y = term.getCursor()
- term.setCursor(1, h)
- if not bsec then
- term.clearLine()
- redrawCursor(true) --WHY, HOW IS THIS UNDEFINED? how
- end
- term.write(sStatus) --ooh, this structure is good
- term.setCursor(_x,_y)
- end
- local function redrawCursor(bsec)
- local size = string.len(tostring(x)) + string.len(tostring(y)) + 4 --this is an offset
- local _x,_y = term.getCursor() --test term.setCursor
- term.setCursor(w - size, h) --this puts it at the end of the bottom line. nice
- if not bsec then
- term.clearLine()
- redrawStatus(true)
- end
- local percent
- if y == 1 then
- percent = "Top"
- elseif y == #tLines then
- percent = "Bot"
- else
- percent = math.floor(y / #tLines * 100) .. "%"
- end
- term.write(y .. "," .. x .. " " .. percent)
- term.setCursor(_x,_y)
- end
- print(2)
- local function setStatus(_s)
- sStatus = _s
- redrawStatus()
- end
- local function load() --should be renamed to init maybe
- local lines = 0
- if fs.exists(sPath) then
- local file = fs.open(sPath, "r")
- local sLine = file:read() --here, tLines is populated by the file's lines
- while sLine do
- table.insert(tLines, sLine)
- sLine = file:read()
- lines = lines + 1
- end
- file:close() --this is very similar to OC it seems, maybe because of lua
- else
- table.insert(tLines,"")
- bNewFile = true
- end
- local _sStatus = "\"" .. sFileName .. "\""
- if bNewFile then
- _sStatus = _sStatus .. " [New File]"
- end
- if bReadOnly then --where is this defined? search later
- _sStatus = _sStatus .. " [Read Only]"
- end
- if not bNewFile then
- _sStatus = _sStatus .. " " .. lines .. "L, " .. getFilesize() .. "C" --maybe count words too. getWordcount()
- end
- setStatus(_sStatus)
- end
- local function save()
- local file = io.open(sPath, "w")
- if file then
- for k,v in pairs(tLines) do --maybe this algorithm could be optimized.
- file:write(v .. "\n")
- end
- file:close()
- return true
- end
- return false
- end
- print(3)
- -- local function reload() --I would like this later
- --loads the file again and sets the cursor to its previous place
- local function redrawText()
- for _y=1, h-1 do --I don't understand how this for works.
- term.setCursor(1 - scrollX, _y)
- term.clearLine()
- local sLine = tLines[_y + scrollY]
- if sLine ~= nil then
- term.write(sLine)
- end
- end
- term.setCursor(x - scrollX, y - scrollY)
- end
- local function setCursor(x, y)
- local screenX = x - scrollX
- local screenY = y - scrollY
- local bRedraw = false
- if screenX < 1 then
- scrollX = x - 1
- screenX = 1
- bRedraw = true
- elseif screenX > w then
- scrollX = x - w
- screenX = w
- bRedraw = true
- end
- if screenY < 1 then
- scrollY = y - 1
- screenY = 1
- bRedraw = true
- elseif screenY > h-1 then
- scrollY = y - (h - 1)
- screenY = h - 1
- bRedraw = true
- end
- term.setCursor(screenX, screenY)
- if bRedraw then redrawText() end
- redrawCursor()
- end
- local function redrawLine()
- local _x,_y = term.getCursor()
- term.setCursor(1 - scrollX, _y)
- term.clearLine()
- term.write(tLines[y])
- term.setCursor(_x, _y)
- end
- local function cursor(param)
- if param == 203 then
- -- Left
- if keyboard.isControlDown() then --implementing this
- x = x
- --Move until you encounter the beginning of a new word
- --space, \n, ., ,...all the word seperator chars
- --maybe I should make a list of those. (or are they tables here?)
- --wait a minute, this seems to be the wrong func. should be in 0 or 2?
- --or no, this func is for the keys
- elseif x > 1 then
- x = x - 1
- setCursor(x,y)
- end
- return true
- elseif param == 205 then
- -- Right
- if x < string.len(tLines[y])+1 then
- x = x + 1
- setCursor(x,y)
- end
- return true
- elseif param == 200 then
- -- Up
- if y > 1 then
- y = y - 1
- local len = string.len(tLines[y])+1
- if x > len then
- x = len
- end
- setCursor(x,y)
- end
- return true
- elseif param == 208 then
- -- Down
- if y < #tLines then
- y = y + 1
- local len = string.len(tLines[y])+1
- if x > len then
- x = len
- end
- setCursor(x,y)
- end
- return true
- elseif param == 199 then
- -- Home
- x = 1
- setCursor(x,y)
- return true
- elseif param == 207 then
- -- End
- x = string.len(tLines[y]) + 1
- setCursor(x,y)
- return true
- elseif param == 201 then
- -- PageUp
- y = y - h + 1
- if y < 1 then y = 1 end
- local len = tLines[y]:len()
- if x > len+1 then
- x = len+1
- end
- setCursor(x,y)
- elseif param == 209 then
- -- PageDown
- y = y + h - 2
- if y > #tLines then
- y = #tLines
- end
- local len = tLines[y]:len()
- if x > len+1 then
- x = len+1
- end --why doesn't this return true?
- setCursor(x,y)
- end
- return false
- end
- local function searchF(s)
- sSearch = s
- for i = x+1, tLines[y]:len() do
- if tLines[y]:sub(i,i+s:len()-1) == s then
- return i,y
- end
- end
- for i = y+1, #tLines do
- if i > #tLines then break end
- for j = 1, tLines[i]:len() do
- if tLines[i]:sub(j,j+s:len()-1):lower() == s:lower() then
- return j,i
- end
- end
- end
- setStatus("search hit BOTTON, continuing at TOP")
- for i = 1, y do
- for j = 1, tLines[i]:len() do
- if tLines[i]:sub(j,j+s:len()-1):lower() == s:lower() then
- return j,i
- end
- end
- end
- setStatus("E486: Pattern not found: " .. s)
- return x,y
- end
- local function searchB(s)
- sSearch = s
- bSearchBack = true
- for i = x-1, 1, -1 do
- if x < 1 then break end
- if tLines[y]:sub(i,i+s:len()-1) == s then
- return i,y
- end
- end
- for i = y-1, 1, -1 do
- if i < 1 then break end
- for j = tLines[i]:len(), 1, -1 do
- if tLines[i]:sub(j,j+s:len()-1):lower() == s:lower() then
- return j,i
- end
- end
- end
- setStatus("search hit TOP, continuing at BOTTOM")
- for i = #tLines, y, -1 do
- for j = tLines[i]:len(), 1, -1 do
- if tLines[i]:sub(j,j+s:len()-1):lower() == s:lower() then
- return j,i
- end
- end
- end
- setStatus("E486: Pattern not found: " .. s)
- return x,y
- end
- local function executecmd(rangemin, rangemax, command, amount, force)
- if force == nil then force = false end
- if amount == nil or amount == "" then amount = 1 end
- if rangemin > rangemax then
- rangemax = rangemin
- end
- if rangemin == 0 and rangemax == 0 then
- rangemin,rangemax = 0,0
- end
- local function _quit()
- if bChanged and not force then
- setStatus("E37: No write since last change (add ! to override)")
- state = 0
- else
- setStatus("")
- state = -1
- end
- end
- local function _save()
- if bReadOnly and not force then
- setStatus("E45: 'readonly' option is set (add ! to override)")
- state = 0
- else
- if not save() then
- setStatus("E212: Can't open file for writing")
- state = 0
- else
- local _sStatus = "\"" .. sFileName .. "\""
- if bNewFile then
- _sStatus = _sStatus .. " [New] "
- bNewFile = false
- end
- _sStatus = _sStatus .. " " .. #tLines .. "L, " .. getFilesize() .. "C written"
- setStatus(_sStatus)
- bChanged = false
- state = 0
- end
- end
- end
- if command == "q" then
- _quit()
- elseif command == "w" then
- _save()
- elseif command == "wq" then
- _save()
- _quit()
- elseif command == "d" then --I have no idea
- local _y = y
- y = rangemin
- if rangemin ~= rangemax then
- amount = rangemax - rangemin + 1
- end
- clipboard = {}
- for i = 1, amount do
- if tLines[y] ~= nil then
- table.insert(clipboard,tLines[y])
- table.remove(tLines, y)
- if #tLines == 0 then table.insert(tLines, "") end
- redrawText()
- bChanged = true
- if tLines[y] == nil then
- y = y - 1
- break
- end
- local len = string.len(tLines[y]) + 1
- if x > len then
- x = len
- setCursor(x,y)
- end
- end
- end
- y = _y
- state = 0
- elseif command:sub(1,1) == "/" then
- x,y = searchF(command:sub(2))
- setCursor(x,y)
- state = 0
- elseif command:sub(1,1) == "?" then
- x,y = searchB(command:sub(2))
- setCursor(x,y)
- state = 0
- elseif command:sub(1,1) == "s" then --what was this?
- elseif command == "=" then
- setStatus(#tLines)
- state = 0
- else
- setStatus("E492: Not an editor command: " .. command)
- state = 0
- end
- end
- -- _i, _j = string.find(s, _currentpattern)
- -- if _i==1 and _j==#s then
- -- do some true things! yay
- local function defaultmode()
- local kb = "" --kb is short for keybuffer; I didn't like how long keybuffer was
- local function resetkb() kb = "" end
- while state == 0 do
- local sEvent,param = os.pullEvent() --sEvent seems to be the kind of event. how many events are there?
- if sEvent == "key" then --up, down, pageup, pagedown, home, end, backspace, del, maybe more
- if param == 28 then param = 208 end --down
- if param == 14 then param = 203 end --left, don't know what 28 and 14 are
- if cursor(param) then bGPressed = false end --so bGPressed isn't actually used anywhere...
- elseif sEvent == "char" then --I need to learn the events
- kb = kb .. param
- -- local _i, _j
- local function attv(patt) --checks if the pattern encompasses the keybuffer.
- _i, _e = string.find(kb, patt) --attv used to stand for assignThingsToVars, it's meaningless now
- return _i == 1 and _e == #kb
- end
- if attv("^i$") then --or I could just do `if kb == "i"`
- state = 2
- -- elseif attv("^a$") then
- -- move the cursor over a char, change to insert mode
- elseif attv("^%s*gg") then --string.sub is inclusive?
- _i, _e = string.find(kb, "gg")
- local _nums = string.sub(kb, 0, _i-1) --will have to debug this
- if not tonumber(nums) then error("!!!!!! in gg nums contained chars!") end --why did I do this?
- if _nums ~= "" then
- x, y = 1, tonumber(nums) --all this crap is to support numbers
- setCursor(x, y)
- else
- x, y = 1, 1
- setCursor(x, y)
- end
- elseif kb == "G" then --need to add support for a number. with num seems to do same as #gg
- x,y = 1,#tLines
- redrawCursor(x,y)
- elseif kb == "yy" then
- clipboard = {tLines[y]}
- keybuffer = ""
- else
- noreset = true --set this elsewhere if you don't want kb to be reset
- end
- if not noreset then kb = "" end
- -- elseif sEvent == "click" then --hope for highlight select maybe
- end
- end
- end
- local function defaultmode() --event pulling is difficult to port
- local keybuffer = ""
- while state == 0 do
- local sEvent,param = os.pullEvent()
- if sEvent == "key" then
- if param == 28 then param = 208 end
- if param == 14 then param = 203 end
- if cursor(param) then
- bGPressed = false
- end
- elseif sEvent == "char" then --yep, this system sucks
- if param == 'i' then --and I will implement some regexes.
- state = 2
- elseif param == ":" then
- state = 1
- elseif param == "π" then
- state = 3
- elseif param == "G" then
- x = 1
- y = #tLines
- setCursor(x,y)
- elseif param == "n" then
- if bSearchBack then
- setStatus("?" .. sSearch)
- x,y = searchB(sSearch)
- else
- setStatus("/" .. sSearch)
- x,y = searchF(sSearch)
- end
- setCursor(x,y)
- elseif param == "N" then
- if bSearchBack then
- setStatus("/" .. sSearch)
- x,y = searchF(sSearch)
- else
- setStatus("?" .. sSearch)
- x,y = searchB(sSearch)
- end
- elseif param == "p" then
- for i = #clipboard, 1, -1 do
- table.insert(tLines,y+1,clipboard[i])
- end
- redrawText()
- bChanged = true
- elseif param == "P" then
- for i = #clipboard, 1, -1 do
- table.insert(tLines,y,clipboard[i])
- end
- redrawText()
- bChanged = true
- end
- if param == "g" then --shouldn't this be up with G?
- if keybuffer == "g" then
- x = 1
- y = 1
- setCursor(x,y)
- keybuffer = ""
- else
- keybuffer = "g" --reacts with gg and not g then, and in the crappy way
- end
- elseif param == "y" then
- if keybuffer == "y" then
- clipboard = {tLines[y]}
- keybuffer = ""
- else
- keybuffer = "y"
- end
- elseif param == "d" then
- if keybuffer == "d" then
- clipboard = {tLines[y]}
- table.remove(tLines,y)
- if #tLines == 0 then table.insert(tLines,"") end
- redrawText()
- if y > #tLines then
- y = y - 1
- setCursor(x,y)
- end
- if x > tLines[y]:len()+1 then
- x = tLines[y]:len()
- setCursor(x,y)
- end
- bChanged = true
- keybuffer = ""
- else
- keybuffer = "d"
- end
- else
- keybuffer = ""
- end
- end
- end
- end
- local function commandmode() --
- local command = ":"
- term.setCursor(2,h) --maybe I'll have to align the destination coords, not likely though
- setStatus(":")
- while state == 1 do
- local _x,_y = term.getCursor()
- local sEvent,param = os.pullEvent() --event.pull(nil, ???therestofthefunc)
- if sEvent == "key" then
- if param == 28 then
- -- Return
- command = command:sub(2)
- if command:sub(1,1) == "s" or command:sub(1,1) == "/" or command:sub(1,1) == "?" then
- executecmd(0,0,command,0,false)
- else
- local _,_,minmax,cmd,amnt,force = command:find("(%d*,?%d*)([a-zA-Z=]*)(%d*)(!?)")
- local minim,maxim = 0,0
- local i = 1
- local minmax2,flag = minmax:sub(i,i), false
- while minmax2 ~= "" do
- if minmax2 == "," then
- flag = true
- else
- if flag then
- maxim = maxim * 10 + tonumber(minmax2)
- else
- minim = minim * 10 + tonumber(minmax2)
- end
- end
- i = i + 1
- minmax2 = minmax:sub(i,i)
- end
- executecmd(minim,maxim,cmd,amnt,force == "!")
- end
- elseif param == 59 then
- -- F1, the escape of this vim
- state = 0
- elseif param == 14 then
- -- Backspace
- if _x > 1 then
- command = string.sub(command,1,_x-2) .. string.sub(command,_x)
- _x = _x - 1
- term.setCursor(_x,_y)
- end
- if command == "" then
- state = 0
- end
- setStatus(command)
- elseif param == 203 then --why is left special?
- -- Left
- if _x > 1 then
- _x = _x + 1
- term.setCursor(_x,_y)
- end
- end
- elseif sEvent == "char" then
- command = string.sub(command,1,_x-1) .. param .. string.sub(command,_x)
- setStatus(command)
- _x = _x + 1
- term.setCursor(_x,_y)
- end
- end
- setCursor(x,y)
- end
- local function insertmode()
- local _sStatus = "-- INSERT -- "
- if bReadOnly and not bReadOnlyW then
- _sStatus = _sStatus .. " W10: Changing a readonly file"
- bReadOnlyW = true
- end
- setStatus(_sStatus)
- while state == 2 do
- local sEvent,param = os.pullEvent()
- if sEvent == "key" and not cursor(param) then
- if param == 59 then
- -- F1
- state = 0
- elseif param == 28 then
- -- Return
- local sLine = tLines[y]
- tLines[y] = string.sub(sLine,1,x-1)
- table.insert(tLines,y+1,string.sub(sLine,x))
- redrawText()
- x = 1
- y = y + 1
- setCursor(x,y)
- bChanged = true
- elseif param == 14 then
- -- Backspace
- if x > 1 then
- local sLine = tLines[y]
- tLines[y] = string.sub(sLine,1,x-2) .. string.sub(sLine,x)
- redrawLine()
- x = x - 1
- elseif y > 1 then
- local sPrevLine = tLines[y-1]
- tLines[y-1] = sPrevLine .. tLines[y]
- table.remove(tLines, y)
- redrawText()
- x = string.len(sPrevLine) + 1
- y = y - 1
- end
- setCursor(x,y)
- bChanged = true
- elseif param == 211 then
- -- Del
- local sLine = tLines[y]
- local len = string.len(sLine)+1
- if x < len then
- tLines[y] = string.sub(sLine,1,x-1) .. string.sub(sLine,x+1)
- redrawLine()
- elseif y < #tLines then
- tLines[y] = sLine .. tLines[y+1]
- table.remove(tLines, y+1)
- redrawText()
- end
- bChanged = true
- elseif param == 15 then
- -- Tab
- local sLine = tLines[y]
- tLines[y] = string.sub(sLine,1,x-1) .. " " .. string.sub(sLine,x)
- redrawLine()
- x = x + 4
- setCursor(x,y)
- bChanged = true
- end
- elseif sEvent == "char" then
- local sLine = tLines[y]
- tLines[y] = string.sub(sLine,1,x-1) .. param .. string.sub(sLine,x)
- redrawLine()
- x = x + string.len(param)
- setCursor(x,y)
- bChanged = true
- end
- end
- setStatus("")
- end
- local function tsmode() -- From what I can tell, this is the quitting mode.
- end
- print(4)
- -- Main routine
- local tModes = {}
- tModes[0] = defaultmode
- tModes[1] = commandmode
- tModes[2] = insertmode
- tModes[3] = tsmode
- print(4.1)
- -- term.clear()
- -- term.setCursor(1,1) --not needed after clear()
- term.setCursorBlink(true)
- print(4.2)
- load() --Breakage happens here
- print(4.3)
- redrawText()
- print(4.4)
- redrawS = redrawStatus
- redrawCursor()
- print(4.5)
- while state ~= -1 do
- tModes[state]()
- end
- print(4.6)
- -- term.clear()
- term.setCursor(1,1)
- print(5)
- --Output:
- --# vim file
- --1
- --2
- --3
- --4
- --4.1
- --4.2
- --/tmp/vim/69: attempt to call global `redrawCursor` (a nil value)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement