Changes:
- Autoindent. Currently just copies the previous line's indentation.
- Added delete key.
- Added "Save & Exit" to Ctrl menu.
- Line numbering, vim style. Helps a ton with debugging.
- Home/End/PageUp/PageDown added
Spoiler
local tArgs = { ... }
if #tArgs == 0 then
print( "Usage: edit <path>" )
return
end
local sPath = shell.resolve( tArgs[1] )
local bReadOnly = fs.isReadOnly( sPath )
if fs.exists( sPath ) and fs.isDir( sPath ) then
print( "Cannot edit a directory" )
return
end
local w,h = term.getSize()
local x,y = 1,1
local scrollX, scrollY = 0,0
local bMenu = false
local nMenuItem = 1
local sStatus = ""
local tLines = {}
local function load()
tLines = {}
if fs.exists( sPath ) then
local file = io.open( sPath, "r" )
local sLine = file:read()
while sLine do
table.insert( tLines, sLine )
sLine = file:read()
end
file:close()
else
table.insert( tLines, "" )
end
end
local function save()
local file = io.open( sPath, "w" )
if file then
for n, sLine in ipairs( tLines ) do
file:write( sLine .. "n" )
end
file:close()
return true
end
return false
end
local function redrawText()
for y=1,h-1 do
term.setCursorPos( 1 - scrollX, y )
term.clearLine()
local sLine = tLines[ y + scrollY ]
if sLine ~= nil then
term.write( sLine )
end
end
term.setCursorPos( x - scrollX, y - scrollY )
end
local function redrawLine()
local sLine = tLines[y]
term.setCursorPos( 1 - scrollX, y - scrollY )
term.clearLine()
term.write( sLine )
term.setCursorPos( x - scrollX, y - scrollY )
end
local tMenuItems = { "Save & Exit", "Save", "Exit" }
local function redrawMenu()
term.setCursorPos( 1, h )
term.clearLine()
if not bMenu then
term.write( sStatus )
else
for n,sItem in ipairs( tMenuItems ) do
if n == nMenuItem then
term.write( "["..sItem.."]" )
else
term.write( " "..sItem.." " )
end
end
end
term.setCursorPos( x - scrollX, y - scrollY )
end
local function setStatus( _sText )
sStatus = _sText
redrawMenu()
end
local function setCursor( x, y )
local screenX = x - scrollX
local screenY = y - scrollY
local bRedraw = false
if screenX < 1 then
scrollX = x - 1
screenX = 1
bRedraw = true
elseif screenX > w then
scrollX = x - w
screenX = w
bRedraw = true
end
if screenY < 1 then
scrollY = y - 1
screenY = 1
bRedraw = true
elseif screenY > h-1 then
scrollY = y - (h-1)
screenY = h-1
bRedraw = true
end
if bRedraw then
redrawText()
end
term.setCursorPos( screenX, screenY )
setStatus( string.format('Menu:Ctrl "%s" %uL %u,%u', tArgs[1], #tLines, y, x ) )
end
load()
term.clear()
term.setCursorPos(x,y)
term.setCursorBlink( true )
redrawText()
setStatus( string.format('Menu:Ctrl "%s" %uL %u,%u', tArgs[1], #tLines, y, x ) )
local bRunning = true
local tMenuFunctions = {
["Save & Exit"] = function()
if save() then
setStatus( "Saved to "..sPath )
bRunning = false
else
setStatus( "Access denied" )
end
end,
["Exit"] = function()
bRunning = false
end,
["Save"] = function()
if save() then
setStatus( "Saved to "..sPath )
else
setStatus( "Access denied" )
end
end,
}
local function doMenuItem( _n )
local fnMenu = tMenuFunctions[ tMenuItems[_n] ]
if fnMenu then
fnMenu()
end
bMenu = false
term.setCursorBlink( true )
redrawMenu()
end
while bRunning do
local sEvent, param = os.pullEvent()
if sEvent == "key" then
if param == 200 then
-- Up
if not bMenu then
-- Move cursor up
if y > 1 then
y = y - 1
x = math.min( x, string.len( tLines[y] ) + 1 )
setCursor( x, y )
end
end
elseif param == 208 then
-- Down
if not bMenu then
-- Move cursor down
if y < #tLines then
y = y + 1
x = math.min( x, string.len( tLines[y] ) + 1 )
setCursor( x, y )
end
end
elseif param == 203 then
-- Left
if not bMenu then
-- Move cursor left
if x > 1 then
len = string.len( tLines[y] ) + 1
if x > len then
x = len
else
x = x - 1
end
setCursor( x, y )
end
else
-- Move menu left
nMenuItem = nMenuItem - 1
if nMenuItem < 1 then
nMenuItem = #tMenuItems
end
redrawMenu()
end
elseif param == 205 then
-- Right
if not bMenu then
-- Move cursor right
if x >= string.len( tLines[y] ) + 1 then
x = string.len( tLines[y] ) + 1
else
x = x + 1
end
setCursor( x, y )
else
-- Move menu right
nMenuItem = nMenuItem + 1
if nMenuItem > #tMenuItems then
nMenuItem = 1
end
redrawMenu()
end
elseif param == 199 then
-- Home
if not bMenu then
-- Move cursor to x=1
x = 1
setCursor( x, y )
end
elseif param == 207 then
-- End
if not bMenu then
-- Move cursor to x=len
x = string.len( tLines[y] ) + 1
setCursor( x, y )
end
elseif param == 201 then
-- Page Up
if not bMenu then
-- Move cursor up term.height
w,h = term.getSize()
y = y - h + 1
if y < 1 then y = 1 end
x = math.min( x, string.len( tLines[y] ) + 1 )
setCursor( x, y )
end
elseif param == 209 then
-- Page Down
if not bMenu then
-- Move cursor down term.height
w,h = term.getSize()
y = y + h - 1
if y > #tLines then y = #tLines end
x = math.min( x, string.len( tLines[y] ) + 1 )
setCursor( x, y )
end
elseif param == 14 then
-- Backspace
if not bMenu then
if x > 1 then
-- Remove character
local sLine = tLines[y]
tLines[y] = string.sub(sLine,1,x-2) .. string.sub(sLine,x)
redrawLine()
x = x - 1
setCursor( x, y )
elseif y > 1 then
-- Remove newline
local sPrevLen = string.len( tLines[y-1] )
tLines[y-1] = tLines[y-1] .. tLines[y]
table.remove( tLines, y )
redrawText()
x = sPrevLen + 1
y = y - 1
setCursor( x, y )
end
end
elseif param == 211 then
-- Delete
if not bMenu then
if x <= string.len(tLines[y]) then
-- Remove character
local sLine = tLines[y]
tLines[y] = string.sub(sLine,1,x-1) .. string.sub(sLine,x+1)
redrawLine()
elseif y < #tLines then
-- Remove newline
local sPrevLen = string.len( tLines[y] )
tLines[y] = tLines[y] .. tLines[y+1]
table.remove( tLines, y+1 )
redrawText()
x = sPrevLen + 1
setCursor( x, y )
end
end
elseif param == 28 then
-- Enter
if not bMenu then
-- Newline
local sLine = tLines[y]
local sPrevTab = string.match( sLine, "%s+" )
term.write(sPrevTab)
tLines[y] = string.sub(sLine,1,x-1)
if sPrevTab == nil then
table.insert( tLines, y+1, string.sub(sLine,x) )
x = 1
else
table.insert( tLines, y+1, sPrevTab .. string.sub(sLine,x) )
x = #tLines[y+1]+1
end
redrawText()
y = y + 1
setCursor( x, y )
else
-- Menu selection
doMenuItem( nMenuItem )
end
elseif param == 29 then
-- Menu toggle
bMenu = not bMenu
if bMenu then
term.setCursorBlink( false )
nMenuItem = 1
else
term.setCursorBlink( true )
end
redrawMenu()
end
elseif sEvent == "char" then
if not bMenu then
-- Input text
local sLine = tLines[y]
tLines[y] = string.sub(sLine,1,x-1) .. param .. string.sub(sLine,x)
redrawLine()
x = x + string.len( param )
setCursor( x, y )
else
-- Select menu items
for n,sMenuItem in ipairs( tMenuItems ) do
if string.lower(string.sub(sMenuItem,1,1)) == string.lower(param) then
doMenuItem( n )
break
end
end
end
end
end
term.clear()
term.setCursorBlink( false )
term.setCursorPos( 1, 1 )
Suggestions are welcome, and the ComputerCraft team can certainly steal this since it's 90% their code anyways.