Commit b226ec3c by Phil Hagelberg

Move SSH completion into session instead of server thread.

1 parent c4fcde85
......@@ -26,7 +26,7 @@ end
local complete = function()
local input = lume.trim(editor.get_input())
local send = editor.get_prop("ssh_send")
if(input and send) then send({op="complete", input=input}) end
if(input and send) then send({op="complete", ssrpc=true, input=input}) end
end
-- inherit bindings from console
......
local shell = require("os.orb.shell")
local fs = require("os.orb.fs")
local lume = require("lume")
local utf8 = require("polywell.utf8")
local function completions_for(input, dir, prefixes)
local input_parts = lume.split(input, "/")
if(#input_parts == 1) then
local matches = {}
for _,v in pairs(fs.ls(dir, "/")) do
if(fs.exists(v, dir) and utf8.sub(v, 1, #input) == input) then
local parts = lume.clone(prefixes)
table.insert(parts, v)
if(fs.isdir(v, dir)) then table.insert(parts, "") end
table.insert(matches, table.concat(parts, "/"))
end
end
return matches
else
local first_part = table.remove(input_parts, 1)
table.insert(prefixes, first_part)
return completions_for(table.concat(input_parts, "/"),
dir .. first_part, prefixes)
end
end
return {
new_session = function(stdin, output, username, hostname)
......@@ -40,19 +17,4 @@ return {
-- This will only kill threads that are smash sessions; ugh.
kill = function(session) session.stdin:push("logout") end,
handlers = {
complete = function(session, msg, channel)
local ok, err = pcall(function()
local dir = msg.input:match("^/") and "" or session.CWD
local completions = completions_for(msg.input, dir, {})
channel:push({op="rpc", fn="completions",
args={completions, msg.input}})
end)
if(not ok) then
print("OS handler error:", err)
channel:push({op="status", status="err", out=err})
end
end
},
}
-- This is the file launched in a new thread for each user session on login.
local lume = require("lume")
local utf8 = require("polywell.utf8")
local shell = require("os.orb.shell")
local rpcs = require("os.orb.rpcs")
local fs = require("os.orb.fs")
local env, command, stdin, output, hostname = ...
local read = function() return stdin:demand() end
local function completions_for(input, dir, prefixes)
local input_parts = lume.split(input, "/")
if(#input_parts == 1) then
local matches = {}
for _,v in pairs(fs.ls(dir, "/")) do
if(fs.exists(v, dir) and utf8.sub(v, 1, #input) == input) then
local parts = lume.clone(prefixes)
table.insert(parts, v)
if(fs.isdir(v, dir)) then table.insert(parts, "") end
table.insert(matches, table.concat(parts, "/"))
end
end
return matches
else
local first_part = table.remove(input_parts, 1)
table.insert(prefixes, first_part)
return completions_for(table.concat(input_parts, "/"),
dir .. first_part, prefixes)
end
end
local function read()
local msg = stdin:demand()
if(msg.op == "stdin") then
return msg.stdin
elseif(msg.op == "complete") then
-- we are turning read into a generic RPC dispatch point, which we
-- will likely turn out to regret! but it's our only entry point now.
local ok, err = pcall(function()
local dir = msg.input:match("^/") and "" or env.CWD
local completions = completions_for(msg.input, dir, {})
output:push({op="rpc", fn="completions",
args={completions, msg.input}})
end)
if(not ok) then
print("OS handler error:", err)
output:push({op="status", status="err", out=err})
end
else
print("Unknown op!", lume.serialize(msg))
end
return read()
end
local write = function(...)
local out = table.concat(lume.map({...}, tostring), " ")
......
......@@ -36,16 +36,14 @@ while true do
if(not xpcall(new_session, handle, msg.username, msg.password)) then
output:push({op="status", out="Login failed."})
end
elseif(msg.op == "stdin") then
elseif(msg.op == "stdin" or msg.ssrpc) then -- ssrpc for server-side RPC
local session = sessions[msg.session]
if(session) then
session.stdin:push(msg.stdin)
session.stdin:push(msg)
else
print("Warning: no session", msg.session)
end
elseif(msg.op == "debug") then
pp(sessions)
elseif(msg.op and os.handlers and os.handlers[msg.op]) then
os.handlers[msg.op](sessions[msg.session], msg, output)
end
end
......@@ -257,8 +257,8 @@ return {
completions = function(ship, _, completions, entered)
-- if the last command was not complete, then don't do anything
if(ship.api.editor.last_command() ~=
ship.api.editor.get("complete")) then return end
if(#completions == 1) then
ship.api.editor.get("complete")) then return
elseif(#completions == 1) then
ship.api.editor.textinput(utf8.sub(completions[1], #entered + 1), true)
elseif(#completions > 0) then
local common = utils.longest_common_prefix(completions)
......
......@@ -56,9 +56,11 @@ local test_completion = function()
ship.target_number, ship.target = 2, solotogo
eval("ssh()")
ship.api.editor.end_of_buffer()
ship.api.editor.textinput("/bin/up", true)
ship.api.editor.end_of_buffer()
pass()
ship.api.editor.keypressed("tab")
ship.api.editor.end_of_buffer()
pass()
local first_completed = ship.api.editor.get_line()
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!