mirror of
https://github.com/CCLeonOS/LeonOS.git
synced 2026-03-03 15:01:12 +00:00
309 lines
6.8 KiB
Lua
309 lines
6.8 KiB
Lua
-- A much better editor.
|
|
|
|
local rc = require("rc")
|
|
local keys = require("keys")
|
|
local term = require("term")
|
|
local colors = require("colors")
|
|
local settings = require("settings")
|
|
local textutils = require("textutils")
|
|
|
|
local args = {...}
|
|
|
|
local type_colors = {
|
|
separator = colors[settings.get("edit.color_separator") or "lightBlue"],
|
|
operator = colors[settings.get("edit.color_operator") or "lightGray"],
|
|
keyword = colors[settings.get("edit.color_keyword") or "orange"],
|
|
boolean = colors[settings.get("edit.color_boolean") or "purple"],
|
|
comment = colors[settings.get("edit.color_comment") or "gray"],
|
|
builtin = colors[settings.get("edit.color_global") or "lime"],
|
|
string = colors[settings.get("edit.color_string") or "red"],
|
|
number = colors[settings.get("edit.color_number") or "magenta"]
|
|
}
|
|
|
|
local lines = {}
|
|
local linesDraw = {}
|
|
local run, menu = true, false
|
|
local cx, cy = 1, 1
|
|
local scroll = 0
|
|
local hscroll = 0
|
|
local scroll_offset = settings.get("edit.scroll_offset") or 3
|
|
local scroll_increment = 0
|
|
local scroll_factor = settings.get("edit.scroll_factor") or 8
|
|
local unsaved, changed = false, true
|
|
local file = args[1] or ".new"
|
|
local status = "Press Ctrl for menu"
|
|
|
|
if args[1] then
|
|
local handle = io.open(args[1], "r")
|
|
|
|
if handle then
|
|
for line in handle:lines() do
|
|
lines[#lines+1] = line
|
|
end
|
|
handle:close()
|
|
end
|
|
end
|
|
|
|
if not lines[1] then lines[1] = "" end
|
|
|
|
local win = require("window").create(term.current(), 1, 1, term.getSize())
|
|
|
|
local function redraw()
|
|
local w, h = term.getSize()
|
|
|
|
-- this seems to provide a good responsiveness curve on my machine
|
|
scroll_increment = math.floor(h/scroll_factor)
|
|
|
|
win.reposition(1, 1, w, h)
|
|
|
|
win.setVisible(false)
|
|
|
|
for i=1, h - 1, 1 do
|
|
local line = linesDraw[i]
|
|
win.setCursorPos(1 - hscroll, i)
|
|
win.clearLine()
|
|
if line then
|
|
for t=1, #line, 1 do
|
|
local item = line[t]
|
|
if type(item) == "number" then
|
|
win.setTextColor(item)
|
|
else
|
|
win.write(item)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
win.setCursorPos(1, h)
|
|
win.clearLine()
|
|
win.setTextColor(type_colors.accent or colors.yellow)
|
|
win.write(status)
|
|
win.setTextColor(colors.white)
|
|
|
|
win.setCursorPos(math.min(w, cx), cy - scroll)
|
|
win.setCursorBlink(true)
|
|
|
|
win.setVisible(true)
|
|
end
|
|
|
|
local syntax = require("edit.syntax")
|
|
.new("/leonos/modules/main/edit/syntax/lua.lua")
|
|
|
|
local function rehighlight()
|
|
local line = {}
|
|
linesDraw = {}
|
|
local _, h = term.getSize()
|
|
local text = table.concat(lines, "\n", scroll+1,
|
|
math.min(#lines, scroll+h+1)) or ""
|
|
for token, ttype in syntax(text) do
|
|
if token == "\n" then
|
|
linesDraw[#linesDraw+1] = line
|
|
line = {}
|
|
|
|
else
|
|
repeat
|
|
local bit = token:find("\n")
|
|
local nl = not not bit
|
|
local chunk = token:sub(1, bit or #token)
|
|
token = token:sub(#chunk+1)
|
|
line[#line+1] = type_colors[ttype] or colors.white
|
|
line[#line+1] = chunk
|
|
if nl then
|
|
linesDraw[#linesDraw+1] = line
|
|
line = {}
|
|
end
|
|
until #token == 0
|
|
end
|
|
end
|
|
|
|
if #line > 0 then
|
|
linesDraw[#linesDraw+1] = line
|
|
end
|
|
end
|
|
|
|
local function save()
|
|
if file == ".new" then
|
|
local _, h = term.getSize()
|
|
term.setCursorPos(1, h)
|
|
textutils.coloredWrite(colors.yellow, "filename: ")
|
|
file = term.read()
|
|
end
|
|
|
|
local handle, err = io.open(file, "w")
|
|
if not handle then
|
|
status = err
|
|
|
|
else
|
|
for i=1, #lines, 1 do
|
|
handle:write(lines[i] .. "\n")
|
|
end
|
|
handle:close()
|
|
|
|
status = "Saved to " .. file
|
|
unsaved = false
|
|
end
|
|
end
|
|
|
|
local function processInput()
|
|
local event, id = rc.pullEvent()
|
|
|
|
local w, h = term.getSize()
|
|
|
|
if event == "char" then
|
|
local line = lines[cy]
|
|
unsaved = true
|
|
|
|
if cx > #line then
|
|
line = line .. id
|
|
|
|
elseif cx == 1 then
|
|
line = id .. line
|
|
|
|
else
|
|
line = line:sub(0, cx-1) .. id .. line:sub(cx)
|
|
end
|
|
|
|
cx = cx + 1
|
|
lines[cy] = line
|
|
changed = true
|
|
|
|
elseif event == "key" then
|
|
id = keys.getName(id)
|
|
|
|
if id == "backspace" then
|
|
local line = lines[cy]
|
|
unsaved = true
|
|
|
|
if cx == 1 and cy > 1 then
|
|
local previous = table.remove(lines, cy - 1)
|
|
cy = cy - 1
|
|
cx = #previous + 1
|
|
line = previous .. line
|
|
|
|
else
|
|
if #line > 0 then
|
|
if cx > #line then
|
|
cx = cx - 1
|
|
line = line:sub(1, -2)
|
|
|
|
elseif cx > 1 then
|
|
line = line:sub(0, cx - 2) .. line:sub(cx)
|
|
cx = cx - 1
|
|
end
|
|
end
|
|
end
|
|
|
|
lines[cy] = line
|
|
changed = true
|
|
|
|
elseif id == "enter" then
|
|
if cx == 1 then
|
|
table.insert(lines, cy, "")
|
|
|
|
elseif cx > #lines[cy] then
|
|
table.insert(lines, cy+1, "")
|
|
|
|
else
|
|
local line = lines[cy]
|
|
local before, after = line:sub(0, cx - 1), line:sub(cx)
|
|
lines[cy] = before
|
|
table.insert(lines, cy + 1, after)
|
|
end
|
|
|
|
cy = cy + 1
|
|
cx = 1
|
|
|
|
changed = true
|
|
|
|
elseif id == "up" then
|
|
if cy > 1 then
|
|
cy = cy - 1
|
|
if cy - scroll < scroll_offset then
|
|
local old_scroll = scroll
|
|
scroll = math.max(0, scroll - scroll_increment)
|
|
if scroll < old_scroll then
|
|
rehighlight()
|
|
end
|
|
end
|
|
end
|
|
|
|
cx = math.min(cx, #lines[cy] + 1)
|
|
|
|
elseif id == "down" then
|
|
if cy < #lines then
|
|
cy = math.min(#lines, cy + 1)
|
|
|
|
if cy - scroll > h - scroll_offset then
|
|
local old_scroll = scroll
|
|
scroll = math.max(0, math.min(#lines - h + 1,
|
|
scroll + scroll_increment))
|
|
if scroll > old_scroll then
|
|
rehighlight()
|
|
end
|
|
end
|
|
end
|
|
|
|
cx = math.min(cx, #lines[cy] + 1)
|
|
|
|
elseif id == "left" then
|
|
if cx > 1 then
|
|
cx = cx - 1
|
|
end
|
|
|
|
hscroll = math.max(0, cx - w)
|
|
|
|
elseif id == "right" then
|
|
if cx < #lines[cy] + 1 then
|
|
cx = cx + 1
|
|
end
|
|
|
|
hscroll = math.max(0, cx - w)
|
|
|
|
elseif id == "leftCtrl" or id == "rightCtrl" then
|
|
status = "S:save E:exit"
|
|
menu = true
|
|
end
|
|
end
|
|
end
|
|
|
|
local function processMenuInput()
|
|
local event, id = rc.pullEvent()
|
|
|
|
if event == "char" then
|
|
if id:lower() == "e" then
|
|
if unsaved and menu ~= 2 then
|
|
status = "Lose unsaved work? E:yes C:no"
|
|
menu = 2
|
|
else
|
|
term.at(1, 1).clear()
|
|
run = false
|
|
end
|
|
|
|
elseif id:lower() == "c" and menu == 2 then
|
|
menu = false
|
|
|
|
elseif id:lower() == "s" then
|
|
save()
|
|
menu = false
|
|
end
|
|
|
|
elseif event == "key" then
|
|
id = keys.getName(id)
|
|
|
|
if id == "leftCtrl" or id == "rightCtrl" then
|
|
status = "Press Ctrl for menu"
|
|
menu = false
|
|
end
|
|
end
|
|
end
|
|
|
|
while run do
|
|
if changed then rehighlight() changed = false end
|
|
redraw()
|
|
if menu then
|
|
processMenuInput()
|
|
else
|
|
processInput()
|
|
end
|
|
end
|