Create eldit.lua

To do:
+ file saving
+ syntax formatting
+ other text functions
+ yadda
This commit is contained in:
LDDestroier 2019-03-19 15:55:19 -04:00 committed by GitHub
parent 9e7475e684
commit 2e289f23bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 449 additions and 0 deletions

449
eldit.lua Normal file
View File

@ -0,0 +1,449 @@
-- eldit
-- by lddestroier
-- wget https://raw.githubusercontent.com/LDDestroier/CC/master/eldit.lua
local scr_x, scr_y = term.getSize()
local eldit = {}
eldit.buffer = {{}}
eldit.scrollX = 0
eldit.scrollY = 0
eldit.cursors = {
{x = 1, y = 1, lastX = 1}
}
eldit.selections = {}
eldit.size = {
x = 1,
y = 1,
width = scr_x,
height = scr_y
}
local eClearLine = function(y)
local cx, cy = term.getCursorPos()
term.setCursorPos(eldit.size.x, y or cy)
term.write((" "):rep(eldit.size.width))
term.setCursorPos(cx, cy)
end
local eClear = function()
local cx, cy = term.getCursorPos()
for y = eldit.size.y, eldit.size.y + eldit.size.height - 1 do
term.setCursorPos(eldit.size.x, y)
term.write((" "):rep(eldit.size.width))
end
term.setCursorPos(cx, cy)
end
local explode = function(div, str, replstr, includeDiv)
if (div == '') then
return false
end
local pos, arr = 0, {}
for st, sp in function() return string.find(str, div, pos, false) end do
table.insert(arr, string.sub(replstr or str, pos, st - 1 + (includeDiv and #div or 0)))
pos = sp + 1
end
table.insert(arr, string.sub(replstr or str, pos))
return arr
end
prompt = function(prebuffer)
local keysDown = {}
local miceDown = {}
if type(prebuffer) == "string" then
for i = 1, #prebuffer do
if prebuffer:sub(i,i) == "\n" then
eldit.buffer[#eldit.buffer + 1] = {}
else
eldit.buffer[#eldit.buffer] = prebuffer:sub(i,i)
end
end
elseif type(prebuffer) == "table" then
eldit.buffer = prebuffer
end
local isCursorBlink = false
local isInsert = false
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
end
end
return false
end
local checkIfCursor = function(x, y)
for id, cur in pairs(eldit.cursors) do
if x == cur.x and y == cur.y then
return id
end
end
return false
end
local getChar = function(x, y)
if eldit.buffer[y] then
return eldit.buffer[y][x]
else
return nil
end
end
local render = function()
local cx, cy
for y = 1, eldit.size.height - 1 do -- minus one because it reserves space for the bar
for x = 1, eldit.size.width do
term.setCursorPos(eldit.size.x + x - 1, eldit.size.y + y - 1)
cx = x + eldit.scrollX
cy = y + eldit.scrollY
if checkIfSelected(cx, cy) then
term.setBackgroundColor(colors.blue)
else
term.setBackgroundColor(colors.black)
end
if checkIfCursor(cx, cy) and isCursorBlink then
if isInsert then
term.setTextColor(colors.black)
term.setBackgroundColor(colors.white)
else
term.setTextColor(colors.black)
term.setBackgroundColor(colors.lightGray)
end
else
term.setTextColor(colors.white)
end
term.write(getChar(cx, cy) or " ")
end
end
term.setCursorPos(eldit.size.x, eldit.size.y + eldit.size.height - 1)
term.setBackgroundColor(colors.gray)
eClearLine()
for id,cur in pairs(eldit.cursors) do
term.write("(" .. cur.x .. "," .. cur.y .. ") ")
end
end
local scrollToCursor = function()
local lowCur, highCur = eldit.cursors[1], eldit.cursors[1]
local leftCur, rightCur = eldit.cursors[1], eldit.cursors[1]
for id,cur in pairs(eldit.cursors) do
if cur.y < lowCur.y then
lowCur = cur
elseif cur.y > highCur.y then
highCur = cur
end
if cur.x < leftCur.x then
leftCur = cur
elseif cur.y > rightCur.x then
rightCur = cur
end
end
if lowCur.y - eldit.scrollY < 1 then
eldit.scrollY = highCur.y - 1
elseif highCur.y - eldit.scrollY > eldit.size.height - 1 then
eldit.scrollY = lowCur.y - eldit.size.height + 1
end
if leftCur.x - eldit.scrollX < 1 then
eldit.scrollX = rightCur.x - 1
elseif rightCur.x - eldit.scrollX > eldit.size.width then
eldit.scrollX = leftCur.x - eldit.size.width
end
end
local adjustScroll = function(amount)
eldit.scrollY = math.min(
math.max(
0,
eldit.scrollY + amount
),
math.max(
0,
#eldit.buffer - eldit.size.height + 1
)
)
end
local removeRedundantCursors = function()
local xes = {}
for i = #eldit.cursors, 1, -1 do
if xes[eldit.cursors[i].x] == eldit.cursors[i].y then
table.remove(eldit.cursors, i)
else
xes[eldit.cursors[i].x] = eldit.cursors[i].y
end
end
end
local deleteText = function(mode, direction)
for id,cur in pairs(eldit.cursors) do
if mode == "single" 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])
end
table.remove(eldit.buffer, cur.y)
cur.y = cur.y - 1
cur.x = #eldit.buffer[cur.y] + 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])
end
table.remove(eldit.buffer, cur.y + 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,
}
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)
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)
end
cur.x = pos
end
elseif mode == "line" then
if direction == "forward" then
for i = cur.x, #eldit.buffer[cur.y] do
eldit.buffer[cur.y][i] = nil
end
else
for i = cur.x, 1, -1 do
table.remove(eldit.buffer[cur.y], i)
end
end
end
cur.lastX = cur.x
scrollToCursor()
end
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
removeRedundantCursors()
for id,cur in pairs(eldit.cursors) do
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))
end
cur.x = cur.x + 1
end
cur.lastX = cur.x
end
scrollToCursor()
end
local adjustCursor = function(xmod, ymod, setLastX)
for id,cur in pairs(eldit.cursors) do
cur.x = cur.x + xmod
cur.y = cur.y + ymod
cur.y = math.max(1, math.min(cur.y, #eldit.buffer + 1))
if xmod ~= 0 then
repeat
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
cur.x = cur.x - #eldit.buffer[cur.y] - 1
cur.y = cur.y + 1
end
until (cur.x >= 1 and cur.x <= #eldit.buffer[cur.y] + 1) or ((cur.y == 1 and xmod < 0) or (cur.y == #eldit.buffer and xmod > 0))
end
if setLastX then
cur.lastX = cur.x
else
cur.x = cur.lastX
end
if cur.y < 1 then
cur.y = math.max(1, math.min(cur.y, #eldit.buffer))
cur.x = 1
elseif cur.y > #eldit.buffer then
cur.y = math.max(1, math.min(cur.y, #eldit.buffer))
cur.x = #eldit.buffer[cur.y] + 1
else
cur.y = math.max(1, math.min(cur.y, #eldit.buffer))
cur.x = math.max(1, math.min(cur.x, #eldit.buffer[cur.y] + 1))
end
end
removeRedundantCursors()
scrollToCursor()
end
local makeNewLine = function()
for id,cur in pairs(eldit.cursors) do
table.insert(eldit.buffer, cur.y + 1, {})
for i = cur.x, #eldit.buffer[cur.y] do
if i > cur.x or not isInsert then
table.insert(eldit.buffer[cur.y + 1], eldit.buffer[cur.y][i])
end
eldit.buffer[cur.y][i] = nil
end
cur.x = 1
cur.y = cur.y + 1
end
scrollToCursor()
end
local evt
local tID = os.startTimer(0.5)
local doRender = true
while true do
evt = {os.pullEvent()}
if evt[1] == "timer" then
if evt[2] == tID then
if isCursorBlink then
tID = os.startTimer(0.4)
else
tID = os.startTimer(0.3)
end
isCursorBlink = not isCursorBlink
doRender = true
end
elseif evt[1] == "char" or evt[1] == "paste" then
placeText(evt[2])
doRender = true
elseif evt[1] == "key" then
keysDown[evt[2]] = true
if evt[2] == keys.insert then
isInsert = not isInsert
doRender, isCursorBlink = true, true
elseif evt[2] == keys.enter then
makeNewLine()
doRender, isCursorBlink = true, false
elseif evt[2] == keys.home then
eldit.cursors = {{
x = 1,
y = eldit.cursors[1].y,
lastX = 1
}}
doRender = true
elseif evt[2] == keys["end"] then
eldit.cursors = {{
x = #eldit.buffer[eldit.cursors[1].y] + 1,
y = eldit.cursors[1].y,
lastX = #eldit.buffer[eldit.cursors[1].y] + 1
}}
doRender = true
elseif evt[2] == keys.pageUp then
adjustScroll(-eldit.size.height)
doRender = true
elseif evt[2] == keys.pageDown then
adjustScroll(eldit.size.height)
doRender = true
elseif evt[2] == keys.backspace then
deleteText(keysDown[keys.leftCtrl] and "word" or "single", "backward")
doRender, isCursorBlink = true, false
elseif evt[2] == keys.delete then
deleteText(keysDown[keys.leftCtrl] and "word" or "single", keysDown[keys.leftCtrl] and "forward")
doRender, isCursorBlink = true, false
elseif evt[2] == keys.left then
adjustCursor(-1, 0, true)
doRender, isCursorBlink = true, true
elseif evt[2] == keys.right then
adjustCursor(1, 0, true)
doRender, isCursorBlink = true, true
elseif evt[2] == keys.up then
adjustCursor(0, -1, false)
doRender, isCursorBlink = true, true
elseif evt[2] == keys.down then
adjustCursor(0, 1, false)
doRender, isCursorBlink = true, true
end
elseif evt[1] == "key_up" then
keysDown[evt[2]] = nil
elseif evt[1] == "mouse_click" then
miceDown[evt[2]] = {x = evt[3], y = evt[4]}
if keysDown[keys.leftCtrl] then
table.insert(eldit.cursors, {
x = evt[3] + eldit.scrollX,
y = evt[4] + eldit.scrollY,
lastX = evt[3] + eldit.scrollX
})
else
eldit.cursors = {{
x = evt[3] + eldit.scrollX,
y = evt[4] + eldit.scrollY,
lastX = evt[3] + eldit.scrollX
}}
end
adjustCursor(0, 0, true)
doRender = true
elseif evt[1] == "mouse_drag" then
miceDown[evt[2]] = {x = evt[3], y = evt[4]}
doRender = true
elseif evt[1] == "mouse_up" then
miceDown[evt[2]] = nil
elseif evt[1] == "mouse_scroll" then
local amount = (keysDown[keys.leftCtrl] and eldit.size.height or 1) * evt[2]
adjustScroll(amount)
doRender = true
end
if doRender then
render()
doRender = false
end
end
end
prompt()