From d75ab877df411288b4ff0a28c93775b7eea2c637 Mon Sep 17 00:00:00 2001 From: LDDestroier Date: Tue, 19 Mar 2019 21:50:50 -0400 Subject: [PATCH] Update eldit.lua --- eldit.lua | 323 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 252 insertions(+), 71 deletions(-) diff --git a/eldit.lua b/eldit.lua index 443528d..7f3ea81 100644 --- a/eldit.lua +++ b/eldit.lua @@ -37,6 +37,20 @@ local eClear = function() term.setCursorPos(cx, cy) end +local sortSelections = function() + for id,sel in pairs(eldit.selections) do + table.sort(sel, function(a,b) + return (a.y * eldit.size.width) + a.x < (b.y * eldit.size.width) + b.x + end) + end +end + +local sortCursors = function() + table.sort(eldit.cursors, function(a,b) + return (a.y * eldit.size.width) + a.x < (b.y * eldit.size.width) + b.x + end) +end + local explode = function(div, str, replstr, includeDiv) if (div == '') then return false @@ -92,10 +106,50 @@ prompt = function(prebuffer) local isCursorBlink = false local isInsert = false + local interruptable = { + [" "] = true, + ["["] = true, ["]"] = true, + ["{"] = true, ["}"] = true, + ["("] = true, [")"] = true, + ["|"] = true, + ["/"] = true, + ["\\"] = true, + ["+"] = true, + ["-"] = true, + ["*"] = true, + ["="] = true, + ["."] = true, + [","] = true + } + local checkIfSelected = function(x, y) - for id, sel in pairs(eldit.selections) do - if (x >= sel[1].x or y >= sel[1].y) and (x <= sel[2].x or y <= sel[2].y) then - return id + sortSelections() + local fin + if y >= 1 and y <= #eldit.buffer then + if x >= 1 and x <= #eldit.buffer[y] + 1 then + for id, sel in pairs(eldit.selections) do + + if y == sel[1].y then + if sel[2].y == sel[1].y then + fin = x >= sel[1].x and x <= sel[2].x + else + fin = x >= sel[1].x + end + elseif y == sel[2].y then + if sel[2].y == sel[1].y then + fin = x >= sel[1].x and x <= sel[2].x + else + fin = x <= sel[2].x + end + elseif y > sel[1].y and y < sel[2].y then + fin = true + end + + if fin then + return id + end + + end end end return false @@ -231,101 +285,156 @@ prompt = function(prebuffer) end end - local deleteText = function(mode, direction) + local deleteText = function(mode, direction, _cx, _cy) + local xAdjList = {} + local yAdj = 0 + sortCursors() for id,cur in pairs(eldit.cursors) do + cx = _cx or cur.x - (xAdjList[_cy or cur.y] or 0) + cy = _cy or cur.y - yAdj - if mode == "single" then + if mode == "single" or (direction == "forward" and cx == #eldit.buffer[cy] or (direction == "backward" and cx == 1)) then if direction == "forward" then - - elseif direction == "backward" then - if cur.x > 1 then - cur.x = cur.x - 1 - table.remove(eldit.buffer[cur.y], cur.x) - elseif cur.y > 1 then - for i = 1, #eldit.buffer[cur.y] do - table.insert(eldit.buffer[cur.y - 1], eldit.buffer[cur.y][i]) + if cx < #eldit.buffer[cy] then + xAdjList[cy] = (xAdjList[cy] or 0) + 1 + table.remove(eldit.buffer[cy], cx) + else + for i = 1, #eldit.buffer[cy + 1] do + table.insert(eldit.buffer[cy], eldit.buffer[cy + 1][i]) end - table.remove(eldit.buffer, cur.y) - cur.y = cur.y - 1 - cur.x = #eldit.buffer[cur.y] + 1 + table.remove(eldit.buffer, cy + 1) + yAdj = yAdj + 1 + end + elseif direction == "backward" then + if cx > 1 then + cx = cx - 1 + xAdjList[cy] = (xAdjList[cy] or 0) + 1 + table.remove(eldit.buffer[cy], cx) + elseif cy > 1 then + cx = #eldit.buffer[cy - 1] + 1 + for i = 1, #eldit.buffer[cy] do + table.insert(eldit.buffer[cy - 1], eldit.buffer[cy][i]) + end + table.remove(eldit.buffer, cy) + yAdj = yAdj + 1 + cy = cy - 1 end else - if cur.x >= 1 and cur.x <= #eldit.buffer[cur.y] then - table.remove(eldit.buffer[cur.y], cur.x) - elseif cur.x == #eldit.buffer[cur.y] + 1 and cur.y < #eldit.buffer then - for i = 1, #eldit.buffer[cur.y + 1] do - table.insert(eldit.buffer[cur.y], eldit.buffer[cur.y + 1][i]) + if cx >= 1 and cx <= #eldit.buffer[cy] then + table.remove(eldit.buffer[cy], cx) + elseif cx == #eldit.buffer[cy] + 1 and cy < #eldit.buffer then + for i = 1, #eldit.buffer[cy + 1] do + table.insert(eldit.buffer[cy], eldit.buffer[cy + 1][i]) end - table.remove(eldit.buffer, cur.y + 1) + table.remove(eldit.buffer, cy + 1) + yAdj = yAdj + 1 end end elseif mode == "word" then - local pos = cur.x - local interruptable = { - [" "] = true, - ["["] = true, ["]"] = true, - ["{"] = true, ["}"] = true, - ["("] = true, [")"] = true, - ["|"] = true, - ["/"] = true, - ["\\"] = true, - ["+"] = true, - ["-"] = true, - ["*"] = true, - ["="] = true, - } + local pos = cx if direction == "forward" then repeat pos = pos + 1 - until interruptable[eldit.buffer[cur.y][pos]] or pos >= #eldit.buffer[cur.y] - for i = pos, cur.x, -1 do - table.remove(eldit.buffer[cur.y], i) + until interruptable[eldit.buffer[cy][pos]] or pos >= #eldit.buffer[cy] + for i = pos, cx, -1 do + xAdjList[cy] = (xAdjList[cy] or 0) + 1 + table.remove(eldit.buffer[cy], i) end else repeat pos = pos - 1 - until interruptable[eldit.buffer[cur.y][pos]] or pos <= 1 - for i = cur.x - 1, pos, -1 do - table.remove(eldit.buffer[cur.y], i) + until interruptable[eldit.buffer[cy][pos]] or pos <= 1 + pos = math.max(1, pos) + for i = cx - 1, pos, -1 do + table.remove(eldit.buffer[cy], i) end - cur.x = pos + cx = pos end - elseif mode == "line" then + elseif mode == "line" then -- like word but is only interrupted by newline if direction == "forward" then - for i = cur.x, #eldit.buffer[cur.y] do - eldit.buffer[cur.y][i] = nil + for i = cx, #eldit.buffer[cy] do + eldit.buffer[cy][i] = nil end else - for i = cur.x, 1, -1 do - table.remove(eldit.buffer[cur.y], i) + for i = cx, 1, -1 do + table.remove(eldit.buffer[cy], i) end end end - cur.lastX = cur.x - scrollToCursor() + if _cx then + return yAdj + else + cur.x = cx + cur.y = cy + cur.lastX = cx + end end + removeRedundantCursors() + scrollToCursor() + return yAdj + end + + local deleteSelections = function() + sortSelections() + if #eldit.selections == 0 then + return {}, {} + end + local xAdjusts = {} + local yAdjusts = {} + local xAdj = 0 + local yAdj = 0 + for y = 1, #eldit.buffer do + xAdjusts[y] = {} + if checkIfSelected(#eldit.buffer[y] + 1, y) then + yAdj = yAdj + 1 + end + yAdjusts[y + 1] = yAdj + xAdj = 0 + for x = 2, #eldit.buffer[y] do + xAdjusts[y][x] = xAdj + if checkIfSelected(x, y) then + xAdj = xAdj + 1 + end + end + end + for y = #eldit.buffer, 1, -1 do + for x = #eldit.buffer[y] + 1, 1, -1 do + + if checkIfSelected(x, y) then + if x == #eldit.buffer[y] + 1 then + for i = 1, #eldit.buffer[y + 1] do + table.insert(eldit.buffer[y], eldit.buffer[y + 1][i]) + end + table.remove(eldit.buffer, y + 1) + else + deleteText("single", nil, x, y) + end + end + + end + end + eldit.selections = {} + return xAdjusts, yAdjusts end local placeText = function(text) - for id,sel in pairs(eldit.selections) do - for y = sel[2].y, sel[1].y, -1 do - for x = #eldit.buffer[y], 1, -1 do - if (y > sel[1].y and y < sel[2].y) or (x >= sel[1].x and x <= sel[2].x) then - table.remove(eldit.buffer[y], x) - end - end - end - eldit.cursors[#eldit.cursors + 1] = {x = sel[1].x, y = sel[1].y} - end + local xAdjusts, yAdjusts = deleteSelections() removeRedundantCursors() + sortCursors() + local xAdjList = {} for id,cur in pairs(eldit.cursors) do + cur.y = cur.y - (yAdjusts[cur.y] or 0) + cur.x = cur.x - ((xAdjusts[cur.y] or {})[cur.x] or 0) + (xAdjList[cur.y] or 0) for i = 1, #text do if isInsert then eldit.buffer[cur.y][cur.x + i - 1] = text:sub(i,i) else table.insert(eldit.buffer[cur.y], cur.x, text:sub(i,i)) + if #xAdjusts + #yAdjusts == 0 then + xAdjList[cur.y] = (xAdjList[cur.y] or 0) + 1 + end end cur.x = cur.x + 1 end @@ -334,14 +443,30 @@ prompt = function(prebuffer) scrollToCursor() end - local adjustCursor = function(xmod, ymod, setLastX) + local adjustCursor = function(_xmod, _ymod, setLastX, mode) for id,cur in pairs(eldit.cursors) do + if mode == "word" then + xmod = (_xmod / math.abs(_xmod)) + ymod = 0 + repeat + xmod = xmod + (_xmod / math.abs(_xmod)) + until interruptable[eldit.buffer[cur.y][cur.x + xmod]] or cur.x + xmod >= #eldit.buffer[cur.y] or cur.x + xmod <= 1 + xmod = xmod - math.min(0, math.max(xmod, -1)) + else + xmod = _xmod + ymod = _ymod + end + if mode == "flip" then + if eldit.buffer[cur.y + ymod] then + eldit.buffer[cur.y], eldit.buffer[cur.y + ymod] = eldit.buffer[cur.y + ymod], eldit.buffer[cur.y] + end + end cur.x = cur.x + xmod cur.y = cur.y + ymod - cur.y = math.max(1, math.min(cur.y, #eldit.buffer + 1)) + cur.y = math.max(1, math.min(cur.y, #eldit.buffer)) if xmod ~= 0 then repeat - if cur.x < 1 and cur.y > 1 then + if cur.x < 1 and cur.y > 1 then cur.y = cur.y - 1 cur.x = cur.x + #eldit.buffer[cur.y] + 1 elseif cur.x > #eldit.buffer[cur.y] + 1 and cur.y < #eldit.buffer then @@ -367,6 +492,10 @@ prompt = function(prebuffer) end end removeRedundantCursors() + if (not keysDown[keys.leftCtrl]) and not (xmod == 0 and ymod == 0) then + eldit.selections = {} + isSelecting = false + end scrollToCursor() end @@ -399,9 +528,11 @@ prompt = function(prebuffer) end local evt - local tID = os.startTimer(0.5) - local bartID = os.startTimer(0.1) - local doRender = true + local lastMouse = {} -- last place you clicked onscreen + local isSelecting = false -- whether or not you are selecting text + local tID = os.startTimer(0.5) -- timer for cursor blinking + local bartID = os.startTimer(0.1) -- timer for bar message to go away + local doRender = true -- if true, renders while true do evt = {os.pullEvent()} @@ -439,6 +570,22 @@ prompt = function(prebuffer) elseif evt[2] == keys.s then saveFile() + elseif evt[2] == keys.left then + adjustCursor(-1, 0, true, "word") + doRender, isCursorBlink = true, true + + elseif evt[2] == keys.right then + adjustCursor(1, 0, true, "word") + doRender, isCursorBlink = true, true + + elseif evt[2] == keys.up then + adjustCursor(0, -1, false, "flip") + doRender, isCursorBlink = true, true + + elseif evt[2] == keys.down then + adjustCursor(0, 1, false, "flip") + doRender, isCursorBlink = true, true + end else @@ -457,6 +604,7 @@ prompt = function(prebuffer) y = eldit.cursors[1].y, lastX = 1 }} + scrollToCursor() doRender = true elseif evt[2] == keys["end"] then @@ -465,6 +613,7 @@ prompt = function(prebuffer) y = eldit.cursors[1].y, lastX = #eldit.buffer[eldit.cursors[1].y] + 1 }} + scrollToCursor() doRender = true elseif evt[2] == keys.pageUp then @@ -480,7 +629,7 @@ prompt = function(prebuffer) doRender, isCursorBlink = true, false elseif evt[2] == keys.delete then - deleteText("single", nil) + deleteText("single", "forward") doRender, isCursorBlink = true, false elseif evt[2] == keys.left then @@ -518,20 +667,52 @@ prompt = function(prebuffer) y = evt[4] + eldit.scrollY, lastX = evt[3] + eldit.scrollX }} + eldit.selections = {} end + lastMouse = { + x = evt[3], + y = evt[4], + scrollX = eldit.scrollX, + scrollY = eldit.scrollY, + ctrl = keysDown[keys.leftCtrl], + curID = #eldit.cursors, + } + sortSelections() adjustCursor(0, 0, true) doRender = true elseif evt[1] == "mouse_drag" then miceDown[evt[2]] = {x = evt[3], y = evt[4]} - doRender = true + if lastMouse.x and lastMouse.y and lastMouse.curID then + local adjMX, adjMY = lastMouse.x + lastMouse.scrollX, lastMouse.y + lastMouse.scrollY + local adjEX, adjEY = evt[3] + eldit.scrollX, evt[4] + eldit.scrollY + eldit.selections[#eldit.selections + ((lastMouse.ctrl and not isSelecting) and 1 or 0)] = { + { + x = math.min(adjMX, #eldit.buffer[adjMY]), + y = adjMY + }, + { + x = math.min(adjEX, #eldit.buffer[adjEY]), + y = adjEY + } + } + sortSelections() + eldit.cursors[lastMouse.curID] = { + x = eldit.selections[#eldit.selections][1].x, + y = eldit.selections[#eldit.selections][1].y, + lastX = eldit.selections[#eldit.selections][1].x + } + adjustCursor(0, 0) + isSelecting = true + doRender = true + end elseif evt[1] == "mouse_up" then miceDown[evt[2]] = nil + isSelecting = false elseif evt[1] == "mouse_scroll" then - local amount = (keysDown[keys.leftCtrl] and eldit.size.height or 1) * evt[2] if keysDown[keys.leftAlt] then - adjustScroll(amount, 0) + adjustScroll((keysDown[keys.leftCtrl] and eldit.size.width or 1) * evt[2], 0) else - adjustScroll(0, amount) + adjustScroll(0, (keysDown[keys.leftCtrl] and eldit.size.height or 1) * evt[2]) end doRender = true end