This commit is contained in:
Florian Nücke 2014-08-08 15:52:57 +02:00
commit e3a6a3a9b4
2 changed files with 113 additions and 9 deletions

View File

@ -148,6 +148,76 @@ end
local args, options = shell.parse(...)
local history = {}
local lastSearch
local function drawPrompt()
local foreground = component.gpu.setForeground(0xFF0000)
term.write(expand(os.getenv("PS1") or "$ "))
component.gpu.setForeground(foreground)
end
local function getMatchingPrograms(pattern)
local res = {}
for dir in string.gmatch(os.getenv("PATH"), "[a-zA-Z0-9/.]+") do
for file in fs.list(dir) do
if string.match(file, "^" .. pattern .. "(.+)[.]lua") then
res[#res+1] = file:match("(.+).lua")
end
end
end
return res
end
local function getMatchingFiles(pattern)
local res = {}
local dir = fs.isDirectory(pattern) and pattern or fs.path(pattern) or "/"
local name = (dir == pattern) and "" or fs.name(pattern) or ""
for file in fs.list(dir) do
if string.match(file, "^" .. name) then
res[#res+1] = file
end
end
return res
end
local function hintHandler(line)
local base, space, after = string.match(line, "(.+)(%s)(.+)")
local searchProgram = not base
if not base then
base = ""
after = line or ""
end
if searchProgram then
local matches
if after:find("[/.]") == 1 then
matches = getMatchingFiles(after)
if #matches == 1 then
lastSearch = ""
local ret = base .. (space or "") .. after .. matches[1]:gsub(after:match("[/]*(%w+)$"),"",1)
return ret:gsub("[^/]$","%1 ")
end
else
matches = getMatchingPrograms(after)
if #matches == 1 then
lastSearch = ""
return matches[1] .. " "
end
end
if lastSearch == line then return matches end
else
local matches = getMatchingFiles(after)
for k in ipairs(matches)do
local ret = base .. space .. after .. (matches[k]):gsub(after:match("[/]*(%w+)$") or "","",1)
matches[k] = ret:gsub("[^/]$","%1 "):gsub("/$","")
end
return matches
end
lastSearch = line
end
if #args == 0 and (io.input() == io.stdin or options.i) and not options.c then
-- interactive shell.
while true do
@ -158,10 +228,8 @@ if #args == 0 and (io.input() == io.stdin or options.i) and not options.c then
term.clear()
end
while term.isAvailable() do
local foreground = component.gpu.setForeground(0xFF0000)
term.write(expand(os.getenv("PS1") or "$ "))
component.gpu.setForeground(foreground)
local command = term.read(history)
drawPrompt()
local command = term.read(history, nil, hintHandler)
if not command then
term.write("exit\n")
return -- eof

View File

@ -101,7 +101,7 @@ function term.isAvailable()
return component.isAvailable("gpu") and component.isAvailable("screen")
end
function term.read(history, dobreak)
function term.read(history, dobreak, hint, prompt)
checkArg(1, history, "table", "nil")
history = history or {}
table.insert(history, "")
@ -109,6 +109,9 @@ function term.read(history, dobreak)
local scrollX, scrollY = 0, #history - 1
local cursorX = 1
local hintCache = (type(hint)=="table" and #hint > 1)and hint
local selectedHint = 0
local function getCursor()
return cursorX, 1 + scrollY
end
@ -247,29 +250,61 @@ function term.read(history, dobreak)
right(unicode.len(value))
end
local function tab()
if not hintCache then
if type(hint) == "function" then
local h = hint(line())
if type(h) == "string" then
local _, cby = getCursor()
history[cby] = after
elseif type(h) == "table" and #h > 0 then
hintCache = h
selectedHint = 1
local _, cby = getCursor()
history[cby] = hintCache[selectedHint] or ""
end
end
else
selectedHint = (selectedHint+1)<=#hintCache and (selectedHint+1) or 1
local _, cby = getCursor()
history[cby] = hintCache[selectedHint] or ""
end
redraw()
ende()
end
local function cleanHint()
if type(hint) ~= "table" then
hintCache = nil
end
end
local function onKeyDown(char, code)
term.setCursorBlink(false)
if code == keyboard.keys.back then
if left() then delete() end
if left() then delete() end cleanHint()
elseif code == keyboard.keys.delete then
delete()
delete()cleanHint()
elseif code == keyboard.keys.left then
left()
elseif code == keyboard.keys.right then
right()
elseif code == keyboard.keys.home then
home()
home()cleanHint()
elseif code == keyboard.keys["end"] then
ende()
ende()cleanHint()
elseif code == keyboard.keys.up then
up()
elseif code == keyboard.keys.down then
down()
elseif code == keyboard.keys.tab and hint then
tab()
elseif code == keyboard.keys.enter then
local cbx, cby = getCursor()
if cby ~= #history then -- bring entry to front
history[#history] = line()
table.remove(history, cby)
cleanHint()
end
return true, history[#history] .. "\n"
elseif keyboard.isControlDown() and code == keyboard.keys.d then
@ -282,6 +317,7 @@ function term.read(history, dobreak)
return true, nil
elseif not keyboard.isControl(char) then
insert(unicode.char(char))
cleanHint()
end
term.setCursorBlink(true)
term.setCursorBlink(true) -- force toggle to caret