Guest User

shell

a guest
Jul 24th, 2016
59
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 9.13 KB | None | 0 0
  1.  
  2. local multishell = multishell
  3. local parentShell = shell
  4. local parentTerm = term.current()
  5.  
  6. if multishell then
  7.     multishell.setTitle( multishell.getCurrent(), "shell" )
  8. end
  9.  
  10. local bExit = false
  11. local sDir = (parentShell and parentShell.dir()) or ""
  12. local sPath = (parentShell and parentShell.path()) or ".:/rom/programs"
  13. local tAliases = (parentShell and parentShell.aliases()) or {}
  14. local tCompletionInfo = (parentShell and parentShell.getCompletionInfo()) or {}
  15. local tProgramStack = {}
  16.  
  17. local shell = {}
  18. local tEnv = {
  19.     [ "shell" ] = shell,
  20.     [ "multishell" ] = multishell,
  21. }
  22.  
  23. -- Colours
  24. local promptColour, textColour, bgColour
  25. if term.isColour() then
  26.     promptColour = colours.yellow
  27.     textColour = colours.white
  28.     bgColour = colours.black
  29. else
  30.     promptColour = colours.white
  31.     textColour = colours.white
  32.     bgColour = colours.black
  33. end
  34.  
  35. local function run( _sCommand, ... )
  36.     local sPath = shell.resolveProgram( _sCommand )
  37.     if sPath ~= nil then
  38.         tProgramStack[#tProgramStack + 1] = sPath
  39.         if multishell then
  40.             multishell.setTitle( multishell.getCurrent(), fs.getName( sPath ) )
  41.         end
  42.         local result = os.run( tEnv, sPath, ... )
  43.         tProgramStack[#tProgramStack] = nil
  44.         if multishell then
  45.             if #tProgramStack > 0 then
  46.                 multishell.setTitle( multishell.getCurrent(), fs.getName( tProgramStack[#tProgramStack] ) )
  47.             else
  48.                 multishell.setTitle( multishell.getCurrent(), "shell" )
  49.             end
  50.         end
  51.         return result
  52.     else
  53.         printError( "No such program" )
  54.         return false
  55.     end
  56. end
  57.  
  58. local function tokenise( ... )
  59.     local sLine = table.concat( { ... }, " " )
  60.     local tWords = {}
  61.     local bQuoted = false
  62.     for match in string.gmatch( sLine .. "\"", "(.-)\"" ) do
  63.         if bQuoted then
  64.             table.insert( tWords, match )
  65.         else
  66.             for m in string.gmatch( match, "[^ \t]+" ) do
  67.                 table.insert( tWords, m )
  68.             end
  69.         end
  70.         bQuoted = not bQuoted
  71.     end
  72.     return tWords
  73. end
  74.  
  75. -- Install shell API
  76. function shell.run( ... )
  77.     local tWords = tokenise( ... )
  78.     local sCommand = tWords[1]
  79.     if sCommand then
  80.         return run( sCommand, table.unpack( tWords, 2 ) )
  81.     end
  82.     return false
  83. end
  84.  
  85. function shell.exit()
  86.     bExit = true
  87. end
  88.  
  89. function shell.dir()
  90.     return sDir
  91. end
  92.  
  93. function shell.setDir( _sDir )
  94.     sDir = _sDir
  95. end
  96.  
  97. function shell.path()
  98.     return sPath
  99. end
  100.  
  101. function shell.setPath( _sPath )
  102.     sPath = _sPath
  103. end
  104.  
  105. function shell.resolve( _sPath )
  106.     local sStartChar = string.sub( _sPath, 1, 1 )
  107.     if sStartChar == "/" or sStartChar == "\\" then
  108.         return fs.combine( "", _sPath )
  109.     else
  110.         return fs.combine( sDir, _sPath )
  111.     end
  112. end
  113.  
  114. function shell.resolveProgram( _sCommand )
  115.     -- Substitute aliases firsts
  116.     if tAliases[ _sCommand ] ~= nil then
  117.         _sCommand = tAliases[ _sCommand ]
  118.     end
  119.  
  120.     -- If the path is a global path, use it directly
  121.     local sStartChar = string.sub( _sCommand, 1, 1 )
  122.     if sStartChar == "/" or sStartChar == "\\" then
  123.         local sPath = fs.combine( "", _sCommand )
  124.         if fs.exists( sPath ) and not fs.isDir( sPath ) then
  125.             return sPath
  126.         end
  127.         return nil
  128.     end
  129.    
  130.     -- Otherwise, look on the path variable
  131.     for sPath in string.gmatch(sPath, "[^:]+") do
  132.         sPath = fs.combine( shell.resolve( sPath ), _sCommand )
  133.         if fs.exists( sPath ) and not fs.isDir( sPath ) then
  134.             return sPath
  135.         end
  136.     end
  137.    
  138.     -- Not found
  139.     return nil
  140. end
  141.  
  142. function shell.programs( _bIncludeHidden )
  143.     local tItems = {}
  144.    
  145.     -- Add programs from the path
  146.     for sPath in string.gmatch(sPath, "[^:]+") do
  147.         sPath = shell.resolve( sPath )
  148.         if fs.isDir( sPath ) then
  149.             local tList = fs.list( sPath )
  150.             for n=1,#tList do
  151.                 local sFile = tList[n]
  152.                 if not fs.isDir( fs.combine( sPath, sFile ) ) and
  153.                    (_bIncludeHidden or string.sub( sFile, 1, 1 ) ~= ".") then
  154.                     tItems[ sFile ] = true
  155.                 end
  156.             end
  157.         end
  158.     end
  159.  
  160.     -- Sort and return
  161.     local tItemList = {}
  162.     for sItem, b in pairs( tItems ) do
  163.         table.insert( tItemList, sItem )
  164.     end
  165.     table.sort( tItemList )
  166.     return tItemList
  167. end
  168.  
  169. local function completeProgram( sLine )
  170.     if #sLine > 0 and string.sub( sLine, 1, 1 ) == "/" then
  171.         -- Add programs from the root
  172.         return fs.complete( sLine, "", true, false )
  173.  
  174.     else
  175.         local tResults = {}
  176.         local tSeen = {}
  177.  
  178.         -- Add aliases
  179.         for sAlias, sCommand in pairs( tAliases ) do
  180.             if #sAlias > #sLine and string.sub( sAlias, 1, #sLine ) == sLine then
  181.                 local sResult = string.sub( sAlias, #sLine + 1 )
  182.                 if not tSeen[ sResult ] then
  183.                     table.insert( tResults, sResult )
  184.                     tSeen[ sResult ] = true
  185.                 end
  186.             end
  187.         end
  188.  
  189.         -- Add programs from the path
  190.         local tPrograms = shell.programs()
  191.         for n=1,#tPrograms do
  192.             local sProgram = tPrograms[n]
  193.             if #sProgram > #sLine and string.sub( sProgram, 1, #sLine ) == sLine then
  194.                 local sResult = string.sub( sProgram, #sLine + 1 )
  195.                 if not tSeen[ sResult ] then
  196.                     table.insert( tResults, sResult )
  197.                     tSeen[ sResult ] = true
  198.                 end
  199.             end
  200.         end
  201.  
  202.         -- Sort and return
  203.         table.sort( tResults )
  204.         return tResults
  205.     end
  206. end
  207.  
  208. local function completeProgramArgument( sProgram, nArgument, sPart, tPreviousParts )
  209.     local tInfo = tCompletionInfo[ sProgram ]
  210.     if tInfo then
  211.         return tInfo.fnComplete( shell, nArgument, sPart, tPreviousParts )
  212.     end
  213.     return nil
  214. end
  215.  
  216. function shell.complete( sLine )
  217.     if #sLine > 0 then
  218.         local tWords = tokenise( sLine )
  219.         local nIndex = #tWords
  220.         if string.sub( sLine, #sLine, #sLine ) == " " then
  221.             nIndex = nIndex + 1
  222.         end
  223.         if nIndex == 1 then
  224.             local sBit = tWords[1] or ""
  225.             local sPath = shell.resolveProgram( sBit )
  226.             if tCompletionInfo[ sPath ] then
  227.                 return { " " }
  228.             else
  229.                 local tResults = completeProgram( sBit )
  230.                 for n=1,#tResults do
  231.                     local sResult = tResults[n]
  232.                     local sPath = shell.resolveProgram( sBit .. sResult )
  233.                     if tCompletionInfo[ sPath ] then
  234.                         tResults[n] = sResult .. " "
  235.                     end
  236.                 end
  237.                 return tResults
  238.             end
  239.  
  240.         elseif nIndex > 1 then
  241.             local sPath = shell.resolveProgram( tWords[1] )
  242.             local sPart = tWords[nIndex] or ""
  243.             local tPreviousParts = tWords
  244.             tPreviousParts[nIndex] = nil
  245.             return completeProgramArgument( sPath , nIndex - 1, sPart, tPreviousParts )
  246.  
  247.         end
  248.     end
  249.     return nil
  250. end
  251.  
  252. function shell.completeProgram( sProgram )
  253.     return completeProgram( sProgram )
  254. end
  255.  
  256. function shell.setCompletionFunction( sProgram, fnComplete )
  257.     tCompletionInfo[ sProgram ] = {
  258.         fnComplete = fnComplete
  259.     }
  260. end
  261.  
  262. function shell.getCompletionInfo()
  263.     return tCompletionInfo
  264. end
  265.  
  266. function shell.getRunningProgram()
  267.     if #tProgramStack > 0 then
  268.         return tProgramStack[#tProgramStack]
  269.     end
  270.     return nil
  271. end
  272.  
  273. function shell.setAlias( _sCommand, _sProgram )
  274.     tAliases[ _sCommand ] = _sProgram
  275. end
  276.  
  277. function shell.clearAlias( _sCommand )
  278.     tAliases[ _sCommand ] = nil
  279. end
  280.  
  281. function shell.aliases()
  282.     -- Copy aliases
  283.     local tCopy = {}
  284.     for sAlias, sCommand in pairs( tAliases ) do
  285.         tCopy[sAlias] = sCommand
  286.     end
  287.     return tCopy
  288. end
  289.  
  290. if multishell then
  291.     function shell.openTab( ... )
  292.         local tWords = tokenise( ... )
  293.         local sCommand = tWords[1]
  294.         if sCommand then
  295.             local sPath = shell.resolveProgram( sCommand )
  296.             if sPath == "rom/programs/shell" then
  297.                 return multishell.launch( tEnv, sPath, table.unpack( tWords, 2 ) )
  298.             elseif sPath ~= nil then
  299.                 return multishell.launch( tEnv, "rom/programs/shell", sCommand, table.unpack( tWords, 2 ) )
  300.             else
  301.                 printError( "No such program" )
  302.             end
  303.         end
  304.     end
  305.  
  306.     function shell.switchTab( nID )
  307.         multishell.setFocus( nID )
  308.     end
  309. end
  310.  
  311. local tArgs = { ... }
  312. if #tArgs > 0 then
  313.     -- "shell x y z"
  314.     -- Run the program specified on the commandline
  315.     shell.run( ... )
  316.  
  317. else
  318.     -- "shell"
  319.     -- Print the header
  320.     term.setBackgroundColor( bgColour )
  321.     term.setTextColour( promptColour )
  322.     print( os.version() )
  323.     term.setTextColour( textColour )
  324.  
  325.     -- Run the startup program
  326.     if parentShell == nil then
  327.         shell.run( "/rom/startup" )
  328.     end
  329.  
  330.     -- Read commands and execute them
  331.     local tCommandHistory = {}
  332.     while not bExit do
  333.         term.redirect( parentTerm )
  334.         term.setBackgroundColor( bgColour )
  335.         term.setTextColour( promptColour )
  336.         write( shell.dir() .. "> " )
  337.         term.setTextColour( textColour )
  338.  
  339.         local sLine = read( nil, tCommandHistory, shell.complete )
  340.         table.insert( tCommandHistory, sLine )
  341.         shell.run( sLine )
  342.     end
  343. end
Add Comment
Please, Sign In to add comment