Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local multishell = multishell
- local parentShell = shell
- local parentTerm = term.current()
- if multishell then
- multishell.setTitle( multishell.getCurrent(), "ex-sh" )
- end
- local bExit = false
- local sDir = (parentShell and parentShell.dir()) or ""
- local sPath = (parentShell and parentShell.path()) or ".:/rom/programs"
- local tAliases = (parentShell and parentShell.aliases()) or {}
- local tProgramStack = {}
- local shell = {}
- local tEnv = {
- [ "shell" ] = shell,
- [ "multishell" ] = multishell,
- }
- -- Colours
- local promptColour, textColour, bgColour
- if term.isColour() then
- promptColour = colours.yellow
- textColour = colours.white
- bgColour = colours.black
- else
- promptColour = colours.white
- textColour = colours.white
- bgColour = colours.black
- ghostColor = colours.black
- end
- local function run( _sCommand, ... )
- local sPath = shell.resolveProgram( _sCommand )
- if sPath ~= nil then
- tProgramStack[#tProgramStack + 1] = sPath
- if multishell then
- multishell.setTitle( multishell.getCurrent(), fs.getName( sPath ) )
- end
- local result = os.run( tEnv, sPath, ... )
- tProgramStack[#tProgramStack] = nil
- if multishell then
- if #tProgramStack > 0 then
- multishell.setTitle( multishell.getCurrent(), fs.getName( tProgramStack[#tProgramStack] ) )
- else
- multishell.setTitle( multishell.getCurrent(), "ex-sh" )
- end
- end
- return result
- else
- printError( "No such program" )
- return false
- end
- end
- local function tokenise( ... )
- local sLine = table.concat( { ... }, " " )
- local tWords = {}
- local bQuoted = false
- for match in string.gmatch( sLine .. "\"", "(.-)\"" ) do
- if bQuoted then
- table.insert( tWords, match )
- else
- for m in string.gmatch( match, "[^ \t]+" ) do
- table.insert( tWords, m )
- end
- end
- bQuoted = not bQuoted
- end
- return tWords
- end
- -- Install shell API
- function shell.run( ... )
- local tWords = tokenise( ... )
- local sCommand = tWords[1]
- if sCommand then
- return run( sCommand, unpack( tWords, 2 ) )
- end
- return false
- end
- function shell.exit()
- bExit = true
- end
- function shell.dir()
- return sDir
- end
- function shell.setDir( _sDir )
- sDir = _sDir
- end
- function shell.path()
- return sPath
- end
- function shell.setPath( _sPath )
- sPath = _sPath
- end
- function shell.resolve( _sPath )
- local sStartChar = string.sub( _sPath, 1, 1 )
- if sStartChar == "/" or sStartChar == "\\" then
- return fs.combine( "", _sPath )
- else
- return fs.combine( sDir, _sPath )
- end
- end
- function shell.resolveProgram( _sCommand )
- -- Substitute aliases firsts
- if tAliases[ _sCommand ] ~= nil then
- _sCommand = tAliases[ _sCommand ]
- end
- -- If the path is a global path, use it directly
- local sStartChar = string.sub( _sCommand, 1, 1 )
- if sStartChar == "/" or sStartChar == "\\" then
- local sPath = fs.combine( "", _sCommand )
- if fs.exists( sPath ) and not fs.isDir( sPath ) then
- return sPath
- end
- return nil
- end
- -- Otherwise, look on the path variable
- for sPath in string.gmatch(sPath, "[^:]+") do
- sPath = fs.combine( shell.resolve( sPath ), _sCommand )
- if fs.exists( sPath ) and not fs.isDir( sPath ) then
- return sPath
- end
- end
- -- Not found
- return nil
- end
- function shell.programs( _bIncludeHidden )
- local tItems = {}
- -- Add programs from the path
- for sPath in string.gmatch(sPath, "[^:]+") do
- sPath = shell.resolve( sPath )
- if fs.isDir( sPath ) then
- local tList = fs.list( sPath )
- for n,sFile in pairs( tList ) do
- if not fs.isDir( fs.combine( sPath, sFile ) ) and
- (_bIncludeHidden or string.sub( sFile, 1, 1 ) ~= ".") then
- tItems[ sFile ] = true
- end
- end
- end
- end
- -- Sort and return
- local tItemList = {}
- for sItem, b in pairs( tItems ) do
- table.insert( tItemList, sItem )
- end
- table.sort( tItemList )
- return tItemList
- end
- function shell.getRunningProgram()
- if #tProgramStack > 0 then
- return tProgramStack[#tProgramStack]
- end
- return nil
- end
- function shell.setAlias( _sCommand, _sProgram )
- tAliases[ _sCommand ] = _sProgram
- end
- function shell.clearAlias( _sCommand )
- tAliases[ _sCommand ] = nil
- end
- function shell.aliases()
- -- Add aliases
- local tCopy = {}
- for sAlias, sCommand in pairs( tAliases ) do
- tCopy[sAlias] = sCommand
- end
- return tCopy
- end
- if multishell then
- function shell.openTab( ... )
- local tWords = tokenise( ... )
- local sCommand = tWords[1]
- if sCommand then
- local sPath = shell.resolveProgram( sCommand )
- if sPath == "rom/programs/shell" then
- return multishell.launch( tEnv, sPath, unpack( tWords, 2 ) )
- elseif sPath ~= nil then
- return multishell.launch( tEnv, "rom/programs/shell", sPath, unpack( tWords, 2 ) )
- else
- printError( "No such program" )
- end
- end
- end
- function shell.switchTab( nID )
- multishell.setFocus( nID )
- end
- end
- --[[ Ext-shell additions --]]
- --File Useage --
- local function save(A,B) local file = fs.open(tostring(A),"w") file.write(B) file.close() end
- local function saveT(A,B) save(A,textutils.serialize(B)) end
- local function saveTL(A,B) save(A,string.gsub(textutils.serialize(B),"\n%s*","")) end
- local function get(A) local file = fs.open(tostring(A),"r") if not file then return false end local data = file.readAll() file.close() if data then return data end end
- local function getT(A) local data = get(A) if data then data = textutils.unserialize(data) end if data then return data end end
- local saveDir= (parentShell and parentShell.getRunningProgram and parentShell.getRunningProgram()) or "/"
- saveDir=string.sub(saveDir,1,#saveDir-#fs.getName(saveDir))
- if fs.isReadOnly(saveDir) then saveDir="/" end
- --Additional Colors setup
- local argumentColour, programColour, systemColour, dirColour, fileColour ,ghostColor
- if term.isColour() then
- argumentColour = colours.cyan
- programColour = colours.lightBlue
- systemColour = colours.orange
- dirColour = colours.green
- fileColour = colours.lightGrey
- ghostColor = colours.grey
- else
- argumentColour = colours.white
- programColour = colours.white
- systemColour = colours.white
- dirColour = colours.white
- fileColour = colours.white
- ghostColor = colours.black
- end
- --Argument Tables help functions
- local function sumtab(A,B)
- C={}
- for i,k in ipairs(A) do
- table.insert( C, k )
- end
- for i,k in ipairs(B) do
- table.insert( C, k )
- end
- return C
- end
- local function setall(A,B)
- local function Rev(A) local Revt,i,j={} for i,j in ipairs(A) do Revt[j]=i end return Revt end
- local C=Rev(A)
- return setmetatable({},{["__index"]=function(tab, key) if C[key] then return B end end})
- end
- local function setany(B)
- return setmetatable({},{["__index"]=function(tab, key) return B end})
- end
- local function peripherallook(A)
- local per = peripheral.getNames()
- for i=#per,1,-1 do
- if peripheral.getType(per[i])~=A then table.remove(per,i) end
- end
- return per
- end
- local function hostnameslookup(sProtocol)
- -- Build list of host IDs
- local tResults = {}
- local close=false
- if not rednet.isOpen() then
- for i,k in pairs(rs.getSides()) do
- if peripheral.getType( k ) == "modem" then
- rednet.open(k)
- close=k
- break
- end
- end
- if not close then return tResults end
- end
- -- Broadcast a lookup packet
- rednet.broadcast( {
- sType = "lookup",
- sProtocol = sProtocol,
- sHostname = sHostname,
- }, "dns" )
- -- Start a timer
- local timer = os.startTimer( 0.5 )
- -- Wait for events
- while true do
- local event, p1, p2, p3 = os.pullEvent()
- if event == "rednet_message" then
- -- Got a rednet message, check if it's the response to our request
- local nSenderID, tMessage, sMessageProtocol = p1, p2, p3
- if sMessageProtocol == "dns" and tMessage.sType == "lookup response" then
- if tMessage.sProtocol == sProtocol then
- table.insert( tResults, tMessage.sHostname )
- end
- end
- else
- -- Got a timer event, check it's the end of our timeout
- if p1 == timer then
- break
- end
- end
- end
- if close then
- rednet.close(close)
- end
- return tResults
- end
- local ArgLists = {
- ['side']={'left', 'right', 'top', 'bottom', 'front', 'back'},
- ['slots']={},
- ['equip']={'left', 'right'},
- ['direction']={'left', 'right', 'forward', 'back', 'down', 'up'},
- ['turn']={'left', 'right'},
- ['power']={},
- ['colors']={'white','orange','magenta','lightBlue','yellow','lime','pink','gray','lightGray','cyan','purple','blue','brown','green','red','black'},
- ['topic']=help.topics(),
- }
- table.insert(ArgLists['topic'],1,'index')
- for i=1,16 do
- ArgLists['slots'][i]=tostring(i)
- end
- for i=0,15 do
- ArgLists['power'][i+1]=tostring(i)
- end
- table.insert(ArgLists['power'],1,'false')
- table.insert(ArgLists['power'],1,'true')
- --Standard programs argument list.
- --If first is in arguments then go next until you reach current word
- --List programs on first word (or in case of restart) use shell.resolveProgram on first word to get path
- --If there is 'restart' look for word in arguments and repeat starting process
- --When you reach word you need
- --If there is an ['file']=true then is simply to start filesystem pathfinding
- --If there is an 'specialArgs' and you are in tab mode then run it and set result as 'args' content
- --If you are outside of whole table do filesystem tab-complete without programs
- local tProgramsArguments={
- --['rom/program/path']={['suggest']="mode",['args']={'get','set','clear'},['next']={},['specialArgs']=function() return peripherallook("drive") end},
- --Complicated argument lists
- ['rom/programs/label']={['suggest']='mode',['args']={'get','set','clear'},['next']={
- ['get']={['suggest']='[side]',['optional']=true,['args']={},['specialArgs']=function() return peripherallook("drive") end},
- ['set']={['suggest']='[side] text',['optional']=true,['args']={},['specialArgs']=function() return peripherallook("drive") end,['next']=setall(ArgLists['side'],{'text'})},
- ['clear']={['suggest']='[side]',['optional']=true,['args']={},['specialArgs']=function() return peripherallook("drive") end},
- },
- },
- ['rom/programs/fun/dj']={['suggest']='mode',['args']={'play','stop'},['next']={
- ['play']={['suggest']='[drive]',['optional']=true,['args']={},['specialArgs']=function() return peripherallook("drive") end},
- },
- },
- ['rom/programs/gps'] = {['suggest']='mode',['args']={'locate', 'host'},['next']={
- ['host']={['suggest']='[coordinates]'},
- },
- },
- ['rom/programs/redstone'] = {['suggest']='mode',['args']={'probe', 'set' , 'pulse'},['next']={
- ['pulse']={['suggest']='side',['args']=ArgLists['side'],['next']=setall(ArgLists['side'],{['suggest']='count',['args']={},['next']=setany({['suggest']='perdoit',['args']={}})})},
- ['set']={['suggest']='side',['args']=ArgLists['side'],['next']=setall(ArgLists['side'],{['suggest']='[color] value',['optional']=true,['args']=sumtab(ArgLists['power'],ArgLists['colors']),['next']={setall(ArgLists['colors'],{['suggest']='value',['args']=ArgLists['power']})}})},
- },
- },
- ['rom/programs/rednet/chat'] = {['suggest']='mode',['args']={'join', 'host'},['next']={
- ['join']={['suggest']='hostname',['args']={},['specialArgs']=function() return hostnameslookup("chat") end,['next']=setany({['suggest']='username'})},
- ['host']={['suggest']='hostname',['next']={}},
- },
- },
- ['rom/programs/http/pastebin'] = {['suggest']='mode',['args']={'put', 'get' , 'run'},['next']={
- ['put']={['suggest']='filename',['file']=true},
- ['run']={['suggest']='code',['args']={}},
- ['get']={['suggest']='code',['args']={},['next']=setany({['suggest']='filename',['file']=true})},
- },
- },
- ['rom/programs/monitor'] = {['suggest']='side',['args']={},['specialArgs']=function() return peripherallook("monitor") end,['next']=setany({['suggest']='program',['restart']=true})},
- --Filesystem operations
- ['rom/programs/copy'] = {['suggest']='source',['file']=true,['next']=setany({['suggest']='destination',['file']=true,['next']={}})},
- ['rom/programs/rename'] = {['suggest']='source',['file']=true,['next']=setany({['suggest']='destination',['file']=true,['next']={}})},
- ['rom/programs/move'] = {['suggest']='source',['file']=true,['next']=setany({['suggest']='destination',['file']=true,['next']={}})},
- --2 argument list
- ['rom/programs/turtle/equip'] = {['suggest']='slo',['args']=ArgLists['slots'],['next']=setall(ArgLists['slots'],{['suggest']='side',['args']=ArgLists['equip']})},
- ['rom/programs/turtle/go'] = {['suggest']='direction',['args']=ArgLists['direction'],['next']=setall(ArgLists['direction'],{['suggest']='[distance]',['args']={}})},
- ['rom/programs/turtle/turn'] = {['suggest']='side',['args']=ArgLists['turn'],['next']=setall(ArgLists['turn'],{['suggest']='[turns]',['args']={}})},
- --one argument that can be suggested and is needed
- ['rom/programs/turtle/unequip'] = {['suggest']='side',['args']=ArgLists['equip']},
- ['rom/programs/eject'] = {['suggest']='side',['args']=ArgLists['side']},
- --one argument that can be suggested but optional
- ['rom/programs/help'] = {['suggest']='[topic]',['args']=ArgLists['topic']},
- ['rom/programs/programs'] = {['suggest']='[all]',['args']={"all"}},
- --simple arguments that will not be suggested (or are a filepaths)
- ['rom/programs/turtle/craft'] = {['suggest']='amount',['args']={}},
- ['rom/programs/cd'] = {['suggest']='path',['file']=true},
- ['rom/programs/delete'] = {['suggest']='path',['file']=true},
- ['rom/programs/mkdir'] = {['suggest']='path',['file']=true},
- ['rom/programs/list'] = {['suggest']='[path]',['file']=true},
- ['rom/programs/edit'] = {['suggest']='path',['file']=true},
- ['rom/programs/type'] = {['suggest']='path',['file']=true},
- ['rom/programs/advanced/paint'] = {['suggest']='path',['file']=true},
- ['rom/programs/advanced/bg'] = {['suggest']='program',['restart']=true},
- ['rom/programs/advanced/fg'] = {['suggest']='program',['restart']=true},
- ['rom/programs/shell'] = {['suggest']='[program]',['restart']=true},
- ['rom/programs/turtle/refuel'] = {['suggest']='amount',['args']={}},
- ['rom/programs/turtle/tunnel'] = {['suggest']='length',['args']={}},
- ['rom/programs/turtle/excavate'] = {['suggest']='diameter',['args']={}},
- }
- --System Commands Tables (arugments and functions)
- --If first is in System Commands arguments then go next until you reach current word using same algorythm as table before.
- local tSystemArguments={
- --['rom/program/path']={['suggest']="mode",['args']={'get','set','clear'},['next']={},['specialArgs']=function() return peripherallook("drive") end},
- ['!lua']={['suggest']="lua code",},
- ['!rlua']={},
- ['!wild']={['suggest']="Wildcard path",},
- ['!cat']={['suggest']="path",['file']=true,['next']={}},
- ['!find']={['suggest']="Filename to find",},
- }
- tSystemArguments['!cat']['next']=setany(tSystemArguments['!cat'])
- --locals for SystemFunctions
- local LuatEnv = {["_echo"] = function( ... ) return ... end,}
- setmetatable( LuatEnv, { __index = getfenv() } )
- local nextPrefix=""
- --Those are the functions you run providing whole sLine.
- local tSystemFunctions={
- --['!name']=function(_String) end,
- ['!lua']=function(_String)
- local nForcePrint = 0
- local func, e = loadstring( _String, "lua" )
- local func2, e2 = loadstring( "return _echo(".._String..");", "lua" )
- if not func then
- if func2 then
- func = func2
- e = nil
- nForcePrint = 1
- end
- else
- if func2 then
- func = func2
- end
- end
- if func then
- setfenv( func, LuatEnv )
- local tResults = { pcall( func ) }
- if tResults[1] then
- local n = 1
- while (tResults[n + 1] ~= nil) or (n <= nForcePrint) do
- local value = tResults[ n + 1 ]
- if type( value ) == "table" then
- local ok, serialised = pcall( textutils.serialise, value )
- if ok then
- print( serialised )
- else
- print( tostring( value ) )
- end
- else
- print( tostring( value ) )
- end
- n = n + 1
- end
- else
- printError( tResults[2] )
- end
- else
- printError( e )
- end
- nextPrefix="!lua "
- end,
- ['!rlua']=function(_String) LuatEnv = {["_echo"] = function( ... ) return ... end,} setmetatable( LuatEnv, { __index = getfenv() } ) print("Lua Enviroment Reset") end,
- ['!cowsay']=function(_String) local offline = {"Allan please add cow and tux detail","Play Minecraft. Oh wait, you are!","Go home, you're drunk.","VIFIIIINOOOOOOO!!!! I'M WATCHING YOU!!!!","WOOF!","Meow!","Don't cry because it's over, smile because it happened.","You only live once, but if you do it right, once is enough.","Behind every great man, there is a woman rolling her eyes.","A day without sunshine is like, you know, night.","Housework can't kill you, but why take the chance?","Localize your variables Csstform","I don't care if I'm a lemming. I'm not going.","I program, therefore I am.","I support everyone's right to be an idiot. I may need it someday.","I think we're all Bozos on this bus.","If a listener nods his head when you're explaining your program, wake him up.","If at first you don't succeed, redefine success.","Misery loves company, but company does not reciprocate.","Many receive advice, few profit from it.","Make it right before you make it faster.",} print(offline[math.random(1,#offline)]) end,
- ['!wild']=function(_String) print("Wildcard result:") textutils.pagedTabulate( programColour , fs.find(shell.resolve(tokenise(_String)[1]))) end,
- ['!cat']=function(_String)
- local out={}
- for i,k in ipairs(tokenise(_String)) do
- local path=shell.resolve(k)
- if not fs.exists(path) then print("File "..k.." don't exists") return end
- if fs.isDir(path) then print(k.." is a directory") return end
- local file = fs.open(path, "r")
- table.insert(out,file.readAll())
- file.close()
- end
- textutils.pagedPrint(table.concat(out))
- end,
- ['!find']=function(_String)
- local target = tokenise(_String)[1]
- if not target or target == "" then print("No target specified") return end
- local matches={}
- target=string.lower(target)
- local function process(path)
- local T=fs.list(path)
- for _,k in ipairs(T) do
- local cpath=path.."/"..k
- if string.find(string.lower(k), target , 1 , not patt) then table.insert(matches,cpath) end
- if fs.isDir(cpath) then process(cpath) end
- end
- end
- local function list(_Tlist)
- local tFiles = {}
- local tDirs = {}
- for n, sItem in pairs(_Tlist) do
- if fs.isDir( sItem ) then
- table.insert( tDirs, sItem )
- else
- table.insert( tFiles, sItem )
- end
- end
- table.sort( tDirs ) table.sort( tFiles )
- textutils.pagedTabulate(dirColour , tDirs , fileColour, tFiles)
- end
- process("")
- list(matches)
- end,
- ['!test']=function(_String) print("s",_String,"e") end,
- }
- --This is list of them generated from tSystemArguments and sorted by alphabeth.
- local tSystemFunctionsNames={}
- for i,k in pairs(tSystemArguments) do
- table.insert( tSystemFunctionsNames, i )
- end
- table.sort( tSystemFunctionsNames )
- --Tab completiton Main functions
- local function tabtokenise( sLine ) --cuts line into table of words and gives 2nd table of start/stop points of each word - ("") matter.
- local tWords = {}
- local tPoints = {}
- local bQuoted = false
- local nOff = 0
- for start,match,stop in string.gmatch( sLine .. "\"", "()(.-)()\"" ) do
- if bQuoted then
- table.insert( tWords, match )
- table.insert( tPoints, {start,stop})
- nOff = stop
- else
- for sta,m,sto in string.gmatch( match, "()([^ \t]+)()" ) do
- table.insert( tWords, m )
- table.insert( tPoints, {sta+nOff,sto+nOff})
- end
- end
- bQuoted = not bQuoted
- end
- if string.sub( sLine, #sLine, #sLine )==" " and #tWords>0 then table.insert( tWords, "" ) table.insert( tPoints, {#sLine,#sLine+1} ) end
- return tWords,tPoints
- end
- local function common(_String,_Cur) --need a total rewrite propably. Is supposed to find common start part of 2 given strings.
- if not _Cur then return _String end
- for i=#_String,1,-1 do
- local a,b=string.sub (_String,1,i),string.sub(_Cur,1,i)
- if a==b then return a end
- end
- return ""
- end
- --if first is in arguments then go next until you reach current word
- --list programs on first word (or in case of restart) use shell.resolveProgram on firs word to get path
- --if no next then stop suggesting and just do programs+filesystem
- --if there is 'restart' look for word in arguments and repeat starting process
- --when you reach word you need
- --if there is an ['file']=true then is simply to start filesystem pathfinding
- --if there is an 'specialArgs' then run it and add result it to args content using sumtab
- --if you are outside of whole table do filesystem tab-complete without programs
- local function tabcomplete(sLine,nPos,SpecialMode) --Main tabcomplete
- local tWords,tPoints = tabtokenise(sLine) --create 2 tables and fill then with content.
- --list of functions used by this function
- local function loopstarter(nCurrent,nNeeded,bFirstLoop) --returns sSuggestion,tArguments,bSystem,bPrograms,bFilesystem
- if nNeeded==0 then return "",{},false,false,true end
- local function loop(tab,num,current)
- if not tab then tab={} end
- if tab['restart'] then
- if num==current then
- local suggest,t1,b1,b2,b3 = loopstarter(num,current)
- suggest = (#tWords[num]==0 and tab['suggest']) or suggest
- return suggest,t1,b1,b2,b3
- else return loopstarter(num,current) end
- elseif num==current then
- if tab['specialArgs'] and SpecialMode then tab['args']=tab['specialArgs']() end
- return ((#tWords[num]==0 and tab['suggest']) or ""),(tab['args'] or {}),false,false,tab['file']
- elseif tab['next'] then return loop(tab['next'][tWords[num]],num+1,current)
- else return "",{},false,false,true end
- end
- local first=shell.resolveProgram( tWords[nCurrent] or "" )
- if tProgramsArguments[first] then --written word matches one of programs
- local tab=tProgramsArguments[first]
- if nCurrent==nNeeded then --nothing else written - return suggestions for that program,{} for arguments
- return (tab['suggest'] and " "..tab['suggest']),{},bFirstLoop,true,true
- else return loop(tab,nCurrent+1,nNeeded) end --look deeper into system along this program path.
- elseif bFirstLoop and tSystemArguments[ tWords[nCurrent] or "" ] then
- local tab=tSystemArguments[ tWords[nCurrent] or "" ]
- if nCurrent==nNeeded then --nothing else written - return suggestions for that command,{} for arguments
- return (tab['suggest'] and " "..tab['suggest']),{},bFirstLoop,true,true
- else return loop(tab,nCurrent+1,nNeeded) end --look deeper into system along this command path.
- end
- --we have no match in system
- return "",{},bFirstLoop and nCurrent==nNeeded,nCurrent==nNeeded,true --,filesystem and Syst
- end
- --New Code
- --find if you are in word or at end if it
- local Word=0
- local ending=0
- local letter=nPos+1
- for i,k in ipairs(tPoints) do
- if letter>=k[1] and letter<=k[2] then Word=i break end
- ending=k[2]
- end
- --start stop points of said word.
- local starts=tPoints[Word] and tPoints[Word][1] or nPos
- local stops=tPoints[Word] and tPoints[Word][2] or nPos
- --list tables of possible completitions.
- local sSuggestion,tArguments,tSystem,tPrograms,tFiles = loopstarter(1,Word,true)
- --Sanitizing magic for pattern needs ^$()%.[]*+-?
- local sWord=tWords[Word] or ""
- local pattern="^"..string.gsub(sWord,"[%^%$%(%)%%%.%[%]%*%+%-%?]",function(A) return "%"..A end) --..".*"
- local sCommon=nil --common part of all names in the list.
- --tArguments Analisis.
- local tTemp=tArguments
- tArguments = {}
- for i,k in pairs(tTemp) do
- if string.match(k, pattern ) then table.insert( tArguments, k ) sCommon=common(k,sCommon) end
- end
- --tSystem analisis.
- if tSystem then
- tSystem = {}
- for i,k in pairs(tSystemFunctionsNames) do
- if string.match(k, pattern ) then table.insert( tSystem, k ) sCommon=common(k,sCommon) end
- end
- else tSystem={} end
- --tPrograms analisis.
- if tPrograms then
- tPrograms = {}
- -- Add programs from the path
- for sPath in string.gmatch(sPath, "[^:]+") do
- if sPath~="." then --skip current folder contents.
- sPath = shell.resolve( sPath )
- if fs.isDir( sPath ) then
- local tList = fs.list( sPath )
- for n,sFile in pairs( tList ) do
- if not fs.isDir( fs.combine( sPath, sFile ) ) then
- if string.match(sFile, pattern ) then table.insert( tPrograms, sFile ) sCommon=common(sFile,sCommon) end
- end
- end
- end
- end
- end
- table.sort( tPrograms )
- else tPrograms={} end
- --future plans?:
- --CTRL+!-0 combos in multishell
- --so you type " and it does "|"
- --if ghost has " " inside and is added quote whole word in if its not quoted already.
- --tFiles analisis
- local tDirs = {}
- if tFiles then
- tFiles={}
- local AllFiles={} --result from list
- local name=fs.getName(sWord.."a")
- name=string.sub( name , 1 , #name-1) --fix for . handling
- local rootpath = shell.resolve(sWord.."a")
- rootpath=string.sub( rootpath , 1 , #rootpath-1) --fix for . handling
- local namelessrootpath = #rootpath==0 and "" or string.sub( rootpath , 1 , #rootpath-#name)
- local path = sWord
- local namelesspath = #path==0 and "" or string.sub( path , 1 , #path-#name)
- local patternfile="^"..string.gsub(name,"[%^%$%(%)%%%.%[%]%*%+%-%?]",function(A) return "%"..A end) --..".*"
- if path=="" then --we are at sDir
- AllFiles=fs.list(sDir)
- namelesspath=sWord
- namelessrootpath=sDir
- elseif string.match(sWord,"[\\/]$") and fs.exists(rootpath) then --ends with / or\ - foldercase or rootcase.
- AllFiles=fs.list(rootpath)
- namelesspath=sWord
- namelessrootpath=rootpath
- elseif fs.exists(namelessrootpath) then --has some content i can match to.
- for i,k in pairs(fs.list(namelessrootpath)) do
- if string.match(k, patternfile ) then
- table.insert(AllFiles,k)
- end
- end
- end
- for i,k in pairs(AllFiles) do
- sCommon=common(namelesspath..k,sCommon)
- if fs.isDir(namelessrootpath..k) then
- table.insert(tDirs,k)
- else
- table.insert(tFiles,k)
- end
- end
- table.sort( tFiles )
- table.sort( tDirs )
- else tFiles={} end
- --if SpecialMode and more then one possibility - print them all.
- if SpecialMode and #tArguments+#tSystem+#tPrograms+#tFiles+#tDirs>1 then
- pcall( function()
- print()
- textutils.pagedTabulate( argumentColour, tArguments , systemColour , tSystem , programColour , tPrograms , dirColour , tDirs , fileColour, tFiles)
- end)
- end
- sCommon = sCommon or ""
- if #tWords>0 then sCommon= (sCommon and string.sub(sCommon, #sWord+1)) or "" end
- local ghost = sCommon..(sSuggestion or "")
- return starts,stops,ghost,sCommon,#tArguments+#tSystem+#tPrograms+#tFiles+#tDirs,#tDirs
- end
- local function tabread( _sReplaceChar, _tHistory , _sPrefix)
- term.setCursorBlink( true )
- local sLine = _sPrefix or ""
- local sGhost = ""
- local nHistoryPos
- local nPos = #sLine
- if _sReplaceChar then
- _sReplaceChar = string.sub( _sReplaceChar, 1, 1 )
- end
- local w = term.getSize()
- local sx = term.getCursorPos()
- local function ghost()
- local last = string.match(sLine,"()[ \t]*$")+1
- if nPos==#sLine then
- local _,_,suggest=tabcomplete(sLine,nPos)
- sGhost = suggest or ""
- else
- sGhost = ""
- end
- end
- local function redraw( _sCustomReplaceChar )
- if _sCustomReplaceChar~=" " then ghost() end
- local nScroll = 0
- if sx + nPos + #sGhost >= w then
- nScroll = (sx + nPos + #sGhost) - w
- end
- local cx,cy = term.getCursorPos()
- term.setCursorPos( sx, cy )
- local sReplace = _sCustomReplaceChar or _sReplaceChar
- if sReplace then
- term.write( string.rep( sReplace, math.max( string.len(sLine) - nScroll, 0 )+string.len(sGhost) ) )
- else
- term.write( string.sub( sLine, nScroll + 1 ) )
- term.setTextColour(ghostColor)
- term.write( sGhost )
- term.setTextColour(textColour)
- end
- term.setCursorPos( sx + nPos - nScroll, cy )
- end
- redraw()
- while true do
- local sEvent, param = os.pullEvent()
- if sEvent == "char" then
- -- Typed key
- redraw(" ")
- sLine = string.sub( sLine, 1, nPos ) .. param .. string.sub( sLine, nPos + 1 )
- nPos = nPos + 1
- redraw()
- elseif sEvent == "paste" then
- -- Pasted text
- redraw(" ")
- sLine = string.sub( sLine, 1, nPos ) .. param .. string.sub( sLine, nPos + 1 )
- nPos = nPos + string.len( param )
- redraw()
- elseif sEvent == "key" then
- if param == keys.enter then
- -- Enter
- if sLine ~= "" and sLine ~= _sPrefix then break end
- elseif param == keys.left then
- -- Left
- if nPos > 0 then
- redraw(" ")
- nPos = nPos - 1
- redraw()
- end
- elseif param == keys.right then
- -- Right
- if nPos < string.len(sLine) then
- redraw(" ")
- nPos = nPos + 1
- redraw()
- end
- elseif param == keys.up or param == keys.down then
- -- Up or down
- if _tHistory then
- redraw(" ")
- if param == keys.up then
- -- Up
- if nHistoryPos == nil then
- if #_tHistory > 0 then
- nHistoryPos = #_tHistory
- end
- elseif nHistoryPos > 1 then
- nHistoryPos = nHistoryPos - 1
- end
- else
- -- Down
- if nHistoryPos == #_tHistory then
- nHistoryPos = nil
- elseif nHistoryPos ~= nil then
- nHistoryPos = nHistoryPos + 1
- end
- end
- if nHistoryPos then
- sLine = _tHistory[nHistoryPos]
- nPos = string.len( sLine )
- else
- sLine = ""
- nPos = 0
- end
- redraw()
- end
- elseif param == keys.backspace then
- -- Backspace
- if nPos > 0 then
- redraw(" ")
- sLine = string.sub( sLine, 1, nPos - 1 ) .. string.sub( sLine, nPos + 1 )
- nPos = nPos - 1
- redraw()
- end
- elseif param == keys.home then
- -- Home
- redraw(" ")
- nPos = 0
- redraw()
- elseif param == keys.delete then
- -- Delete
- if nPos < string.len(sLine) then
- redraw(" ")
- sLine = string.sub( sLine, 1, nPos ) .. string.sub( sLine, nPos + 2 )
- redraw()
- end
- elseif param == keys["end"] then
- -- End
- redraw(" ")
- nPos = string.len(sLine)
- redraw()
- elseif param == keys["tab"] then
- -- Tab
- --redraw(" ")
- term.setCursorBlink( false )
- local Pos1,Pos2,suggest,common,finds,folders=tabcomplete(sLine,nPos,true)
- if finds>0 then --do nothing
- local word=common or ""
- if finds==1 and common then
- redraw(" ")
- if folders==1 then word=word.."/"
- elseif Pos2-1==#sLine then word=word.." " end
- else
- term.setTextColour( promptColour )
- write( shell.dir() .. "> " )
- term.setTextColour( textColour )
- sx, sy = term.getCursorPos()
- end
- --place common inplace
- sLine = string.sub( sLine, 1, Pos2-1 ) .. word .. string.sub( sLine, Pos2 )
- nPos=math.min(math.max(Pos2-1+#word,0),#sLine)
- end
- term.setCursorBlink( true )
- redraw()
- elseif param == keys["pageUp"] then
- --scrollMove(parenth)
- elseif param == keys["pageDown"] then
- --scrollMove(-parenth)
- end
- elseif sEvent == "mouse_scroll" then
- --mouse scroll detected
- --scrollMove(-param)
- elseif sEvent == "term_resize" then
- -- Terminal resized
- w = term.getSize()
- redraw()
- end
- end
- local cx, cy = term.getCursorPos()
- term.setCursorBlink( false )
- term.setCursorPos( w + 1, cy )
- print()
- return sLine
- end
- --special functions testing
- local function tabrun(sLine)
- local tWords = tokenise(sLine)
- local sCommand = tWords[1]
- if tSystemFunctions[sCommand] then
- return pcall( function() tSystemFunctions[sCommand](string.sub( sLine, #sCommand+1)) end)
- end
- return shell.run( sLine )
- end
- --back to almost normal execution
- local tArgs = { ... }
- if #tArgs > 0 then
- -- "shell x y z"
- -- Run the program specified on the commandline
- shell.run( ... )
- else
- -- "shell"
- -- Print the header
- if term.getCursorPos()>1 then print() end
- term.setBackgroundColor( bgColour )
- term.setTextColour( promptColour )
- print( os.version()," Extended" )
- term.setTextColour( textColour )
- -- Run the startup program
- if parentShell == nil then
- shell.run( "/rom/startup" )
- end
- --pernament history.
- local tCommandHistoryfile=fs.combine(saveDir,".shell.log")
- local tCommandHistory = {}
- if fs.exists(tCommandHistoryfile) then tCommandHistory = getT(tCommandHistoryfile) or {} end
- -- Read commands and execute them
- while not bExit do
- term.redirect( parentTerm )
- term.setBackgroundColor( bgColour )
- term.setTextColour( promptColour )
- --local tx,ty=term.getCursorPos()
- if term.getCursorPos()>1 then print() end
- write( shell.dir() .. "> " )
- term.setTextColour( textColour )
- local sLine = tabread( nil, tCommandHistory, nextPrefix)
- if sLine ~= tCommandHistory[#tCommandHistory] then
- table.insert( tCommandHistory, sLine )
- if tCommandHistory[101] then table.remove(tCommandHistory,1) end
- saveTL(tCommandHistoryfile,tCommandHistory)
- end
- nextPrefix=""
- tabrun( sLine )--shell.run( sLine )--
- end
- --fixing stuff
- term.setBackgroundColor( bgColour )
- term.setTextColour( promptColour )
- print( os.version()," Extended Shutting Down" )
- term.setTextColour( textColour )
- term.redirect( parentTerm )
- end
Add Comment
Please, Sign In to add comment