From ca7dfcb010000c34101770d6d9b7eb2543708a47 Mon Sep 17 00:00:00 2001 From: edraft Date: Thu, 6 Nov 2025 10:39:10 +0100 Subject: [PATCH] Initial commit --- edt.lua | 996 +++++++++++++++++++++++++++++++++++++++++++++++++++ programs.cfg | 11 + 2 files changed, 1007 insertions(+) create mode 100644 edt.lua create mode 100644 programs.cfg diff --git a/edt.lua b/edt.lua new file mode 100644 index 0000000..658ce72 --- /dev/null +++ b/edt.lua @@ -0,0 +1,996 @@ +local fs = require("filesystem") +local keyboard = require("keyboard") +local shell = require("shell") +local term = require("term") -- TODO use tty and cursor position instead of global area and gpu +local text = require("text") +local unicode = require("unicode") + +-- Monokai color scheme +local bgColor = 0x272822 +local lineColor = 0x39392F +local textColor = 0xF8F8F2 +local keywordColor = 0xF92672 +local commentColor = 0x75715E +local stringColor = 0xE6DB74 +local valueColor = 0xAE81FF +local builtinColor = 0x66D9EF +local lineNrColor = 0x90908A + +local keywords = { + ['break'] = true, + ['do'] = true, + ['else'] = true, + ['for'] = true, + ['if'] = true, + ['elseif'] = true, + ['return'] = true, + ['then'] = true, + ['repeat'] = true, + ['while'] = true, + ['until'] = true, + ['end'] = true, + ['function'] = true, + ['local'] = true, + ['in'] = true, + ['and'] = true, + ['or'] = true, + ['not'] = true, + + ['+'] = true, + ['-'] = true, + ['%'] = true, + ['#'] = true, + ['*'] = true, + ['/'] = true, + ['^'] = true, + ['='] = true, + ['=='] = true, + ['~='] = true, + ['<'] = true, + ['<='] = true, + ['>'] = true, + ['>='] = true, + ['..'] = true +} + +local builtins = { + ['assert'] = true, + ['collectgarbage'] = true, + ['dofile'] = true, + ['error'] = true, + ['getfenv'] = true, + ['getmetatable'] = true, + ['ipairs'] = true, + ['loadfile'] = true, + ['loadstring'] = true, + ['module'] = true, + ['next'] = true, + ['pairs'] = true, + ['pcall'] = true, + ['print'] = true, + ['rawequal'] = true, + ['rawget'] = true, + ['rawset'] = true, + ['require'] = true, + ['select'] = true, + ['setfenv'] = true, + ['setmetatable'] = true, + ['tonumber'] = true, + ['tostring'] = true, + ['type'] = true, + ['unpack'] = true, + ['xpcall'] = true +} + +local values = { + ['false'] = true, + ['nil'] = true, + ['true'] = true, + ['_G'] = true, + ['_VERSION'] = true +} + +local patterns = { + {"^%-%-%[%[.-%]%]", commentColor}, + {"^%-%-.*", commentColor}, + {"^\"\"", stringColor}, + {"^\".-[^\\]\"", stringColor}, + {"^\'\'", stringColor}, + {"^\'.-[^\\]\'", stringColor}, + {"^%[%[.-%]%]", stringColor}, + {"^[%w_%+%-%%%#%*%/%^%=%~%<%>%.]+", function(text) + if values[text] or tonumber(text) then + local match = text:find('^0x%x%x%x%x%x%x$') + + if match then + local luminosity = 0.2126 * tonumber('0x' .. text:sub(3, 4)) + 0.7152 * tonumber('0x' .. text:sub(5, 6)) + 0.0722 * tonumber('0x' .. text:sub(7, 8)) + + if luminosity > 20 then + return 0x000000, tonumber(text) + else + return 0xffffff, tonumber(text) + end + else + return valueColor + end + elseif keywords[text] then + return keywordColor + elseif builtins[text] then + return builtinColor + end + + return textColor + end} +} + +local cache = {} +local currentMargin = 7 + +if not term.isAvailable() then + return +end +local gpu = term.gpu() + +local originalFg = gpu.setForeground(textColor) +local originalBg = gpu.setBackground(bgColor) + +local function resetColors() + gpu.setForeground(originalFg) + gpu.setBackground(originalBg) +end + +local args, options = shell.parse(...) +if #args == 0 then + resetColors() + io.write("Usage: edit ") + return +end + +local filename = shell.resolve(args[1]) +local file_parentpath = fs.path(filename) + +if fs.exists(file_parentpath) and not fs.isDirectory(file_parentpath) then + resetColors() + io.stderr:write(string.format("Not a directory: %s\n", file_parentpath)) + return 1 +end + +local readonly = options.r or fs.get(filename) == nil or fs.get(filename).isReadOnly() + +if fs.isDirectory(filename) then + resetColors() + io.stderr:write("file is a directory\n") + return 1 +elseif not fs.exists(filename) and readonly then + resetColors() + io.stderr:write("file system is read only\n") + return 1 +end + +local function loadConfig() + local env = {} + local config = loadfile("/etc/edit.cfg", nil, env) + if config then + pcall(config) + end + env.keybinds = env.keybinds or { + left = {{"left"}}, + right = {{"right"}}, + up = {{"up"}}, + down = {{"down"}}, + home = {{"home"}}, + eol = {{"end"}}, + pageUp = {{"pageUp"}}, + pageDown = {{"pageDown"}}, + + backspace = {{"back"}}, + delete = {{"delete"}}, + deleteLine = {{"control", "delete"}, {"shift", "delete"}}, + newline = {{"enter"}}, + + save = {{"control", "s"}}, + close = {{"control", "w"}}, + find = {{"control", "f"}}, + findnext = {{"control", "g"}, {"control", "n"}, {"f3"}}, + + jump = {{'control', 'j'}} + } + + if not config then + local root = fs.get("/") + if root and not root.isReadOnly() then + fs.makeDirectory("/etc") + local f = io.open("/etc/edit.cfg", "w") + if f then + local serialization = require("serialization") + for k, v in pairs(env) do + f:write(k.."="..tostring(serialization.serialize(v, math.huge)).."\n") + end + f:close() + end + end + end + return env +end + +term.clear() +term.setCursorBlink(true) + +local running = true +local buffer = {} +local scrollX, scrollY = 0, 0 +local config = loadConfig() + +local getKeyBindHandler + +local function helpStatusText() + local function prettifyKeybind(label, command) + local keybind = type(config.keybinds) == "table" and config.keybinds[command] + if type(keybind) ~= "table" or type(keybind[1]) ~= "table" then return "" end + local alt, control, shift, key + for _, value in ipairs(keybind[1]) do + if value == "alt" then alt = true + elseif value == "control" then control = true + elseif value == "shift" then shift = true + else key = value end + end + if not key then return "" end + return label .. ": [" .. + (control and "Ctrl+" or "") .. + (alt and "Alt+" or "") .. + (shift and "Shift+" or "") .. + unicode.upper(key) .. + "] " + end + return prettifyKeybind("Save", "save") .. + prettifyKeybind("Close", "close") .. + prettifyKeybind("Find", "find") .. + prettifyKeybind('Jump to line', 'jump') +end + +local currentStatus = '' + +local function setStatus(value) + local x, y, w, h = term.getGlobalArea() + value = unicode.wlen(value) > w - 10 and unicode.wtrunc(value, w - 9) or value + value = text.padRight(value, w - 10) + gpu.set(x, y + h - 1, value) + + currentStatus = value +end + +local function getArea() + local x, y, w, h = term.getGlobalArea() + return x + currentMargin, y, w - currentMargin, h - 1 +end + +local function removePrefix(line, length) + if length >= unicode.wlen(line) then + return "" + else + local prefix = unicode.wtrunc(line, length + 1) + local suffix = unicode.sub(line, unicode.len(prefix) + 1) + length = length - unicode.wlen(prefix) + if length > 0 then + suffix = (" "):rep(unicode.charWidth(suffix) - length) .. unicode.sub(suffix, 2) + end + return suffix + end +end + +local function lengthToChars(line, length) + if length > unicode.wlen(line) then + return unicode.len(line) + 1 + else + local prefix = unicode.wtrunc(line, length) + return unicode.len(prefix) + 1 + end +end + +local function isWideAtPosition(line, x) + local index = lengthToChars(line, x) + if index > unicode.len(line) then + return false, false + end + local prefix = unicode.sub(line, 1, index) + local char = unicode.sub(line, index, index) + return unicode.isWide(char), unicode.wlen(prefix) == x +end + +local function drawLine(x, y, w, h, lineNr) + local yLocal = lineNr - scrollY + local drawY = y - 1 + lineNr - scrollY + + if yLocal > 0 and yLocal <= h then + local colors = {} + local line = buffer[lineNr] or "" + + if cache[lineNr] and cache[lineNr][1] == line then + colors = cache[lineNr][2] + else + local function appendTextInColor(text, color, bgcolor) + local data = colors[#colors] + + if data ~= nil then + if data[2] == color and data[3] == bgcolor then + data[1] = data[1] .. text + else + colors[#colors + 1] = {text, color, bgcolor} + end + else + colors[#colors + 1] = {text, color, bgcolor} + end + end + + local len = 0 + + for char = 1, line:len() do + if char > len then + local patternFound = false + + for pat = 1, #patterns do + local data = patterns[pat] + local foundb, founde = line:find(data[1], char) + + if foundb ~= nil then + local text = line:sub(foundb, founde) + local color = data[2] + local bgcolor = data[3] + + if type(color) == 'function' then + color, bgcolor = color(text) + end + + appendTextInColor(text, color, bgcolor) + len = len + (founde - foundb + 1) + + patternFound = true + break + end + end + + if not patternFound then + appendTextInColor(line:sub(char, char), textColor) + len = len + 1 + end + end + end + + cache[lineNr] = {line, colors} + end + + local i = 0 + local cx, cy = term.getCursor() + local lineBg = bgColor + + if cy + scrollY == lineNr then + lineBg = lineColor + end + + gpu.setBackground(lineBg) + gpu.fill(1, y - 1 + lineNr - scrollY, 7, 1, ' ') + gpu.fill(x, drawY, w + currentMargin, 1, ' ') + + if lineNr <= #buffer then + for l = 1, #colors do + local data = colors[l] + local text = data[1] + local color = data[2] + local bg = data[3] + local drawAt = i - scrollX + x + + if drawAt + text:len() > 0 then + local currentColor = gpu.setForeground(color) + local currentBg = gpu.setBackground(bg or lineBg) + gpu.set(drawAt, drawY, text) + gpu.setForeground(currentColor) + gpu.setBackground(currentBg) + end + + i = i + text:len() + end + + local currentColor = gpu.setForeground(lineNrColor) + local number = tostring(math.floor(lineNr)) + + gpu.fill(1, y - 1 + lineNr - scrollY, 7, 1, ' ') + gpu.set(2 + (5 - number:len()), y - 1 + lineNr - scrollY, number) + gpu.setForeground(currentColor) + gpu.setBackground(bgColor) + end + end +end + +local function getCursor() + local cx, cy = term.getCursor() + return cx + scrollX - currentMargin, cy + scrollY +end + +local function line() + local cbx, cby = getCursor() + return buffer[cby] +end + +local function getNormalizedCursor() + local cbx, cby = getCursor() + local wide, right = isWideAtPosition(buffer[cby], cbx) + if wide and right then + cbx = cbx - 1 + end + return cbx, cby +end + +local function setCursor(nbx, nby) + local x, y, w, h = getArea() + nby = math.max(1, math.min(#buffer, nby)) + + local ncy = nby - scrollY + if ncy > h then + term.setCursorBlink(false) + local sy = nby - h + local dy = math.abs(scrollY - sy) + scrollY = sy + if h > dy then + gpu.copy(x - currentMargin, y + dy, w + currentMargin, h - dy, 0, -dy) + end + for lineNr = nby - (math.min(dy, h) - 1), nby do + drawLine(x, y, w, h, lineNr) + end + elseif ncy < 1 then + term.setCursorBlink(false) + local sy = nby - 1 + local dy = math.abs(scrollY - sy) + scrollY = sy + if h > dy then + gpu.copy(x - currentMargin, y, w + currentMargin, h - dy, 0, dy) + end + for lineNr = nby, nby + (math.min(dy, h) - 1) do + drawLine(x, y, w, h, lineNr) + end + end + term.setCursor(term.getCursor(), nby - scrollY) + + nbx = math.max(1, math.min(unicode.wlen(line()) + 1, nbx)) + local wide, right = isWideAtPosition(line(), nbx) + local ncx = nbx - scrollX + if ncx > w or (ncx + 1 > w and wide and not right) then + term.setCursorBlink(false) + scrollX = nbx - w + ((wide and not right) and 1 or 0) + for lineNr = 1 + scrollY, math.min(h + scrollY, #buffer) do + drawLine(x, y, w, h, lineNr) + end + elseif ncx < 1 or (ncx - 1 < 1 and wide and right) then + term.setCursorBlink(false) + scrollX = nbx - 1 - ((wide and right) and 1 or 0) + for lineNr = 1 + scrollY, math.min(h + scrollY, #buffer) do + drawLine(x, y, w, h, lineNr) + end + end + term.setCursor(nbx - scrollX + currentMargin, nby - scrollY) + nbx, nby = getCursor() + gpu.set(x + w - 10, y + h, text.padLeft(string.format("%d,%d", nby, nbx), 10)) +end + +local function highlight(bx, by, length, enabled) + local x, y, w, h = getArea() + local cx, cy = bx - scrollX, by - scrollY + cx = math.max(1, math.min(w, cx)) + cy = math.max(1, math.min(h, cy)) + length = math.max(1, math.min(w - cx, length)) + + local fg, fgp = gpu.getForeground() + local bg, bgp = gpu.getBackground() + if enabled then + gpu.setForeground(bg, bgp) + gpu.setBackground(fg, fgp) + end + local indexFrom = lengthToChars(buffer[by], bx) + local value = unicode.sub(buffer[by], indexFrom) + if unicode.wlen(value) > length then + value = unicode.wtrunc(value, length + 1) + end + gpu.set(x - 1 + cx, y - 1 + cy, value) + if enabled then + gpu.setForeground(fg, fgp) + gpu.setBackground(bg, bgp) + end +end + +local function home() + local cbx, cby = getCursor() + setCursor(1, cby) +end + +local function ende() + local cbx, cby = getCursor() + setCursor(unicode.wlen(line()) + 1, cby) +end + +local function left() + local cbx, cby = getNormalizedCursor() + if cbx > 1 then + local wideTarget, rightTarget = isWideAtPosition(line(), cbx - 1) + if wideTarget and rightTarget then + setCursor(cbx - 2, cby) + else + setCursor(cbx - 1, cby) + end + return true + elseif cby > 1 then + setCursor(cbx, cby - 1) + ende() + return true + end +end + +local function right(n) + n = n or 1 + local cbx, cby = getNormalizedCursor() + local be = unicode.wlen(line()) + 1 + local wide, right = isWideAtPosition(line(), cbx + n) + if wide and right then + n = n + 1 + end + if cbx + n <= be then + setCursor(cbx + n, cby) + elseif cby < #buffer then + setCursor(1, cby + 1) + end +end + +local function up(n) + n = n or 1 + local cbx, cby = getCursor() + if cby > 1 then + setCursor(cbx, cby - n) + end +end + +local function down(n) + n = n or 1 + local cbx, cby = getCursor() + if cby < #buffer then + setCursor(cbx, cby + n) + end +end + +local function delete(fullRow) + local cx, cy = term.getCursor() + local cbx, cby = getCursor() + local x, y, w, h = getArea() + local function deleteRow(row) + local content = table.remove(buffer, row) + local rcy = cy + (row - cby) + if rcy <= h then + gpu.copy(x, y + rcy, w, h - rcy, 0, -1) + drawLine(x, y, w, h, row + (h - rcy)) + end + return content + end + if fullRow then + term.setCursorBlink(false) + if #buffer > 1 then + deleteRow(cby) + else + buffer[cby] = "" + gpu.fill(x, y - 1 + cy, w, 1, " ") + end + setCursor(1, cby) + elseif cbx <= unicode.wlen(line()) then + term.setCursorBlink(false) + local index = lengthToChars(line(), cbx) + buffer[cby] = unicode.sub(line(), 1, index - 1) .. + unicode.sub(line(), index + 1) + drawLine(x, y, w, h, cby) + elseif cby < #buffer then + term.setCursorBlink(false) + local append = deleteRow(cby + 1) + buffer[cby] = buffer[cby] .. append + drawLine(x, y, w, h, cby) + else + return + end + setStatus(helpStatusText()) +end + +-- enter() jetzt mit Schalter für Auto-Indent +local function enter(autoIndent) + if autoIndent == nil then autoIndent = true end + + term.setCursorBlink(false) + local cx, cy = term.getCursor() + local cbx, cby = getCursor() + local x, y, w, h = getArea() + local index = lengthToChars(line(), cbx) + table.insert(buffer, cby + 1, unicode.sub(buffer[cby], index)) + buffer[cby] = unicode.sub(buffer[cby], 1, index - 1) + drawLine(x, y, w, h, cby) + if cy < h then + if cy < h - 1 then + gpu.copy(x, y + cy, w, h - (cy + 1), 0, 1) + end + drawLine(x, y, w, h, cby + 1) + end + + if autoIndent then + local whitespace = buffer[cby]:match('^[%s]+') or "" + buffer[cby + 1] = whitespace .. buffer[cby + 1] + setCursor(1 + whitespace:len(), cby + 1) + else + setCursor(1, cby + 1) + end + + setStatus(helpStatusText()) +end + +local findText = "" + +local function find() + local x, y, w, h = getArea() + local cx, cy = term.getCursor() + local cbx, cby = getCursor() + local ibx, iby = cbx, cby + while running do + if unicode.len(findText) > 0 then + local sx, sy + for syo = 1, #buffer do + sy = (iby + syo - 1 + #buffer - 1) % #buffer + 1 + sx = string.find(buffer[sy], findText, syo == 1 and ibx or 1, true) + if sx and (sx >= ibx or syo > 1) then + break + end + end + if not sx then + sy = iby + sx = string.find(buffer[sy], findText, nil, true) + end + if sx then + sx = unicode.wlen(string.sub(buffer[sy], 1, sx - 1)) + 1 + cbx, cby = sx, sy + setCursor(cbx, cby) + highlight(cbx, cby, unicode.wlen(findText), true) + end + end + term.setCursor(7 + unicode.wlen(findText), h + 1) + setStatus("Find: " .. findText) + + local _, address, char, code = term.pull("key_down") + if address == term.keyboard() then + local handler, name = getKeyBindHandler(code) + highlight(cbx, cby, unicode.wlen(findText), false) + if name == "newline" then + break + elseif name == "close" then + handler() + elseif name == "backspace" then + findText = unicode.sub(findText, 1, -2) + elseif name == "find" or name == "findnext" then + ibx = cbx + 1 + iby = cby + elseif not keyboard.isControl(char) then + findText = findText .. unicode.char(char) + end + end + end + setCursor(cbx, cby) + setStatus(helpStatusText()) +end + +local function fix() + local x, y, w, h = getArea() + + gpu.fill(x, y, w, h, ' ') + + for i = 1, #buffer do + if i > scrollY and i <= (scrollY + h) then + drawLine(x, y, w, h, i) + end + end +end + +local function jump() + local x, y, w, h = getArea() + local cx, cy = term.getCursor() + local currentStatus = currentStatus + + setStatus('Jump to line #') + + local current = '' + + while true do + local _, address, char, code = term.pull('key_down') + + char = math.floor(char) + + if address == term.keyboard() then + if char == 13 then + break + elseif char >= string.byte('0') and char <= string.byte('9') then + if current:len() < 5 then + current = current .. string.char(char) + end + elseif char == 127 then + if current:len() > 0 then + current = current:sub(1, -1) + end + end + + term.setCursor(15, h + 1) + gpu.set(15, h + 1, ' ') + term.write(current) + end + end + + term.setCursor(cx, cy) + + current = tonumber(current) + + if current then + if current <= #buffer then + setCursor(1, current) + setStatus('Jumped to line ' .. tostring(current)) + else + setStatus('Line ' .. tostring(current) .. ' does not exist') + end + else + setStatus(currentStatus) + end +end + +local keyBindHandlers = { + left = left, + right = right, + up = up, + down = down, + home = home, + eol = ende, + pageUp = function() + local x, y, w, h = getArea() + up(h - 1) + end, + pageDown = function() + local x, y, w, h = getArea() + down(h - 1) + end, + + backspace = function() + if not readonly and left() then + delete() + end + end, + delete = function() + if not readonly then + delete() + end + end, + deleteLine = function() + if not readonly then + delete(true) + end + end, + newline = function() + if not readonly then + enter() + end + end, + + save = function() + if readonly then return end + local new = not fs.exists(filename) + local backup + if not new then + backup = filename .. "~" + for i = 1, math.huge do + if not fs.exists(backup) then + break + end + backup = filename .. "~" .. i + end + fs.copy(filename, backup) + end + if not fs.exists(file_parentpath) then + fs.makeDirectory(file_parentpath) + end + local f, reason = io.open(filename, "w") + if f then + local chars, firstLine = 0, true + for _, line in ipairs(buffer) do + if not firstLine then + line = "\n" .. line + end + firstLine = false + f:write(line) + chars = chars + unicode.len(line) + end + f:close() + local format + if new then + format = [["%s" [New] %dL,%dC written]] + else + format = [["%s" %dL,%dC written]] + end + setStatus(string.format(format, fs.name(filename), #buffer, chars)) + else + setStatus(reason) + end + if not new then + fs.remove(backup) + end + end, + close = function() + running = false + end, + find = function() + findText = "" + find() + end, + findnext = find, + + jump = jump +} + +getKeyBindHandler = function(code) + if type(config.keybinds) ~= "table" then return end + local result, resultName, resultWeight = nil, nil, 0 + for command, keybinds in pairs(config.keybinds) do + if type(keybinds) == "table" and keyBindHandlers[command] then + for _, keybind in ipairs(keybinds) do + if type(keybind) == "table" then + local alt, control, shift, key + for _, value in ipairs(keybind) do + if value == "alt" then alt = true + elseif value == "control" then control = true + elseif value == "shift" then shift = true + else key = value end + end + local keyboardAddress = term.keyboard() + if (not alt or keyboard.isAltDown(keyboardAddress)) and + (not control or keyboard.isControlDown(keyboardAddress)) and + (not shift or keyboard.isShiftDown(keyboardAddress)) and + code == keyboard.keys[key] and + #keybind > resultWeight + then + resultWeight = #keybind + resultName = command + result = keyBindHandlers[command] + end + end + end + end + end + return result, resultName +end + +local function insert(value) + if not value or unicode.len(value) < 1 then + return + end + term.setCursorBlink(false) + local cx, cy = term.getCursor() + local cbx, cby = getCursor() + local x, y, w, h = getArea() + local index = lengthToChars(line(), cbx) + buffer[cby] = unicode.sub(line(), 1, index - 1) .. + value .. + unicode.sub(line(), index) + drawLine(x, y, w, h, cby) + right(unicode.wlen(value)) + setStatus(helpStatusText()) +end + +local function onKeyDown(char, code) + local handler = getKeyBindHandler(code) + if handler then + handler() + elseif readonly and code == keyboard.keys.q then + running = false + elseif not readonly then + if not keyboard.isControl(char) then + insert(unicode.char(char)) + elseif unicode.char(char) == "\t" then + insert(" ") + end + end +end + +-- WICHTIG: hier das Einfügen fixen +local function onClipboard(value) + value = value:gsub("\r\n", "\n") + local cbx, cby = getCursor() + local start = 1 + local l = value:find("\n", 1, true) + if l then + repeat + local line = string.sub(value, start, l - 1) + line = text.detab(line, 2) + insert(line) + -- beim Einfügen KEIN Auto-Indent + enter(false) + start = l + 1 + l = value:find("\n", start, true) + until not l + end + insert(string.sub(value, start)) +end + +local function onClick(x, y) + setCursor(x + scrollX, y + scrollY) +end + +local function onScroll(direction) + local cbx, cby = getCursor() + setCursor(cbx, cby - direction * 12) +end + +do + local f = io.open(filename) + if f then + local x, y, w, h = getArea() + local chars = 0 + for line in f:lines() do + table.insert(buffer, line) + chars = chars + unicode.len(line) + if #buffer <= h then + drawLine(x, y, w, h, #buffer) + end + end + f:close() + if #buffer == 0 then + table.insert(buffer, "") + end + local format + if readonly then + format = [["%s" [readonly] %dL,%dC]] + else + format = [["%s" %dL,%dC]] + end + setStatus(string.format(format, fs.name(filename), #buffer, chars)) + else + table.insert(buffer, "") + setStatus(string.format([["%s" [New File] ]], fs.name(filename))) + end + setCursor(1, 1) +end + +while running do + local startX = scrollX + local startY = scrollY + local _, startC = getCursor() + + local event, address, arg1, arg2, arg3 = term.pull() + if address == term.keyboard() or address == term.screen() then + local blink = true + if event == "key_down" then + onKeyDown(arg1, arg2) + elseif event == "clipboard" and not readonly then + onClipboard(arg1) + elseif event == "touch" or event == "drag" then + local x, y, w, h = getArea() + arg1 = arg1 - x + 1 + arg2 = arg2 - y + 1 + if arg1 >= 1 and arg2 >= 1 and arg1 <= w and arg2 <= h then + onClick(arg1, arg2) + end + elseif event == "scroll" then + onScroll(arg3) + else + blink = false + end + if blink then + term.setCursorBlink(true) + end + + local _, endC = getCursor() + local x, y, w, h = getArea() + + if startC ~= endC then + drawLine(x, y, w, h, startC) + end + + drawLine(x, y, w, h, endC) + end +end + +resetColors() +term.clear() +term.setCursorBlink(true) diff --git a/programs.cfg b/programs.cfg new file mode 100644 index 0000000..fd1a031 --- /dev/null +++ b/programs.cfg @@ -0,0 +1,11 @@ +{ + ["edt"] = { + files = { + ["master/edt.lua"] = "/usr/bin" + }, + name = "edt -- shedit 2", + description = "An advanced text editor for the terminal.", + authors = "edraft", + repo = "tree/master/edt" + }, +} \ No newline at end of file