Inspired by a recent editor baked into the FORTH REPL in 30 lines of code, here’s one baked into the Lua REPL. Requires 100 lines, though. Something like this should be doable for BASIC as well.
-- line editor in the Lua REPL
-- available commands:
-- l'1' - moves cursor down by 1 line
-- l'-2' - moves cursor up by 2 lines
-- c'abc' - changes line at cursor to 'abc'
-- a'abc' - appends 'abc' below cursor line, moves cursor to it
-- s'' - shows current screen (up to N lines)
-- n'' - page down
-- b'' - page up
-- f'a' - find line matching 'a' downwards with wrap
-- F'a' - find line matching 'a' upwards with wrap
-- command/fn args are often strings so I can avoid pressing
-- the shift key
-- e.g. n() would work like n'', but require pressing shift.
Filename = ''
Lines = {}
function save(filename)
if #filename == 0 and #Filename > 0 then
filename = Filename
end
if #filename == 0 then
print('file?')
return
end
io.output(filename)
for _,line in ipairs(Lines) do
io.write(line..'\n')
end
io.close()
end
Cursor_line = 0 -- valid range: 0 + [1..#Lines]
function clamp()
Cursor_line = math.max(Cursor_line, 1)
Cursor_line = math.min(Cursor_line, #Lines) -- might become 0 if no Lines
end
Screen_top = 1
N = 4 -- 32 -- number of lines to display per screen
function scroll()
while Cursor_line > Screen_top+N-1 do
Screen_top = Screen_top+N
end
while Cursor_line < Screen_top do
Screen_top = Screen_top-N
end
end
-- show current screen
function s(linestr)
if #linestr > 0 then
Screen_top = int(linestr)
end
local l = Screen_top
print('====', Filename, l)
for i = l, math.min(l+N-1,#Lines) do
if i == Cursor_line then io.write('\027[7m') end
if i == Cursor_line and #Lines[i] == 0 then
print(' ') -- indicate cursor on empty line
else
print(Lines[i])
end
if i == Cursor_line then io.write('\027[0m') end
end
print('----')
end
-- add new line below cursor and move cursor to it
function a(line)
table.insert(Lines, Cursor_line+1, line)
Cursor_line = Cursor_line+1
clamp() scroll() s''
end
-- change line at cursor
function c(line)
if Cursor_line == 0 then return end
Lines[Cursor_line] = line
Cursor_line = Cursor_line+1
clamp() scroll() s''
end
-- move cursor line relatively
function l(nstr)
local n = int(nstr)
Cursor_line = Cursor_line+n
clamp() scroll() s''
end
-- scroll
function n()
if Screen_top + N <= #Lines then
Screen_top = Screen_top + N
Cursor_line = Screen_top
end
s''
end
function b()
if Screen_top - N > 0 then
Screen_top = Screen_top - N
Cursor_line = Screen_top
end
s''
end
-- find
function f(pat)
for i = Cursor_line+1, #Lines do
if Lines[i]:find(pat) then
Cursor_line = i
clamp() scroll() s'' return
end
end
for i = 1, Cursor_line-1 do
if Lines[i]:find(pat) then
Cursor_line = i
clamp() scroll() s'' return
end
end
end
function F(pat)
for i = Cursor_line-1, 1, -1 do
if Lines[i]:find(pat) then
Cursor_line = i
clamp() scroll() s'' return
end
end
for i = #Lines, Cursor_line+1, -1 do
if Lines[i]:find(pat) then
Cursor_line = i
clamp() scroll() s'' return
end
end
end
function int(s) return math.floor(tonumber(s)) end
if #arg > 0 then
Filename = arg[1]
print('loading '..Filename)
Lines = {}
for line in io.lines(Filename) do
table.insert(Lines, line)
end
print(#Lines, 'lines')
Cursor_line = 1
end
s'1'