This is my attempt at a simple file explorer. The controls are as follows:
enter = change directory, e = edit, r = run, c = copy, p = paste, delete = delete, backspace = exit

Running the program with the argument "false" disables the argument prompt for the run command.

Suggestions are appreciated, but please note that I'm a novice at lua.

Spoiler

-- File Explorer (fexp)
-- Beta 1.0.0
-- by inventor2514

local tArgs = { ... }
bMode = true
if #tArgs > 0 then
if tArgs[1] == "false" then
bMode = false
end
end

function exitDir(tPath)
if #tPath > 0 then
table.remove(tPath)
end
return tPath
end

function enterDir(tPath, sDir)
table.insert(tPath, sDir)
return tPath
end

function getPath(tPath)
local sPath = ""
for i,sDir in ipairs(tPath) do
sPath = fs.combine(sPath, sDir)
end
return sPath
end

function makePath(sPath)
local pattern = "/%w*"
local tPath = {}
for sDir in string.gmatch(sPath, pattern) do
table.insert(tPath, string.sub(sDir, 2))
end
return tPath
end

function makeArgs(sArgs)
local pattern = " %w*"
local tArgs = {}
for sArg in string.gmatch(" " .. sArgs, pattern) do
table.insert(tArgs, string.sub(sArg, 2))
end
return tArgs
end

local function makeList()
local sPath = getPath(tPath)
local tList = fs.list(sPath)
local tDirs = {}
local tFiles = {}
for i,sName in ipairs(tList) do
if fs.isDir(fs.combine(sPath, sName)) then
table.insert(tDirs, sName)
else
table.insert(tFiles, sName)
end
end
table.sort(tDirs)
table.sort(tFiles)
local tAll = {}
if #tDirs > 0 then
for i,sName in ipairs(tDirs) do table.insert(tAll, sName) end
end
if #tFiles > 0 then
for i,sName in ipairs(tFiles) do table.insert(tAll, sName) end
end
return tAll
end

local function readyBuffer()
local tBuffer = {"/.."}
local sPath = getPath(tPath)
for i,sName in ipairs(tList) do
if fs.isDir(fs.combine(sPath, sName)) then
table.insert(tBuffer, "/" .. sName)
else
table.insert(tBuffer, sName)
end
end
return tBuffer
end

local function dispBuffer()
term.clear()
local xPos, yPos = term.getCursorPos()
term.setCursorPos(1,1)
local limit = start + yMax
if limit > #tBuffer then limit = #tBuffer end
for i=start, limit do
local x, y = term.getCursorPos()
term.write(tBuffer[i])
term.setCursorPos(x, y + 1)
end
term.setCursorPos(xPos, yPos)
end

local function scrollUp()
if line > 1 then
line = line - 1
local xPos, yPos = term.getCursorPos()
if yPos~=1 then
term.setCursorPos(xPos, yPos - 1)
else
start = start - 1
end
end
end

local function scrollDown()
if line < #tBuffer then
line = line + 1
local xPos, yPos = term.getCursorPos()
if yPos~=yMax then
term.setCursorPos(xPos, yPos + 1)
else
start = start + 1
end
end
end

local function changeDir()
local sPath = getPath(tPath)
if line==1 then
tPath = exitDir(tPath)
bRefresh = true
else
local sName = tList[line - 1]
if fs.isDir(fs.combine(sPath, sName)) then
tPath = enterDir(tPath, sName)
bRefresh = true
end
end
end

local function edit()
local sPath = getPath(tPath)
local sName = tList[line - 1]
if not fs.isDir(fs.combine(sPath, sName)) then
local xPos, yPos = term.getCursorPos()
if sName~=shell.getRunningProgram() then
term.clear()
term.setCursorPos(1,1)
shell.run("edit",sName)
end
term.setCursorPos(xPos, yPos)
term.setCursorBlink(true)
end
end

local function run()
local sPath = getPath(tPath)
local sName = tList[line - 1]
if not fs.isDir(fs.combine(sPath, sName)) then
local xPos, yPos = term.getCursorPos()
if sName~=shell.getRunningProgram() then
local sArgs = ""
local tArgs = {}
if bMode then
term.clear()
term.setCursorPos(1,1)
print("Arguments:")
sArgs = io.read()
tArgs = makeArgs(sArgs)
end
term.clear()
term.setCursorPos(1,1)
term.setCursorBlink(false)
if #tArgs == 0 then
pcall(shell.run(sName))
else
pcall(shell.run(sName, unpack(tArgs)))
end
end
term.setCursorBlink(true)
sleep(2)
term.setCursorPos(xPos, yPos)
end
end

local function copy()
local sPath = getPath(tPath)
local sName = tList[line - 1]
sClip = fs.combine(sPath, sName)
end

local function paste()
local sPath = getPath(tPath)
local sName = fs.getName(sClip)
sPath = fs.combine(sPath, sName)
if not fs.isReadOnly(sPath) and sClip ~= sPath then
if fs.exists(sPath) then fs.delete(sPath) end
fs.copy(sClip, sPath)
bRefresh = true
end
end

local function delete()
local sPath = getPath(tPath)
local sName = tList[line - 1]
sPath = fs.combine(sPath, sName)
if not fs.isReadOnly(sPath) then
fs.delete(sPath)
bRefresh = true
end
end

-- initialize
term.clear()
term.setCursorPos(1,1)
term.setCursorBlink(true)
local sSave = shell.dir()
tPath = makePath(sSave)
bRefresh = true
xMax, yMax = term.getSize()
sClip = nil
-- main program loop
repeat
-- refresh if necessary
if bRefresh==true then
  bRefresh = false
  term.setCursorPos(1,1)
  line = 1
  start = 1
  tList = makeList()
  tBuffer = readyBuffer()
  shell.setDir(getPath(tPath))
end
-- display buffer
dispBuffer()
-- get os event
local sEvent, arg1, arg2 = os.pullEvent()
-- respond to up arrow
if sEvent=="key" and arg1==200 then
  scrollUp()
end
-- respond to down arrow
if sEvent=="key" and arg1==208 then
  scrollDown()
end
-- respond to enter
if sEvent=="key" and arg1==28 then
  changeDir()
end
-- respond to e
if sEvent=="char" and arg1=="e" and line > 1 then
  edit()
end
-- respond to r
if sEvent=="char" and arg1=="r" and line > 1 then
  run()
end
-- respond to c
if sEvent=="char" and arg1=="c" and line > 1 then
  copy()
end
-- respond to p
if sEvent=="char" and arg1=="p" and sClip~=nil then
  paste()
end
-- respond to delete
if sEvent=="key" and arg1==211 and line > 1 then
  delete()
end
-- end loop with backspace
until sEvent=="key" and arg1==14

-- cleanup
shell.setDir(sSave)
term.clear()
term.setCursorPos(1,1)