mirror of
https://github.com/20kdc/OC-KittenOS.git
synced 2024-11-26 04:18:05 +11:00
Compare commits
2 Commits
ca4b6e5df2
...
fe17b0fb93
Author | SHA1 | Date | |
---|---|---|---|
|
fe17b0fb93 | ||
|
c9157a1b7c |
@ -93,7 +93,7 @@ return {
|
||||
},
|
||||
["app-kmt"] = {
|
||||
desc = "Line-terminal for MUDs & such",
|
||||
v = 1,
|
||||
v = 2,
|
||||
deps = {
|
||||
"neo",
|
||||
"zzz-license-pd"
|
||||
|
@ -10,11 +10,11 @@ local termClose
|
||||
|
||||
if not ok then
|
||||
termId = nil
|
||||
neo.executeAsync("svc-t", function (res)
|
||||
assert(neo.executeAsync("svc-t", function (res)
|
||||
termId = res.access
|
||||
termClose = res.close
|
||||
neo.scheduleTimer(0)
|
||||
end, "luashell")
|
||||
end, "luashell"))
|
||||
while not termId do
|
||||
coroutine.yield()
|
||||
end
|
||||
@ -32,7 +32,7 @@ event.listen("k.procdie", function (_, _, pid)
|
||||
end
|
||||
end)
|
||||
|
||||
TERM.write(([[
|
||||
TERM.write([[
|
||||
KittenOS NEO Shell Usage Notes
|
||||
|
||||
Prefixing = is an alias for 'return '.
|
||||
@ -46,7 +46,7 @@ os.exit(): quit the shell
|
||||
=listCmdApps(): -t- (terminal) apps
|
||||
event: useful for setting up listeners
|
||||
without breaking shell functionality
|
||||
]]):gsub("[\r]*\n", "\r\n"))
|
||||
]])
|
||||
|
||||
function listCmdApps()
|
||||
local apps = {}
|
||||
|
@ -30,7 +30,10 @@ local console = {}
|
||||
-- This must not go below 3.
|
||||
local conW = 40
|
||||
local conCX, conCY = 1, 1
|
||||
local conCV = false
|
||||
local conSCX, conSCY = 1, 1
|
||||
-- Performance
|
||||
local consoleShown = {}
|
||||
local conCYShown
|
||||
for i = 1, 14 do
|
||||
console[i] = (" "):rep(conW)
|
||||
end
|
||||
@ -70,6 +73,9 @@ local window = neo.requireAccess("x.neo.pub.window", "window")(conW, #console +
|
||||
|
||||
local function setSize(w, h)
|
||||
conW = w
|
||||
for i = 1, #console do
|
||||
consoleShown[i] = nil
|
||||
end
|
||||
while #console < h do
|
||||
table.insert(console, "")
|
||||
end
|
||||
@ -101,7 +107,7 @@ end
|
||||
local function draw(i)
|
||||
if console[i] then
|
||||
window.span(1, i, console[i], 0, 0xFFFFFF)
|
||||
if i == conCY and conCV then
|
||||
if i == conCY and not leText then
|
||||
window.span(conCX, i, unicode.sub(console[i], conCX, conCX), 0xFFFFFF, 0)
|
||||
end
|
||||
elseif leText then
|
||||
@ -109,7 +115,13 @@ local function draw(i)
|
||||
end
|
||||
end
|
||||
local function drawDisplay()
|
||||
for i = 1, #console do draw(i) end
|
||||
for i = 1, #console do
|
||||
if consoleShown[i] ~= console[i] or i == conCY or i == conCYShown then
|
||||
draw(i)
|
||||
consoleShown[i] = console[i]
|
||||
end
|
||||
end
|
||||
conCYShown = conCY
|
||||
end
|
||||
|
||||
-- Terminal Visual --
|
||||
@ -127,6 +139,13 @@ local function consoleSU()
|
||||
end
|
||||
end
|
||||
|
||||
local function consoleCLS()
|
||||
for i = 1, #console do
|
||||
console[i] = (" "):rep(conW)
|
||||
end
|
||||
conCX, conCY = 1, 1
|
||||
end
|
||||
|
||||
local function writeFF()
|
||||
if conCY ~= #console then
|
||||
conCY = conCY + 1
|
||||
@ -139,6 +158,7 @@ local function writeData(data)
|
||||
-- handle data until completion
|
||||
while #data > 0 do
|
||||
local char = unicode.sub(data, 1, 1)
|
||||
--neo.emergency("svc-t.data: " .. char:byte())
|
||||
data = unicode.sub(data, 2)
|
||||
-- handle character
|
||||
if char == "\t" then
|
||||
@ -147,6 +167,8 @@ local function writeData(data)
|
||||
end
|
||||
if char == "\r" then
|
||||
conCX = 1
|
||||
elseif char == "\x00" then
|
||||
-- caused by TELNET \r rules
|
||||
elseif char == "\n" then
|
||||
conCX = 1
|
||||
writeFF()
|
||||
@ -171,29 +193,17 @@ local function writeData(data)
|
||||
end
|
||||
|
||||
local function writeANSI(s)
|
||||
--neo.emergency("svc-t.ansi: " .. s)
|
||||
-- This supports just about enough to get by.
|
||||
if s == "c" then
|
||||
for i = 1, #console do
|
||||
console[i] = (" "):rep(conW)
|
||||
end
|
||||
conCX, conCY = 1, 1
|
||||
consoleCLS()
|
||||
return
|
||||
end
|
||||
local pfx = s:sub(1, 1)
|
||||
local cmd = s:sub(#s)
|
||||
if pfx == "[" then
|
||||
local np = tonumber(s:sub(2, -2)) or 1
|
||||
if cmd == "H" or cmd == "f" then
|
||||
local p = s:find(";")
|
||||
if not p then
|
||||
conCX, conCY = 1, 1
|
||||
else
|
||||
conCY = tonumber(s:sub(2, p - 1)) or 1
|
||||
conCX = tonumber(s:sub(p + 1, -2)) or 1
|
||||
end
|
||||
elseif cmd == "K" then
|
||||
console[conCY] = unicode.sub(console[conCY], 1, conCX - 1) .. (" "):rep(1 + conW - conCX)
|
||||
elseif cmd == "A" then
|
||||
if cmd == "A" then
|
||||
conCY = conCY - np
|
||||
elseif cmd == "B" then
|
||||
conCY = conCY + np
|
||||
@ -201,14 +211,34 @@ local function writeANSI(s)
|
||||
conCX = conCX + np
|
||||
elseif cmd == "D" then
|
||||
conCX = conCX - np
|
||||
elseif cmd == "S" then
|
||||
for i = 1, np do
|
||||
consoleSU()
|
||||
elseif cmd == "f" or cmd == "H" then
|
||||
local p = s:find(";")
|
||||
if not p then
|
||||
conCY = np
|
||||
conCX = 1
|
||||
else
|
||||
conCY = tonumber(s:sub(2, p - 1)) or 1
|
||||
conCX = tonumber(s:sub(p + 1, -2)) or 1
|
||||
end
|
||||
elseif cmd == "T" then
|
||||
for i = 1, np do
|
||||
consoleSD()
|
||||
elseif cmd == "J" then
|
||||
consoleCLS()
|
||||
elseif cmd == "K" then
|
||||
if s == "[K" or s == "[0K" then
|
||||
-- bash needs this
|
||||
console[conCY] = unicode.sub(console[conCY], 1, conCX - 1) .. (" "):rep(1 + conW - conCX)
|
||||
else
|
||||
console[conCY] = (" "):rep(conW)
|
||||
end
|
||||
elseif cmd == "n" then
|
||||
if s == "[6n" then
|
||||
for _, v in pairs(sendSigs) do
|
||||
v("data", "\x1b[" .. conY .. ";" .. conX .. "R")
|
||||
end
|
||||
end
|
||||
elseif cmd == "s" then
|
||||
conSCX, conSCY = conCX, conCY
|
||||
elseif cmd == "u" then
|
||||
conCX, conCY = conSCX, conSCY
|
||||
end
|
||||
end
|
||||
conCX = math.min(math.max(math.floor(conCX), 1), conW)
|
||||
@ -372,10 +402,24 @@ local function key(a, c)
|
||||
-- Line Editing not active.
|
||||
-- For now support a bare minimum.
|
||||
for _, v in pairs(sendSigs) do
|
||||
if control then
|
||||
if a == 99 then
|
||||
v("telnet", "\xFF\xF4")
|
||||
end
|
||||
if a == "\x03" then
|
||||
v("telnet", "\xFF\xF4")
|
||||
elseif c == 199 then
|
||||
v("data", "\x1b[H")
|
||||
elseif c == 201 then
|
||||
v("data", "\x1b[5~")
|
||||
elseif c == 207 then
|
||||
v("data", "\x1b[F")
|
||||
elseif c == 209 then
|
||||
v("data", "\x1b[6~")
|
||||
elseif c == 203 then
|
||||
v("data", "\x1b[D")
|
||||
elseif c == 205 then
|
||||
v("data", "\x1b[C")
|
||||
elseif c == 200 then
|
||||
v("data", "\x1b[A")
|
||||
elseif c == 208 then
|
||||
v("data", "\x1b[B")
|
||||
elseif a == "\r" then
|
||||
v("data", "\r\n")
|
||||
elseif a then
|
||||
|
@ -3,8 +3,8 @@ ocemu {
|
||||
components {
|
||||
{"gpu", "c1-gpu-tier3", 0, 160, 50, 3},
|
||||
{"gpu", "c1-gpu-tier1", 0, 50, 16, 1},
|
||||
-- {"screen_sdl2", "c1-screen-tier3", -1, 160, 50, 3},
|
||||
{"screen_sdl2", "c1-screen-tier1", -1, 50, 16, 1},
|
||||
{"screen_sdl2", "c1-screen-tier3", -1, 160, 50, 3},
|
||||
-- {"screen_sdl2", "c1-screen-tier1", -1, 50, 16, 1},
|
||||
{"modem", "c1-modem", 1, false},
|
||||
{"eeprom", "c1-eeprom", 9, "lua/bios.lua"},
|
||||
{"filesystem", "c1-tmpfs", -1, "tmpfs", "tmpfs", false, 5},
|
||||
|
@ -1,181 +1,96 @@
|
||||
-- This is released into the public domain.
|
||||
-- No warranty is provided, implied or otherwise.
|
||||
|
||||
-- app-kmt.lua : LC emergency plan
|
||||
-- app-kmt.lua : just a utility now
|
||||
-- Authors: 20kdc
|
||||
|
||||
local lcOverride = false
|
||||
local l15 = "20kdc.duckdns.org:8888"
|
||||
|
||||
-- unicode.safeTextFormat'd lines
|
||||
local console = {
|
||||
"┎┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┒",
|
||||
"┋ ┃ ╱ ┃╲ ╱┃ ▀▀┃▀▀ ┋",
|
||||
"┋ ┃╳ ┃ ╲ ╱ ┃ ┃ ┋",
|
||||
"┋ ┃ ╲ ┃ ╲╱ ┃ ┃ ┋",
|
||||
"┋ ┋",
|
||||
"┋ KittenOS NEO MUD Terminal ┋",
|
||||
"┖┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┚",
|
||||
":Type text, Enter key sends.",
|
||||
":'>' is 'from you', '<' 'to you'.",
|
||||
":':' is 'internal message'.",
|
||||
":Control-Arrows resizes window.",
|
||||
-- ":F5/F6 copies/pastes current line.",
|
||||
":",
|
||||
":",
|
||||
":Enter target server:port",
|
||||
-- 14
|
||||
}
|
||||
--++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
-- sW must not go below 3.
|
||||
-- sH must not go below 2.
|
||||
local sW, sH = 40, 15
|
||||
local inet = neo.requireAccess("c.internet", "internet").list()()
|
||||
local windows = neo.requireAccess("x.neo.pub.window", "windows")
|
||||
local window = windows(sW, sH)
|
||||
|
||||
local tcp = nil
|
||||
local dummyTcp = {read = function() return "" end, write = function() end, close = function() end}
|
||||
local tcpBuf = ""
|
||||
local _, _, termId = ...
|
||||
local ok = pcall(function ()
|
||||
assert(string.sub(termId, 1, 12) == "x.neo.pub.t/")
|
||||
end)
|
||||
|
||||
local function fmtLine(s)
|
||||
s = unicode.safeTextFormat(s)
|
||||
local l = unicode.len(s)
|
||||
return unicode.sub(s .. (" "):rep(sW - l), -sW)
|
||||
end
|
||||
local termClose
|
||||
|
||||
local function line(i)
|
||||
if i ~= sH then
|
||||
assert(console[i], "console" .. i)
|
||||
window.span(1, i, fmtLine(console[i]), 0xFFFFFF, 0)
|
||||
else
|
||||
window.span(1, i, fmtLine(l15), 0, 0xFFFFFF)
|
||||
if not ok then
|
||||
termId = nil
|
||||
assert(neo.executeAsync("svc-t", function (res)
|
||||
termId = res.access
|
||||
termClose = res.close
|
||||
neo.scheduleTimer(0)
|
||||
end, "kmt"))
|
||||
while true do
|
||||
if coroutine.yield() == "k.timer" then break end
|
||||
end
|
||||
end
|
||||
local term = neo.requireAccess(termId, "terminal")
|
||||
|
||||
local function incoming(s)
|
||||
local function shift(f)
|
||||
for i = 1, #console - 1 do
|
||||
console[i] = console[i + 1]
|
||||
end
|
||||
console[#console] = f
|
||||
end
|
||||
-- Need to break this safely.
|
||||
shift("")
|
||||
for i = 1, unicode.len(s) do
|
||||
local ch = unicode.sub(s, i, i)
|
||||
if unicode.wlen(console[#console] .. ch) > sW then
|
||||
shift(" ")
|
||||
end
|
||||
console[#console] = console[#console] .. ch
|
||||
end
|
||||
for i = 1, #console do
|
||||
line(i)
|
||||
end
|
||||
end
|
||||
term.write([[
|
||||
┎┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┒
|
||||
┋ ┃ ╱ ┃╲ ╱┃ ▀▀┃▀▀ ┋
|
||||
┋ ┃╳ ┃ ╲ ╱ ┃ ┃ ┋
|
||||
┋ ┃ ╲ ┃ ╲╱ ┃ ┃ ┋
|
||||
┋ ┋
|
||||
┋ KittenOS NEO MUD Terminal ┋
|
||||
┖┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┚
|
||||
export TERM=ansi.sys <- IMPORTANT!!!
|
||||
Enter target server:port...
|
||||
]])
|
||||
|
||||
local function submitLine()
|
||||
incoming(">" .. l15)
|
||||
if not tcp then
|
||||
tcp = inet.connect(l15)
|
||||
if not tcp then
|
||||
incoming(":The connection could not be created.")
|
||||
tcp = dummyTcp
|
||||
else
|
||||
if not tcp.finishConnect() then
|
||||
incoming(":Warning: finishConnect = false")
|
||||
end
|
||||
neo.scheduleTimer(os.uptime() + 0.1)
|
||||
end
|
||||
else
|
||||
-- PRJblackstar doesn't need \r but others might
|
||||
tcp.write(l15 .. "\r\n")
|
||||
end
|
||||
l15 = ""
|
||||
line(sH)
|
||||
end
|
||||
local targetBuffer = ""
|
||||
|
||||
if lcOverride then
|
||||
submitLine()
|
||||
end
|
||||
|
||||
local function clipEnt(tx)
|
||||
tx = tx:gsub("\r", "")
|
||||
local ci = tx:find("\n") or (#tx + 1)
|
||||
tx = tx:sub(1, ci - 1)
|
||||
l15 = tx
|
||||
line(sH)
|
||||
end
|
||||
|
||||
local control = false
|
||||
neo.scheduleTimer(0)
|
||||
while true do
|
||||
local e = {coroutine.yield()}
|
||||
if e[1] == "k.timer" then
|
||||
while true do
|
||||
while tcp do
|
||||
local b, e = tcp.read(neo.readBufSize)
|
||||
if not b then
|
||||
if e then
|
||||
incoming(":Warning: " .. e)
|
||||
term.write("\nkmt: " .. tostring(e) .. "\n")
|
||||
tcp.close()
|
||||
tcp = dummyTcp
|
||||
tcp = nil
|
||||
end
|
||||
break
|
||||
elseif b == "" then
|
||||
break
|
||||
else
|
||||
tcpBuf = tcpBuf .. b:gsub("\r", "")
|
||||
while true do
|
||||
local nlp = tcpBuf:find("\n")
|
||||
if nlp then
|
||||
incoming("<" .. tcpBuf:sub(1, nlp - 1))
|
||||
tcpBuf = tcpBuf:sub(nlp + 1)
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
term.write(b)
|
||||
end
|
||||
end
|
||||
neo.scheduleTimer(os.uptime() + 0.1)
|
||||
elseif e[1] == "x.neo.pub.window" then
|
||||
if e[3] == "close" then
|
||||
if tcp then
|
||||
tcp.close()
|
||||
end
|
||||
return
|
||||
elseif e[3] == "clipboard" then
|
||||
clipEnt(e[4])
|
||||
elseif e[3] == "key" then
|
||||
if e[5] == 29 or e[5] == 157 then
|
||||
control = e[6]
|
||||
elseif e[6] then
|
||||
if not control then
|
||||
if e[4] == 8 or e[4] == 127 then
|
||||
l15 = unicode.sub(l15, 1, -2)
|
||||
elseif e[4] == 13 then
|
||||
submitLine()
|
||||
elseif e[4] >= 32 then
|
||||
l15 = l15 .. unicode.char(e[4])
|
||||
end
|
||||
line(sH)
|
||||
elseif e[5] == 203 and sW > 8 then
|
||||
sW = sW - 1
|
||||
window.setSize(sW, sH)
|
||||
elseif e[5] == 200 and sH > 2 then
|
||||
sH = sH - 1
|
||||
table.remove(console, 1)
|
||||
window.setSize(sW, sH)
|
||||
elseif e[5] == 205 then
|
||||
sW = sW + 1
|
||||
window.setSize(sW, sH)
|
||||
elseif e[5] == 208 then
|
||||
sH = sH + 1
|
||||
table.insert(console, 1, "")
|
||||
window.setSize(sW, sH)
|
||||
neo.scheduleTimer(os.uptime() + 0.049)
|
||||
elseif e[1] == "k.procdie" then
|
||||
if e[3] == term.pid then
|
||||
break
|
||||
end
|
||||
elseif e[1] == termId then
|
||||
if targetBuffer and e[2] == "data" then
|
||||
targetBuffer = targetBuffer .. e[3]:gsub("\r", "")
|
||||
local p = targetBuffer:find("\n")
|
||||
if p then
|
||||
local ok, res, rer = pcall(inet.connect, targetBuffer:sub(1, p - 1))
|
||||
targetBuffer = targetBuffer:sub(p + 1):gsub("\n", "\r\n")
|
||||
if not ok then
|
||||
-- Likes to return this kind
|
||||
term.write("kmt: " .. tostring(res) .. "\n")
|
||||
elseif not res then
|
||||
-- Could theoretically return this kind
|
||||
term.write("kmt: " .. tostring(rer) .. "\n")
|
||||
else
|
||||
-- Hopefully this kind
|
||||
term.write("kmt: Connecting...\n")
|
||||
tcp = res
|
||||
tcp.write(targetBuffer)
|
||||
targetBuffer = nil
|
||||
end
|
||||
end
|
||||
elseif e[3] == "line" then
|
||||
line(e[4])
|
||||
elseif tcp and e[2] == "data" or e[2] == "telnet" then
|
||||
tcp.write(e[3])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if tcp then
|
||||
tcp.close()
|
||||
end
|
||||
|
||||
|
@ -1,34 +1,27 @@
|
||||
The "svc-t" program / "x.svc.t"
|
||||
The "svc-t" program / "x.neo.pub.t"
|
||||
permission makes up the terminal
|
||||
subsystem for KittenOS NEO.
|
||||
|
||||
--- THEORETICAL TERMINALS MODEL ---
|
||||
|
||||
The theoretical model for terminals
|
||||
in KittenOS NEO is a TELNET client
|
||||
that only supports the ECHO option,
|
||||
and uses the non-standard behavior
|
||||
of treating ECHO ON as 'enable local
|
||||
line editing'.
|
||||
in KittenOS NEO is a TELNET client,
|
||||
using the non-standard behavior of
|
||||
treating a lack of remote echo as
|
||||
meaning 'local line editing'.
|
||||
|
||||
To prevent code size going too far,
|
||||
the client is extremely restricted
|
||||
in capabilities.
|
||||
the shipped terminal supports:
|
||||
|
||||
1. Built-in history as part of the
|
||||
line editing functionality
|
||||
|
||||
2. ANSI.SYS-compatible display, but
|
||||
no support for attributes.
|
||||
|
||||
If you really want full support,
|
||||
write a better terminal application.
|
||||
|
||||
Features that get added will be added
|
||||
in accordance with ANSI/TELNET where
|
||||
reasonable or in a compatible-ish
|
||||
fashion where unreasonable.
|
||||
|
||||
The defaults will be set based on
|
||||
whatever app-luashell requires, as
|
||||
this is what is expected of modern
|
||||
terminal systems regardless of what
|
||||
the standards may have to say.
|
||||
|
||||
A process starting another process
|
||||
connected to the same terminal is
|
||||
advised to wait for that process to
|
||||
@ -82,7 +75,7 @@ When the terminal has shown, the
|
||||
function provided is called with a
|
||||
table as follows:
|
||||
|
||||
access = "x.svc.t/<...>"
|
||||
access = "x.neo.pub.t/<...>"
|
||||
close = function (): close terminal
|
||||
|
||||
The k.kill permission and the close
|
||||
@ -95,7 +88,7 @@ In either case, when the access has
|
||||
been acquired, the following API is
|
||||
presented:
|
||||
|
||||
id = "x.svc.t/<...>"
|
||||
id = "x.neo.pub.t/<...>"
|
||||
pid = <The terminal's PID.>
|
||||
write = function (text): Writes the
|
||||
TELNET data to the terminal.
|
||||
|
Loading…
Reference in New Issue
Block a user