Advertisement
Guest User

multishell

a guest
Dec 1st, 2015
85
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 9.18 KB | None | 0 0
  1.  
  2. -- Setup process switching
  3. local parentTerm = term.current()
  4. local w,h = parentTerm.getSize()
  5.  
  6. local tProcesses = {}
  7. local nCurrentProcess = nil
  8. local nRunningProcess = nil
  9. local bShowMenu = false
  10. local bWindowsResized = false
  11.  
  12. local function selectProcess( n )
  13.     if nCurrentProcess ~= n then
  14.         if nCurrentProcess then
  15.             local tOldProcess = tProcesses[ nCurrentProcess ]
  16.             tOldProcess.window.setVisible( false )
  17.         end
  18.         nCurrentProcess = n
  19.         if nCurrentProcess then
  20.             local tNewProcess = tProcesses[ nCurrentProcess ]
  21.             tNewProcess.window.setVisible( true )
  22.             tNewProcess.bInteracted = true
  23.         end
  24.     end
  25. end
  26.  
  27. local function setProcessTitle( n, sTitle )
  28.     tProcesses[ n ].sTitle = sTitle
  29. end
  30.  
  31. local function resumeProcess( nProcess, sEvent, ... )
  32.     local tProcess = tProcesses[ nProcess ]
  33.     local sFilter = tProcess.sFilter
  34.     if sFilter == nil or sFilter == sEvent or sEvent == "terminate" then
  35.         local nPreviousProcess = nRunningProcess
  36.         nRunningProcess = nProcess
  37.         term.redirect( tProcess.terminal )
  38.         local ok, result = coroutine.resume( tProcess.co, sEvent, ... )
  39.         tProcess.terminal = term.current()
  40.         if ok then
  41.             tProcess.sFilter = result
  42.         else
  43.             printError( result )
  44.         end
  45.         nRunningProcess = nPreviousProcess
  46.     end
  47. end
  48.  
  49. local function launchProcess( tProgramEnv, sProgramPath, ... )
  50.     local tProgramArgs = { ... }
  51.     local nProcess = #tProcesses + 1
  52.     local tProcess = {}
  53.     tProcess.sTitle = fs.getName( sProgramPath )
  54.     if bShowMenu then
  55.         tProcess.window = window.create( parentTerm, 1, 2, w, h-1, false )
  56.     else
  57.         tProcess.window = window.create( parentTerm, 1, 1, w, h, false )
  58.     end
  59.     tProcess.co = coroutine.create( function()
  60.         os.run( tProgramEnv, sProgramPath, table.unpack( tProgramArgs ) )
  61.         if not tProcess.bInteracted then
  62.             term.setCursorBlink( false )
  63.             print( "Press any key to continue" )
  64.             os.pullEvent( "char" )
  65.         end
  66.     end )
  67.     tProcess.sFilter = nil
  68.     tProcess.terminal = tProcess.window
  69.     tProcess.bInteracted = false
  70.     tProcesses[ nProcess ] = tProcess
  71.     resumeProcess( nProcess )
  72.     return nProcess
  73. end
  74.  
  75. local function cullProcess( nProcess )
  76.     local tProcess = tProcesses[ nProcess ]
  77.     if coroutine.status( tProcess.co ) == "dead" then
  78.         if nCurrentProcess == nProcess then
  79.             selectProcess( nil )
  80.         end
  81.         table.remove( tProcesses, nProcess )
  82.         if nCurrentProcess == nil then
  83.             if nProcess > 1 then
  84.                 selectProcess( nProcess - 1 )
  85.             elseif #tProcesses > 0 then
  86.                 selectProcess( 1 )
  87.             end
  88.         end
  89.         return true
  90.     end
  91.     return false
  92. end
  93.  
  94. local function cullProcesses()
  95.     local culled = false
  96.     for n=#tProcesses,1,-1 do
  97.         culled = culled or cullProcess( n )
  98.     end
  99.     return culled
  100. end
  101.  
  102. -- Setup the main menu
  103. local menuMainTextColor, menuMainBgColor, menuOtherTextColor, menuOtherBgColor
  104. if parentTerm.isColor() then
  105.     menuMainTextColor, menuMainBgColor = colors.white, colors.lightBlue
  106.     menuOtherTextColor, menuOtherBgColor = colors.gray, colors.blue
  107. else
  108.     menuMainTextColor, menuMainBgColor = colors.white, colors.black
  109.     menuOtherTextColor, menuOtherBgColor = colors.black, colors.white
  110. end
  111.  
  112. local function redrawMenu()
  113.     if bShowMenu then
  114.         -- Draw menu
  115.         parentTerm.setCursorPos( 1, 1 )
  116.         parentTerm.setBackgroundColor( menuOtherBgColor )
  117.         parentTerm.clearLine()
  118.         for n=1,#tProcesses do
  119.             if n == nCurrentProcess then
  120.                 parentTerm.setTextColor( menuMainTextColor )
  121.                 parentTerm.setBackgroundColor( menuMainBgColor )
  122.             else
  123.                 parentTerm.setTextColor( menuOtherTextColor )
  124.                 parentTerm.setBackgroundColor( menuOtherBgColor )
  125.             end
  126.             parentTerm.write( " " .. tProcesses[n].sTitle .. " " )
  127.         end
  128.  
  129.         -- Put the cursor back where it should be
  130.         local tProcess = tProcesses[ nCurrentProcess ]
  131.         if tProcess then
  132.             tProcess.window.restoreCursor()
  133.         end
  134.     end
  135. end
  136.  
  137. local function resizeWindows()
  138.     local windowY, windowHeight
  139.     if bShowMenu then
  140.         windowY = 2
  141.         windowHeight = h-1
  142.     else
  143.         windowY = 1
  144.         windowHeight = h
  145.     end
  146.     for n=1,#tProcesses do
  147.         local tProcess = tProcesses[n]
  148.         local window = tProcess.window
  149.         local x,y = tProcess.window.getCursorPos()
  150.         if y > windowHeight then
  151.             tProcess.window.scroll( y - windowHeight )
  152.             tProcess.window.setCursorPos( x, windowHeight )
  153.         end
  154.         tProcess.window.reposition( 1, windowY, w, windowHeight )
  155.     end
  156.     bWindowsResized = true
  157. end
  158.  
  159. local function setMenuVisible( bVis )
  160.     if bShowMenu ~= bVis then
  161.         bShowMenu = bVis
  162.         resizeWindows()
  163.         redrawMenu()
  164.     end
  165. end
  166.  
  167. local multishell = {}
  168.  
  169. function multishell.getFocus()
  170.     return nCurrentProcess
  171. end
  172.  
  173. function multishell.setFocus( n )
  174.     if n >= 1 and n <= #tProcesses then
  175.         selectProcess( n )
  176.         redrawMenu()
  177.         return true
  178.     end
  179.     return false
  180. end
  181.  
  182. function multishell.getTitle( n )
  183.     if n >= 1 and n <= #tProcesses then
  184.         return tProcesses[n].sTitle
  185.     end
  186.     return nil
  187. end
  188.  
  189. function multishell.setTitle( n, sTitle )
  190.     if n >= 1 and n <= #tProcesses then
  191.         setProcessTitle( n, sTitle )
  192.         redrawMenu()
  193.     end
  194. end
  195.  
  196. function multishell.getCurrent()
  197.     return nRunningProcess
  198. end
  199.  
  200. function multishell.launch( tProgramEnv, sProgramPath, ... )
  201.     local previousTerm = term.current()
  202.     setMenuVisible( (#tProcesses + 1) >= 2 )
  203.     local nResult = launchProcess( tProgramEnv, sProgramPath, ... )
  204.     redrawMenu()
  205.     term.redirect( previousTerm )
  206.     return nResult
  207. end
  208.  
  209. function multishell.getCount()
  210.     return #tProcesses
  211. end
  212.  
  213. -- Begin
  214. parentTerm.clear()
  215. setMenuVisible( false )
  216. selectProcess( launchProcess( {
  217.     ["shell"] = shell,
  218.     ["multishell"] = multishell,
  219. }, "/rom/programs/shell" ) )
  220. redrawMenu()
  221.  
  222. -- Run processes
  223. while #tProcesses > 0 do
  224.     -- Get the event
  225.     local tEventData = { os.pullEventRaw() }
  226.     local sEvent = tEventData[1]
  227.     if sEvent == "term_resize" then
  228.         -- Resize event
  229.         w,h = parentTerm.getSize()
  230.         resizeWindows()
  231.         redrawMenu()
  232.  
  233.     elseif sEvent == "char" or sEvent == "key" or sEvent == "key_up" or sEvent == "paste" or sEvent == "terminate" then
  234.         -- Keyboard event
  235.         -- Passthrough to current process
  236.         resumeProcess( nCurrentProcess, table.unpack( tEventData ) )
  237.         if cullProcess( nCurrentProcess ) then
  238.             setMenuVisible( #tProcesses >= 2 )
  239.             redrawMenu()
  240.         end
  241.  
  242.     elseif sEvent == "mouse_click" then
  243.         -- Click event
  244.         local button, x, y = tEventData[2], tEventData[3], tEventData[4]
  245.         if bShowMenu and y == 1 then
  246.             -- Switch process
  247.             local tabStart = 1
  248.             for n=1,#tProcesses do
  249.                 tabEnd = tabStart + string.len( tProcesses[n].sTitle ) + 1
  250.                 if x >= tabStart and x <= tabEnd then
  251.                     selectProcess( n )
  252.                     redrawMenu()
  253.                     break
  254.                 end
  255.                 tabStart = tabEnd + 1
  256.             end
  257.         else
  258.             -- Passthrough to current process
  259.             resumeProcess( nCurrentProcess, sEvent, button, x, (bShowMenu and y-1) or y )
  260.             if cullProcess( nCurrentProcess ) then
  261.                 setMenuVisible( #tProcesses >= 2 )
  262.                 redrawMenu()
  263.             end
  264.         end
  265.  
  266.     elseif sEvent == "mouse_drag" or sEvent == "mouse_up" or sEvent == "mouse_scroll" then
  267.         -- Other mouse event
  268.         local p1, x, y = tEventData[2], tEventData[3], tEventData[4]
  269.         if not (bShowMenu and y == 1) then
  270.             -- Passthrough to current process
  271.             resumeProcess( nCurrentProcess, sEvent, p1, x, (bShowMenu and y-1) or y )
  272.             if cullProcess( nCurrentProcess ) then
  273.                 setMenuVisible( #tProcesses >= 2 )
  274.                 redrawMenu()
  275.             end
  276.         end
  277.  
  278.     else
  279.         -- Other event
  280.         -- Passthrough to all processes
  281.         local nLimit = #tProcesses -- Storing this ensures any new things spawned don't get the event
  282.         for n=1,nLimit do
  283.             resumeProcess( n, table.unpack( tEventData ) )
  284.         end
  285.         if cullProcesses() then
  286.             setMenuVisible( #tProcesses >= 2 )
  287.             redrawMenu()
  288.         end
  289.     end
  290.  
  291.     if bWindowsResized then
  292.         -- Pass term_resize to all processes
  293.         local nLimit = #tProcesses -- Storing this ensures any new things spawned don't get the event
  294.         for n=1,nLimit do
  295.             resumeProcess( n, "term_resize" )
  296.         end
  297.         bWindowsResized = false
  298.         if cullProcesses() then
  299.             setMenuVisible( #tProcesses >= 2 )
  300.             redrawMenu()
  301.         end
  302.     end
  303. end
  304.  
  305. -- Shutdown
  306. term.redirect( parentTerm )
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement