mirror of
				https://github.com/LDDestroier/CC/
				synced 2025-10-30 23:12:59 +00:00 
			
		
		
		
	Create eldit.lua
To do: + file saving + syntax formatting + other text functions + yadda
This commit is contained in:
		
							
								
								
									
										449
									
								
								eldit.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										449
									
								
								eldit.lua
									
									
									
									
									
										Normal 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() | ||||||
		Reference in New Issue
	
	Block a user
	 LDDestroier
					LDDestroier